This week I’ve been looking at using Strophe and Greasemonkey to try to make an evocative but simple two-screen prototype for web-based on demand video. It was a bit fiddly in parts but it’s very useful once you get it going. Danbri has been building prototypes like these for some time, but it’s taken me this long to get round to having my own version working because you need your own XMPP server (that’s not strictly true, but more on that later). R&D Prototyping team have also recently been creating demonstrations with a similar setup. This is a technical blog post which should help you create a similar setup if you are interested in this technique.
Why are we doing this?
In the NoTube social web area we are experimenting with using XMPP for communication between devices, primarily because we want to look at social APIs for TV – and XMPP provides a lot of the infrastructure we need there (such as friends, groups, messaging). First we need some basic control of video, so before we start putting friends into the mixture we are implementing some of the usual remote commands such as play / pause, and also ‘nowp’ (now playing).
We’ve done this with an XMPP python bot talking to MythTV and an iPhone as a controller, but it was slow work to build the iPhone interface, and the client code isn’t usable on other non-Apple devices.
Getting it working
The basic process is this:
- Install jabber server
- Create two accounts and make them friends
- Put an http rewrite file in the right place
- Create ‘near’ and ‘far’ webpages to represent the remote and player
- Create a Greasemonkey script and iFrame for the web based video player
A word of warning: this is fiddly. Things are changing in the APIs in browsers, in particular, cross-domain iframe loopholes are being closed and browsers are using the postmessage system instead, which is fine, as long we you realise what’s going on (and can control the iframe content, which is why we need Greasemonkey).
Here’s each step in a bit more detail.
By far the least confusing way of getting this working is to create a new domain, e.g. jabber.yourdomain.com. You’ll need to fix the DNS with your provider and then edit apache virtual hosts file (for me on ubuntu it’s
/etc/apache2/sites-enabled/000-default), for example:
Allow from all
and then restart apache
sudo /etc/init.d/apache2 restart
Install jabber server
In Ubuntu this is as straightforward as ‘
sudo apt-get install ejabberd‘. OpenFire is also apparently easy.
Configure jabber server
pico /etc/ejabberd/ejabberd.cfg (yeah I use pico! got a problem? :-) )
You need quite a recent version of ejabberd (later than 2.0), and then it includes BOSH.
Create two accounts and make them friends
svn co https://svn.process-one.net/ejabberd-modules
sudo cp mod_admin_extra.beam /usr/lib/ejabberd/ebin/
On the commandline:
ejabberdctl register near jabber.yourhostname.com password
ejabberdctl register far jabber.yourhostname.com password
ejabberdctl add-rosteritem jabber.yourhostname.com near jabber.yourhostname.com near buttons both
ejabberdctl add-rosteritem near jabber.yourhostname.com far jabber.yourhostname.com far buttons both
Put an http rewrite file in the right place
The simplest thing to do is this:
Create a new directory in the correct domain
The directory can be called anything, but it needs to match your apache vhost config above.
Create an .htaccess file in that directory
RewriteRule http-bind http://localhost:5280/http-bind/ [P]
RewriteRule http-bind/ http://localhost:5280/http-bind/ [P]
RewriteRule http-poll http://localhost:5280/http-poll/ [P]
RewriteRule http-poll/ http://localhost:5280/http-poll/ [P]
RewriteRule admin/ http://localhost:5280/admin/ [P]
This means that the http interface to ejabberd is in the correct domain. If you put your ‘near’ and ‘far’ files in this directory or a subdirectory, that should work.
You mght need to enable rewrite and proxy modules in apache.
Create ‘near’ and ‘far’ webpages to represent the remote and player
Each has an on_message function and also sends messages. It’s all pretty straightforward. Info/query (iq messages rather than chat messages) are what we should be using to pass messages and they are a little bit more fiddly, but I’ve put some examples here: near, far. You’ll need strophe.js in the same directory.
Near sends load and play messages, while far sends nowp (now playing).
At this stage you should be able to see these two pages communicating. Load ‘near’ into Safari or similar and far into Firefox (3). Click play or load in ‘near’ and you should see a response in ‘far’.
Create a Greasemonkey script and iframe for the web based video player
We want the ‘far’ strophe page to control a player from a different site. For this you can put the player site as an iframe into the ‘far’ page.
iFrames are confusing and using Greasemonkey with iFrames is even more so. In modern browsers, iFrame-based hacks for communicating between cross-site iFrames are not allowed, so you need to use HTML5’s postMessage instead. This is much easier.
For the iFrame player Greasemonkey script to post to the enclosing ‘far’ page do this:
message is a string.
The ‘far’ page checks for messages like this:
The far page can also send messages like this:
var win = document.getElementById("frameid").contentWindow;
and the Greasemonkey script uses receiveMessage as before.
Using near, far and test_greasemonkey.user.js, with test.html on a different server (all in this directory), you should be able to send messages from near that affect test.html. Then all you need to do is adapt it to the site you are interested in controlling.
CORS (Cross Origin Resource Sharing)
- Strophe API
- Anders Conbere: Get XMPP – BOSH working with Ejabberd, Firefox and Strophe
- Postmessage in Mozilla
- Michael Mahemoff – Cross-Domain Communication with IFrames
- GreaseMonkey Manual – Installing scripts
- GreaseMonkey – UnsafeWindow
- Cross-Origin Resource Sharing (CORS)
Update – May 16 2011
I recently had to install ejabberd elsewhere and forgot how incredibly fiddly it is to get working. So here’s a few gotchas and possible solutions:
Problem: ejabberd won’t start
Try starting it as root user (not just sudo):
Problem: ejabberd won’t start in background
ejabberd start -detached
Problem: running ejabberdctl gives an error like “Failed RPC connection to the node ‘ejabberd@localhost': nodedown
Problem: bosh not working, even though the page /http-bind says it is
Edit modules part of config make sure you have right config! there are two! – check
ps ax | grep ejabberd
and that will show the correct one. The modules section should contain:
Problem: Mysteriously still not working, on Amazon EC2
Make sure the right ports are open: 5222, 5223, 5280 – on EC2 you have to open these using for example the configuration dashboard. It’s under ‘security groups’
Problem: Mysteriously still not working
HTML client must be on the same domain as http-bind