State management

Renderers behave like state machines. Operations may or may not be valid depending on the renderer's state, or may change their behavior depending on it. For example, a STOP command may be ignored if the renderer is already stopped, but otherwise it should stop any ongoing playback.

The renderer's state machine has four states:

A renderer is Stopped if it is not playing any media. Whenever the renderer receives the order to play some media content, it moves to the Transitioning state. In this state, the renderer attempts to get anything it may need to play the selected item, for example, it should get the URI of the item to be played by invoking mafw_source_get_metadata, and then use this URI to start playback using the underlying playback engine (for example, GStreamer). The renderer moves to the Playing state once playback has been started by the underlying playback engine. During this state, the user can call mafw_renderer_pause, which makes the renderer move to Paused state. In this state, it is possible to call mafw_renderer_resume to continue playback. Also, the user may call mafw_renderer_stop at any time, making the renderer move back to the Stopped state again.

Application developers should react to state changes in the renderer and update the application accordingly. For example, when the renderer is in the Stopped state the developer may want to disable the Pause button, however if the renderer state is Playing it may be enabled.

Renderers inform about their state changes using the "state-changed" signal. Application developers should connect to this signal and place any state related management code there. It is also possible to query a renderer about its state by using mafw_renderer_get_status.

Here is a small code snippet illustrating these concepts:

static void
state_changed_cb(MafwRenderer *renderer, MafwPlayState state,
                 gpointer user_data)
{
        switch (state) {
                case Playing:
                        /* Enable Pause button */
                        break;
                case Paused:
                        /* Enable Resume button */
                        break;
                case Stopped:
                        /* Disable Pause/Resume button */
                        break;
                default:
                        break;
        }
}

static void
set_state_changed_handler(MafwRenderer *renderer)
{
        g_signal_connect(renderer, "state-changed",
                         G_CALLBACK(state_changed_cb), NULL);
}