Several people complained that my custom ringtones application is too slow when receiving calls, so I started analysing what ringtoned does when a new call is received. The three main operations in this case are creating the object that represents a call after retrieving all the needed information (caller ID, etc.) from Telepathy, looking up the contact that matches the caller and playing the ringtone.
The Telepathy bit just needed to be slightly smarter, but was already quite fast. The contact look up was already very fast, unless you have so many contacts to make your address book unusable.
The code that needed more optimisation was the one that plays ringtones. It turned out that using GStreamer with playbin2 (the element able to detect and play all the supported file types) is not fast enough for this use case. I tried different approaches and in the end I decided to always use uncompressed wave files and stream them directly to PulseAudio.[1]
Note that GStreamer is not the best solution just in this very specific case, for all the other use cases GStreamer is still the best solution.
After these changes I was really expecting to get very good performances, but it was still quite slow. My analysis was showing that, since when ringtoned gets notified from Telepathy of the existence of a new call to when it starts streaming to PulseAudio, less than 0.1 seconds passes, so why was it still slow?
At this point I tried using bustle to generate graphs of the D-Bus activity when a call is received. The graphs showed that the delay was not ringtoned’s fault, but a bug in Maemo causing a freeze that made the dispatching of new calls about 4 seconds slower when ringtoned was running. Somebody is now working on the bug and trying to figure out why it’s happening, in the meantime I’m working around it watching for new calls in a different way.[2]
Ringtoned and the related packages are available in Maemo extras-devel under the name “Custom ringtones for your contacts”. If you don’t want to add the extras-devel repository (as it contains a lot of unstable software, you have been warned!), you can download ringtoned directly from my personal repository:

Install from my personal repository
(follow the link on the N900 browser)
The only known big problem left is that ringtoned breaks vibration, I will fix it in the next days/week.
Update: It looks like MyContacts is incompatible with ringtoned, so you cannot use these two programs together.
[1] The file is uncompressed in background, so you can still use any type of file for ringtones. Just notice that, when you update from a previous version, the first time you receive a call from a contact that already had a custom ringtone you will get the default ringtone and not the custom one as previous versions were not generating the uncompressed file.
[2] For people interested in Telepathy: the freeze happens if there is an observer running, even if at that point the dispatching to observers didn’t start yet! The (ugly, but effective) solution was to just listens to the NewChannels signal directly. When the Maemo bug will be fixed I will revert my code to use an observer.