...In Which We Triumph Over Barcraft Streaming Woes

We just finished up a Barcraft at Pluckers here in Austin, and I thought I'd do a post on the video issues we had and the goofy hack I pulled together to make the technical side work.

Before all the text, here are some shiny pictures:

(download)

Note: All those familiar with Barcraft / Starcraft skip the next few paragraphs.

<barcraft:summary>

If you are unfamiliar with a Barcraft, it's simply a group of awesome nerds getting together to watch an eSports event. What means eSports? It's competitive video gaming with cash prizes, sponsorships, professional video gamers, etc. Yes, it's real, yes it's gaining popularity, and yes, it's geeky. As geeky as watching competitve poker, chess, or, in my opinion, some of the "traditional" sports. 

At any rate, it is possible (although rare) for a player to become so good at certain video games that they can play it full time, enabled by sponsorships and tournament winnings. See this site to see the winnings of some of the best Starcraft players, and remember this doesn't include salaries paid by the team / sponsors.

Starcraft is a complicated strategy game, something like real time Risk + chess where the pieces can shoot each other. In summary, you gather resources to build up an army to defeat an opponent's army. 

Anyway, we get a big group of people together to watch the larger tournaments.

</barcraft:summary>

Pluckers is a great place for a Barcraft -- lots of TVs, a bar, a dining area, and a patio. Everyone loves wings, and most people love a fried Twinkie. So when the Barcraft outgrew the last location, Andrew (our tireless leader and the producer of a Starcraft documentary) pulled strings and now we have room for nearly 300 people for the biggest events.

Dsc00196

However...

As I assume is common at sports bars, Pluckers does not have a well-engineered A/V solution. Approximately two thirds of the televisions are wired to use the same composite (old-school RCA / standard definition) source, but the other televisions support either HDMI or VGA, and have to be hooked up individually. Some of them are just inaccessible.

At the last Barcraft, this limitation wasn't known in time to try to fix it. So, to support all the televisions for the ~250 people who showed up, we had four or five laptops, each streaming from the MLG live site, hooked up to the various "clumps" of televisions. This meant that the streams were anywhere between 5 and 45 seconds apart, and we saturated the Plucker's network and had terrible buffering problems, usually during the best parts of the games.

The situation remained the same as this Barcraft approached, so I tried a number of different solutions. I tried wireless HDMI transmitters, but the consumer ones were garbage and renting a decent system was over $600. I looked into HDMI -> cat5e systems, but the pricing was similar and we would have had network cables and HDMI splitters all over the place.

Finally, I decided we could just "re-stream" the screen contents of a single computer streaming from the live site. The other laptops would then "re-broadcast" the internal stream, ensuring the majority of the traffic occurs within the internal network. Additionally, the televisions all show the exact same source, and are mostly synced (at least within half a second or so).

Recipe for Successful Hackery

If you find yourself in a similar situation, here are the technical bits to recreate my setup. You're going to need a few ingredients:

  • A "source" laptop / computer (for these instructions, running Ubuntu Linux, but you can do it with Mac and probably Windows as well)
  • One or more "destination" laptops hooked up to televisions, projectors, what have you.
  • VLC installed on every machine.
  • FFMPEG installed on the "source" laptop (optional, but the way I prefer)
  • All laptops connected to the same network, via wired connections.
    • We tried wireless for a while, but get enough people using smartphones and laptops within the same space and you are asking for interference, dropped frames, and artifacts.

If you are following closely, and have Ubuntu on your "source" box, run the following command to install the necessary pieces:

sudo apt-get install vlc ffmpeg pavucontrol

Once that's complete, you can drop the following script contents into a file called "screenshare.sh" (or whatever you want):

 

 

You'll need to run chmod a+x screenshare.sh so you can execute it, and change any parameters to tweak the output quality. If you are video savvy, you'll notice I'm doing a high(ish) bitrate MPEG2 stream instead of an H.264 stream. The reason for this is that if you are streaming from a web site, it is 99.9% likely to be H.264, and 99.9% likely to be through Flash. (note: I just completely made up those numbers.) Watching H.264, especially through Flash, and especially at HD / high quality, is already utilizing a fair chunk of your system's resources -- I decided that throwing a fast-but-large MPEG2 stream down the internal network was just a smarter choice. Feel free to argue, and post your improvements in the comments if you are awesome.

Note that you can certainly accomplish this on Mac (and probably Windows), and you might not even need ffmpeg. I like to control all aspects of the stream, and ffmpeg is my buddy for life, so this is how I rolled.

Once you have that set up, simply run ./screenshare.sh on the "source" laptop and you should see ffmpeg printing out framerates, bitrates, etc. Now, armed with the IP address of your "source" laptop, go to each "destination" laptop, open VLC, click Media -> Open Network Stream... and enter rtsp://10.10.10.10:5544/stream in the URL field, replacing 10.10.10.10 with the IP address of your source computer.

Dsc00150

After a few seconds, you should have marvelous 720p video streaming, nearly synced, to all of your devices. Note that this isn't terribly scalable -- in the end, we had a total of four laptops streaming (and a few mobile phones, oddly enough) and the network handled it beautifully, but your results may vary depending on what you are doing. (It is not advised to download torrents during this process. :))

The End

Anyway, that's the long and short of it. We had a blast, had 100-something people show up, and once we got the kinks worked out, the stream was solid. We still need to work out some quality issues (I hate streaming 720p only to end up with half the televisions showing standard definition), and obviously it would be nice to not have to deal with any of this. However, until Pluckers upgrades its A/V system, this should work nicely for us.

Let me know if you find this useful, or if you have improvements / issues getting it to work.

Shoutout to Mothership, a new gaming-centered store in Austin, and SteelSeries for sponsoring this month's Barcraft. Also to Andrew, who does all the real work and toils without rest to ensure we all have an awesome Barcraft experience.

A Python Script for Teleporting your Mouse!

<TLDR>Get the script here.</TLDR>

(This is mostly for Linux users -- Mac users look elsewhere.)

So, I finally got around to playing with x2x. For those of you who are unfamiliar, it allows you to control a remote machine with a local machine's input devices (mouse, keyboard). Some of you are saying "Aha! That's what they invented VNC for!" x2x is different -- it doesn't actually display what's on the other screen, but rather treats the remote monitor / TV like another attached display.

It is great for our controlling our home HTPC when it's running Google Music, RDIO, XMBC, etc. while I'm working on my laptop. I can just scroll over to the right and I'm controlling the TV, which is miles better than a crappy remote or ridiculously slow VNC refreshes when playing 1080p video.

Anyway, after browsing a blog post that wrote a couple of bash script wrappers, I thought, "Hey, Python can do that, maybe a bit better."

So, here's my github gist for the mouseporter script that starts an x2x session. You'll need Python 2.6+, x2x on both the remote machine and local machine, and faith in code downloaded from the intarwebz. :)

All you have to do (on Ubuntu, anyway) is:

 

Here's an embedded version of the Gist for copying / pasting.

Simple Socket.IO Chat Room Creator

So, yeah, I guess there's something to all this Node.JS hype. :)

I've been toying around with different modules (express, zeromq, socket.io) for a side project idea, and I have to say it's been a lot of fun. CoffeeScript + Node.JS is even better. I think Python may be getting a bit jealous. (I still love you Tornado. :))

Anyway, I decided to throw the goofy chat room creator (like EVERY OTHER Socket.IO "experiment") up on a server and github. (It's not in CoffeeScript though.)

<friends>It's UBERCHAT -- It's new, it's (not) German, it's extra tough!</friends>

(download)

Really basic, supports room creation with random id room URLs, simple private messaging, away / active, etc. Also supports crashing, I'm sure. There's no persistence or anything clever yet, so if the one instance of Node goes, so do all the rooms. :) Gogo redis... later.

Best Poboys in Austin

(download)

I usually post about Python and dev stuff, but I figured I'd share my new food obsession.

At 3rd and Congress, there's a trailer called Turf n Surf that serves fantastic poboys. My personal favorite is the Kiss yo Mama, which has bacon wrapped grilled shrimp, fresh slaw, and loads of awesome.

Anyway, if you are in the area, check em out.

Espresso Vim Plugin

Totally forgot to post this a few days ago when I put it up on Github. I wrote a quick little CoffeeScript –> minified Javascript compiler plugin for vim the other day, out of total laziness. It uses the CoffeeScript syntax library from the original CoffeeScript vim project. I call it Espresso because I think I’m clever.

You’ll need to have CoffeeScript and JSMin available in the path, and I’ve only tested it in Linux, so let me know if it explodes on you.

Introduction to Tornado

So I did an introduction to Tornado talk at the recent Austin Web Python Users' Group (or AWPUG as it is better known). It was a lot more fun for me than I bet it was for those who had to hear me yammer on. Thankfully, Travis Swicegood followed with an excellent talk on Class-based views in Django 1.3.

Someone had a Flip video camera going, so the intarweb may soon be blasted with my incomprehensible jabbering.

Anyway, here are the slides from my talk:

Also, I made a fake site for people to see how one might construct an async API-dependent website in Tornado pretty quickly. It depends on Torn, a project a few of us are working on which shamelessly apes a subset of django-admin.py, just for Tornado sites.

As an aside, someone asked me a question about why you would pick Tornado over gevent, when gevent will let you use any WSGI framework on top of magically asynchronous sockets. I mumbled something about "explicit versus implicit" and the Zen of Python, but in retrospect I totally bombed that question.

While the explicit nature of Tornado IS awesome, as is the performance of epoll, etc., Tornado is genius in the fact that it somehow manages to provide very low-level, simple access to all parts of the HTTP request-response cycle and yet simultaneously includes most helpers you might need for building a slick web application. By overwriting a few methods, I can create a custom authentication system in a few lines, using whatever data backend I choose.

You can do the same with Django, but the difference is that Django's shortcuts tend to make you follow Django conventions. Tornado provides the tools to easily create your own. Tie that in with slick async single-sign-on libraries for Twitter, Facebook, Google, OAuth, etc. and that's just one simple example of one of Tornado's many benefits. Personally, I just tend to work faster in Tornado, with more flexibility.

Anyway, that's what I should have said. :)

Laziness FTW

So, I'm horrible at maintaining a blog. I'm going to be oblivious to my own weaknesses and assume it's because managing my own Wordpress installation is just too time consuming (or some other equally inaccurate reason I'm too lazy to post), and I've ported all my stuff to Posterous now. I can just email a post now, so surely I'll be more proactive, right?

...yeah...

Anyway, my massive library of something like ten posts have been imported here, and all the code formatting, etc. has disappeared. Let's see how long I go before forgetting to update for another year and a half...

URL Checker

I wrote a quick Python script designed to search a file / remote address for URLs and return the HTTP status codes for each one. It's quick and dirty, and the regex needs some tweaking, but for the most part it works. The reason I didn't just use a link checker is that I was actually testing RSS feeds, so this was designed to grab URLs throughout the feed as opposed to just A tags. It lists anything in the 40x range.

Read the rest of this post »

Tornado RPC Library on Google Code

I finished my JSON-RPC and XML-RPC handlers for Tornado, and so I've thrown them up on Google Code. Now people can test my JSON-RPC v2.0 implementation on my jsonrpclib library. :) Which is just what everyone was dying to do, I'm sure. Usage is pretty simple, it's designed to be a.) pretty transparent and b.) easily ported between XML-RPC and JSON-RPC to compare speed, network transfer, etc. times. For example, here's the complete code for XML-RPC client (after installing Tornado and the TornadoRPC library):

To use JSON-RPC, you'd just change any instance of xml/XML to json/JSON. There are several benefits to using JSON, such as smaller transfer size, keyword arguments, notifications, etc., but to use it you are required to install my jsonrpclib implementation.