After talking about Grilo at GUADEC-ES, I’ll be talking next thursday about MAFWGriloSource in a lightning talk during GUADEC. Both events are sponsored by Igalia.
Planet maemo: category "feed:70bebeb934a26428d85371654b6c3163"
Thank Aldon Hynes, who sent me an email with some comments about MafwGriloSource behavior in the N900, I could fix a bug and implement a feature. The bug was a limitation when browsing, as you could only see the first 64 results. It was caused by a problem with indexes when returning the results, as I alwayes sent 0. When fixing this, the interface was requesting more and adding them to the treeview. Then we had all results in the treeview.
As I explained in another post, some colleagues at Igalia were creating the Grilo framework to gather multimedia content and ease the creation of that kind of applications. The origins of Grilo are in MAFW, which is the multimedia application framework used in Maemo 5 (Fremantle) to power the official media player, and that we had created in collaboration with Nokia and other companies, but we wanted to go beyond its limitations and Grilo is the result.
My submission for this year’s GUADEC:
This is a _lightning talk_ about how the evolution from MAFW (Multimedia Aplication FrameWork used in Fremantle official media player) to Grilo (new multimedia framework for application aiming to provide easy access to many sources of media) and how they can work together to provide a better user experience and access to more media in the Maemo 5 platform (Fremantle)
As you may know, some colleagues at Igalia are developing a framework to gather, browse and query multimedia sources called Grilo. Of course it is no replacement for GStreamer as it is at a much higher level and we are focusing in gathering, browsing and querying so far.
We were an important part of the main developers of MAFW, so in this case we are trying to learn from the mistakes and try to create a more useful and easy to use framework.
One of my first steps, as a test, will be creating a MAFW pluging for Grilo, so that we can have all sources managed by Grilo running on the Fremantle official media player (as soon as bug 9361 gets fixed) with the consequence of having integrated important and interesting features as Youtube, podcasts, Jamendo, Shoutcast and so on.
Seekability when streaming contents involves almost all layers of a multimedia player and it is not a trivial issue. First, your interface needs to have a seekbar or something to do that. Of course, the media you are streaming has to seekable, meaning container and codecs used. And we cannot forget the transport either, this is, HTTP, local access and so on.
Thank Gods, GStreamer does a wonderful job making easier everything related to transport, decoding, containers, etc. But in the case of UPnP-DLNA, there is a extension saying if the media you are playing is seekable or not.
We did not have support for that in MAFW and we needed it, I added the request for the metadata key MAFW_METADATA_KEY_IS_SEEKABLE
when requesting data to play media, so now we have duration, uri and seekability. Our approach had to be consevative (otherwise, GStreamer seekability would have been enough), and then if MAFW source provides the metadata key and media is not seekable, se just say it is not seekable. Otherwise, we rely on GStreamer, that has the final responsibility (which is logical, if it cannot seek, seeking is impossible). Of course, seekability depends on duration, meaning, if there is no duration, we cannot seek as we would not know the seeking limits.
About how to implement that in the sources, the only one needing it was mafw-upnp-source. In the other ones we just want to rely on GStreamer, but for UPnP, if we want to honor DLNA specification, we had to do that. Specification is fun itself and of course, adding that every vendor/provider implements what it wants makes it more difficult. A proof is that a friend of mine bought a TV claiming to be DLNA certified and it only works with the crappy server provided by the vendor, closed of course, and with a lot of missing features, like subtitles support, IIRC (yes Zeenix, I told him to use Rygel and Philippe, it was before you joining Igalia :-p). Now with new gupnp
this was reworked, but when I wrote it, we had to check the DLNA_OP
fields to know if it was seekable or not and it was a pain in the ass to decide what the default was depending on the missing options and so on.
Fortunately, it is working fine now, I think.
I had this post planned for a long time, but here it goes.
When we were developing the renderer some time ago, we saw that code was getting out of control because handling state changes was becoming hell, so we decided to rework it applying the State Pattern. Though Zeenix thinks it was my wife’s idea, it was actually Iago’s.
The other day I found a function that was sinning against that pattern. It was _update_playcount_cb
. When it was written, the call had been place in a central point where every media change going thru, but it was a bit ugly as it was using an if statement checking for the current state. This application of the state pattern is not completely canonical as we keep the current state but only because state classes are stateless and we want to keep them as Singleton’s, so the easiest way was keeping that variable to point the current state, but of course using it in an if statement is ugly.
Fortunately, I checked where it was needed to call that function and it saw it was in couple of places, so I reworked the code a bit and place the calls in the exact places where it was needed, so i didn’t need to make that function support the state pattern (in fact it would have been stupid).
But this state pattern still needs some finetuning. We’d need to remove the worker and increase the number of states and add substates to control for example the buffering and hide properly some GStreamer state changes that would make the code easier to understand and maintain.
Should we rely on GStreamer timeouts when handling disconnections or should we write some code with conic to immediately detect if network goes down and raise the proper error? Good question, uh?
Issues are network changes and how conic handles them. Because AFAIK, if conic changes it connection it signals the disconnection and then the connection to the other network, (for example if you switch from one WLAN to another or it switches from WLAN to Bluetooth GPRS or viceversa). Issue is that we don’t handle connections ourselves but GStreamer does. They rely in underlying components, such souphttpsrc (which happened to have a problem with the timeout) so they raise an error when that timeout expires. They have more components dealing with different kind of servers that can behave in a different way.
When network goes down and other one comes, we would have to ask for other connection if we are currently playing a stream, but I don’t know if those GStreamer underlying components can handle those connection changes gracefully because the underlying protocols can be stafeful or stateless.
In those cases, we would need to handle those changes ourselves. We would need to set a timeout to see if a new connection event comes or raise the error if not and if it comes, hope that GStreamer can handle that change gracefully.
We think those changes would make the code more complex and wouldn’t fix problems perfectly since maybe GStreamer cannot handle it, so we think it is better to keep things as they currently are, raising the error when GStreamer says so and we don’t have a connection.
Yes, finally it is public that we are contributing to MAFW project, born for the Maemo platform.
My latest jobs were focused in the mafw-gst-renderer
component so feel free to ask me any questions related to that or any other component.
I am damm lazy to blog, but I will try to do it sometimes to talk about what I did for the project so that you can stay tuned and follow a bit project’s evolution.
Small things
These last days I touched some small issues as changing a bit the way we destroy the GStreamer pipeline, since we we checking for asynchronous state changes when setting it to NULL that should never happen.