mycroes

There's always time to play

Sunday, December 21, 2008

GDM in Xnest

I wanted to change my GDM theme and watch it without logging out, so the logical thing for me was to run it inside an Xnest. I had no clue how to do that though, but after some searching I found the following:
$ gdmflexiserver --xnest

Voila, you never need to know more...

Thursday, September 4, 2008

Using ext4 on Gentoo (and probably other distro's)

Keeping it short:
when creating ext4 filesystems with e2fsprogs' (1.41.1 works great for me) mkfs.ext4 I couldn't mount them. The error I found in dmesg was
[ 5994.790520] EXT4-fs: loop0: not marked OK to use with test code.
After a bit of googling I found that to use ext4 filesystems with the current in-kernel ext4dev driver you need to tell the filesystem it can be used by an experimental driver. The option for mkfs.ext4 to do this is -E test_fs. After this you can mount your ext4 filesystems without any issues (not without specifying ext4dev as filesystem with -t though).

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)

Thursday, August 7, 2008

iPod Touch iTunes Remote without iTunes?

With the new iPod firmware Apple also released a remote for iTunes as iPhone/iPod Touch application. The application is quite nice, but I won't go into much detail on usability etc right now (if I ever will at all). The thing I wanted to discuss is using the remote application without iTunes. I would love to use the remote for my normal machine or my home theatre pc. The application has support for 'Movies' and 'Television Shows' too, so it would be usable for mythtv. Actually it could be possible to abuse playlists or whatever (ratings for priorities?) to use the application to schedule recordings.

So this is all nice and stuff, but where is the documentation? Well I guess there isn't any. It seems however that Apple is using Daap to control iTunes. A daap server is just a special HTTP server, so the protocol is easy. Also the services (remote and touch-able) are exported using bonjour/zeroconf, so I can fake these services using avahi. So far I managed to create the services so iTunes will think my computer is a iTunes remote. It sends the pincode it uses for connection, but that's how far I've gotten up to now. The pincode is encrypted or hashed, but I guess the hash contains more than just the pincode. I used telnet to send a pincode to the remote application (getting the pincode by having iTunes sending it to netcat), but it just failed with a 404. Perhaps I'm doing something wrong.

I'm going to continue work on this, I already thought of some other stuff to try, so if you're interested leave a comment so I know people want this. Also if you know more than me already, feel free to leave it in a comment too...

Wednesday, June 18, 2008

gstreamer television recording

I've been trying to record stuff from my tv tuner card using gstreamer. I like gstreamer as a multimedia framework and I like some apps that use it, so although there are enough other options I wanted to try this using gstreamer first.

The first issue was to record something from the tv card. I started by installing the video4linux gstreamer plugin. I actually started with installing version 1, then noticed there was a version 2 and because that's what the kernel uses natively I decided to go for v4l2. The gstreamer plugin is called v4l2src. I already read that to display something you need to run it through ffmpegcolorspace. To get it more useful you also need to specify resolution and framerate so to get something useful on my screen I started with
gst-launch-0.10 v4l2src device=/dev/video0 ! \
video/x-raw-yuv,width=768,height=520,framerate=\(fraction\)30000/1001 ! \
ffmpegcolorspace ! ximagesink

This works, but you still need to control the tv card or else you'll probably just see snow. There's a few different ways to control the tv card, but I wanted something as small as possible because I only needed to change the frequency to a desired frequency. I found dov4l, a small program that can do all the basic stuff that I needed done. To switch to discovery channel I could do a simple
./dov4l -f 496000000
from the folder where I unpacked the dov4l sources after I ran make. So now I actually had discovery channel displaying on my computer screen. Next step was audio. I use a bt878 tv card so I can use snd_bt87x to capture audio from the tuner device. A simple
gst-launch-0.10 alsasrc device=hw:1,0 ! alsasink
gave sound, so now I had audio and video from my tv card.

Now the hardest part was to get it all into a file. I'd seen various websites explaining some simple gstreamer stuff, and that at least taught me about muxing and demuxing. Actually, I didn't know much about the basics either. In short you usually want to encode video into something, encode audio into something and then dump it into a media container. So one common media container everyone knows is the avi format. I actually started out with ogg (vorbis and theora in an ogg container), but that gave me issues with both picture and sound so I soon moved to lame to convert my audio into mp3 and used ffenc_mpeg4 to convert my video into mpeg4. Dumping that into an avi container I ran into audio sync issues. After asking in #gstreamer on freenode I was told that the avi container doesn't handle time very well (or at all), so I should use another container and they pointed me to matroska. At this moment I was able to record to a file and view it afterwards, but that was not enough for me...

I wanted to use something modern. Although I quite like matroska containers because they're quite well supported on all platforms (vlc supports them, so any platform that supports vlc can in some way handle them) I was looking more for something like mp4. ffmpeg offers a muxing plugin for mp4, but I haven't gotten it to also use audio and I can only play it with mplayer then, so that's not really an option. I could however use something else in the matroska container. So I decided to use x264 for video. I'm on gentoo so I prefer to install by using ebuilds (although I'm using paludis so importare works for me too), so I went looking for an ebuild. The easy solution is to copy an existing gst-plugins-bad plugin ebuild (like the lame ebuild) and name it gst-plugins-x264-0.10.6.ebuild and place it in a correctly named folder in an overlay. Remove the deps that don't make sense (only lame for this specific plugin) and you should be able to install the plugin. I first tried with -0.10.7, but that wants gstreamer-0.10.19, so I decided to stick with gst-plugins-x264-0.10.6. Now I also needed something decent for audio, and I decided to go for faac, which seems to be reasonably supported these days and I ended up with the following line to do nice gstreamer recording from my tv card:
gst-launch-0.10 matroskamux name=mux ! \
filesink location=test.mkv alsasrc device=hw:1,0 ! \
audio/x-raw-int,channels=2,rate=32000,depth=16 ! \
audioconvert ! faac ! queue ! \
mux. v4l2src device=/dev/video0 ! \
video/x-raw-yuv,width=768,height=520,framerate=\(fraction\)30000/1001 ! \
ffmpegcolorspace ! x264enc ! queue ! mux.

I started with a capture resolution of 924x576, because that's what my card supports, but x264enc doesn't like that. Besides the fact that it complains that it can't encode fast when the width or height is not a multiple of 16 it wasn't properly encoding on that resolution. So as you can see I dropped it to 768x520, which gives a very decent picture, even for full screen viewing. Have fun watching!

Thursday, June 5, 2008

Ripping audio from youtube movies (using gstreamer)

Today my girlfriend needed the audio from a youtube clip, so I decided to see how easy I could get it. I started by getting the flv from the clip, one useful source for that is downloadflv.com. After I had the file I verified I could actually play it, double clicking opened totem and started playing, so far so good.

Because totem managed to play I thought gstreamer should be able to open the file and I already knew gstreamer was capable of converting and after about 3 tries I came up with the following command:
gst-launch-0.10 filesrc location=file.flv ! decodebin ! audioconvert ! lame ! filesink location=file.mp3

This
- opens the file
- decodes the file (I guess this is needed to rip audio only)
- does something with audio, I don't know if you always need this but I think this is a sort of wrapper to match input with output plugins
- encodes to mp3 audio
- writes to a file

There's much more you can do with gstreamer, so if you found another one of those 'this might be useful every once or twice in five years' commands please let me know in comments.

Wednesday, June 4, 2008

How to get google gadgets to get gadget metadata

So it seems that now google gadgets for linux has been announced a lot of people want to try it. Seems most of them are retarded too and can't get it working. Because I have nothing against retarded people I'm going to list what I've found out:
- The error "Failed to update gadget metadata" can mean a couple of things.
- Curl needs to use openssl for cryptography to work with ggl.
- On gentoo you seem to need recent ca-certificates. In my case, upgrading from amd64 to ~amd64 worked.
- a simple `curl https://desktop.google.com/desktop` can show you why ggl can't fetch metadata.

I hope someone reads this and thinks it's useful, please leave a comment if so.