mycroes

There's always time to play

Friday, August 8, 2008

Pairing the Itunes Remote app with your own server

I got a bit further today, but first I'll start with information you would need to try this yourself.

You need a working installation of a zeroconf implementation, the implementation of choice is avahi in my case. You need to set up two services for your zeroconf implementation, I'm using avahi so I made two files in /etc/avahi/services:

touch-remote.service:
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name>Long magic iPod identifier</name>
<service>
<type>_touch-remote._tcp</type>
<port>50508</port>
<txt-record>DvNm=Test remote</txt-record>
<txt-record>RemV=10000</txt-record>
<txt-record>DvTy=iPod</txt-record>
<txt-record>RemN=Remote</txt-record>
<txt-record>txtvers=1</txt-record>
<txt-record>Pair=pairing code</txt-record>
</service>
</service-group>

The first bold string is to be replaced with your iPod's id exported in _touch-remote._tcp on your ipod (it actually is the service name, as the xml shows). The next bold string is to be replaced with the paircode. Because ultimately my goal is to have the remote app talk to my own application, I will need to copy this from the ipod as well. I always first click 'Add library' (I assume that's what it is, I've got mine set to Dutch...), then copy the id, then save the file (make sure to keep the pincode screen open, new pincode means new pairing code). Now on my laptop with iTunes (in Windows) I immediately see 'Test remote' appear at the remotes list, isn't that great?

touch-able.service:
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name>47975973649ECA79</name>
<service>
<type>_touch-able._tcp</type>
<port>3689</port>
<txt-record>Ver=131072</txt-record>
<txt-record>DvSv=1905</txt-record>
<txt-record>DbId=47975973649ECA7B</txt-record>
<txt-record>DvTy=iTunes</txt-record>
<txt-record>OSsi=0xD97F</txt-record>
<txt-record>txtvers=1</txt-record>
<txt-record>CtlN=Test library</txt-record>
</service>
</service-group>

This file has some magic strings in it too, but these are less interesting. Name is obviously an identifier, this is how the remote will find the server after the server application has requested pairing. DbId is almost the same as name, in my case it happened to be 3 more than DbId. I changed both numbers (but kept the difference the same) because I would otherwise immediately get an error that the remote was not paired, seems it was connecting to iTunes (duplicate IDs). CtlN is the name the remote app will list as the library name, it actually works...

Now on to the next part, the connection.
When you click on a remote in iTunes it asks you to enter a pincode. As soon as you enter the code iTunes will make a http request to the port the _touch-remote._tcp service is running on (changes everytime on ipod touch, always seems to be port 505xx). Actually it probably should be seen as a DAAP request, but since DAAP is just special http it won't really matter. The request will feature a pairing-code and a database id, both as GET vars. The pairing code seems to be a hash of the pairing code the _touch-remote._tcp service lists combined with the pin code. I have not even tried to figure out how it's calculated, except for the fact that it's just as long as a md5 sum.

In the case with our fake remote, we can run netcat on port 50508 (port I chose/used), to do this, run 'nc -l -p 50508' in a terminal. Now if I click on 'Test remote' and enter my pin, iTunes sends a nice pairing-code. Because we used the service pairing code from the real remote for our fake remote, and typed the correct pincode, the remote will be happy if we forward the request. You can do this by just copying/pasting the request iTunes made into telnet or netcat connected to the real remote app. When forwarding the request, be sure to replace the database id iTunes passes along for the id you entered as name in touch-able.service. Now you should have paired your iTunes remote with your computer.

This pairing process is currently quite complicated, but I don't think I'm able to solve the hashing riddle without reverse engineering iTunes or the remote application, but I'm not sure I would actually manage to do that and also I'm not sure if it would be legal to do so. Not that I really care that much about it being legal (just applies to this case), if someone else would solve the issue I'd be happy to use it.

So what's next? Well now that it's paired the remote will connect to the port listed for the touch-able service and request server info ('GET /server-info HTTP/1.1'). It's easy to get this from iTunes (just forward the request), the real issue is that almost everything that iTunes and the Remote pass to eachother is gzip or zlib compressed. Wireshark seems to be able to decompress most of it, but the response the remote sends to complete pairing seems to be compressed too and I haven't succeeded in decompressing it yet. It should be valid http traffic, actually it also starts with '200 ok', so I know I succeeded in pairing.

The next step is to send some server info (and see what the remote likes and doesn't like) and then figure out the login process. So far I know the remote sends a login request with a paring-guid or something, at least it's a magic number that should identify the remote to iTunes so iTunes can check if it's really paired. Nice for security, but for now I'll guess that part will be happy with another '200 ok'. The remote does however continue after this by passing a session id along when asking for information, so it could be I have to return a session id on login, after which the session id can be used to identify connected remotes.

When there's a real session I can start digging into the harder stuff (at least I'll guess it'll be hard). Some things will probably be quite easy (fetching album-art, fetching volume settings, changing them), getting a playlist will probably be harder...

What also comes to mind right now is that you can use the remote to set speaker volumes for the so-called airtunes speakers. Perhaps it would be nice to abuse this, I can definately understand anyone that wants to create a fake speaker to control whatever slider on his system.

That's it for now, if someone can give me tips on the compression (maybe I should look at wget, curl or whatever code?) I would be very happy, other than that I'm hoping to postpone programming as long as possible so I have more time to think about design.

Edit: Short-term conclusions:
* The DbId/name for the server isn't used in the pairing hash
* The remote port number isn't used in the pairing hash (makes life a bit easier)
* Having the remote paired will make it request /server-info, on teh port specified for the touch-able service, and it stays paired for now... (I guess login can kill pairing)

20 comments:

Jeffrey Sharkey said...

hey just wanted to give you a heads up that i decoded the rest of DACP and wrote an android client:

http://dacp.jsharkey.org/

thanks for your help figuring out the MDNS side of things. :)

Unknown said...

Hi Michael,

linked from Jeff's blog entry I found yours. I recently bought an iPod touch and use it as remote for iTunes running on my HTPC.

I thought about linking the remote to the audio capabilities of my Synology NAS. Have you continued working on a server skeleton that can be reused for such a project?

Regards,
klaus.

Michael Croes said...

Hi Klaus,

I haven't continued my work, however I would be happy to continue it when someone figures out the pairing.

The easiest starting point for the remote functionality would probably be mt-daapd because the remote is an extension to apple's daap protocol, but it's useless without being able to pair the remote...

I have quite some other things to do too, but having a nice remote for banshee would be really great, so maybe some day soon I'll continue.
Regards,

Michael

Unknown said...

Michael,

I thought this is more or less figured out by Jeffrey (http://dacp.jsharkey.org/).

Or am I wrong?

klaus.

Unknown said...

Ok, now I see. It's the other way round.

Unknown said...

Did anyone ever figure out the pairing hash? I'm trying to do something similar, in which I would like to re-use the pre-built remote app, with a dapp server to control playout.

Any info is appreciated.

Michael Croes said...

As far as I know the pairing still hasn't been discovered. However the need has gotten smaller since there's some remotes in the app store for other applications, that are used for open source projects like mythtv.

Unknown said...

There may still be advantages to using the Apple ipod remote.

Could you fudge a pairing by switching the IP addresses of machines once the pairing is made?

The iPod Guy said...

a very solid implimentation, definately gonna work this one out! nice work


Rich
http://www.vstinternetsolutions.com

Michael Croes said...

Thanks. And then imagine I figured this out over a year ago ;-) . It's not really special though, but at that time noone seemed to even try.

Kai said...

Nice work..

Guess someone has figured out the pairing in the mean time as there is a project doing active work on a daap able player which allows dacp remotes to control:

http://code.google.com/p/stereo/

Haven't found the time to look into the details to much, but it seems they are using the iphone remote app as their reference dacp remote.

Might be the missing piece of the puzzle to get the iphone remote controlling mt-daap servers like firefly. (if you add sort of a player app in the middle)

Dustin said...

It doesn't look like Stereo figured out pairing, as much as a way around it. They have an iPhone App that changes the settings for Remote.app and adds a Stereo instance as a trusted source.
I think.

Kai said...

Hmm, ok thought the Stero guys got it nailed down.

Anyway got a similar look n feel expierience going using mpd, raop (airtunes) and mpod as remote control running of my tiny little NAS system. Not quite the real iThing yet but very very close.

Michael Paul Bailey said...

I was able to decode the pairing code. If anyone is interested, I've posted the source code on my blog.

iTunes Remote pairing code

Unknown said...

Hi Guys,

I'm the lead author on the stereo project (http://stereo.googlecode.com).

Michael emailed me with his decoded hash which I am planning to integrate into stereo whenever I get a chance.

At the moment, as someone observed, we use an iphone app (on a jailbroken iphone) to fool the iphone into thinking that it has already been authenticated.

We also have a html+javascript and ruby implementations of DACP clients, and a Java implementation of a DACP compatible music server.

Stereo is an ongoing project for allowing several users to contribute music to and share control of a communal jukebox in our graduate lab.

Hope someone else finds it useful!

Michael Paul Bailey said...

Thanks for the code Stephen (and Jeffrey). I am looking into integrating the iPhone Remote into Boxee and XBMC. I had been building the code myself, but perhaps I will just take advantage of you guys' lost weekends rather than creating a slew of my own on this project.

Thanks for the help.

Rob Mitchell said...

How easy would it be to update Firefly media server so that any NAS device using this service will pair with an AppleTV.

Currently any NAS device on the market which uses Firefly media server cannot stream to AppleTV directly because of the lack of pairing interface on the NAS device to accept the ATV pin code.

Thoughts?

Michael Croes said...

@Rob Mitchell:
I'm afraid that isn't as easy as the iphone/itunes association. However, I don't have an AppleTV and I've never used one, so maybe it's about the same. Either way a good place to start out with such things is a network traffic dump with wireshark.

Anonymous said...

Hey Michael,

Any idea why I get "Untitled Playlist" when my device shows up in iTunes" when "Pairing the iTunes Remote appl with your own server".

Anonymous said...

Hey Michael,

Any idea why I get "Untitled Playlist" when my device shows up in iTunes" when "Pairing the iTunes Remote appl with your own server".