As some of you may know (or not), I've been developing a cross-platform media player for a while now, on and off for the past 4 years. However, life gets in the way and during all this time I've only seriously invested maybe 3 months in this project.
The player is (ironically) called EternalWave, even tough it was originally called EternalWave 4. The 4 came from the fact that I had developed previous versions of an audio player that only did one thing: loop trough a song over and over (hence the eternal part). The first version only played wav files and only worked in windows (hence the wave). Version 2 played audio and video trough DirectShow. Version 3 never existed, I skipped the number on purpose since the difference between 2 and 4 was really huge.
After I started using C# heavily, I felt compelled to do a bigger and more complex project, and the idea of a media player fits in that box pretty nicely. I started coding EternalWave 4 in C# as a plugin-based, audio player. Yes, only audio. I managed to write decoders for mp3 and ogg and wav by porting JLayer and JOrbis to C#, and then doing minor modifications. I wrote the wav 'decoder' myself since it only required to parse the RIFF format of wave files.I managed to code two different audio outputs for windows, through DirectSound and through Win32 API. And then it hit me.
Mono was getting really serious back in those days. What if I could make this media player work in several platforms? Since mono was supposed to work in *nix environments, hypothetically I could have my media player up and running in Linux and Mac OS X in no time.
Easier said than done.
I went for it, and decided to try to run my media player in Ubuntu. Started writing and audio output module trough Alsa, which eventually worked pretty well. However, when I decided to make the player cross-platform, the user interface became a serious problem. Mono didn't have full support for the Windows Forms API, and sometimes had support but behaved differently. Even though I had an skinning system for the user interface, that allowed you to define it in an XML file (pretty much as XAML works), and custom controls in order to control the not so stable behavior in different platforms, I quickly realized that making the UI work was taking most of the development time. After I started using Mac OS X, I tried to run my media player. While it did run, and the core functionality (decoding, etc.) seemed to work, the UI looked horrible.
Conclusion: if you want to make something truly cross-platform you have to rely on technologies known to work on all the platforms you want to target. Windows Forms works flawlessly in windows, but the support in Mono was not the best. I don't blame the mono team for this, they do the best they can with what they have.
So what cross-platform user interface framework could I use for this project? GTK+? GTK#? wxWidgets? (ughh), Qt?
GTK# would had been the reasonable choice, since it has been well developed for C# and has very good documentation. As reasonable as that sounds I dropped it as an option because it makes your application look like a Gnome application, no matter what platform you run it. Not that I have anything against Gnome, but having a media player (a very UI sensitive application) in Windows or OS X looking like a Gnome app would certainly make someone's eyes hurt.
Welcome, Qt.
Oh wait, isn't Qt made in C++? Yes.
How can you make Qt work in a C# application? It's hell.
So, instead of going straight to coding hell, I decided to port the whole thing to C++. While this sounds as a heavy load, it really isn't. I only have to port the core of the audio player and the plugin management system. There are plenty of audio (and video) decoders written in C/C++ that I can easily use. No need to port the ones I have in C#.Changing to C++/Qt gives me a lot of benefits and only one serious drawback:
Benefits:
- Performance boost: minor performance boost, but helps this kind of application as audio and video decoding can become cpu hungry. Also I need to do a lot of memory marshalling/unmarshalling in C# to be able to communicate with low level sound APIs. That is no longer needed if I port to C++.
- Open Source audio/video decoders: there is a huge amount of those written in C or C++. To be able to use those in C# would have required making a PInvoke layer for each of them to make them usable in the media player. This would have been serious work.
- Posibility of video output: I can hypotetically use SDL for video output. Hence the player can become an audio/video player instead of an audio-only player.
- Qt is awesome: Qt is very stable and powerful. Has plenty of features to cover all your UI needs. Has support for almost everything your app may need to do. And it uses the platform's look and feel whenever possible.
Drawbacks:
- It's C++: Memory leaks, dangling references, multiple class inheritance, buffer overflows, there are no interfaces, no formal delegates, compiler errors are sometimes impossible to understand, ... The complaint list can keep going.
In my opinion, the pros outweigh the cons. Besides Qt makes the cons a bit more bearable with its object model.
So here we go, on for the development (again) of one of the most challenging but fun projects I've had the pleasure to develop. I learned a lot doing this in C#, and I think I'll learn even more doing it with Qt/C++, especially because doing it this way, there is the posibility that I will open the source of it.