2 * This file is a part of MAFW
4 * Copyright (C) 2007, 2008, 2009 Nokia Corporation, all rights reserved.
6 * Contact: Visa Smolander <visa.smolander@nokia.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; version 2.1 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
31 #include <dbus/dbus.h>
32 #include <libgnomevfs/gnome-vfs.h>
34 #include <libmafw/mafw.h>
35 #include "mafw-gst-renderer.h"
36 #include "mafw-gst-renderer-utils.h"
37 #include "mafw-gst-renderer-worker.h"
39 #include "mafw-gst-renderer-state-playing.h"
40 #include "mafw-gst-renderer-state-stopped.h"
41 #include "mafw-gst-renderer-state-paused.h"
42 #include "mafw-gst-renderer-state-transitioning.h"
47 #include <conicconnectionevent.h>
51 #define G_LOG_DOMAIN "mafw-gst-renderer"
53 #define is_current_uri_stream(self) \
54 (((self)->media != NULL) && ((self)->media->uri != NULL) && \
55 uri_is_stream((self)->media->uri))
57 #define GCONF_OSSO_AF "/system/osso/af"
58 #define GCONF_BATTERY_COVER_OPEN "/system/osso/af/mmc-cover-open"
59 #define HAL_VIDEOOUT_UDI "/org/freedesktop/Hal/devices" \
60 "/platform_soc_audio_logicaldev_input"
62 /*----------------------------------------------------------------------------
63 Static variable definitions
64 ----------------------------------------------------------------------------*/
66 /*----------------------------------------------------------------------------
68 ----------------------------------------------------------------------------*/
70 static gboolean mafw_gst_renderer_initialize(MafwRegistry *registry,
72 static void mafw_gst_renderer_deinitialize(GError **error);
74 /*----------------------------------------------------------------------------
75 GObject initialization
76 ----------------------------------------------------------------------------*/
78 static void mafw_gst_renderer_dispose(GObject *object);
79 static void mafw_gst_renderer_finalize(GObject *object);
81 /*----------------------------------------------------------------------------
83 ----------------------------------------------------------------------------*/
84 static void _property_modified(LibHalContext *ctx, const char *udi,
85 const char *key, dbus_bool_t is_removed,
86 dbus_bool_t is_added);
87 static gboolean _tv_out_is_connected(LibHalContext *ctx, const char *udi);
89 /*----------------------------------------------------------------------------
91 ----------------------------------------------------------------------------*/
93 static void _battery_cover_open_cb(GConfClient *client,
96 MafwGstRenderer *renderer);
98 /*----------------------------------------------------------------------------
99 Gnome VFS notifications
100 ----------------------------------------------------------------------------*/
102 static void _volume_pre_unmount_cb(GnomeVFSVolumeMonitor *monitor,
103 GnomeVFSVolume *volume,
104 MafwGstRenderer *renderer);
106 /*----------------------------------------------------------------------------
108 ----------------------------------------------------------------------------*/
110 static void _signal_state_changed(MafwGstRenderer * self);
111 static void _signal_media_changed(MafwGstRenderer * self);
112 static void _signal_playlist_changed(MafwGstRenderer * self);
113 static void _signal_transport_actions_property_changed(MafwGstRenderer * self);
115 /*----------------------------------------------------------------------------
117 ----------------------------------------------------------------------------*/
119 static void _set_error_policy(MafwGstRenderer *renderer, MafwRendererErrorPolicy policy);
120 static MafwRendererErrorPolicy _get_error_policy(MafwGstRenderer *renderer);
122 static void mafw_gst_renderer_set_property(MafwExtension *self, const gchar *key,
123 const GValue *value);
124 static void mafw_gst_renderer_get_property(MafwExtension *self, const gchar *key,
125 MafwExtensionPropertyCallback callback,
128 /*----------------------------------------------------------------------------
130 ----------------------------------------------------------------------------*/
132 static void _notify_metadata(MafwSource *cb_source,
133 const gchar *cb_object_id,
134 GHashTable *cb_metadata,
135 gpointer cb_user_data,
136 const GError *cb_error);
138 /*----------------------------------------------------------------------------
139 Notification operations
140 ----------------------------------------------------------------------------*/
142 static void _notify_play(MafwGstRendererWorker *worker, gpointer owner);
143 static void _notify_pause(MafwGstRendererWorker *worker, gpointer owner);
144 static void _notify_seek(MafwGstRendererWorker *worker, gpointer owner);
145 static void _notify_buffer_status(MafwGstRendererWorker *worker, gpointer owner,
147 static void _notify_eos(MafwGstRendererWorker *worker, gpointer owner);
148 static void _error_handler(MafwGstRendererWorker *worker, gpointer owner,
149 const GError *error);
152 /*----------------------------------------------------------------------------
154 ----------------------------------------------------------------------------*/
156 static void _connection_init(MafwGstRenderer *renderer);
159 /*----------------------------------------------------------------------------
160 Plugin initialization
161 ----------------------------------------------------------------------------*/
164 * Registers the plugin descriptor making this plugin available to the
165 * framework and applications
167 G_MODULE_EXPORT MafwPluginDescriptor mafw_gst_renderer_plugin_description = {
168 { .name = MAFW_GST_RENDERER_PLUGIN_NAME },
169 .initialize = mafw_gst_renderer_initialize,
170 .deinitialize = mafw_gst_renderer_deinitialize,
173 static gboolean mafw_gst_renderer_initialize(MafwRegistry *registry,
176 MafwGstRenderer *self;
178 g_assert(registry != NULL);
179 self = MAFW_GST_RENDERER(mafw_gst_renderer_new(registry));
180 mafw_registry_add_extension(registry, MAFW_EXTENSION(self));
185 static void mafw_gst_renderer_deinitialize(GError **error)
189 /*----------------------------------------------------------------------------
190 GObject initialization
191 ----------------------------------------------------------------------------*/
193 G_DEFINE_TYPE(MafwGstRenderer, mafw_gst_renderer, MAFW_TYPE_RENDERER);
195 static void mafw_gst_renderer_class_init(MafwGstRendererClass *klass)
197 GObjectClass *gclass = NULL;
198 MafwRendererClass *renderer_class = NULL;
199 const gchar *preloaded_plugins[] = {"playback", "uridecodebin",
200 "coreelements", "typefindfunctions", "omx", "selector",
201 "autodetect", "pulseaudio", "audioconvert", "audioresample",
202 "xvimagesink", "ffmpegcolorspace", "videoscale", NULL};
206 gclass = G_OBJECT_CLASS(klass);
207 g_return_if_fail(gclass != NULL);
209 renderer_class = MAFW_RENDERER_CLASS(klass);
210 g_return_if_fail(renderer_class != NULL);
214 gclass->dispose = mafw_gst_renderer_dispose;
215 gclass->finalize = mafw_gst_renderer_finalize;
219 renderer_class->play = mafw_gst_renderer_play;
220 renderer_class->play_object = mafw_gst_renderer_play_object;
221 renderer_class->stop = mafw_gst_renderer_stop;
222 renderer_class->pause = mafw_gst_renderer_pause;
223 renderer_class->resume = mafw_gst_renderer_resume;
224 renderer_class->get_status = mafw_gst_renderer_get_status;
226 /* Playlist operations */
228 renderer_class->assign_playlist = mafw_gst_renderer_assign_playlist;
229 renderer_class->next = mafw_gst_renderer_next;
230 renderer_class->previous = mafw_gst_renderer_previous;
231 renderer_class->goto_index = mafw_gst_renderer_goto_index;
233 /* Playback position */
235 renderer_class->set_position = mafw_gst_renderer_set_position;
236 renderer_class->get_position = mafw_gst_renderer_get_position;
240 renderer_class->get_current_metadata =
241 mafw_gst_renderer_get_current_metadata;
245 MAFW_EXTENSION_CLASS(klass)->get_extension_property =
246 (gpointer) mafw_gst_renderer_get_property;
247 MAFW_EXTENSION_CLASS(klass)->set_extension_property =
248 (gpointer) mafw_gst_renderer_set_property;
250 gst_init(NULL, NULL);
253 /* Pre-load some common plugins */
254 while (preloaded_plugins[i])
256 plugin = G_OBJECT(gst_plugin_load_by_name(preloaded_plugins[i]));
258 g_object_unref(plugin);
260 g_debug("Can not load plugin: %s", preloaded_plugins[i]);
265 static void mafw_gst_renderer_init(MafwGstRenderer *self)
267 MafwGstRenderer *renderer = NULL;
268 GError *error = NULL;
270 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
272 renderer = MAFW_GST_RENDERER(self);
273 g_return_if_fail(renderer != NULL);
275 mafw_extension_add_property(MAFW_EXTENSION(self), "volume", G_TYPE_UINT);
276 mafw_extension_add_property(MAFW_EXTENSION(self), "mute", G_TYPE_BOOLEAN);
277 mafw_extension_add_property(MAFW_EXTENSION(self), "xid", G_TYPE_UINT);
278 mafw_extension_add_property(MAFW_EXTENSION(self), "error-policy", G_TYPE_UINT);
279 MAFW_EXTENSION_SUPPORTS_AUTOPAINT(self);
280 MAFW_EXTENSION_SUPPORTS_COLORKEY(self);
281 #ifdef HAVE_GDKPIXBUF
282 mafw_extension_add_property(MAFW_EXTENSION(self),
283 "current-frame-on-pause",
286 mafw_extension_add_property(MAFW_EXTENSION(self),
287 MAFW_PROPERTY_GST_RENDERER_TV_CONNECTED,
289 MAFW_EXTENSION_SUPPORTS_TRANSPORT_ACTIONS(self);
290 renderer->media = g_new0(MafwGstRendererMedia, 1);
291 renderer->media->seekability = SEEKABILITY_UNKNOWN;
292 renderer->current_state = Stopped;
294 renderer->playlist = NULL;
295 renderer->iterator = NULL;
296 renderer->seeking_to = -1;
297 renderer->update_playcount_id = 0;
299 self->worker = mafw_gst_renderer_worker_new(self);
301 /* Set notification handlers for worker */
302 renderer->worker->notify_play_handler = _notify_play;
303 renderer->worker->notify_pause_handler = _notify_pause;
304 renderer->worker->notify_seek_handler = _notify_seek;
305 renderer->worker->notify_error_handler = _error_handler;
306 renderer->worker->notify_eos_handler = _notify_eos;
307 renderer->worker->notify_buffer_status_handler = _notify_buffer_status;
309 renderer->states = g_new0 (MafwGstRendererState*, _LastMafwPlayState);
310 renderer->states[Stopped] =
311 MAFW_GST_RENDERER_STATE(mafw_gst_renderer_state_stopped_new(self));
312 renderer->states[Transitioning] =
313 MAFW_GST_RENDERER_STATE(
314 mafw_gst_renderer_state_transitioning_new(self));
315 renderer->states[Playing] =
316 MAFW_GST_RENDERER_STATE(mafw_gst_renderer_state_playing_new(self));
317 renderer->states[Paused] =
318 MAFW_GST_RENDERER_STATE(mafw_gst_renderer_state_paused_new(self));
320 renderer->current_state = Stopped;
321 renderer->resume_playlist = FALSE;
322 renderer->playback_mode = MAFW_GST_RENDERER_MODE_PLAYLIST;
325 renderer->connected = FALSE;
326 renderer->connection = NULL;
328 _connection_init(renderer);
330 renderer->gconf_client = gconf_client_get_default();
331 gconf_client_add_dir(renderer->gconf_client, GCONF_OSSO_AF,
332 GCONF_CLIENT_PRELOAD_ONELEVEL, &error);
334 g_warning("%s", error->message);
339 gconf_client_notify_add(renderer->gconf_client,
340 GCONF_BATTERY_COVER_OPEN,
341 (GConfClientNotifyFunc) _battery_cover_open_cb,
346 g_warning("%s", error->message);
350 if (gnome_vfs_init()) {
351 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
352 g_signal_connect(monitor, "volume-pre-unmount",
353 G_CALLBACK(_volume_pre_unmount_cb), renderer);
355 g_warning("Failed to initialize gnome-vfs");
359 static void mafw_gst_renderer_dispose(GObject *object)
361 MafwGstRenderer *renderer;
363 g_return_if_fail(MAFW_IS_GST_RENDERER(object));
365 renderer = MAFW_GST_RENDERER(object);
367 if (renderer->worker != NULL) {
368 mafw_gst_renderer_worker_exit(renderer->worker);
369 renderer->seek_pending = FALSE;
370 g_free(renderer->worker);
371 renderer->worker = NULL;
374 if (renderer->registry != NULL) {
375 g_object_unref(renderer->registry);
376 renderer->registry = NULL;
379 if (renderer->states != NULL) {
382 for (i = 0; i < _LastMafwPlayState; i++) {
383 if (renderer->states[i] != NULL)
384 g_object_unref(renderer->states[i]);
386 g_free(renderer->states);
387 renderer->states = NULL;
390 if (renderer->hal_ctx != NULL) {
391 libhal_device_remove_property_watch(renderer->hal_ctx,
394 libhal_ctx_shutdown(renderer->hal_ctx, NULL);
395 libhal_ctx_free(renderer->hal_ctx);
399 if (renderer->connection != NULL) {
400 g_object_unref(renderer->connection);
401 renderer->connection = NULL;
405 if (renderer->gconf_client != NULL) {
406 g_object_unref(renderer->gconf_client);
407 renderer->gconf_client = NULL;
410 G_OBJECT_CLASS(mafw_gst_renderer_parent_class)->dispose(object);
413 static void mafw_gst_renderer_finalize(GObject *object)
415 MafwGstRenderer *self = (MafwGstRenderer*) object;
417 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
419 mafw_gst_renderer_clear_media(self);
427 G_OBJECT_CLASS(mafw_gst_renderer_parent_class)->finalize(object);
431 * mafw_gst_renderer_new:
432 * @registry: The registry that owns this renderer.
434 * Creates a new MafwGstRenderer object
436 GObject *mafw_gst_renderer_new(MafwRegistry* registry)
440 DBusConnection *conn;
446 object = g_object_new(MAFW_TYPE_GST_RENDERER,
447 "uuid", MAFW_GST_RENDERER_UUID,
448 "name", MAFW_GST_RENDERER_NAME,
449 "plugin", MAFW_GST_RENDERER_PLUGIN_NAME,
451 g_assert(object != NULL);
452 MAFW_GST_RENDERER(object)->registry = g_object_ref(registry);
454 /* Set default error policy */
455 MAFW_GST_RENDERER(object)->error_policy =
456 MAFW_RENDERER_ERROR_POLICY_CONTINUE;
458 MAFW_GST_RENDERER(object)->tv_connected = FALSE;
460 /* Setup hal connection for reacting usb cable connected event */
461 dbus_error_init(&err);
462 conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
464 if (dbus_error_is_set(&err)) {
465 g_warning("Couldn't setup HAL connection: %s", err.message);
466 dbus_error_free(&err);
470 ctx = libhal_ctx_new();
471 libhal_ctx_set_dbus_connection(ctx, conn);
472 libhal_ctx_set_user_data(ctx, object);
474 if (libhal_ctx_init(ctx, &err) == FALSE) {
475 if (dbus_error_is_set(&err)) {
476 g_warning("Could not initialize hal: %s", err.message);
477 dbus_error_free(&err);
479 g_warning("Could not initialize hal");
484 libhal_device_add_property_watch(ctx, HAL_VIDEOOUT_UDI, &err);
486 if (dbus_error_is_set(&err)) {
487 g_warning("Could not start watching usb device: %s",
489 dbus_error_free(&err);
493 libhal_ctx_set_device_property_modified(ctx, _property_modified);
495 /* Initializes blanking policy */
496 jackets = libhal_find_device_by_capability(ctx,
497 "input.jack.video-out",
499 if (jackets != NULL) {
502 if (_tv_out_is_connected(ctx, *jack)) {
503 MAFW_GST_RENDERER(object)->tv_connected = TRUE;
509 blanking_control(*jack == NULL);
510 libhal_free_string_array(jackets);
513 MAFW_GST_RENDERER(object)->hal_ctx = ctx;
517 libhal_ctx_shutdown(ctx, NULL);
519 libhal_ctx_free(ctx);
525 * mafw_gst_renderer_error_quark:
527 * Fetches the quark representing the domain of the errors in the
530 * Return value: a quark identifying the error domain of the
531 * #MafwGstRenderer objects.
534 GQuark mafw_gst_renderer_error_quark(void)
536 return g_quark_from_static_string("mafw-gst-renderer-error-quark");
539 void mafw_gst_renderer_set_playback_mode(MafwGstRenderer *self,
540 MafwGstRendererPlaybackMode mode)
542 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
543 self->playback_mode = mode;
546 MafwGstRendererPlaybackMode mafw_gst_renderer_get_playback_mode(
547 MafwGstRenderer *self)
549 g_return_val_if_fail(MAFW_IS_GST_RENDERER(self),
550 MAFW_GST_RENDERER_MODE_STANDALONE);
551 return self->playback_mode;
554 /*----------------------------------------------------------------------------
556 ----------------------------------------------------------------------------*/
558 static MafwSource* _get_source(MafwGstRenderer *renderer,
559 const gchar *object_id)
562 gchar* sourceid = NULL;
564 g_assert(object_id != NULL);
566 /* Attempt to find a source that provided the object ID */
567 mafw_source_split_objectid(object_id, &sourceid, NULL);
568 source = MAFW_SOURCE(mafw_registry_get_extension_by_uuid(
569 renderer->registry, sourceid));
575 void mafw_gst_renderer_get_metadata(MafwGstRenderer* self,
576 const gchar* objectid,
581 g_assert(self != NULL);
584 * Any error here is an error when trying to Play, so
585 * it must be handled by error policy.
586 * Problem: if we get an error here and we are not in
587 * Transitioning yet (maybe we are still in Stopped state)
588 * then the policy may move to next and stay Stopped (instead of
589 * trying to play), so errors need to be handled by the policy
590 * in an idle callback, so that any error that may happen here
591 * is not processed until we have moved to Transitioning state
594 source = _get_source(self, objectid);
597 /* List of metadata keys that we are interested in when going to
598 Transitioning state */
599 static const gchar * const keys[] =
600 { MAFW_METADATA_KEY_URI,
601 MAFW_METADATA_KEY_IS_SEEKABLE,
602 MAFW_METADATA_KEY_DURATION,
605 /* Source found, get metadata */
606 mafw_source_get_metadata(source, objectid,
614 /* This is a playback error: execute error policy */
615 MafwGstRendererErrorClosure *error_closure;
616 error_closure = g_new0(MafwGstRendererErrorClosure, 1);
617 error_closure->renderer = self;
618 g_set_error (&(error_closure->error),
619 MAFW_EXTENSION_ERROR,
620 MAFW_EXTENSION_ERROR_EXTENSION_NOT_AVAILABLE,
621 "Unable to find source for current object ID");
622 g_idle_add(mafw_gst_renderer_manage_error_idle, error_closure);
626 void mafw_gst_renderer_set_object(MafwGstRenderer *self, const gchar *object_id)
628 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
630 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
631 g_return_if_fail(object_id != NULL);
633 /* This is intended to be called only when using play_object(),
634 * as for playlists we use set_media_playlist()
637 /* Stop any ongoing playback */
638 mafw_gst_renderer_clear_media(renderer);
641 renderer->media->object_id = g_strdup(object_id);
643 /* Signal media changed */
644 _signal_media_changed(renderer);
649 * mafw_gst_renderer_clear_media:
651 * @renderer A #MafwGstRenderer whose media to clear
653 * Clears & frees the renderer's current media details
655 void mafw_gst_renderer_clear_media(MafwGstRenderer *self)
657 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
658 g_return_if_fail(self->media != NULL);
660 g_free(self->media->object_id);
661 self->media->object_id = NULL;
663 g_free(self->media->uri);
664 self->media->uri = NULL;
666 g_free(self->media->title);
667 self->media->title = NULL;
669 g_free(self->media->artist);
670 self->media->artist = NULL;
672 g_free(self->media->album);
673 self->media->album = NULL;
675 self->media->duration = 0;
676 self->media->position = 0;
681 * mafw_gst_renderer_set_media_playlist:
683 * @self A #MafwGstRenderer, whose media to set
685 * Set current media from the renderer's playlist, using the current playlist index.
687 void mafw_gst_renderer_set_media_playlist(MafwGstRenderer* self)
689 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
691 /* Get rid of old media details */
692 mafw_gst_renderer_clear_media(self);
694 if (self->playlist != NULL &&
695 mafw_playlist_iterator_get_size(self->iterator, NULL) > 0) {
696 /* Get the current item from playlist */
697 self->media->object_id =
698 g_strdup(mafw_playlist_iterator_get_current_objectid(self->iterator));
700 self->media->object_id = NULL;
703 _signal_media_changed(self);
707 /*----------------------------------------------------------------------------
709 ----------------------------------------------------------------------------*/
712 _con_ic_status_handler(ConIcConnection *conn, ConIcConnectionEvent *event,
715 MafwGstRenderer *renderer = (MafwGstRenderer *) data;
717 g_assert(MAFW_IS_GST_RENDERER(renderer));
719 renderer->connected =
720 con_ic_connection_event_get_status(event) ==
721 CON_IC_STATUS_CONNECTED;
725 _connection_init(MafwGstRenderer *renderer)
727 g_assert (MAFW_IS_GST_RENDERER(renderer));
729 if (renderer->connection == NULL) {
730 renderer->connection = con_ic_connection_new();
731 renderer->connected = FALSE;
733 g_assert(renderer->connection != NULL);
736 g_object_set(renderer->connection, "automatic-connection-events",
738 g_signal_connect(renderer->connection, "connection-event",
739 G_CALLBACK (_con_ic_status_handler), renderer);
741 con_ic_connection_connect(renderer->connection,
742 CON_IC_CONNECT_FLAG_AUTOMATICALLY_TRIGGERED);
746 /*----------------------------------------------------------------------------
748 ----------------------------------------------------------------------------*/
750 static gboolean _tv_out_is_connected(LibHalContext *ctx, const char *udi)
752 gboolean is_tv_out_jack = FALSE;
760 jack_types = libhal_device_get_property_strlist(ctx, udi,
763 if (jack_types == NULL) {
769 if (strcmp(*jack, "video-out") == 0) {
770 is_tv_out_jack = TRUE;
777 libhal_free_string_array(jack_types);
779 return is_tv_out_jack;
782 static void _property_modified(LibHalContext *ctx, const char *udi,
783 const char *key, dbus_bool_t is_removed,
784 dbus_bool_t is_added)
786 MafwGstRenderer *renderer;
788 GValue value = { 0 };
790 g_debug("HAL property modified! jack changed\n");
791 connected = _tv_out_is_connected(ctx, udi);
792 renderer = MAFW_GST_RENDERER(libhal_ctx_get_user_data(ctx));
793 if (renderer->tv_connected != connected) {
794 /* Notify the change */
795 renderer->tv_connected = connected;
796 g_value_init(&value, G_TYPE_BOOLEAN);
797 g_value_set_boolean(&value, renderer->tv_connected);
798 mafw_extension_emit_property_changed(
799 MAFW_EXTENSION(renderer),
800 MAFW_PROPERTY_GST_RENDERER_TV_CONNECTED,
802 g_value_unset(&value);
804 blanking_control(connected == FALSE);
807 /*----------------------------------------------------------------------------
809 ----------------------------------------------------------------------------*/
811 static void _battery_cover_open_cb(GConfClient *client,
814 MafwGstRenderer *renderer)
816 GConfValue *value = NULL;
817 gboolean is_cover_open;
819 value = gconf_entry_get_value(entry);
820 is_cover_open = gconf_value_get_bool(value);
823 /* External mmc could be removed!. */
824 const gchar *emmc_path = g_getenv("MMC_MOUNTPOINT");
826 mafw_gst_renderer_state_handle_pre_unmount(
827 MAFW_GST_RENDERER_STATE(
828 renderer->states[renderer->current_state]),
833 /*----------------------------------------------------------------------------
834 Gnome VFS notifications
835 ----------------------------------------------------------------------------*/
837 static void _volume_pre_unmount_cb(GnomeVFSVolumeMonitor *monitor,
838 GnomeVFSVolume *volume,
839 MafwGstRenderer *renderer)
841 gchar *location = gnome_vfs_volume_get_activation_uri(volume);
846 mafw_gst_renderer_state_handle_pre_unmount(
847 MAFW_GST_RENDERER_STATE(
848 renderer->states[renderer->current_state]),
854 /*----------------------------------------------------------------------------
856 ----------------------------------------------------------------------------*/
860 * _signal_state_changed:
861 * @self: A #MafwGstRenderer
863 * Signals state_changed to all UIs
865 static void _signal_state_changed(MafwGstRenderer * self)
867 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
869 g_signal_emit_by_name(MAFW_RENDERER(self),
870 "state-changed", self->current_state);
874 * _signal_playlist_changed:
875 * @self: A #MafwGstRenderer
877 * Signals playlist update to all UIs
879 static void _signal_playlist_changed(MafwGstRenderer * self)
881 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
883 g_signal_emit_by_name(MAFW_RENDERER(self),
884 "playlist-changed", self->playlist);
888 * _signal_media_changed:
889 * @self: A #MafwGstRenderer
891 * Signals media_changed to all UIs
893 static void _signal_media_changed(MafwGstRenderer *self)
896 MafwGstRendererPlaybackMode mode;
899 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
901 mode = mafw_gst_renderer_get_playback_mode(MAFW_GST_RENDERER(self));
902 if ((mode == MAFW_GST_RENDERER_MODE_STANDALONE) ||
903 (self->iterator == NULL)) {
906 index = mafw_playlist_iterator_get_current_index(self->iterator);
909 g_signal_emit_by_name(MAFW_RENDERER(self),
912 self->media->object_id);
916 * _signal_transport_actions_property_changed:
917 * @self: A #MafwGstRenderer
919 * Signals transport_actions property_changed to all UIs
921 static void _signal_transport_actions_property_changed(MafwGstRenderer * self)
925 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
927 value = mafw_gst_renderer_state_get_property_value(
928 MAFW_GST_RENDERER_STATE(
929 self->states[self->current_state]),
930 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS);
933 mafw_extension_emit_property_changed(
934 MAFW_EXTENSION(self),
935 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS,
937 g_value_unset(value);
943 /*----------------------------------------------------------------------------
944 State pattern support
945 ----------------------------------------------------------------------------*/
947 void mafw_gst_renderer_set_state(MafwGstRenderer *self, MafwPlayState state)
949 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
951 self->current_state = state;
952 _signal_state_changed(self);
953 _signal_transport_actions_property_changed(self);
956 void mafw_gst_renderer_play(MafwRenderer *self, MafwRendererPlaybackCB callback,
959 MafwGstRenderer *renderer = (MafwGstRenderer*) self;
960 GError *error = NULL;
962 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
964 g_return_if_fail((renderer->states != 0) &&
965 (renderer->current_state != _LastMafwPlayState) &&
966 (renderer->states[renderer->current_state] != NULL));
968 mafw_gst_renderer_state_play(
969 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
972 if (callback != NULL)
973 callback(self, user_data, error);
978 void mafw_gst_renderer_play_object(MafwRenderer *self,
979 const gchar *object_id,
980 MafwRendererPlaybackCB callback,
983 MafwGstRenderer *renderer = (MafwGstRenderer*) self;
984 GError *error = NULL;
986 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
987 g_return_if_fail(object_id != NULL);
989 g_return_if_fail((renderer->states != 0) &&
990 (renderer->current_state != _LastMafwPlayState) &&
991 (renderer->states[renderer->current_state] != NULL));
993 mafw_gst_renderer_state_play_object(
994 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
998 if (callback != NULL)
999 callback(self, user_data, error);
1001 g_error_free(error);
1004 void mafw_gst_renderer_stop(MafwRenderer *self, MafwRendererPlaybackCB callback,
1007 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1008 GError *error = NULL;
1010 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1012 g_return_if_fail((renderer->states != 0) &&
1013 (renderer->current_state != _LastMafwPlayState) &&
1014 (renderer->states[renderer->current_state] != NULL));
1016 renderer->play_failed_count = 0;
1017 mafw_gst_renderer_state_stop(
1018 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1021 if (callback != NULL)
1022 callback(self, user_data, error);
1024 g_error_free(error);
1028 void mafw_gst_renderer_pause(MafwRenderer *self, MafwRendererPlaybackCB callback,
1031 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1032 GError *error = NULL;
1034 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1036 g_return_if_fail((renderer->states != 0) &&
1037 (renderer->current_state != _LastMafwPlayState) &&
1038 (renderer->states[renderer->current_state] != NULL));
1040 mafw_gst_renderer_state_pause(
1041 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1044 if (callback != NULL)
1045 callback(self, user_data, error);
1047 g_error_free(error);
1050 void mafw_gst_renderer_resume(MafwRenderer *self, MafwRendererPlaybackCB callback,
1053 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1054 GError *error = NULL;
1056 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1058 g_return_if_fail((renderer->states != 0) &&
1059 (renderer->current_state != _LastMafwPlayState) &&
1060 (renderer->states[renderer->current_state] != NULL));
1062 mafw_gst_renderer_state_resume(
1063 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1066 if (callback != NULL)
1067 callback(self, user_data, error);
1069 g_error_free(error);
1072 void mafw_gst_renderer_next(MafwRenderer *self, MafwRendererPlaybackCB callback,
1075 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1076 GError *error = NULL;
1078 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1080 g_return_if_fail((renderer->states != 0) &&
1081 (renderer->current_state != _LastMafwPlayState) &&
1082 (renderer->states[renderer->current_state] != NULL));
1084 renderer->play_failed_count = 0;
1085 mafw_gst_renderer_state_next(
1086 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1089 if (callback != NULL)
1090 callback(self, user_data, error);
1092 g_error_free(error);
1095 void mafw_gst_renderer_previous(MafwRenderer *self, MafwRendererPlaybackCB callback,
1098 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1099 GError *error = NULL;
1101 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1103 g_return_if_fail((renderer->states != 0) &&
1104 (renderer->current_state != _LastMafwPlayState) &&
1105 (renderer->states[renderer->current_state] != NULL));
1107 renderer->play_failed_count = 0;
1108 mafw_gst_renderer_state_previous(
1109 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1112 if (callback != NULL)
1113 callback(self, user_data, error);
1115 g_error_free(error);
1118 void mafw_gst_renderer_goto_index(MafwRenderer *self, guint index,
1119 MafwRendererPlaybackCB callback,
1122 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1123 GError *error = NULL;
1125 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1127 g_return_if_fail((renderer->states != 0) &&
1128 (renderer->current_state != _LastMafwPlayState) &&
1129 (renderer->states[renderer->current_state] != NULL));
1131 renderer->play_failed_count = 0;
1132 mafw_gst_renderer_state_goto_index(
1133 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1137 if (callback != NULL)
1138 callback(self, user_data, error);
1140 g_error_free(error);
1143 void mafw_gst_renderer_get_position(MafwRenderer *self, MafwRendererPositionCB callback,
1146 MafwGstRenderer *renderer;
1148 GError *error = NULL;
1150 g_return_if_fail(callback != NULL);
1151 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1153 renderer = MAFW_GST_RENDERER(self);
1155 g_return_if_fail((renderer->states != 0) &&
1156 (renderer->current_state != _LastMafwPlayState) &&
1157 (renderer->states[renderer->current_state] != NULL));
1159 mafw_gst_renderer_state_get_position(
1160 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1164 callback(self, pos, user_data, error);
1166 g_error_free(error);
1169 void mafw_gst_renderer_set_position(MafwRenderer *self, MafwRendererSeekMode mode,
1170 gint seconds, MafwRendererPositionCB callback,
1173 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1174 GError *error = NULL;
1176 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1178 g_return_if_fail((renderer->states != 0) &&
1179 (renderer->current_state != _LastMafwPlayState) &&
1180 (renderer->states[renderer->current_state] != NULL));
1182 mafw_gst_renderer_state_set_position(
1183 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1188 if (callback != NULL)
1189 callback(self, seconds, user_data, error);
1191 g_error_free(error);
1194 gboolean mafw_gst_renderer_manage_error_idle(gpointer data)
1196 MafwGstRendererErrorClosure *mec = (MafwGstRendererErrorClosure *) data;
1198 mafw_gst_renderer_manage_error(mec->renderer, mec->error);
1200 g_error_free(mec->error);
1206 static void _run_error_policy(MafwGstRenderer *self, const GError *in_err,
1209 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1211 gboolean play_next = FALSE;
1213 /* Check what to do on error */
1214 if (in_err->code == MAFW_EXTENSION_ERROR_OUT_OF_MEMORY) {
1217 MafwGstRendererPlaybackMode mode;
1219 mode = mafw_gst_renderer_get_playback_mode(self);
1221 if (mode == MAFW_GST_RENDERER_MODE_PLAYLIST) {
1222 /* In playlist mode we try to play next if
1223 error policy suggests so */
1225 (_get_error_policy(self) ==
1226 MAFW_RENDERER_ERROR_POLICY_CONTINUE);
1228 /* In standalone mode, then switch back to playlist
1229 mode and resume if necessary or move to Stopped
1231 mafw_gst_renderer_set_playback_mode(
1232 self, MAFW_GST_RENDERER_MODE_PLAYLIST);
1233 mafw_gst_renderer_set_media_playlist(self);
1234 if (self->resume_playlist) {
1235 mafw_gst_renderer_play(MAFW_RENDERER(self),
1238 mafw_gst_renderer_worker_stop(self->worker);
1239 mafw_gst_renderer_set_state(self, Stopped);
1241 if (out_err) *out_err = g_error_copy(in_err);
1243 /* Bail out, he have already managed the error
1244 for the case of standalone mode */
1250 if (self->playlist){
1251 MafwPlaylistIteratorMovementResult result;
1253 result = mafw_playlist_iterator_move_to_next(self->iterator,
1255 self->play_failed_count++;
1257 if (mafw_playlist_iterator_get_size(self->iterator,
1259 self->play_failed_count)
1261 mafw_gst_renderer_state_stop(
1262 MAFW_GST_RENDERER_STATE(self->states[self->current_state]),
1264 self->play_failed_count = 0;
1265 mafw_gst_renderer_set_media_playlist(self);
1266 } else if (result !=
1267 MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_OK) {
1268 mafw_playlist_iterator_reset(self->iterator, NULL);
1269 mafw_gst_renderer_set_media_playlist(self);
1270 mafw_gst_renderer_stop(MAFW_RENDERER(self), NULL, NULL);
1272 mafw_gst_renderer_set_media_playlist(self);
1273 mafw_gst_renderer_play(MAFW_RENDERER(self), NULL, NULL);
1276 if (out_err) *out_err = g_error_copy(in_err);
1279 /* We cannot move to next in the playlist or decided
1280 we do not want to do it, just stop on error */
1281 mafw_gst_renderer_stop(MAFW_RENDERER(self), NULL, NULL);
1282 if (out_err) *out_err = g_error_copy(in_err);
1286 static void _metadata_set_cb(MafwSource *self, const gchar *object_id,
1287 const gchar **failed_keys, gpointer user_data,
1288 const GError *error)
1290 if (error != NULL) {
1291 g_debug("Ignoring error received when setting metadata: "
1292 "%s (%d): %s", g_quark_to_string(error->domain),
1293 error->code, error->message);
1295 g_debug("Metadata set correctly");
1300 * _update_playcount_metadata_cb:
1301 * @cb_source: The #MafwSource that sent the metadata results
1302 * @cb_object_id: The object ID, whose metadata results were received
1303 * @cb_metadata: GHashTable containing metadata key-value pairs
1304 * @cb_user_data: Optional user data pointer (self)
1305 * @cb_error: Set if any errors occurred during metadata browsing
1307 * Receives the results of a metadata request about the playcount. It increases
1308 * it, or sets to 1, and sets the metadata to that.
1310 static void _update_playcount_metadata_cb (MafwSource *cb_source,
1311 const gchar *cb_object_id,
1312 GHashTable *cb_metadata,
1313 gpointer cb_user_data,
1314 const GError *cb_error)
1316 GValue *curval = NULL;
1317 gint curplaycount = -1;
1318 GHashTable *mdata = cb_user_data;
1320 if (cb_error == NULL) {
1322 curval = mafw_metadata_first(cb_metadata,
1323 MAFW_METADATA_KEY_PLAY_COUNT);
1324 if (curval && !G_VALUE_HOLDS(curval, G_TYPE_INT))
1328 curplaycount = g_value_get_int(curval);
1332 { /* Playing at first time, or not supported... */
1336 mdata = mafw_metadata_new();
1337 mafw_metadata_add_int(mdata,
1338 MAFW_METADATA_KEY_PLAY_COUNT,
1342 g_warning("_playcount_metadata received an error: "
1343 "%s (%d): %s", g_quark_to_string(cb_error->domain),
1344 cb_error->code, cb_error->message);
1346 g_hash_table_unref(mdata);
1353 mafw_source_set_metadata(cb_source, cb_object_id, mdata,
1354 _metadata_set_cb, NULL);
1355 g_hash_table_unref(mdata);
1360 * mafw_gst_renderer_add_lastplayed:
1361 * @mdata: Exisiting mdata, or NULL
1363 * Sets the MAFW_METADATA_KEY_LAST_PLAYED metadata in the given metadata-table,
1364 * or creates a new metadata-table, and sets the current time there.
1366 static GHashTable *mafw_gst_renderer_add_lastplayed(GHashTable *mdata)
1368 GHashTable *metadata;
1373 metadata = mafw_metadata_new();
1379 g_get_current_time(&timeval);
1381 mafw_metadata_add_long(metadata,
1382 MAFW_METADATA_KEY_LAST_PLAYED,
1388 * mafw_gst_renderer_increase_playcount:
1389 * @self: Gst renderer
1390 * @object_id: The object ID of the touched object
1391 * @mdat: Existing metadatas to add the playcount to, or NULL
1393 * Increases the playcount of the given object.
1395 static void mafw_gst_renderer_increase_playcount(MafwGstRenderer* self,
1396 const gchar *object_id, GHashTable *mdat)
1400 g_assert(self != NULL);
1401 source = _get_source(self, object_id);
1404 static const gchar * const keys[] =
1405 { MAFW_METADATA_KEY_PLAY_COUNT, NULL };
1407 mafw_source_get_metadata(source, object_id,
1409 _update_playcount_metadata_cb,
1416 * mafw_gst_renderer_update_stats:
1419 * Updates both playcount and lastplayed after a while.
1421 gboolean mafw_gst_renderer_update_stats(gpointer data)
1423 MafwGstRenderer *renderer = (MafwGstRenderer *) data;
1425 /* Update stats only for audio content */
1426 if (renderer->media->object_id &&
1427 !renderer->worker->media.has_visual_content) {
1428 GHashTable *mdata = mafw_gst_renderer_add_lastplayed(NULL);
1429 mafw_gst_renderer_increase_playcount(renderer,
1430 renderer->media->object_id,
1433 renderer->update_playcount_id = 0;
1437 void mafw_gst_renderer_update_source_duration(MafwGstRenderer *renderer,
1440 GHashTable *metadata;
1443 source = _get_source(renderer, renderer->media->object_id);
1444 g_return_if_fail(source != NULL);
1446 renderer->media->duration = duration;
1448 g_debug("updated source duration to %d", duration);
1450 metadata = mafw_metadata_new();
1451 mafw_metadata_add_int(metadata, MAFW_METADATA_KEY_DURATION, duration);
1453 mafw_source_set_metadata(source, renderer->media->object_id, metadata,
1454 _metadata_set_cb, NULL);
1455 g_hash_table_unref(metadata);
1460 * @source: The #MafwSource that sent the metadata results
1461 * @objectid: The object ID, whose metadata results were received
1462 * @metadata: GHashTable containing metadata key-value pairs
1463 * @userdata: Optional user data pointer (self)
1464 * @error: Set if any errors occurred during metadata browsing
1466 * Receives the results of a metadata request.
1468 static void _notify_metadata (MafwSource *cb_source,
1469 const gchar *cb_object_id,
1470 GHashTable *cb_metadata,
1471 gpointer cb_user_data,
1472 const GError *cb_error)
1474 MafwGstRenderer *renderer = (MafwGstRenderer*) cb_user_data;
1475 GError *mafw_error = NULL;
1476 GError *error = NULL;
1479 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1481 g_return_if_fail((renderer->states != 0) &&
1482 (renderer->current_state != _LastMafwPlayState) &&
1483 (renderer->states[renderer->current_state] != NULL));
1485 g_debug("running _notify_metadata...");
1487 mval = mafw_metadata_first(cb_metadata, MAFW_METADATA_KEY_URI);
1489 if (cb_error == NULL && mval != NULL) {
1490 mafw_gst_renderer_state_notify_metadata(
1491 MAFW_GST_RENDERER_STATE(
1492 renderer->states[renderer->current_state]),
1498 g_set_error(&mafw_error,
1499 MAFW_RENDERER_ERROR,
1500 MAFW_RENDERER_ERROR_URI_NOT_AVAILABLE, "%s",
1501 cb_error ? cb_error->message : "URI not available");
1502 mafw_gst_renderer_manage_error(renderer, mafw_error);
1503 g_error_free(mafw_error);
1507 static void _notify_play(MafwGstRendererWorker *worker, gpointer owner)
1509 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1510 GError *error = NULL;
1512 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1514 g_return_if_fail((renderer->states != 0) &&
1515 (renderer->current_state != _LastMafwPlayState) &&
1516 (renderer->states[renderer->current_state] != NULL));
1518 g_debug("running _notify_play...");
1520 mafw_gst_renderer_state_notify_play(renderer->states[renderer->current_state],
1523 if (error != NULL) {
1524 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1528 g_error_free (error);
1532 static void _notify_pause(MafwGstRendererWorker *worker, gpointer owner)
1534 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1535 GError *error = NULL;
1537 g_return_if_fail(MAFW_IS_GST_RENDERER (renderer));
1539 g_return_if_fail((renderer->states != 0) &&
1540 (renderer->current_state != _LastMafwPlayState) &&
1541 (renderer->states[renderer->current_state] != NULL));
1543 mafw_gst_renderer_state_notify_pause(renderer->states[renderer->current_state],
1546 if (error != NULL) {
1547 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1548 error->domain, error->code,
1550 g_error_free(error);
1554 static void _notify_buffer_status (MafwGstRendererWorker *worker,
1558 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1559 GError *error = NULL;
1561 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1563 g_return_if_fail((renderer->states != 0) &&
1564 (renderer->current_state != _LastMafwPlayState) &&
1565 (renderer->states[renderer->current_state] != NULL));
1567 mafw_gst_renderer_state_notify_buffer_status(
1568 renderer->states[renderer->current_state],
1572 if (error != NULL) {
1573 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1574 error->domain, error->code,
1576 g_error_free(error);
1580 static void _notify_seek(MafwGstRendererWorker *worker, gpointer owner)
1582 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1583 GError *error = NULL;
1585 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1587 g_return_if_fail((renderer->states != 0) &&
1588 (renderer->current_state != _LastMafwPlayState) &&
1589 (renderer->states[renderer->current_state] != NULL));
1591 mafw_gst_renderer_state_notify_seek(renderer->states[renderer->current_state],
1594 if (error != NULL) {
1595 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1596 error->domain, error->code,
1598 g_error_free(error);
1602 static void _playlist_changed_handler(MafwPlaylistIterator *iterator,
1603 gboolean clip_changed, GQuark domain,
1604 gint code, const gchar *message,
1607 MafwGstRenderer *renderer = (MafwGstRenderer*) user_data;
1609 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1611 g_return_if_fail((renderer->states != 0) &&
1612 (renderer->current_state != _LastMafwPlayState) &&
1613 (renderer->states[renderer->current_state] != NULL));
1615 /* We update the current index and media here, for this is
1616 the same for all the states. Then we delegate in the state
1617 to finish the task (for example, start playback if needed) */
1619 if (renderer->playlist == NULL) {
1620 g_critical("Got iterator:contents-changed but renderer has no" \
1621 "playlist assigned!. Skipping...");
1626 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1627 domain, code, message);
1629 GError *error = NULL;
1630 MafwGstRendererPlaybackMode mode;
1632 mode = mafw_gst_renderer_get_playback_mode(renderer);
1634 /* Only in non-playobject mode */
1635 if (clip_changed && mode == MAFW_GST_RENDERER_MODE_PLAYLIST)
1636 mafw_gst_renderer_set_media_playlist(renderer);
1638 /* We let the state know if the current clip has changed as
1639 result of this operation, so it can do its work */
1640 mafw_gst_renderer_state_playlist_contents_changed_handler(
1641 renderer->states[renderer->current_state],
1645 if (error != NULL) {
1646 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1647 error->domain, error->code,
1649 g_error_free(error);
1654 static void _error_handler(MafwGstRendererWorker *worker, gpointer owner,
1655 const GError *error)
1657 MafwGstRenderer *renderer = MAFW_GST_RENDERER(owner);
1659 mafw_gst_renderer_manage_error(renderer, error);
1662 void mafw_gst_renderer_manage_error(MafwGstRenderer *self, const GError *error)
1664 GError *new_err = NULL;
1665 GError *raise_error = NULL;
1666 GQuark new_err_domain = MAFW_RENDERER_ERROR;
1667 gint new_err_code = 0;
1669 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1671 g_return_if_fail((self->states != 0) &&
1672 (self->current_state != _LastMafwPlayState) &&
1673 (self->states[self->current_state] != NULL));
1675 g_warning("Got error in renderer:\n\tdomain: %d, code: %d, message: %s",
1676 error->domain, error->code, error->message);
1678 /* Get a MAFW error */
1679 if (error->domain == GST_RESOURCE_ERROR) {
1680 /* handle RESOURCE errors */
1681 switch (error->code) {
1682 case GST_RESOURCE_ERROR_READ:
1683 if (is_current_uri_stream(self)) {
1685 if (self->connected) {
1686 new_err_code = MAFW_RENDERER_ERROR_STREAM_DISCONNECTED;
1688 new_err_domain = MAFW_EXTENSION_ERROR;
1689 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1692 /* Stream + cannot read resource ->
1694 new_err_code = MAFW_RENDERER_ERROR_STREAM_DISCONNECTED;
1697 /* This shouldn't happen */
1698 /* Unknown RESOURCE error */
1699 new_err_domain = MAFW_EXTENSION_ERROR;
1700 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1703 case GST_RESOURCE_ERROR_NOT_FOUND:
1705 if (!is_current_uri_stream(self) || self->connected) {
1707 MAFW_RENDERER_ERROR_INVALID_URI;
1709 new_err_domain = MAFW_EXTENSION_ERROR;
1710 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1714 MAFW_RENDERER_ERROR_INVALID_URI;
1717 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
1718 case GST_RESOURCE_ERROR_OPEN_READ:
1720 if (!is_current_uri_stream(self) || self->connected) {
1722 MAFW_RENDERER_ERROR_MEDIA_NOT_FOUND;
1724 new_err_domain = MAFW_EXTENSION_ERROR;
1725 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1729 MAFW_RENDERER_ERROR_MEDIA_NOT_FOUND;
1732 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
1733 new_err_domain = MAFW_EXTENSION_ERROR;
1734 new_err_code = MAFW_EXTENSION_ERROR_OUT_OF_MEMORY;
1736 case GST_RESOURCE_ERROR_WRITE:
1737 /* DSP renderers send ERROR_WRITE when they find
1739 new_err_code = MAFW_RENDERER_ERROR_CORRUPTED_FILE;
1741 case GST_RESOURCE_ERROR_SEEK:
1742 new_err_code = MAFW_RENDERER_ERROR_CANNOT_SET_POSITION;
1745 /* Unknown RESOURCE error */
1746 new_err_domain = MAFW_EXTENSION_ERROR;
1747 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1750 } else if (error->domain == GST_STREAM_ERROR) {
1751 /* handle STREAM errors */
1752 switch (error->code) {
1753 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
1754 new_err_code = MAFW_RENDERER_ERROR_TYPE_NOT_AVAILABLE;
1756 case GST_STREAM_ERROR_FORMAT:
1757 case GST_STREAM_ERROR_WRONG_TYPE:
1758 case GST_STREAM_ERROR_FAILED:
1759 new_err_code = MAFW_RENDERER_ERROR_UNSUPPORTED_TYPE;
1761 case GST_STREAM_ERROR_DECODE:
1762 case GST_STREAM_ERROR_DEMUX:
1763 new_err_code = MAFW_RENDERER_ERROR_CORRUPTED_FILE;
1765 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
1766 new_err_code = MAFW_RENDERER_ERROR_CODEC_NOT_FOUND;
1768 case GST_STREAM_ERROR_DECRYPT:
1769 case GST_STREAM_ERROR_DECRYPT_NOKEY:
1770 new_err_code = MAFW_RENDERER_ERROR_DRM;
1773 /* Unknown STREAM error */
1774 new_err_domain = MAFW_EXTENSION_ERROR;
1775 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1777 } else if (error->domain == MAFW_GST_RENDERER_ERROR) {
1778 /* Handle own errors. Errors that belong to this domain:
1779 - MAFW_GST_RENDERER_ERROR_PLUGIN_NOT_FOUND,
1780 - MAFW_GST_RENDERER_ERROR_VIDEO_CODEC_NOT_SUPPORTED,
1781 - MAFW_GST_RENDERER_ERROR_AUDIO_CODEC_NOT_SUPPORTED */
1782 new_err_code = MAFW_RENDERER_ERROR_UNSUPPORTED_TYPE;
1783 } else if (error->domain == MAFW_RENDERER_ERROR) {
1784 /* Worker may have sent MAFW_RENDERER_ERROR as well.
1785 No processing needed */
1786 new_err_code = error->code;
1790 new_err_domain = MAFW_EXTENSION_ERROR;
1791 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1794 g_set_error(&new_err, new_err_domain, new_err_code, "%s", error->message);
1796 _run_error_policy(self, new_err, &raise_error);
1797 g_error_free(new_err);
1800 g_signal_emit_by_name(MAFW_EXTENSION (self), "error",
1801 raise_error->domain,
1803 raise_error->message);
1804 g_error_free(raise_error);
1808 static void _notify_eos(MafwGstRendererWorker *worker, gpointer owner)
1810 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1811 GError *error = NULL;
1813 g_return_if_fail(MAFW_IS_GST_RENDERER (renderer));
1815 g_return_if_fail((renderer->states != 0) &&
1816 (renderer->current_state != _LastMafwPlayState) &&
1817 (renderer->states[renderer->current_state] != NULL));
1819 mafw_gst_renderer_state_notify_eos(renderer->states[renderer->current_state],
1822 if (error != NULL) {
1823 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1824 error->domain, error->code,
1826 g_error_free(error);
1830 /*----------------------------------------------------------------------------
1832 ----------------------------------------------------------------------------*/
1834 void mafw_gst_renderer_get_status(MafwRenderer *self, MafwRendererStatusCB callback,
1837 MafwGstRenderer* renderer;
1839 MafwGstRendererPlaybackMode mode;
1841 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1842 g_return_if_fail(callback != NULL);
1843 renderer = MAFW_GST_RENDERER(self);
1845 mode = mafw_gst_renderer_get_playback_mode(MAFW_GST_RENDERER(self));
1846 if ((mode == MAFW_GST_RENDERER_MODE_STANDALONE) || (renderer->iterator == NULL)) {
1850 mafw_playlist_iterator_get_current_index(renderer->iterator);
1853 /* TODO: Set error parameter */
1854 callback(self, renderer->playlist, index, renderer->current_state,
1855 (const gchar*) renderer->media->object_id, user_data, NULL);
1858 void mafw_gst_renderer_get_current_metadata(MafwRenderer *self,
1859 MafwRendererMetadataResultCB callback,
1862 MafwGstRenderer *renderer;
1863 GHashTable *metadata;
1865 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1866 renderer = MAFW_GST_RENDERER(self);
1868 metadata = mafw_gst_renderer_worker_get_current_metadata(
1872 (const gchar*) renderer->media->object_id,
1878 /*----------------------------------------------------------------------------
1880 ----------------------------------------------------------------------------*/
1883 _playlist_contents_changed_handler(MafwPlaylist *playlist,
1884 guint from, guint nremove,
1886 MafwGstRenderer *renderer)
1888 /* Item(s) added to playlist, so new playable items could come */
1890 renderer->play_failed_count = 0;
1893 gboolean mafw_gst_renderer_assign_playlist(MafwRenderer *self,
1894 MafwPlaylist *playlist,
1897 MafwGstRenderer* renderer = (MafwGstRenderer*) self;
1899 g_return_val_if_fail(MAFW_IS_GST_RENDERER(self), FALSE);
1901 /* Get rid of previously assigned playlist */
1902 if (renderer->playlist != NULL) {
1903 g_signal_handlers_disconnect_matched(renderer->iterator,
1904 (GSignalMatchType) G_SIGNAL_MATCH_FUNC,
1906 _playlist_changed_handler,
1908 g_signal_handlers_disconnect_matched(renderer->playlist,
1909 (GSignalMatchType) G_SIGNAL_MATCH_FUNC,
1911 G_CALLBACK(_playlist_contents_changed_handler),
1913 /* Decrement the use count of the previous playlist because the
1914 renderer isn't going to use it more */
1915 mafw_playlist_decrement_use_count(renderer->playlist, NULL);
1917 g_object_unref(renderer->iterator);
1918 g_object_unref(renderer->playlist);
1921 /* Assign the new playlist */
1922 if (playlist == NULL) {
1923 renderer->playlist = NULL;
1924 renderer->iterator = NULL;
1926 GError *new_error = NULL;
1927 MafwPlaylistIterator *iterator = NULL;
1929 iterator = mafw_playlist_iterator_new();
1930 mafw_playlist_iterator_initialize(iterator, playlist,
1933 g_object_ref(playlist);
1935 if (new_error == NULL) {
1937 renderer->playlist = playlist;
1938 renderer->iterator = iterator;
1940 /* Increment the use_count to avoid the playlist destruction
1941 while the playlist is assigned to some renderer */
1942 mafw_playlist_increment_use_count(renderer->playlist, NULL);
1944 g_signal_connect(iterator,
1946 G_CALLBACK(_playlist_changed_handler),
1948 g_signal_connect(renderer->playlist,
1950 G_CALLBACK(_playlist_contents_changed_handler),
1954 g_propagate_error (error, new_error);
1958 /* Set the new media and signal playlist changed signal */
1959 _signal_playlist_changed(renderer);
1960 mafw_gst_renderer_set_media_playlist(renderer);
1964 mafw_gst_renderer_stop(MAFW_RENDERER(renderer), NULL , NULL);
1969 MafwGstRendererMovementResult mafw_gst_renderer_move(MafwGstRenderer *renderer,
1970 MafwGstRendererMovementType type,
1974 MafwGstRendererMovementResult value = MAFW_GST_RENDERER_MOVE_RESULT_OK;
1976 if (renderer->playlist == NULL) {
1977 value = MAFW_GST_RENDERER_MOVE_RESULT_NO_PLAYLIST;
1979 MafwPlaylistIteratorMovementResult result;
1982 case MAFW_GST_RENDERER_MOVE_TYPE_INDEX:
1984 mafw_playlist_iterator_move_to_index(renderer->iterator,
1988 case MAFW_GST_RENDERER_MOVE_TYPE_PREV:
1990 mafw_playlist_iterator_move_to_prev(renderer->iterator,
1993 case MAFW_GST_RENDERER_MOVE_TYPE_NEXT:
1995 mafw_playlist_iterator_move_to_next(renderer->iterator,
2001 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_OK:
2002 value = MAFW_GST_RENDERER_MOVE_RESULT_OK;
2003 mafw_gst_renderer_set_media_playlist(renderer);
2005 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_INVALID:
2006 g_critical("Iterator is invalid!");
2007 value = MAFW_GST_RENDERER_MOVE_RESULT_ERROR;
2009 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_ERROR:
2010 value = MAFW_GST_RENDERER_MOVE_RESULT_ERROR;
2012 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_LIMIT:
2013 value = MAFW_GST_RENDERER_MOVE_RESULT_PLAYLIST_LIMIT;
2021 /*----------------------------------------------------------------------------
2023 ----------------------------------------------------------------------------*/
2025 static void _set_error_policy(MafwGstRenderer *renderer, MafwRendererErrorPolicy policy)
2027 renderer->error_policy = policy;
2030 static MafwRendererErrorPolicy _get_error_policy(MafwGstRenderer *renderer)
2032 return renderer->error_policy;
2035 static void mafw_gst_renderer_get_property(MafwExtension *self,
2037 MafwExtensionPropertyCallback callback,
2040 MafwGstRenderer *renderer;
2041 GValue *value = NULL;
2042 GError *error = NULL;
2044 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
2045 g_return_if_fail(callback != NULL);
2046 g_return_if_fail(key != NULL);
2048 renderer = MAFW_GST_RENDERER(self);
2049 if (!strcmp(key, MAFW_PROPERTY_RENDERER_VOLUME)) {
2052 volume = mafw_gst_renderer_worker_get_volume(
2055 value = g_new0(GValue, 1);
2056 g_value_init(value, G_TYPE_UINT);
2057 g_value_set_uint(value, volume);
2059 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_MUTE)) {
2061 mute = mafw_gst_renderer_worker_get_mute(renderer->worker);
2062 value = g_new0(GValue, 1);
2063 g_value_init(value, G_TYPE_BOOLEAN);
2064 g_value_set_boolean(value, mute);
2066 else if (!strcmp (key, MAFW_PROPERTY_RENDERER_XID)) {
2068 xid = mafw_gst_renderer_worker_get_xid(renderer->worker);
2069 value = g_new0(GValue, 1);
2070 g_value_init(value, G_TYPE_UINT);
2071 g_value_set_uint(value, xid);
2073 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_ERROR_POLICY)) {
2075 policy = _get_error_policy(renderer);
2076 value = g_new0(GValue, 1);
2077 g_value_init(value, G_TYPE_UINT);
2078 g_value_set_uint(value, policy);
2080 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_AUTOPAINT)) {
2081 value = g_new0(GValue, 1);
2082 g_value_init(value, G_TYPE_BOOLEAN);
2083 g_value_set_boolean(
2085 mafw_gst_renderer_worker_get_autopaint(
2087 } else if (!strcmp(key, MAFW_PROPERTY_RENDERER_COLORKEY)) {
2088 value = g_new0(GValue, 1);
2089 g_value_init(value, G_TYPE_INT);
2092 mafw_gst_renderer_worker_get_colorkey(
2095 #ifdef HAVE_GDKPIXBUF
2096 else if (!strcmp(key,
2097 MAFW_PROPERTY_GST_RENDERER_CURRENT_FRAME_ON_PAUSE)) {
2098 gboolean current_frame_on_pause;
2099 current_frame_on_pause =
2100 mafw_gst_renderer_worker_get_current_frame_on_pause(renderer->worker);
2101 value = g_new0(GValue, 1);
2102 g_value_init(value, G_TYPE_BOOLEAN);
2103 g_value_set_boolean(value, current_frame_on_pause);
2106 else if (!strcmp(key,
2107 MAFW_PROPERTY_GST_RENDERER_TV_CONNECTED)) {
2108 value = g_new0(GValue, 1);
2109 g_value_init(value, G_TYPE_BOOLEAN);
2110 g_value_set_boolean(value, renderer->tv_connected);
2112 else if (!strcmp(key,
2113 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS)){
2114 /* Delegate in the state. */
2115 value = mafw_gst_renderer_state_get_property_value(
2116 MAFW_GST_RENDERER_STATE(
2117 renderer->states[renderer->current_state]),
2118 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS);
2121 /* Something goes wrong. */
2122 error = g_error_new(
2123 MAFW_GST_RENDERER_ERROR,
2124 MAFW_EXTENSION_ERROR_GET_PROPERTY,
2125 "Error while getting the property value");
2129 /* Unsupported property */
2130 error = g_error_new(MAFW_GST_RENDERER_ERROR,
2131 MAFW_EXTENSION_ERROR_GET_PROPERTY,
2132 "Unsupported property");
2135 callback(self, key, value, user_data, error);
2138 static void mafw_gst_renderer_set_property(MafwExtension *self,
2140 const GValue *value)
2142 MafwGstRenderer *renderer;
2144 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
2145 g_return_if_fail(key != NULL);
2147 renderer = MAFW_GST_RENDERER(self);
2149 if (!strcmp(key, MAFW_PROPERTY_RENDERER_VOLUME)) {
2150 guint volume = g_value_get_uint(value);
2153 mafw_gst_renderer_worker_set_volume(renderer->worker,
2155 /* Property-changed emision is done by worker */
2158 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_MUTE)) {
2159 gboolean mute = g_value_get_boolean(value);
2160 mafw_gst_renderer_worker_set_mute(renderer->worker, mute);
2162 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_XID)) {
2163 XID xid = g_value_get_uint(value);
2164 mafw_gst_renderer_worker_set_xid(renderer->worker, xid);
2166 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_ERROR_POLICY)) {
2167 MafwRendererErrorPolicy policy = g_value_get_uint(value);
2168 _set_error_policy(renderer, policy);
2170 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_AUTOPAINT)) {
2171 mafw_gst_renderer_worker_set_autopaint(
2173 g_value_get_boolean(value));
2175 #ifdef HAVE_GDKPIXBUF
2176 else if (!strcmp(key,
2177 MAFW_PROPERTY_GST_RENDERER_CURRENT_FRAME_ON_PAUSE)) {
2178 gboolean current_frame_on_pause = g_value_get_boolean(value);
2179 mafw_gst_renderer_worker_set_current_frame_on_pause(renderer->worker,
2180 current_frame_on_pause);
2185 /* FIXME I'm not sure when to emit property-changed signals.
2186 * Maybe we should let the worker do it, when the change
2187 * reached the hardware... */
2188 mafw_extension_emit_property_changed(self, key, value);
2191 /* vi: set noexpandtab ts=8 sw=8 cino=t0,(0: */