November 1, 2007

Simple MP3 Player for Pocket PC

When I was asked to create an audio guide based on Pocket PC technology and MP3 sound tracks, I had no clue where to go and how to achieve this. So, I went for a little net-surfing and what I found was a neat library: FMOD Sound System from Firelight Technologies. They propose a more-than-complete set of functions, enabling you to create just about any sound recording/playing application, for desktops and Pocket PCs. You can read more about it here. Download the API and see for yourself! (You're just another WinAmp away...)


For my system, I needed of course, a CE version of their DLL. If you are developing in C++ for CE then it's all right. If you are coding in .NET, then start the troubles.


Without even going into the definitions, one could realize at least the difficulties of communicating from managed code to unmanaged code. Actually it's the opposite way around that gives you headaches. On Pocket PCs, as well as normal desktop apps, it is possible to directly call a DLL function right from the .NET code, using the correct DLLImport attributes, like in this example

Talking back is much harder, especially when it can occur any time, i.e. with event firing. I must admit that I have not succeeded in having the fmodce.dll talk back to my .NET CF app. This is a shame because it would allow the application to get event callbacks from that DLL, thus enabling the application to control the stream even more. A number of good coders on FMOD's forum have posted some hints, but none of them helped me out. The only event I was asking for, in this simple app was the "End of track" event. Well, I finally worked around this problem, which you can read later on.

Download project here

Compact Framework version

Some good CodeProject contributors pointed out that my code wasn't working on Compact Framework 2.0. This behavior has nothing to do with FMOD's library, but that is due to a bug in .NET CF 1.0. In my code, I use a condense of what I could find on the net, to get a pointer to the stream

What you need to know is that, in .NET CF 1.0, the function AddrOfPinnedObject does not return the address of the pinned object, but the address is shifted by 4 bytes, which corresponds to the size of the pointer itself. So to retrieve the correct address, you must point 4 bytes further! Look in the net for the AddrOfPinnedObject function and you'll get plenty of details. This workaround is not necessary in .NET CF 2.0 because the bug has been fixed in this version, so our bug-fix needs to be conditional. One more thing: the bug fix mentioned above is not a good bug-fix in fact, because although .NET CF 2.0 doesn't have this problem anymore, it might be solved as well in later releases of .NET CF 1.x (as Service Packs). Should this happen, the code above wouldn't work anymore. The only good way then, would be to allocate the needed memory yourself, and create your own pointer to that chunk of memory, as shown here (MSDN site) (par. 6.14). So the perfect way - free from version check - would be.