iTunesSync
Problem:
Better quality music from my car stereo system
Background:
Update
I’ve stumbled across the tune2air WMA3000, a professional implementation of parts of Option 1 below. I’ve just started using it, but it does read my playlists and radio stations from the Music app and present them in the interface as expected. When content is playing from Google Music or Spotify, it shows the currently playing title (though only if you exit from the Entertainment screen and return). Quality also seems to be a bit improved from other cheap bluetooth adapters I’ve used. It’s not perfect (still plays over analog audio), but it does solve one or two of the problems. Worth a shot if you’re looking for something more seamless, though still not enabling digital-only audio.
End Update
Likely in an effort to avoid fees for the playback of Fairplay-encrypted content, BMW chose to work around the problem of integrating an iPod (or iPhone, though that was still a very recent device in 2007-2008) to the head unit of their vehicles. In my particular case with the E90, the solution was to create a hybrid system.
A typical head unit would implement the iPod Accessory protocol, allowing the head unit to display track information, playlists, control playback of tracks from the device, and stream tracks from the device, entirely digitally via USB with a 30-pin dock connector. Especially in the electrically noisy environment of an automobile, this can be the difference between an average listening experience and a great one. However, as the files are being sent digitally, Fairplay encryption must be applied at every step, similar to the protected path concept used as part of HDMI. Otherwise, playback is prohibited, ostensibly because an unprotected digital copy would be a goldmine for pirates and thieves. Instead, as many of these “protection” systems do, it has simply made the life of the average consumer more difficult.
In this particular case, BMW chose to forgo paying the fees and instead bypassed the problem. They created a cable that offered both a USB connection and an analog audio connection via the line out pins available on a 30-pin dock connector. They implemented the iPod control protocol and opted to output audio from iDevices over an analog connection. This results in what seems to be a seamless experience from the user side (save for needing a special, expensive proprietary cable). However, as I noticed when I bought my car, the most expensive sound option available on my vehicle was rather underwhelming. I attempted to address the issue with equalizer settings, which resulted in some improvement.
One day whilst browsing the forums at e90post.com, I came across a complaint thread regarding the auxiliary in port in these cars. Forum members suggested to instead use a USB hard drive or memory stick, as the head unit did support reading files directly from a FAT32-formatted file system. Also, surprisingly, the unit supported M3U playlists. I tested this idea by loading a few files onto a memory stick and was clearly able to discern the difference between the poor analog audio input and the much-cleaner digital input.
Options:
I considered a number of possible solutions to this problem, some more fanciful than others. My primary goals were to maintain flexibility of synchronizing files wirelessly, as I had been doing with my iPod touch, while creating a system that would allow me to present files to the head unit in a form where they would be played directly from the head unit as opposed to the line out pins on the iDevice.
Option 1:
I wanted to maintain another bit of flexibility in having a bluetooth streaming input, which was not an option for this particular model of car nor the version of the iDrive (entirely unrelated to Apple) system BMW provided. I had achieved this by using a dock-to-bluetooth adapter that supported A2DP.
I considered using some sort of embedded device to achieve both ends. I played around with the idea of using a device like a Raspberry Pi in USB slave mode to emulate a mass storage device. I would use a bluetooth adapter for the Pi to allow streaming of audio from a bluetooth device (exposing songs as “fake” files to the head unit) and building a sort of bridge in software. Simultaneously, I would host files on the Pi itself on an SD card and similarly expose them on the fake mass storage device the head unit would see. A number of issues arose when I researched more into this idea.
- This is not trivial.
- The Raspberry Pi actually does not have data pins that connect to the USB port that powers the device. Even if it did, while the chipset seems to support USB OTG mode (so as to appear as a USB slave device as opposed to a USB host, such as your average computer), there seems to be no software support at present. However, an alternative was available in the Beagleboard, which does support USB OTG.
- I knew very generally of how USB devices communicate and how mass storage devices are implemented. This would required a significant investment of time to learn the requisite details.
- While there are libraries that take care of the complexities of the bluetooth stack, there was still the open question of how one would convert a streaming track over bluetooth to a file on a mass storage device. It turns out that bluetooth streaming supports a particular set of protocols and bitrates, AAC among them. Theoretically, one should simply be able to feed blocks coming in from the bluetooth device and send them along to the USB host connected to the mass storage side as long as the file is correctly identified as an AAC file. However, this would have to be borne out in practice, which was asking for quite a bit, I think.
- The question came as to how to power the device when the car was not on so as to sync files wirelessly. Also, the car would power the USB port that connected to the iDevice preemptively when one unlocked the car (so as to speed booting of an iPod, I imagine). In addition, it would keep the port powered for a short time after one had locked the car. It seemed that the device would have to a) boot very quickly and b) be robust enough to take these repeated power cycles, which I did not trust the flash memory nor the device to handle well.
- This is not trivial.
Option 2:
I considered simply creating a script that would read my iTunes library file, extract track information from a list of playlists, convert the tracks if necessary (as would be the case with ALAC files), and create M3U playlists that mirrored the iTunes playlists. This was the option I chose for expediency and simplicity, though there was an enhancement I considered.
Option 2a:
One limitation of this concept was that I would have to manually load the files onto a USB stick periodically. What I really needed was some sort of Wifi-enabled mass storage device.
I finally settled on this idea. Using a jailbroken iPhone 4 that I still had, I would load an app that would make the iPhone appear as a mass storage device. As the iPhone has both Wifi and a battery, it solved a number of the problems I considered with Option 1. I could use Option 2 to create the file structure and sync it wirelessly to the iPhone while achieving my goal of an entirely digital delivery of music to the head unit. I would either try to “push” from a computer on my network periodically to the iPhone, or the iPhone could try to find that computer periodically and trigger a sync.
Solution:
I ended up implementing Option 2 with a bit of trickery which allowed me to include bluetooth streaming as well. The door is still open for Option 2a, but I think that can wait for another day.
The script can be found on github. Given a few settings, including the path to one’s iTunes library file, an output directory, and a list of playlists, it will create a directory structure in the output directory containing the tracks in a subfolder and a series of M3U playlists at the root.
There were a number of issues during development. I chose Python because it seemed like it had a decent audio handling library in the audiotools module. As I discovered, however, the audiotools module would often be unable to open many of my music files. In addition, even if it was capable of opening files, it would often be unable to convert them even though they played back correctly in any player. I account this to a lack of flexibility in the audiotools module that many programmers creating playback software must have developed over years of attempting to play poorly constructed audio files.
I chose instead to rely on a built-in binary in OSX to do my conversions to AAC, afconvert. I have yet to find a file in my library it fails to handle, though using it is slightly awkward as it must be invoked on the command line through Python’s subprocess module. It also unfortunately creates a dependency on OSX, which I would have preferred not to introduce. I considered trying to use ffmpeg to maintain a semblance of cross-platform compatibility, but ffmpeg doesn’t seem to have a decent AAC converter. I could use MP3 encoding via the LAME library instead, and that may be an option I will add at a later time.
It was at this point I discovered yet another limitation of the BMW head unit. While it did support M3U playlists, it did not support the metadata information that M3U playlists support. To see the proper track information, I would have to tag the newly-converted files correctly as opposed to relying on the M3U playlists for that information. I ended up using another library for that as well.
Regarding the bluetooth streaming, the trickery I employed involved a bit of a quirk with the way the USB connection works with the bluetooth-to-dock connector. My particular connector appears as an iDevice with no songs or playlists, but it does stream audio over the line out pins on its dock connector. I could not have both the USB stick and the bluetooth device connected simultaneously.
I ended up hooking up the USB stick to the USB port. I connected the split cable originally used for connecting my iPod to a USB car charger that could be plugged in to the armrest 12V power jack. I had to use a right-angle adapter to make it fit while the armrest was closed. I connected the other end to the aux port. Thus, I could listen to files on the USB stick and switch over to the aux input to stream audio (usually podcasts) over bluetooth.
Conclusion:
Sadly this is only really a problem on E90 vehicles with the split aux/dock connector cable setup, available on E90 BMWs between 2006 and 2008. However, it has improved the listening experience significantly and I would highly recommend it.