WWDC 2008

I will be attending WWDC next week. If anyone wants to meet up, send me an email. We are still looking for a full-time Cocoa developer to work out of our San Francisco office.

doubleTwist is a one year old start-up in San Francisco backed by the same people who were behind Skype and Last.FM. Our mission is to simplify the flow of media to a wide range of CE devices and between family and friends. We are looking for a Cocoa developer to join our Mac team and work on the MacOS X version of doubleTwist. The Mac team currently consists of three people.

3+ years of Objective-C and Cocoa experience
A passion for improving the user experience around digital media

Experience with one or more of these APIs: IOKit, QTKit, CoreAudio
Involvement in/contributions to open source projects
Experience with the iPhone SDK

To apply, send your resume to jon at doubletwist.com. If possible, include code samples and/or links to open source projects you’ve contributed to.

Looking for a Cocoa developer

We are looking for a Cocoa developer (either full-time in San Francisco or contract based from any location) to work on the MacOS X version of doubleTwist. I’m currently working on the MacOS X version and I need an additional developer. Unlike the Windows version of doubleTwist, the MacOS X version has a native look and feel :-) If you’re interested, please get in touch. We’re also looking for a Mac designer/artist to do some graphics+icon work on a contract basis.

Rogue developers

Update: The issue has been resolved. See update at the bottom of the post.

In August 2004, I reverse engineered Apple’s AirTunes protocol and released JustePort, the first non-Apple application to enable streaming to the AirPort Express. Because of my work, Rogue Amoeba was able to develop their $25 AirFoil application – a much more user friendly tool for streaming to the AirPort Express. I didn’t have any problems with this – I released JustePort as open source so that others could build similar applications by learning from my source code. What I did not particularly like though was the product page for Airfoil, claiming “It’s not just for iTunes anymore”. This misleading statement, suggesting that Airfoil was the first tool of its kind and that Rogue Amoeba did the hard work to enable non-Apple streaming to the AirPort Express, has since been removed from the Airfoil product page.

I was reading Rogue Amoeba’s blog today and noticed that they’ve released a Linux version of their Airfoil Speakers application. Airfoil Speakers is a complimentary application to AirFoil that implements the server part of the AirTunes protocol. By installing Airfoil Speakers on a computer (e.g. your home theater PC) you can stream audio to it using Airfoil from another computer. The release of the Linux version of Airfoil Speakers piqued my curiosity so I downloaded it and had a look. It uses .NET and requires mono. I downloaded the Windows version as well and it shares the core with the Linux version.

I ran AirfoilSpeakers.exe (MD5: 82b7ef8c05958ccb6e24289c8b21a27c) from the Windows version through monodis to see if I could find anything interesting. I came across this:

.namespace AirfoilServer.AirTunes
.class private auto ansi beforefieldinit Utility
extends [mscorlib]System.Object

// method line 853
.method public static hidebysig
default void LeReverse (unsigned int8[] arr, int32 index, int32 length) cil managed
// Method begins at RVA 0x104b6
// Code size 16 (0x10)
.maxstack 8
IL_0000: ldsfld bool [mscorlib]System.BitConverter::IsLittleEndian
IL_0005: brfalse.s IL_000f

IL_0007: ldarg.0
IL_0008: ldarg.1
IL_0009: ldarg.2
IL_000a: call void class [mscorlib]System.Array::Reverse(class [mscorlib]System.Array, int32, int32)
IL_000f: ret
} // end of method Utility::LeReverse

// method line 854
.method public static hidebysig
default void LeReverse (unsigned int8[] arr) cil managed
// Method begins at RVA 0x104c7
// Code size 11 (0xb)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.0
IL_0002: ldarg.0
IL_0003: ldlen
IL_0004: conv.i4
IL_0005: call void class AirfoilServer.AirTunes.Utility::LeReverse(unsigned int8[], int32, int32)
IL_000a: ret
} // end of method Utility::LeReverse

// method line 855
.method public static hidebysig
default void RijndaelDecrypt (unsigned int8[] Buf, int32 Offset, int32 Count, unsigned int8[] Key, unsigned int8[] IV) cil managed
// Method begins at RVA 0x104d4
// Code size 80 (0x50)
.maxstack 5
.locals init (
class [mscorlib]System.Security.Cryptography.Rijndael V_0,
class [mscorlib]System.IO.MemoryStream V_1,
class [mscorlib]System.Security.Cryptography.ICryptoTransform V_2,
class [mscorlib]System.Security.Cryptography.CryptoStream V_3)
IL_0000: call class [mscorlib]System.Security.Cryptography.Rijndael class [mscorlib]System.Security.Cryptography.Rijndael::Create()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldc.i4.1
IL_0008: callvirt instance void class [mscorlib]System.Security.Cryptography.SymmetricAlgorithm::set_Mode(valuetype [mscorlib]System.Security.Cryptography.CipherMode)
IL_000d: ldloc.0
IL_000e: ldc.i4.1
IL_000f: callvirt instance void class [mscorlib]System.Security.Cryptography.SymmetricAlgorithm::set_Padding(valuetype [mscorlib]System.Security.Cryptography.PaddingMode)
IL_0014: newobj instance void class [mscorlib]System.IO.MemoryStream::.ctor()
IL_0019: stloc.1
IL_001a: ldloc.0
IL_001b: ldarg.3
IL_001c: ldarg.s 4
IL_001e: callvirt instance class [mscorlib]System.Security.Cryptography.ICryptoTransform class [mscorlib]System.Security.Cryptography.SymmetricAlgorithm::CreateDecryptor(unsigned int8[], unsigned int8[])
IL_0023: stloc.2
IL_0024: ldloc.1
IL_0025: ldloc.2
IL_0026: ldc.i4.1
IL_0027: newobj instance void class [mscorlib]System.Security.Cryptography.CryptoStream::.ctor(class [mscorlib]System.IO.Stream, class [mscorlib]System.Security.Cryptography.ICryptoTransform, valuetype [mscorlib]System.Security.Cryptography.CryptoStreamMode)
IL_002c: stloc.3
IL_002d: ldloc.3
IL_002e: ldarg.0
IL_002f: ldarg.1
IL_0030: ldarg.2
IL_0031: ldc.i4.s 0x10
IL_0033: div
IL_0034: ldc.i4.s 0x10
IL_0036: mul
IL_0037: callvirt instance void class [mscorlib]System.IO.Stream::Write(unsigned int8[], int32, int32)
IL_003c: ldloc.3
IL_003d: callvirt instance void class [mscorlib]System.IO.Stream::Close()
IL_0042: ldloc.1
IL_0043: callvirt instance unsigned int8[] class [mscorlib]System.IO.MemoryStream::ToArray()
IL_0048: ldarg.0
IL_0049: ldc.i4.0
IL_004a: callvirt instance void class [mscorlib]System.Array::CopyTo(class [mscorlib]System.Array, int32)
IL_004f: ret
} // end of method Utility::RijndaelDecrypt

// method line 856
.method public hidebysig specialname rtspecialname
instance default void .ctor () cil managed
// Method begins at RVA 0x10530
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void object::.ctor()
IL_0006: ret
} // end of method Utility::.ctor

} // end of class AirfoilServer.AirTunes.Utility

That Utility class looks very familiar. Where have I seen those exact functions before? Oh, that’s right, it’s the Utility class licensed under the GPL from my DeDRMS and SharpMusique source code packages.

I can’t say I’m surprised. GPL’ed code is frequently used in violation of the license. MacTheRipper, a popular DVD ripper for MacOS X, has been violating the GPL for years by using libdvdcss and refusing to release the source code.

I’m not going to be too hard on Rogue Amoeba though. Unlike many Mac users, they are against closed platforms. See their blog post about the iPhone SDK as well as the future of code signing in MacOS X.

Update: Quentin from Rogue Amoeba got in touch via email. The code ended up in Airfoil Speakers due to an honest mistake. Quentin writes:

We use a lot of open source software in our products, could not make them as good as we do without it in fact. And as such, we do our best to make sure the licenses are followed. All our commercial software is GPL-free, some use LGPL’ed libraries, and some BSD/MIT code in places. We try to make sure all the code we use is correctly acknowledged, and give back when we can (http://rogueamoeba.com/sources/, www.rogueamoeba.com/utm/2008/01/12/perian-is-awesome/).

So we’ve put together Utility.cs-less versions of Airfoil Speakers to fix our GPL compliance. The Linux version we are pushing out immediately (it’s still in beta technically) here: http://bigblueamoeba.com/tmp/airfoilspeakerslinux/. The Windows version will be officially pushed out this week after testing, but is available right now here: http://bigblueamoeba.com/tmp/airfoilspeakerswindows/

Thanks Quentin!

iPhone SDK

“Phones will only run apps signed by Apple. It also applies FairPlay to the package.”

Deric Horn, Apple Inc.

The SDK does look impressive. Hopefully CoreData will get added at some point.

Update: I knew it was too good to be true. From the iPhone HIG:

Only one iPhone application can run at a time, and third-party applications never run in the background. This means that when users switch to another application, answer the phone, or check their email, the application they were using quits. (p. 16)

So much for showing off AIM at the launch event as an example of what you can do with the SDK. Unless you’re someone like AOL, you’re not going to be writing any useful social clients for the iPhone. Oh, and this makes the Kleiner Perkins iFund look even more of a joke than their Java fund a decade ago.

Air in Barcelona

I bought a MacBook Air right after it became available in Apple Stores. It traveled with me to 3GSM (now renamed to Mobile World Congress) in Barcelona three weeks ago. It’s a great notebook and has become my main development machine. However, it’s not without flaws:

  • WiFi is inferior compared to my Thinkpads. This was not unexpected – my MacBook Pro also has shitty WiFi. Apple is apparently incapable of designing a notebook with great WiFi.
  • Keyboard and mouse is inferior compared to my Thinkpads (only an issue when traveling).
  • When connected to my external monitor, the fan runs non-stop (and it’s LOUD).
  • The mono speaker: imagine your grandfather’s AM radio packaged in a notebook.
  • Inferior screen tilt angle compared to my Thinkpads.
  • No BTO option for integrated 3G. Yes, I know, 3G sucks battery and requires a chip the size of Texas. Which is why my Sony Ericsson W880i doesn’t actually exist.


I went for the prayer room, but stayed for the adult content.

doubleTwist bugfix release

We just pushed out another doubleTwist release. It fixes the following issues:

  • Fixed the exception that was occurring if you had http entries in your iTunes library (e.g. streaming radio)
  • doubleTwist now displays properly if you are running Windows at 120dpi
  • Allows + sign in e-mail addresses

You should be getting a notification in the application that there is an update available. If you don’t want to wait for the notification, right click on the doubleTwist tray bar icon and select “Check for update”.

To report bugs, please use our contact form or send them directly to me if you’d prefer that.

Issues that are still not fixed include:

  • iTunes is not detected if your iTunes library is in a non-standard location.
  • If you are behind a corporate proxy server, the installer and/or login to doubleTwist may fail.

Ideas on the next doubleTwist UI

Here is one of the concepts we came up with for the share section of doubleTwist. What do you think? We’d like to make it as easy as possible to share the content you’ve created, whether it’s stored on your computer or a connected device, with your friends. When you connect a device such as a Nokia N95, it shows up under My Devices and you are able to share media directly from your device just like in the current UI. The area in the bottom right corner is a mini player that lets you preview videos before you share.

dT UI concept