I had the opportunity to work on the 2014 MATE GSoC project aimed on providing a replacement for deprecated GstMixer functionality, used by the mate-media and mate-settings-daemon packages.
*** The state before my project:
The mate-media package used to provide two distinct volume control applications. A more modern PulseAudio-based one called MATE Volume Control and a legacy GstMixer-based one. The reason for supporting two separate volume control applications was portability. The newer PulseAudio-based application relies on having functional PulseAudio support in the operating system and many (especially BSD) systems choose not to use PulseAudio by default and prefer the legacy GstMixer-based application instead.
The main problem with GstMixer is that it used to be a part of the gstreamer package, which was removed from gstreamer in version 1.0 and the application relies on the now unsupported version 0.10. This creates maintenance overhead as it requires operating systems and distributions to keep providing packages of an unsupported library.
My project was based on the idea of removing the legacy GstMixer-based application from MATE and improving the newer PulseAudio-based one to support other sound systems as well. The newer application contained a somehow separable PulseAudio support code, which was also duplicated in mate-settings-daemon to provide support for multimedia key actions (changing volume and muting).
I decided the best approach would be to develop a new library, providing an abstraction layer for PulseAudio and other sound systems and allow both the volume control application and the settings daemon to use this library instead of duplicating the existing PulseAudio support code.
I also decided to write the library from scratch, using ideas from both the PulseAudio support code in the applications and also from GstMixer.
*** How my work progressed:
At the start of my project I created a library called libmatemixer. Designing a reasonable API for the library turned out to be very challenging as there are big design differences between PulseAudio and other sound systems. The volume control application also uses many PulseAudio features, which are not available in other sound systems. The approach I took was to make the API initially resemble the existing PulseAudio support code, but in a more robust way to make room to later support at least ALSA and OSS sound systems without requiring larger design changes of the API.
Even so, I couldn't avoid changing and rethinking the API design several times during the project as there were always cases where some parts just didn't fit. I'd say this was one of the major struggles I had with the project. Each time you see a well designed API, it may make you think that it must be so easy to design such thing yourself, but I learned the hard way that it is not :)
During the first half of the coding period I made the library fully functional with most PulseAudio features working and I did some initial work done on porting the applications. I managed to follow my project schedule almost exactly as I planned it.
The second half turned out to be much more challenging. I spent much more time on the project (some days 12-16 hours a day including most weekends), but as the code became more complex, the progress was much slower than I anticipated.
At first I continued porting the applications until I got them into a reasonable shape. I took more time with the volume control program, cleaning it up, rewriting some parts to better match libmatemixer design, removing dead code and improving GTK3 support (which wasn't really a part of the project, but the idea of making user-visible changes was very tempting :)
Then I moved back to libmatemixer and started working on supporting the ALSA and OSS sound systems. I added initial support for both of them fairly quickly, in less than 2 weeks, but making them fully functional took me pretty much another month of time (mainly due to making API changes in libmatemixer, incomplete documentation of both sound systems and OSS differences on Linux/FreeBSD/other BSDs).
I also spent about a week looking into OSS version 4, but after seeing how difficult it is to map OSS4 mixer elements to libmatemixer, I decided to postpone it and later abandoned it completely.
About 2-3 weeks before the end of the coding period, I finally started cleaning things up and adapting the PulseAudio code and the applications to the API changes I made while working on ALSA and OSS. This was the most difficult time for me, I still kept finding API inconsistencies, thinking, rethinking, and my progress was very slow. As I had to spend most of the polishing time fixing problems, the code didn't receive as much testing and polishing as I wanted to, but I managed to complete it and with several late fixes, I can say that the code works very well.
*** So what is libmatemixer like?
The libmatemixer library makes heavy use of GLib and GObject libraries and is written in the C programming language. I have taken care to provide an easy to use API, which will be familiar to programmers experienced with PulseAudio or GstMixer. My intention was to make the library dynamic, flexible, robust, extensible, make good use of GObject features (properties and signals) and follow the OOP principles.
Support for each sound system is provided as a dynamically loaded module (a plugin) and allows for individual modules to be packaged separately. While the supported sound systems differ greatly in functionality, they share a single abstract API and their capabilities can be queried dynamically by applications. They also don't need to worry about which sound system they are running on (though the library tells them if they ask).
The library provides one main entry point to communicate with a sound system, called a Context. Context can be associated with some particular sound system or it can select a working sound system automatically. When done so, the Context can be used to query the system for a list of sound cards and streams (described in the next paragraph).
Most sound cards are capable of providing sound input (recording) and output (playback), in libmatemixer, these input/output "channels" are called streams. Streams may not only be found on sound cards, but a stream may for example exist to output sound over a network (this is possible on PulseAudio and supported by libmatemixer).
Each stream can contain an arbitrary number of volume controls and switches. Volume control is simply a volume slider with any number of channels. Depending on the sound system, controls can have readable/writable volume, a mute toggle and may even support peak level monitoring. Per-application volume controls, per-channel volume, decibel values, balancing, fading and volume limits are all supported. Switches can be used for example to change the active recording source of a sound card or the sound card profile on PulseAudio.
All the elements in libmatemixer are dynamic, they can appear and disappear at any time (for example when user unplugs a USB sound card or starts her music player) and the library provides asynchronous notifications for all events and on all the sound systems using the GObject facilities.
This was only a brief intro and a fraction of supported features. I have taken care to provide support to all features which may be useful to applications and to allow writing both PulseAudio-style mixers (such as the MATE Volume Control with a single input/output volume slider) as well as applications wanting to provide many controls at once, such as the legacy GstMixer application, XFCE mixer or KMix.
As you can see, my goal was to provide a flexible library, not just to match the needs of a single application.
*** Final word
I must say that working on the project was challenging, but I enjoyed it a lot and it was a valuable learning experience. I hope libmatemixer will get a chance and that we can provide it as a production quality code for the next MATE release.
I'd like to thank my mentors Stefano and Martin and the openSUSE program admins Manu and Saurabh for giving me this opportunity (you've all been great!) and of course everyone who followed my project (I'm sure there was at least one person hiding in the shadows).
If you are interested in seeing or playing with the code, see my GitHub:
I keep providing fixes for the packages and they reside in a separate branch called after-gsoc, this branch contains some important fixes and will probably give you a better testing experience ;)
*** But wait, we want screenshots!
Alright, I somehow expected you'd ask, so let me show you MATE Volume Control running on libmatemixer using Pulse, ALSA and OSS (notice the differently named devices, but they are made on the same hardware and OS).
https://dl.dropboxusercontent.com/u/28460082/MATE/alsa-1.png https://dl.dropboxusercontent.com/u/28460082/MATE/alsa-2.png https://dl.dropboxusercontent.com/u/28460082/MATE/oss-1.png https://dl.dropboxusercontent.com/u/28460082/MATE/oss-2.png https://dl.dropboxusercontent.com/u/28460082/MATE/oss-3.png https://dl.dropboxusercontent.com/u/28460082/MATE/pulse-1.png https://dl.dropboxusercontent.com/u/28460082/MATE/pulse-2.png https://dl.dropboxusercontent.com/u/28460082/MATE/pulse-3.png https://dl.dropboxusercontent.com/u/28460082/MATE/pulse-4.png
Thank you and see you next year, Michal ;-)