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 GCONF_MAFW_GST_SUBTITLES_RENDERER "/system/mafw/mafw-gst-subtitles-renderer"
60 #define HAL_VIDEOOUT_UDI "/org/freedesktop/Hal/devices" \
61 "/platform_soc_audio_logicaldev_input"
63 /*----------------------------------------------------------------------------
64 Static variable definitions
65 ----------------------------------------------------------------------------*/
67 /*----------------------------------------------------------------------------
69 ----------------------------------------------------------------------------*/
71 static gboolean mafw_gst_renderer_initialize(MafwRegistry *registry,
73 static void mafw_gst_renderer_deinitialize(GError **error);
75 /*----------------------------------------------------------------------------
76 GObject initialization
77 ----------------------------------------------------------------------------*/
79 static void mafw_gst_renderer_dispose(GObject *object);
80 static void mafw_gst_renderer_finalize(GObject *object);
82 /*----------------------------------------------------------------------------
84 ----------------------------------------------------------------------------*/
85 static void _property_modified(LibHalContext *ctx, const char *udi,
86 const char *key, dbus_bool_t is_removed,
87 dbus_bool_t is_added);
88 static gboolean _tv_out_is_connected(LibHalContext *ctx, const char *udi);
90 /*----------------------------------------------------------------------------
92 ----------------------------------------------------------------------------*/
94 static void _battery_cover_open_cb(GConfClient *client,
97 MafwGstRenderer *renderer);
99 static void _autoload_subtitles_changed_cb(GConfClient *client,
102 MafwGstRenderer *renderer);
104 static void _subtitle_font_changed_cb(GConfClient *client,
107 MafwGstRenderer *renderer);
109 /*----------------------------------------------------------------------------
110 Gnome VFS notifications
111 ----------------------------------------------------------------------------*/
113 static void _volume_pre_unmount_cb(GnomeVFSVolumeMonitor *monitor,
114 GnomeVFSVolume *volume,
115 MafwGstRenderer *renderer);
117 /*----------------------------------------------------------------------------
119 ----------------------------------------------------------------------------*/
121 static void _signal_state_changed(MafwGstRenderer * self);
122 static void _signal_media_changed(MafwGstRenderer * self);
123 static void _signal_playlist_changed(MafwGstRenderer * self);
124 static void _signal_transport_actions_property_changed(MafwGstRenderer * self);
126 /*----------------------------------------------------------------------------
128 ----------------------------------------------------------------------------*/
130 static void _set_error_policy(MafwGstRenderer *renderer, MafwRendererErrorPolicy policy);
131 static MafwRendererErrorPolicy _get_error_policy(MafwGstRenderer *renderer);
133 static void mafw_gst_renderer_set_property(MafwExtension *self, const gchar *key,
134 const GValue *value);
135 static void mafw_gst_renderer_get_property(MafwExtension *self, const gchar *key,
136 MafwExtensionPropertyCallback callback,
139 /*----------------------------------------------------------------------------
141 ----------------------------------------------------------------------------*/
143 static void _notify_metadata(MafwSource *cb_source,
144 const gchar *cb_object_id,
145 GHashTable *cb_metadata,
146 gpointer cb_user_data,
147 const GError *cb_error);
149 /*----------------------------------------------------------------------------
150 Notification operations
151 ----------------------------------------------------------------------------*/
153 static void _notify_play(MafwGstRendererWorker *worker, gpointer owner);
154 static void _notify_pause(MafwGstRendererWorker *worker, gpointer owner);
155 static void _notify_seek(MafwGstRendererWorker *worker, gpointer owner);
156 static void _notify_buffer_status(MafwGstRendererWorker *worker, gpointer owner,
158 static void _notify_eos(MafwGstRendererWorker *worker, gpointer owner);
159 static void _error_handler(MafwGstRendererWorker *worker, gpointer owner,
160 const GError *error);
163 /*----------------------------------------------------------------------------
165 ----------------------------------------------------------------------------*/
167 static void _connection_init(MafwGstRenderer *renderer);
170 /*----------------------------------------------------------------------------
171 Plugin initialization
172 ----------------------------------------------------------------------------*/
175 * Registers the plugin descriptor making this plugin available to the
176 * framework and applications
178 G_MODULE_EXPORT MafwPluginDescriptor mafw_gst_renderer_plugin_description = {
179 { .name = MAFW_GST_RENDERER_PLUGIN_NAME },
180 .initialize = mafw_gst_renderer_initialize,
181 .deinitialize = mafw_gst_renderer_deinitialize,
184 static gboolean mafw_gst_renderer_initialize(MafwRegistry *registry,
187 MafwGstRenderer *self;
189 g_assert(registry != NULL);
190 self = MAFW_GST_RENDERER(mafw_gst_renderer_new(registry));
191 mafw_registry_add_extension(registry, MAFW_EXTENSION(self));
196 static void mafw_gst_renderer_deinitialize(GError **error)
200 /*----------------------------------------------------------------------------
201 GObject initialization
202 ----------------------------------------------------------------------------*/
204 G_DEFINE_TYPE(MafwGstRenderer, mafw_gst_renderer, MAFW_TYPE_RENDERER);
206 static void mafw_gst_renderer_class_init(MafwGstRendererClass *klass)
208 GObjectClass *gclass = NULL;
209 MafwRendererClass *renderer_class = NULL;
210 const gchar *preloaded_plugins[] = {"playback", "uridecodebin",
211 "coreelements", "typefindfunctions", "dsp",
212 "pulseaudio", "xvimagesink", NULL};
216 gclass = G_OBJECT_CLASS(klass);
217 g_return_if_fail(gclass != NULL);
219 renderer_class = MAFW_RENDERER_CLASS(klass);
220 g_return_if_fail(renderer_class != NULL);
224 gclass->dispose = mafw_gst_renderer_dispose;
225 gclass->finalize = mafw_gst_renderer_finalize;
229 renderer_class->play = mafw_gst_renderer_play;
230 renderer_class->play_object = mafw_gst_renderer_play_object;
231 renderer_class->stop = mafw_gst_renderer_stop;
232 renderer_class->pause = mafw_gst_renderer_pause;
233 renderer_class->resume = mafw_gst_renderer_resume;
234 renderer_class->get_status = mafw_gst_renderer_get_status;
236 /* Playlist operations */
238 renderer_class->assign_playlist = mafw_gst_renderer_assign_playlist;
239 renderer_class->next = mafw_gst_renderer_next;
240 renderer_class->previous = mafw_gst_renderer_previous;
241 renderer_class->goto_index = mafw_gst_renderer_goto_index;
243 /* Playback position */
245 renderer_class->set_position = mafw_gst_renderer_set_position;
246 renderer_class->get_position = mafw_gst_renderer_get_position;
250 renderer_class->get_current_metadata =
251 mafw_gst_renderer_get_current_metadata;
255 MAFW_EXTENSION_CLASS(klass)->get_extension_property =
256 (gpointer) mafw_gst_renderer_get_property;
257 MAFW_EXTENSION_CLASS(klass)->set_extension_property =
258 (gpointer) mafw_gst_renderer_set_property;
260 gst_init(NULL, NULL);
263 /* Pre-load some common plugins */
264 while (preloaded_plugins[i])
266 plugin = G_OBJECT(gst_plugin_load_by_name(preloaded_plugins[i]));
268 g_object_unref(plugin);
270 g_debug("Can not load plugin: %s", preloaded_plugins[i]);
275 static void mafw_gst_renderer_init(MafwGstRenderer *self)
277 MafwGstRenderer *renderer = NULL;
278 GError *error = NULL;
280 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
282 renderer = MAFW_GST_RENDERER(self);
283 g_return_if_fail(renderer != NULL);
285 mafw_extension_add_property(MAFW_EXTENSION(self), "volume", G_TYPE_UINT);
286 #ifdef MAFW_GST_RENDERER_ENABLE_MUTE
287 mafw_extension_add_property(MAFW_EXTENSION(self), "mute", G_TYPE_BOOLEAN);
289 mafw_extension_add_property(MAFW_EXTENSION(self), "xid", G_TYPE_UINT);
290 mafw_extension_add_property(MAFW_EXTENSION(self), "error-policy", G_TYPE_UINT);
291 MAFW_EXTENSION_SUPPORTS_AUTOPAINT(self);
292 MAFW_EXTENSION_SUPPORTS_COLORKEY(self);
293 #ifdef HAVE_GDKPIXBUF
294 mafw_extension_add_property(MAFW_EXTENSION(self),
295 "current-frame-on-pause",
298 mafw_extension_add_property(MAFW_EXTENSION(self),
299 MAFW_PROPERTY_GST_RENDERER_TV_CONNECTED,
301 MAFW_EXTENSION_SUPPORTS_TRANSPORT_ACTIONS(self);
302 renderer->media = g_new0(MafwGstRendererMedia, 1);
303 renderer->media->seekability = SEEKABILITY_UNKNOWN;
304 renderer->current_state = Stopped;
306 renderer->playlist = NULL;
307 renderer->iterator = NULL;
308 renderer->seeking_to = -1;
309 renderer->update_playcount_id = 0;
311 self->worker = mafw_gst_renderer_worker_new(self);
313 /* Set notification handlers for worker */
314 renderer->worker->notify_play_handler = _notify_play;
315 renderer->worker->notify_pause_handler = _notify_pause;
316 renderer->worker->notify_seek_handler = _notify_seek;
317 renderer->worker->notify_error_handler = _error_handler;
318 renderer->worker->notify_eos_handler = _notify_eos;
319 renderer->worker->notify_buffer_status_handler = _notify_buffer_status;
321 renderer->states = g_new0 (MafwGstRendererState*, _LastMafwPlayState);
322 renderer->states[Stopped] =
323 MAFW_GST_RENDERER_STATE(mafw_gst_renderer_state_stopped_new(self));
324 renderer->states[Transitioning] =
325 MAFW_GST_RENDERER_STATE(
326 mafw_gst_renderer_state_transitioning_new(self));
327 renderer->states[Playing] =
328 MAFW_GST_RENDERER_STATE(mafw_gst_renderer_state_playing_new(self));
329 renderer->states[Paused] =
330 MAFW_GST_RENDERER_STATE(mafw_gst_renderer_state_paused_new(self));
332 renderer->current_state = Stopped;
333 renderer->resume_playlist = FALSE;
334 renderer->playback_mode = MAFW_GST_RENDERER_MODE_PLAYLIST;
337 renderer->connected = FALSE;
338 renderer->connection = NULL;
340 _connection_init(renderer);
342 renderer->gconf_client = gconf_client_get_default();
343 gconf_client_add_dir(renderer->gconf_client, GCONF_OSSO_AF,
344 GCONF_CLIENT_PRELOAD_ONELEVEL, &error);
346 g_warning("%s", error->message);
351 gconf_client_notify_add(renderer->gconf_client,
352 GCONF_BATTERY_COVER_OPEN,
353 (GConfClientNotifyFunc) _battery_cover_open_cb,
358 g_warning("%s", error->message);
362 gconf_client_add_dir(renderer->gconf_client,
363 GCONF_MAFW_GST_SUBTITLES_RENDERER,
364 GCONF_CLIENT_PRELOAD_ONELEVEL,
367 g_warning("%s", error->message);
372 gconf_client_notify_add(renderer->gconf_client,
373 GCONF_MAFW_GST_SUBTITLES_RENDERER "/autoload_subtitles",
374 (GConfClientNotifyFunc) _autoload_subtitles_changed_cb,
378 g_warning("%s", error->message);
382 gconf_client_notify_add(renderer->gconf_client,
383 GCONF_MAFW_GST_SUBTITLES_RENDERER "/subtitle_encoding",
384 (GConfClientNotifyFunc) _subtitle_font_changed_cb,
388 g_warning("%s", error->message);
392 gconf_client_notify_add(renderer->gconf_client,
393 GCONF_MAFW_GST_SUBTITLES_RENDERER "/subtitle_font",
394 (GConfClientNotifyFunc) _subtitle_font_changed_cb,
398 g_warning("%s", error->message);
402 if (self->worker->pipeline) {
403 gconf_client_notify(renderer->gconf_client,
404 GCONF_MAFW_GST_SUBTITLES_RENDERER "/autoload_subtitles");
406 gconf_client_notify(renderer->gconf_client,
407 GCONF_MAFW_GST_SUBTITLES_RENDERER "/subtitle_encoding");
409 gconf_client_notify(renderer->gconf_client,
410 GCONF_MAFW_GST_SUBTITLES_RENDERER "/subtitle_font");
413 if (gnome_vfs_init()) {
414 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
415 g_signal_connect(monitor, "volume-pre-unmount",
416 G_CALLBACK(_volume_pre_unmount_cb), renderer);
418 g_warning("Failed to initialize gnome-vfs");
422 static void mafw_gst_renderer_dispose(GObject *object)
424 MafwGstRenderer *renderer;
426 g_return_if_fail(MAFW_IS_GST_RENDERER(object));
428 renderer = MAFW_GST_RENDERER(object);
430 if (renderer->worker != NULL) {
431 mafw_gst_renderer_worker_exit(renderer->worker);
432 renderer->seek_pending = FALSE;
433 g_free(renderer->worker);
434 renderer->worker = NULL;
437 if (renderer->registry != NULL) {
438 g_object_unref(renderer->registry);
439 renderer->registry = NULL;
442 if (renderer->states != NULL) {
445 for (i = 0; i < _LastMafwPlayState; i++) {
446 if (renderer->states[i] != NULL)
447 g_object_unref(renderer->states[i]);
449 g_free(renderer->states);
450 renderer->states = NULL;
453 if (renderer->hal_ctx != NULL) {
454 libhal_device_remove_property_watch(renderer->hal_ctx,
457 libhal_ctx_shutdown(renderer->hal_ctx, NULL);
458 libhal_ctx_free(renderer->hal_ctx);
462 if (renderer->connection != NULL) {
463 g_object_unref(renderer->connection);
464 renderer->connection = NULL;
468 if (renderer->gconf_client != NULL) {
469 g_object_unref(renderer->gconf_client);
470 renderer->gconf_client = NULL;
473 G_OBJECT_CLASS(mafw_gst_renderer_parent_class)->dispose(object);
476 static void mafw_gst_renderer_finalize(GObject *object)
478 MafwGstRenderer *self = (MafwGstRenderer*) object;
480 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
482 mafw_gst_renderer_clear_media(self);
490 G_OBJECT_CLASS(mafw_gst_renderer_parent_class)->finalize(object);
494 * mafw_gst_renderer_new:
495 * @registry: The registry that owns this renderer.
497 * Creates a new MafwGstRenderer object
499 GObject *mafw_gst_renderer_new(MafwRegistry* registry)
503 DBusConnection *conn;
509 object = g_object_new(MAFW_TYPE_GST_RENDERER,
510 "uuid", MAFW_GST_RENDERER_UUID,
511 "name", MAFW_GST_RENDERER_NAME,
512 "plugin", MAFW_GST_RENDERER_PLUGIN_NAME,
514 g_assert(object != NULL);
515 MAFW_GST_RENDERER(object)->registry = g_object_ref(registry);
517 /* Set default error policy */
518 MAFW_GST_RENDERER(object)->error_policy =
519 MAFW_RENDERER_ERROR_POLICY_CONTINUE;
521 MAFW_GST_RENDERER(object)->tv_connected = FALSE;
523 /* Setup hal connection for reacting usb cable connected event */
524 dbus_error_init(&err);
525 conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
527 if (dbus_error_is_set(&err)) {
528 g_warning("Couldn't setup HAL connection: %s", err.message);
529 dbus_error_free(&err);
533 ctx = libhal_ctx_new();
534 libhal_ctx_set_dbus_connection(ctx, conn);
535 libhal_ctx_set_user_data(ctx, object);
537 if (libhal_ctx_init(ctx, &err) == FALSE) {
538 if (dbus_error_is_set(&err)) {
539 g_warning("Could not initialize hal: %s", err.message);
540 dbus_error_free(&err);
542 g_warning("Could not initialize hal");
547 libhal_device_add_property_watch(ctx, HAL_VIDEOOUT_UDI, &err);
549 if (dbus_error_is_set(&err)) {
550 g_warning("Could not start watching usb device: %s",
552 dbus_error_free(&err);
556 libhal_ctx_set_device_property_modified(ctx, _property_modified);
558 /* Initializes blanking policy */
559 jackets = libhal_find_device_by_capability(ctx,
560 "input.jack.video-out",
562 if (jackets != NULL) {
565 if (_tv_out_is_connected(ctx, *jack)) {
566 MAFW_GST_RENDERER(object)->tv_connected = TRUE;
572 blanking_control(*jack == NULL);
573 libhal_free_string_array(jackets);
576 MAFW_GST_RENDERER(object)->hal_ctx = ctx;
580 libhal_ctx_shutdown(ctx, NULL);
582 libhal_ctx_free(ctx);
588 * mafw_gst_renderer_error_quark:
590 * Fetches the quark representing the domain of the errors in the
593 * Return value: a quark identifying the error domain of the
594 * #MafwGstRenderer objects.
597 GQuark mafw_gst_renderer_error_quark(void)
599 return g_quark_from_static_string("mafw-gst-renderer-error-quark");
602 void mafw_gst_renderer_set_playback_mode(MafwGstRenderer *self,
603 MafwGstRendererPlaybackMode mode)
605 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
606 self->playback_mode = mode;
609 MafwGstRendererPlaybackMode mafw_gst_renderer_get_playback_mode(
610 MafwGstRenderer *self)
612 g_return_val_if_fail(MAFW_IS_GST_RENDERER(self),
613 MAFW_GST_RENDERER_MODE_STANDALONE);
614 return self->playback_mode;
617 /*----------------------------------------------------------------------------
619 ----------------------------------------------------------------------------*/
621 static MafwSource* _get_source(MafwGstRenderer *renderer,
622 const gchar *object_id)
625 gchar* sourceid = NULL;
627 g_assert(object_id != NULL);
629 /* Attempt to find a source that provided the object ID */
630 mafw_source_split_objectid(object_id, &sourceid, NULL);
631 source = MAFW_SOURCE(mafw_registry_get_extension_by_uuid(
632 renderer->registry, sourceid));
638 void mafw_gst_renderer_get_metadata(MafwGstRenderer* self,
639 const gchar* objectid,
644 g_assert(self != NULL);
647 * Any error here is an error when trying to Play, so
648 * it must be handled by error policy.
649 * Problem: if we get an error here and we are not in
650 * Transitioning yet (maybe we are still in Stopped state)
651 * then the policy may move to next and stay Stopped (instead of
652 * trying to play), so errors need to be handled by the policy
653 * in an idle callback, so that any error that may happen here
654 * is not processed until we have moved to Transitioning state
657 source = _get_source(self, objectid);
660 /* List of metadata keys that we are interested in when going to
661 Transitioning state */
662 static const gchar * const keys[] =
663 { MAFW_METADATA_KEY_URI,
664 MAFW_METADATA_KEY_IS_SEEKABLE,
665 MAFW_METADATA_KEY_DURATION,
668 /* Source found, get metadata */
669 mafw_source_get_metadata(source, objectid,
677 /* This is a playback error: execute error policy */
678 MafwGstRendererErrorClosure *error_closure;
679 error_closure = g_new0(MafwGstRendererErrorClosure, 1);
680 error_closure->renderer = self;
681 g_set_error (&(error_closure->error),
682 MAFW_EXTENSION_ERROR,
683 MAFW_EXTENSION_ERROR_EXTENSION_NOT_AVAILABLE,
684 "Unable to find source for current object ID");
685 g_idle_add(mafw_gst_renderer_manage_error_idle, error_closure);
689 void mafw_gst_renderer_set_object(MafwGstRenderer *self, const gchar *object_id)
691 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
693 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
694 g_return_if_fail(object_id != NULL);
696 /* This is intended to be called only when using play_object(),
697 * as for playlists we use set_media_playlist()
700 /* Stop any ongoing playback */
701 mafw_gst_renderer_clear_media(renderer);
704 renderer->media->object_id = g_strdup(object_id);
706 /* Signal media changed */
707 _signal_media_changed(renderer);
712 * mafw_gst_renderer_clear_media:
714 * @renderer A #MafwGstRenderer whose media to clear
716 * Clears & frees the renderer's current media details
718 void mafw_gst_renderer_clear_media(MafwGstRenderer *self)
720 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
721 g_return_if_fail(self->media != NULL);
723 g_free(self->media->object_id);
724 self->media->object_id = NULL;
726 g_free(self->media->uri);
727 self->media->uri = NULL;
729 g_free(self->media->title);
730 self->media->title = NULL;
732 g_free(self->media->artist);
733 self->media->artist = NULL;
735 g_free(self->media->album);
736 self->media->album = NULL;
738 self->media->duration = 0;
739 self->media->position = 0;
744 * mafw_gst_renderer_set_media_playlist:
746 * @self A #MafwGstRenderer, whose media to set
748 * Set current media from the renderer's playlist, using the current playlist index.
750 void mafw_gst_renderer_set_media_playlist(MafwGstRenderer* self)
752 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
754 /* Get rid of old media details */
755 mafw_gst_renderer_clear_media(self);
757 if (self->playlist != NULL &&
758 mafw_playlist_iterator_get_size(self->iterator, NULL) > 0) {
759 /* Get the current item from playlist */
760 self->media->object_id =
761 g_strdup(mafw_playlist_iterator_get_current_objectid(self->iterator));
763 self->media->object_id = NULL;
766 _signal_media_changed(self);
770 /*----------------------------------------------------------------------------
772 ----------------------------------------------------------------------------*/
775 _con_ic_status_handler(ConIcConnection *conn, ConIcConnectionEvent *event,
778 MafwGstRenderer *renderer = (MafwGstRenderer *) data;
780 g_assert(MAFW_IS_GST_RENDERER(renderer));
782 renderer->connected =
783 con_ic_connection_event_get_status(event) ==
784 CON_IC_STATUS_CONNECTED;
788 _connection_init(MafwGstRenderer *renderer)
790 g_assert (MAFW_IS_GST_RENDERER(renderer));
792 if (renderer->connection == NULL) {
793 renderer->connection = con_ic_connection_new();
794 renderer->connected = FALSE;
796 g_assert(renderer->connection != NULL);
799 g_object_set(renderer->connection, "automatic-connection-events",
801 g_signal_connect(renderer->connection, "connection-event",
802 G_CALLBACK (_con_ic_status_handler), renderer);
804 con_ic_connection_connect(renderer->connection,
805 CON_IC_CONNECT_FLAG_AUTOMATICALLY_TRIGGERED);
809 /*----------------------------------------------------------------------------
811 ----------------------------------------------------------------------------*/
813 static gboolean _tv_out_is_connected(LibHalContext *ctx, const char *udi)
815 gboolean is_tv_out_jack = FALSE;
823 jack_types = libhal_device_get_property_strlist(ctx, udi,
826 if (jack_types == NULL) {
832 if (strcmp(*jack, "video-out") == 0) {
833 is_tv_out_jack = TRUE;
840 libhal_free_string_array(jack_types);
842 return is_tv_out_jack;
845 static void _property_modified(LibHalContext *ctx, const char *udi,
846 const char *key, dbus_bool_t is_removed,
847 dbus_bool_t is_added)
849 MafwGstRenderer *renderer;
851 GValue value = { 0 };
853 g_debug("HAL property modified! jack changed\n");
854 connected = _tv_out_is_connected(ctx, udi);
855 renderer = MAFW_GST_RENDERER(libhal_ctx_get_user_data(ctx));
856 if (renderer->tv_connected != connected) {
857 /* Notify the change */
858 renderer->tv_connected = connected;
859 g_value_init(&value, G_TYPE_BOOLEAN);
860 g_value_set_boolean(&value, renderer->tv_connected);
861 mafw_extension_emit_property_changed(
862 MAFW_EXTENSION(renderer),
863 MAFW_PROPERTY_GST_RENDERER_TV_CONNECTED,
865 g_value_unset(&value);
867 blanking_control(connected == FALSE);
870 /*----------------------------------------------------------------------------
872 ----------------------------------------------------------------------------*/
874 static void _battery_cover_open_cb(GConfClient *client,
877 MafwGstRenderer *renderer)
879 GConfValue *value = NULL;
880 gboolean is_cover_open;
882 value = gconf_entry_get_value(entry);
883 is_cover_open = gconf_value_get_bool(value);
886 /* External mmc could be removed!. */
887 const gchar *emmc_path = g_getenv("MMC_MOUNTPOINT");
889 mafw_gst_renderer_state_handle_pre_unmount(
890 MAFW_GST_RENDERER_STATE(
891 renderer->states[renderer->current_state]),
896 static void _autoload_subtitles_changed_cb(GConfClient *client,
899 MafwGstRenderer *renderer)
901 GConfValue *value = NULL;
902 gboolean enabled = FALSE;
904 value = gconf_entry_get_value(entry);
908 enabled = gconf_value_get_bool(value);
911 renderer->worker->subtitles.enabled = TRUE;
913 renderer->worker->subtitles.enabled = FALSE;
916 static void _subtitle_font_changed_cb(GConfClient *client,
919 MafwGstRenderer *renderer)
921 const gchar *key = NULL;
922 GConfValue *value = NULL;
923 const gchar *str_value = NULL;
925 key = gconf_entry_get_key(entry);
927 /* Only key without absolute path is required */
928 key += strlen(GCONF_MAFW_GST_SUBTITLES_RENDERER) + 1;
930 value = gconf_entry_get_value(entry);
932 str_value = gconf_value_get_string(value);
936 if (strcmp(key, "subtitle_font") == 0) {
937 if (renderer->worker->subtitles.font)
938 g_free(renderer->worker->subtitles.font);
941 renderer->worker->subtitles.font = g_strdup(str_value);
943 renderer->worker->subtitles.font = NULL;
944 } else if (strcmp(key, "subtitle_encoding") == 0) {
945 if (renderer->worker->subtitles.encoding)
946 g_free(renderer->worker->subtitles.encoding);
949 renderer->worker->subtitles.encoding = g_strdup(str_value);
951 renderer->worker->subtitles.encoding = NULL;
953 g_warning("Wrong %s key, %s", GCONF_MAFW_GST_SUBTITLES_RENDERER, key);
957 /*----------------------------------------------------------------------------
958 Gnome VFS notifications
959 ----------------------------------------------------------------------------*/
961 static void _volume_pre_unmount_cb(GnomeVFSVolumeMonitor *monitor,
962 GnomeVFSVolume *volume,
963 MafwGstRenderer *renderer)
965 gchar *location = gnome_vfs_volume_get_activation_uri(volume);
970 mafw_gst_renderer_state_handle_pre_unmount(
971 MAFW_GST_RENDERER_STATE(
972 renderer->states[renderer->current_state]),
978 /*----------------------------------------------------------------------------
980 ----------------------------------------------------------------------------*/
984 * _signal_state_changed:
985 * @self: A #MafwGstRenderer
987 * Signals state_changed to all UIs
989 static void _signal_state_changed(MafwGstRenderer * self)
991 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
993 g_signal_emit_by_name(MAFW_RENDERER(self),
994 "state-changed", self->current_state);
998 * _signal_playlist_changed:
999 * @self: A #MafwGstRenderer
1001 * Signals playlist update to all UIs
1003 static void _signal_playlist_changed(MafwGstRenderer * self)
1005 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1007 g_signal_emit_by_name(MAFW_RENDERER(self),
1008 "playlist-changed", self->playlist);
1012 * _signal_media_changed:
1013 * @self: A #MafwGstRenderer
1015 * Signals media_changed to all UIs
1017 static void _signal_media_changed(MafwGstRenderer *self)
1020 MafwGstRendererPlaybackMode mode;
1023 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1025 mode = mafw_gst_renderer_get_playback_mode(MAFW_GST_RENDERER(self));
1026 if ((mode == MAFW_GST_RENDERER_MODE_STANDALONE) ||
1027 (self->iterator == NULL)) {
1030 index = mafw_playlist_iterator_get_current_index(self->iterator);
1033 g_signal_emit_by_name(MAFW_RENDERER(self),
1036 self->media->object_id);
1040 * _signal_transport_actions_property_changed:
1041 * @self: A #MafwGstRenderer
1043 * Signals transport_actions property_changed to all UIs
1045 static void _signal_transport_actions_property_changed(MafwGstRenderer * self)
1049 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1051 value = mafw_gst_renderer_state_get_property_value(
1052 MAFW_GST_RENDERER_STATE(
1053 self->states[self->current_state]),
1054 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS);
1057 mafw_extension_emit_property_changed(
1058 MAFW_EXTENSION(self),
1059 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS,
1061 g_value_unset(value);
1067 /*----------------------------------------------------------------------------
1068 State pattern support
1069 ----------------------------------------------------------------------------*/
1071 void mafw_gst_renderer_set_state(MafwGstRenderer *self, MafwPlayState state)
1073 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1075 self->current_state = state;
1076 _signal_state_changed(self);
1077 _signal_transport_actions_property_changed(self);
1080 void mafw_gst_renderer_play(MafwRenderer *self, MafwRendererPlaybackCB callback,
1083 MafwGstRenderer *renderer = (MafwGstRenderer*) self;
1084 GError *error = NULL;
1086 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1088 g_return_if_fail((renderer->states != 0) &&
1089 (renderer->current_state != _LastMafwPlayState) &&
1090 (renderer->states[renderer->current_state] != NULL));
1092 mafw_gst_renderer_state_play(
1093 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1096 if (callback != NULL)
1097 callback(self, user_data, error);
1099 g_error_free(error);
1102 void mafw_gst_renderer_play_object(MafwRenderer *self,
1103 const gchar *object_id,
1104 MafwRendererPlaybackCB callback,
1107 MafwGstRenderer *renderer = (MafwGstRenderer*) self;
1108 GError *error = NULL;
1110 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1111 g_return_if_fail(object_id != NULL);
1113 g_return_if_fail((renderer->states != 0) &&
1114 (renderer->current_state != _LastMafwPlayState) &&
1115 (renderer->states[renderer->current_state] != NULL));
1117 mafw_gst_renderer_state_play_object(
1118 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1122 if (callback != NULL)
1123 callback(self, user_data, error);
1125 g_error_free(error);
1128 void mafw_gst_renderer_stop(MafwRenderer *self, MafwRendererPlaybackCB callback,
1131 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1132 GError *error = NULL;
1134 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1136 g_return_if_fail((renderer->states != 0) &&
1137 (renderer->current_state != _LastMafwPlayState) &&
1138 (renderer->states[renderer->current_state] != NULL));
1140 renderer->play_failed_count = 0;
1141 mafw_gst_renderer_state_stop(
1142 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1145 if (callback != NULL)
1146 callback(self, user_data, error);
1148 g_error_free(error);
1152 void mafw_gst_renderer_pause(MafwRenderer *self, MafwRendererPlaybackCB callback,
1155 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1156 GError *error = NULL;
1158 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1160 g_return_if_fail((renderer->states != 0) &&
1161 (renderer->current_state != _LastMafwPlayState) &&
1162 (renderer->states[renderer->current_state] != NULL));
1164 mafw_gst_renderer_state_pause(
1165 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1168 if (callback != NULL)
1169 callback(self, user_data, error);
1171 g_error_free(error);
1174 void mafw_gst_renderer_resume(MafwRenderer *self, MafwRendererPlaybackCB callback,
1177 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1178 GError *error = NULL;
1180 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1182 g_return_if_fail((renderer->states != 0) &&
1183 (renderer->current_state != _LastMafwPlayState) &&
1184 (renderer->states[renderer->current_state] != NULL));
1186 mafw_gst_renderer_state_resume(
1187 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1190 if (callback != NULL)
1191 callback(self, user_data, error);
1193 g_error_free(error);
1196 void mafw_gst_renderer_next(MafwRenderer *self, MafwRendererPlaybackCB callback,
1199 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1200 GError *error = NULL;
1202 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1204 g_return_if_fail((renderer->states != 0) &&
1205 (renderer->current_state != _LastMafwPlayState) &&
1206 (renderer->states[renderer->current_state] != NULL));
1208 renderer->play_failed_count = 0;
1209 mafw_gst_renderer_state_next(
1210 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1213 if (callback != NULL)
1214 callback(self, user_data, error);
1216 g_error_free(error);
1219 void mafw_gst_renderer_previous(MafwRenderer *self, MafwRendererPlaybackCB callback,
1222 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1223 GError *error = NULL;
1225 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1227 g_return_if_fail((renderer->states != 0) &&
1228 (renderer->current_state != _LastMafwPlayState) &&
1229 (renderer->states[renderer->current_state] != NULL));
1231 renderer->play_failed_count = 0;
1232 mafw_gst_renderer_state_previous(
1233 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1236 if (callback != NULL)
1237 callback(self, user_data, error);
1239 g_error_free(error);
1242 void mafw_gst_renderer_goto_index(MafwRenderer *self, guint index,
1243 MafwRendererPlaybackCB callback,
1246 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1247 GError *error = NULL;
1249 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1251 g_return_if_fail((renderer->states != 0) &&
1252 (renderer->current_state != _LastMafwPlayState) &&
1253 (renderer->states[renderer->current_state] != NULL));
1255 renderer->play_failed_count = 0;
1256 mafw_gst_renderer_state_goto_index(
1257 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1261 if (callback != NULL)
1262 callback(self, user_data, error);
1264 g_error_free(error);
1267 void mafw_gst_renderer_get_position(MafwRenderer *self, MafwRendererPositionCB callback,
1270 MafwGstRenderer *renderer;
1272 GError *error = NULL;
1274 g_return_if_fail(callback != NULL);
1275 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1277 renderer = MAFW_GST_RENDERER(self);
1279 g_return_if_fail((renderer->states != 0) &&
1280 (renderer->current_state != _LastMafwPlayState) &&
1281 (renderer->states[renderer->current_state] != NULL));
1283 mafw_gst_renderer_state_get_position(
1284 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1288 callback(self, pos, user_data, error);
1290 g_error_free(error);
1293 void mafw_gst_renderer_set_position(MafwRenderer *self, MafwRendererSeekMode mode,
1294 gint seconds, MafwRendererPositionCB callback,
1297 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1298 GError *error = NULL;
1300 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1302 g_return_if_fail((renderer->states != 0) &&
1303 (renderer->current_state != _LastMafwPlayState) &&
1304 (renderer->states[renderer->current_state] != NULL));
1306 mafw_gst_renderer_state_set_position(
1307 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1312 if (callback != NULL)
1313 callback(self, seconds, user_data, error);
1315 g_error_free(error);
1318 gboolean mafw_gst_renderer_manage_error_idle(gpointer data)
1320 MafwGstRendererErrorClosure *mec = (MafwGstRendererErrorClosure *) data;
1322 mafw_gst_renderer_manage_error(mec->renderer, mec->error);
1324 g_error_free(mec->error);
1330 static void _run_error_policy(MafwGstRenderer *self, const GError *in_err,
1333 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1335 gboolean play_next = FALSE;
1337 /* Check what to do on error */
1338 if (in_err->code == MAFW_EXTENSION_ERROR_OUT_OF_MEMORY) {
1341 MafwGstRendererPlaybackMode mode;
1343 mode = mafw_gst_renderer_get_playback_mode(self);
1345 if (mode == MAFW_GST_RENDERER_MODE_PLAYLIST) {
1346 /* In playlist mode we try to play next if
1347 error policy suggests so */
1349 (_get_error_policy(self) ==
1350 MAFW_RENDERER_ERROR_POLICY_CONTINUE);
1352 /* In standalone mode, then switch back to playlist
1353 mode and resume if necessary or move to Stopped
1355 mafw_gst_renderer_set_playback_mode(
1356 self, MAFW_GST_RENDERER_MODE_PLAYLIST);
1357 mafw_gst_renderer_set_media_playlist(self);
1358 if (self->resume_playlist) {
1359 mafw_gst_renderer_play(MAFW_RENDERER(self),
1362 mafw_gst_renderer_worker_stop(self->worker);
1363 mafw_gst_renderer_set_state(self, Stopped);
1365 if (out_err) *out_err = g_error_copy(in_err);
1367 /* Bail out, he have already managed the error
1368 for the case of standalone mode */
1374 if (self->playlist){
1375 MafwPlaylistIteratorMovementResult result;
1377 result = mafw_playlist_iterator_move_to_next(self->iterator,
1379 self->play_failed_count++;
1381 if (mafw_playlist_iterator_get_size(self->iterator,
1383 self->play_failed_count)
1385 mafw_gst_renderer_state_stop(
1386 MAFW_GST_RENDERER_STATE(self->states[self->current_state]),
1388 self->play_failed_count = 0;
1389 mafw_gst_renderer_set_media_playlist(self);
1390 } else if (result !=
1391 MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_OK) {
1392 mafw_playlist_iterator_reset(self->iterator, NULL);
1393 mafw_gst_renderer_set_media_playlist(self);
1394 mafw_gst_renderer_stop(MAFW_RENDERER(self), NULL, NULL);
1396 mafw_gst_renderer_set_media_playlist(self);
1397 mafw_gst_renderer_play(MAFW_RENDERER(self), NULL, NULL);
1400 if (out_err) *out_err = g_error_copy(in_err);
1403 /* We cannot move to next in the playlist or decided
1404 we do not want to do it, just stop on error */
1405 mafw_gst_renderer_stop(MAFW_RENDERER(self), NULL, NULL);
1406 if (out_err) *out_err = g_error_copy(in_err);
1410 static void _metadata_set_cb(MafwSource *self, const gchar *object_id,
1411 const gchar **failed_keys, gpointer user_data,
1412 const GError *error)
1414 if (error != NULL) {
1415 g_debug("Ignoring error received when setting metadata: "
1416 "%s (%d): %s", g_quark_to_string(error->domain),
1417 error->code, error->message);
1419 g_debug("Metadata set correctly");
1424 * _update_playcount_metadata_cb:
1425 * @cb_source: The #MafwSource that sent the metadata results
1426 * @cb_object_id: The object ID, whose metadata results were received
1427 * @cb_metadata: GHashTable containing metadata key-value pairs
1428 * @cb_user_data: Optional user data pointer (self)
1429 * @cb_error: Set if any errors occurred during metadata browsing
1431 * Receives the results of a metadata request about the playcount. It increases
1432 * it, or sets to 1, and sets the metadata to that.
1434 static void _update_playcount_metadata_cb (MafwSource *cb_source,
1435 const gchar *cb_object_id,
1436 GHashTable *cb_metadata,
1437 gpointer cb_user_data,
1438 const GError *cb_error)
1440 GValue *curval = NULL;
1441 gint curplaycount = -1;
1442 GHashTable *mdata = cb_user_data;
1444 if (cb_error == NULL) {
1446 curval = mafw_metadata_first(cb_metadata,
1447 MAFW_METADATA_KEY_PLAY_COUNT);
1448 if (curval && !G_VALUE_HOLDS(curval, G_TYPE_INT))
1452 curplaycount = g_value_get_int(curval);
1456 { /* Playing at first time, or not supported... */
1460 mdata = mafw_metadata_new();
1461 mafw_metadata_add_int(mdata,
1462 MAFW_METADATA_KEY_PLAY_COUNT,
1466 g_warning("_playcount_metadata received an error: "
1467 "%s (%d): %s", g_quark_to_string(cb_error->domain),
1468 cb_error->code, cb_error->message);
1470 g_hash_table_unref(mdata);
1477 mafw_source_set_metadata(cb_source, cb_object_id, mdata,
1478 _metadata_set_cb, NULL);
1479 g_hash_table_unref(mdata);
1484 * mafw_gst_renderer_add_lastplayed:
1485 * @mdata: Exisiting mdata, or NULL
1487 * Sets the MAFW_METADATA_KEY_LAST_PLAYED metadata in the given metadata-table,
1488 * or creates a new metadata-table, and sets the current time there.
1490 static GHashTable *mafw_gst_renderer_add_lastplayed(GHashTable *mdata)
1492 GHashTable *metadata;
1497 metadata = mafw_metadata_new();
1503 g_get_current_time(&timeval);
1505 mafw_metadata_add_long(metadata,
1506 MAFW_METADATA_KEY_LAST_PLAYED,
1512 * mafw_gst_renderer_increase_playcount:
1513 * @self: Gst renderer
1514 * @object_id: The object ID of the touched object
1515 * @mdat: Existing metadatas to add the playcount to, or NULL
1517 * Increases the playcount of the given object.
1519 static void mafw_gst_renderer_increase_playcount(MafwGstRenderer* self,
1520 const gchar *object_id, GHashTable *mdat)
1524 g_assert(self != NULL);
1525 source = _get_source(self, object_id);
1528 static const gchar * const keys[] =
1529 { MAFW_METADATA_KEY_PLAY_COUNT, NULL };
1531 mafw_source_get_metadata(source, object_id,
1533 _update_playcount_metadata_cb,
1540 * mafw_gst_renderer_update_stats:
1543 * Updates both playcount and lastplayed after a while.
1545 gboolean mafw_gst_renderer_update_stats(gpointer data)
1547 MafwGstRenderer *renderer = (MafwGstRenderer *) data;
1549 /* Update stats only for audio content */
1550 if (renderer->media->object_id &&
1551 !renderer->worker->media.has_visual_content) {
1552 GHashTable *mdata = mafw_gst_renderer_add_lastplayed(NULL);
1553 mafw_gst_renderer_increase_playcount(renderer,
1554 renderer->media->object_id,
1557 renderer->update_playcount_id = 0;
1561 void mafw_gst_renderer_update_source_duration(MafwGstRenderer *renderer,
1564 GHashTable *metadata;
1567 source = _get_source(renderer, renderer->media->object_id);
1568 g_return_if_fail(source != NULL);
1570 renderer->media->duration = duration;
1572 g_debug("updated source duration to %d", duration);
1574 metadata = mafw_metadata_new();
1575 mafw_metadata_add_int(metadata, MAFW_METADATA_KEY_DURATION, duration);
1577 mafw_source_set_metadata(source, renderer->media->object_id, metadata,
1578 _metadata_set_cb, NULL);
1579 g_hash_table_unref(metadata);
1584 * @source: The #MafwSource that sent the metadata results
1585 * @objectid: The object ID, whose metadata results were received
1586 * @metadata: GHashTable containing metadata key-value pairs
1587 * @userdata: Optional user data pointer (self)
1588 * @error: Set if any errors occurred during metadata browsing
1590 * Receives the results of a metadata request.
1592 static void _notify_metadata (MafwSource *cb_source,
1593 const gchar *cb_object_id,
1594 GHashTable *cb_metadata,
1595 gpointer cb_user_data,
1596 const GError *cb_error)
1598 MafwGstRenderer *renderer = (MafwGstRenderer*) cb_user_data;
1599 GError *mafw_error = NULL;
1600 GError *error = NULL;
1603 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1605 g_return_if_fail((renderer->states != 0) &&
1606 (renderer->current_state != _LastMafwPlayState) &&
1607 (renderer->states[renderer->current_state] != NULL));
1609 g_debug("running _notify_metadata...");
1611 mval = mafw_metadata_first(cb_metadata, MAFW_METADATA_KEY_URI);
1613 if (cb_error == NULL && mval != NULL) {
1614 mafw_gst_renderer_state_notify_metadata(
1615 MAFW_GST_RENDERER_STATE(
1616 renderer->states[renderer->current_state]),
1622 g_set_error(&mafw_error,
1623 MAFW_RENDERER_ERROR,
1624 MAFW_RENDERER_ERROR_URI_NOT_AVAILABLE, "%s",
1625 cb_error ? cb_error->message : "URI not available");
1626 mafw_gst_renderer_manage_error(renderer, mafw_error);
1627 g_error_free(mafw_error);
1631 static void _notify_play(MafwGstRendererWorker *worker, gpointer owner)
1633 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1634 GError *error = NULL;
1636 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1638 g_return_if_fail((renderer->states != 0) &&
1639 (renderer->current_state != _LastMafwPlayState) &&
1640 (renderer->states[renderer->current_state] != NULL));
1642 g_debug("running _notify_play...");
1644 mafw_gst_renderer_state_notify_play(renderer->states[renderer->current_state],
1647 if (error != NULL) {
1648 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1652 g_error_free (error);
1656 static void _notify_pause(MafwGstRendererWorker *worker, gpointer owner)
1658 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1659 GError *error = NULL;
1661 g_return_if_fail(MAFW_IS_GST_RENDERER (renderer));
1663 g_return_if_fail((renderer->states != 0) &&
1664 (renderer->current_state != _LastMafwPlayState) &&
1665 (renderer->states[renderer->current_state] != NULL));
1667 mafw_gst_renderer_state_notify_pause(renderer->states[renderer->current_state],
1670 if (error != NULL) {
1671 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1672 error->domain, error->code,
1674 g_error_free(error);
1678 static void _notify_buffer_status (MafwGstRendererWorker *worker,
1682 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1683 GError *error = NULL;
1685 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1687 g_return_if_fail((renderer->states != 0) &&
1688 (renderer->current_state != _LastMafwPlayState) &&
1689 (renderer->states[renderer->current_state] != NULL));
1691 mafw_gst_renderer_state_notify_buffer_status(
1692 renderer->states[renderer->current_state],
1696 if (error != NULL) {
1697 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1698 error->domain, error->code,
1700 g_error_free(error);
1704 static void _notify_seek(MafwGstRendererWorker *worker, gpointer owner)
1706 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1707 GError *error = NULL;
1709 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1711 g_return_if_fail((renderer->states != 0) &&
1712 (renderer->current_state != _LastMafwPlayState) &&
1713 (renderer->states[renderer->current_state] != NULL));
1715 mafw_gst_renderer_state_notify_seek(renderer->states[renderer->current_state],
1718 if (error != NULL) {
1719 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1720 error->domain, error->code,
1722 g_error_free(error);
1726 static void _playlist_changed_handler(MafwPlaylistIterator *iterator,
1727 gboolean clip_changed, GQuark domain,
1728 gint code, const gchar *message,
1731 MafwGstRenderer *renderer = (MafwGstRenderer*) user_data;
1733 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1735 g_return_if_fail((renderer->states != 0) &&
1736 (renderer->current_state != _LastMafwPlayState) &&
1737 (renderer->states[renderer->current_state] != NULL));
1739 /* We update the current index and media here, for this is
1740 the same for all the states. Then we delegate in the state
1741 to finish the task (for example, start playback if needed) */
1743 if (renderer->playlist == NULL) {
1744 g_critical("Got iterator:contents-changed but renderer has no" \
1745 "playlist assigned!. Skipping...");
1750 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1751 domain, code, message);
1753 GError *error = NULL;
1754 MafwGstRendererPlaybackMode mode;
1756 mode = mafw_gst_renderer_get_playback_mode(renderer);
1758 /* Only in non-playobject mode */
1759 if (clip_changed && mode == MAFW_GST_RENDERER_MODE_PLAYLIST)
1760 mafw_gst_renderer_set_media_playlist(renderer);
1762 /* We let the state know if the current clip has changed as
1763 result of this operation, so it can do its work */
1764 mafw_gst_renderer_state_playlist_contents_changed_handler(
1765 renderer->states[renderer->current_state],
1769 if (error != NULL) {
1770 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1771 error->domain, error->code,
1773 g_error_free(error);
1778 static void _error_handler(MafwGstRendererWorker *worker, gpointer owner,
1779 const GError *error)
1781 MafwGstRenderer *renderer = MAFW_GST_RENDERER(owner);
1783 mafw_gst_renderer_manage_error(renderer, error);
1786 void mafw_gst_renderer_manage_error(MafwGstRenderer *self, const GError *error)
1788 GError *new_err = NULL;
1789 GError *raise_error = NULL;
1790 GQuark new_err_domain = MAFW_RENDERER_ERROR;
1791 gint new_err_code = 0;
1793 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1795 g_return_if_fail((self->states != 0) &&
1796 (self->current_state != _LastMafwPlayState) &&
1797 (self->states[self->current_state] != NULL));
1799 g_warning("Got error in renderer:\n\tdomain: %d, code: %d, message: %s",
1800 error->domain, error->code, error->message);
1802 /* Get a MAFW error */
1803 if (error->domain == GST_RESOURCE_ERROR) {
1804 /* handle RESOURCE errors */
1805 switch (error->code) {
1806 case GST_RESOURCE_ERROR_READ:
1807 if (is_current_uri_stream(self)) {
1809 if (self->connected) {
1810 new_err_code = MAFW_RENDERER_ERROR_STREAM_DISCONNECTED;
1812 new_err_domain = MAFW_EXTENSION_ERROR;
1813 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1816 /* Stream + cannot read resource ->
1818 new_err_code = MAFW_RENDERER_ERROR_STREAM_DISCONNECTED;
1821 /* This shouldn't happen */
1822 /* Unknown RESOURCE error */
1823 new_err_domain = MAFW_EXTENSION_ERROR;
1824 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1827 case GST_RESOURCE_ERROR_NOT_FOUND:
1829 if (!is_current_uri_stream(self) || self->connected) {
1831 MAFW_RENDERER_ERROR_INVALID_URI;
1833 new_err_domain = MAFW_EXTENSION_ERROR;
1834 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1838 MAFW_RENDERER_ERROR_INVALID_URI;
1841 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
1842 case GST_RESOURCE_ERROR_OPEN_READ:
1844 if (!is_current_uri_stream(self) || self->connected) {
1846 MAFW_RENDERER_ERROR_MEDIA_NOT_FOUND;
1848 new_err_domain = MAFW_EXTENSION_ERROR;
1849 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1853 MAFW_RENDERER_ERROR_MEDIA_NOT_FOUND;
1856 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
1857 new_err_domain = MAFW_EXTENSION_ERROR;
1858 new_err_code = MAFW_EXTENSION_ERROR_OUT_OF_MEMORY;
1860 case GST_RESOURCE_ERROR_WRITE:
1861 /* DSP renderers send ERROR_WRITE when they find
1863 new_err_code = MAFW_RENDERER_ERROR_CORRUPTED_FILE;
1865 case GST_RESOURCE_ERROR_SEEK:
1866 new_err_code = MAFW_RENDERER_ERROR_CANNOT_SET_POSITION;
1869 /* Unknown RESOURCE error */
1870 new_err_domain = MAFW_EXTENSION_ERROR;
1871 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1874 } else if (error->domain == GST_STREAM_ERROR) {
1875 /* handle STREAM errors */
1876 switch (error->code) {
1877 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
1878 new_err_code = MAFW_RENDERER_ERROR_TYPE_NOT_AVAILABLE;
1880 case GST_STREAM_ERROR_FORMAT:
1881 case GST_STREAM_ERROR_WRONG_TYPE:
1882 case GST_STREAM_ERROR_FAILED:
1883 new_err_code = MAFW_RENDERER_ERROR_UNSUPPORTED_TYPE;
1885 case GST_STREAM_ERROR_DECODE:
1886 case GST_STREAM_ERROR_DEMUX:
1887 new_err_code = MAFW_RENDERER_ERROR_CORRUPTED_FILE;
1889 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
1890 new_err_code = MAFW_RENDERER_ERROR_CODEC_NOT_FOUND;
1892 case GST_STREAM_ERROR_DECRYPT:
1893 case GST_STREAM_ERROR_DECRYPT_NOKEY:
1894 new_err_code = MAFW_RENDERER_ERROR_DRM;
1897 /* Unknown STREAM error */
1898 new_err_domain = MAFW_EXTENSION_ERROR;
1899 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1901 } else if (error->domain == MAFW_GST_RENDERER_ERROR) {
1902 /* Handle own errors. Errors that belong to this domain:
1903 - MAFW_GST_RENDERER_ERROR_PLUGIN_NOT_FOUND,
1904 - MAFW_GST_RENDERER_ERROR_VIDEO_CODEC_NOT_SUPPORTED,
1905 - MAFW_GST_RENDERER_ERROR_AUDIO_CODEC_NOT_SUPPORTED */
1906 new_err_code = MAFW_RENDERER_ERROR_UNSUPPORTED_TYPE;
1907 } else if (error->domain == MAFW_RENDERER_ERROR) {
1908 /* Worker may have sent MAFW_RENDERER_ERROR as well.
1909 No processing needed */
1910 new_err_code = error->code;
1914 new_err_domain = MAFW_EXTENSION_ERROR;
1915 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1918 g_set_error(&new_err, new_err_domain, new_err_code, "%s", error->message);
1920 _run_error_policy(self, new_err, &raise_error);
1921 g_error_free(new_err);
1924 g_signal_emit_by_name(MAFW_EXTENSION (self), "error",
1925 raise_error->domain,
1927 raise_error->message);
1928 g_error_free(raise_error);
1932 static void _notify_eos(MafwGstRendererWorker *worker, gpointer owner)
1934 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1935 GError *error = NULL;
1937 g_return_if_fail(MAFW_IS_GST_RENDERER (renderer));
1939 g_return_if_fail((renderer->states != 0) &&
1940 (renderer->current_state != _LastMafwPlayState) &&
1941 (renderer->states[renderer->current_state] != NULL));
1943 mafw_gst_renderer_state_notify_eos(renderer->states[renderer->current_state],
1946 if (error != NULL) {
1947 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1948 error->domain, error->code,
1950 g_error_free(error);
1954 /*----------------------------------------------------------------------------
1956 ----------------------------------------------------------------------------*/
1958 void mafw_gst_renderer_get_status(MafwRenderer *self, MafwRendererStatusCB callback,
1961 MafwGstRenderer* renderer;
1963 MafwGstRendererPlaybackMode mode;
1965 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1966 g_return_if_fail(callback != NULL);
1967 renderer = MAFW_GST_RENDERER(self);
1969 mode = mafw_gst_renderer_get_playback_mode(MAFW_GST_RENDERER(self));
1970 if ((mode == MAFW_GST_RENDERER_MODE_STANDALONE) || (renderer->iterator == NULL)) {
1974 mafw_playlist_iterator_get_current_index(renderer->iterator);
1977 /* TODO: Set error parameter */
1978 callback(self, renderer->playlist, index, renderer->current_state,
1979 (const gchar*) renderer->media->object_id, user_data, NULL);
1982 void mafw_gst_renderer_get_current_metadata(MafwRenderer *self,
1983 MafwRendererMetadataResultCB callback,
1986 MafwGstRenderer *renderer;
1987 GHashTable *metadata;
1989 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1990 renderer = MAFW_GST_RENDERER(self);
1992 metadata = mafw_gst_renderer_worker_get_current_metadata(
1996 (const gchar*) renderer->media->object_id,
2002 /*----------------------------------------------------------------------------
2004 ----------------------------------------------------------------------------*/
2007 _playlist_contents_changed_handler(MafwPlaylist *playlist,
2008 guint from, guint nremove,
2010 MafwGstRenderer *renderer)
2012 /* Item(s) added to playlist, so new playable items could come */
2014 renderer->play_failed_count = 0;
2017 gboolean mafw_gst_renderer_assign_playlist(MafwRenderer *self,
2018 MafwPlaylist *playlist,
2021 MafwGstRenderer* renderer = (MafwGstRenderer*) self;
2023 g_return_val_if_fail(MAFW_IS_GST_RENDERER(self), FALSE);
2025 /* Get rid of previously assigned playlist */
2026 if (renderer->playlist != NULL) {
2027 g_signal_handlers_disconnect_matched(renderer->iterator,
2028 (GSignalMatchType) G_SIGNAL_MATCH_FUNC,
2030 _playlist_changed_handler,
2032 g_signal_handlers_disconnect_matched(renderer->playlist,
2033 (GSignalMatchType) G_SIGNAL_MATCH_FUNC,
2035 G_CALLBACK(_playlist_contents_changed_handler),
2037 /* Decrement the use count of the previous playlist because the
2038 renderer isn't going to use it more */
2039 mafw_playlist_decrement_use_count(renderer->playlist, NULL);
2041 g_object_unref(renderer->iterator);
2042 g_object_unref(renderer->playlist);
2045 /* Assign the new playlist */
2046 if (playlist == NULL) {
2047 renderer->playlist = NULL;
2048 renderer->iterator = NULL;
2050 GError *new_error = NULL;
2051 MafwPlaylistIterator *iterator = NULL;
2053 iterator = mafw_playlist_iterator_new();
2054 mafw_playlist_iterator_initialize(iterator, playlist,
2057 g_object_ref(playlist);
2059 if (new_error == NULL) {
2061 renderer->playlist = playlist;
2062 renderer->iterator = iterator;
2064 /* Increment the use_count to avoid the playlist destruction
2065 while the playlist is assigned to some renderer */
2066 mafw_playlist_increment_use_count(renderer->playlist, NULL);
2068 g_signal_connect(iterator,
2070 G_CALLBACK(_playlist_changed_handler),
2072 g_signal_connect(renderer->playlist,
2074 G_CALLBACK(_playlist_contents_changed_handler),
2078 g_propagate_error (error, new_error);
2082 /* Set the new media and signal playlist changed signal */
2083 _signal_playlist_changed(renderer);
2084 mafw_gst_renderer_set_media_playlist(renderer);
2088 mafw_gst_renderer_stop(MAFW_RENDERER(renderer), NULL , NULL);
2093 MafwGstRendererMovementResult mafw_gst_renderer_move(MafwGstRenderer *renderer,
2094 MafwGstRendererMovementType type,
2098 MafwGstRendererMovementResult value = MAFW_GST_RENDERER_MOVE_RESULT_OK;
2100 if (renderer->playlist == NULL) {
2101 value = MAFW_GST_RENDERER_MOVE_RESULT_NO_PLAYLIST;
2103 MafwPlaylistIteratorMovementResult result;
2106 case MAFW_GST_RENDERER_MOVE_TYPE_INDEX:
2108 mafw_playlist_iterator_move_to_index(renderer->iterator,
2112 case MAFW_GST_RENDERER_MOVE_TYPE_PREV:
2114 mafw_playlist_iterator_move_to_prev(renderer->iterator,
2117 case MAFW_GST_RENDERER_MOVE_TYPE_NEXT:
2119 mafw_playlist_iterator_move_to_next(renderer->iterator,
2125 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_OK:
2126 value = MAFW_GST_RENDERER_MOVE_RESULT_OK;
2127 mafw_gst_renderer_set_media_playlist(renderer);
2129 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_INVALID:
2130 g_critical("Iterator is invalid!");
2131 value = MAFW_GST_RENDERER_MOVE_RESULT_ERROR;
2133 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_ERROR:
2134 value = MAFW_GST_RENDERER_MOVE_RESULT_ERROR;
2136 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_LIMIT:
2137 value = MAFW_GST_RENDERER_MOVE_RESULT_PLAYLIST_LIMIT;
2145 /*----------------------------------------------------------------------------
2147 ----------------------------------------------------------------------------*/
2149 static void _set_error_policy(MafwGstRenderer *renderer, MafwRendererErrorPolicy policy)
2151 renderer->error_policy = policy;
2154 static MafwRendererErrorPolicy _get_error_policy(MafwGstRenderer *renderer)
2156 return renderer->error_policy;
2159 static void mafw_gst_renderer_get_property(MafwExtension *self,
2161 MafwExtensionPropertyCallback callback,
2164 MafwGstRenderer *renderer;
2165 GValue *value = NULL;
2166 GError *error = NULL;
2168 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
2169 g_return_if_fail(callback != NULL);
2170 g_return_if_fail(key != NULL);
2172 renderer = MAFW_GST_RENDERER(self);
2173 if (!strcmp(key, MAFW_PROPERTY_RENDERER_VOLUME)) {
2176 volume = mafw_gst_renderer_worker_get_volume(
2179 value = g_new0(GValue, 1);
2180 g_value_init(value, G_TYPE_UINT);
2181 g_value_set_uint(value, volume);
2183 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_MUTE)) {
2185 mute = mafw_gst_renderer_worker_get_mute(renderer->worker);
2186 value = g_new0(GValue, 1);
2187 g_value_init(value, G_TYPE_BOOLEAN);
2188 g_value_set_boolean(value, mute);
2190 else if (!strcmp (key, MAFW_PROPERTY_RENDERER_XID)) {
2192 xid = mafw_gst_renderer_worker_get_xid(renderer->worker);
2193 value = g_new0(GValue, 1);
2194 g_value_init(value, G_TYPE_UINT);
2195 g_value_set_uint(value, xid);
2197 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_ERROR_POLICY)) {
2199 policy = _get_error_policy(renderer);
2200 value = g_new0(GValue, 1);
2201 g_value_init(value, G_TYPE_UINT);
2202 g_value_set_uint(value, policy);
2204 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_AUTOPAINT)) {
2205 value = g_new0(GValue, 1);
2206 g_value_init(value, G_TYPE_BOOLEAN);
2207 g_value_set_boolean(
2209 mafw_gst_renderer_worker_get_autopaint(
2211 } else if (!strcmp(key, MAFW_PROPERTY_RENDERER_COLORKEY)) {
2212 value = g_new0(GValue, 1);
2213 g_value_init(value, G_TYPE_INT);
2216 mafw_gst_renderer_worker_get_colorkey(
2219 #ifdef HAVE_GDKPIXBUF
2220 else if (!strcmp(key,
2221 MAFW_PROPERTY_GST_RENDERER_CURRENT_FRAME_ON_PAUSE)) {
2222 gboolean current_frame_on_pause;
2223 current_frame_on_pause =
2224 mafw_gst_renderer_worker_get_current_frame_on_pause(renderer->worker);
2225 value = g_new0(GValue, 1);
2226 g_value_init(value, G_TYPE_BOOLEAN);
2227 g_value_set_boolean(value, current_frame_on_pause);
2230 else if (!strcmp(key,
2231 MAFW_PROPERTY_GST_RENDERER_TV_CONNECTED)) {
2232 value = g_new0(GValue, 1);
2233 g_value_init(value, G_TYPE_BOOLEAN);
2234 g_value_set_boolean(value, renderer->tv_connected);
2236 else if (!strcmp(key,
2237 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS)){
2238 /* Delegate in the state. */
2239 value = mafw_gst_renderer_state_get_property_value(
2240 MAFW_GST_RENDERER_STATE(
2241 renderer->states[renderer->current_state]),
2242 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS);
2245 /* Something goes wrong. */
2246 error = g_error_new(
2247 MAFW_GST_RENDERER_ERROR,
2248 MAFW_EXTENSION_ERROR_GET_PROPERTY,
2249 "Error while getting the property value");
2253 /* Unsupported property */
2254 error = g_error_new(MAFW_GST_RENDERER_ERROR,
2255 MAFW_EXTENSION_ERROR_GET_PROPERTY,
2256 "Unsupported property");
2259 callback(self, key, value, user_data, error);
2262 static void mafw_gst_renderer_set_property(MafwExtension *self,
2264 const GValue *value)
2266 MafwGstRenderer *renderer;
2268 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
2269 g_return_if_fail(key != NULL);
2271 renderer = MAFW_GST_RENDERER(self);
2273 if (!strcmp(key, MAFW_PROPERTY_RENDERER_VOLUME)) {
2274 guint volume = g_value_get_uint(value);
2277 mafw_gst_renderer_worker_set_volume(renderer->worker,
2279 /* Property-changed emision is done by worker */
2282 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_MUTE)) {
2283 gboolean mute = g_value_get_boolean(value);
2284 mafw_gst_renderer_worker_set_mute(renderer->worker, mute);
2286 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_XID)) {
2287 XID xid = g_value_get_uint(value);
2288 mafw_gst_renderer_worker_set_xid(renderer->worker, xid);
2290 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_ERROR_POLICY)) {
2291 MafwRendererErrorPolicy policy = g_value_get_uint(value);
2292 _set_error_policy(renderer, policy);
2294 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_AUTOPAINT)) {
2295 mafw_gst_renderer_worker_set_autopaint(
2297 g_value_get_boolean(value));
2299 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_COLORKEY)) {
2300 mafw_gst_renderer_worker_set_colorkey(
2302 g_value_get_int(value));
2304 #ifdef HAVE_GDKPIXBUF
2305 else if (!strcmp(key,
2306 MAFW_PROPERTY_GST_RENDERER_CURRENT_FRAME_ON_PAUSE)) {
2307 gboolean current_frame_on_pause = g_value_get_boolean(value);
2308 mafw_gst_renderer_worker_set_current_frame_on_pause(renderer->worker,
2309 current_frame_on_pause);
2314 /* FIXME I'm not sure when to emit property-changed signals.
2315 * Maybe we should let the worker do it, when the change
2316 * reached the hardware... */
2317 mafw_extension_emit_property_changed(self, key, value);
2320 /* vi: set noexpandtab ts=8 sw=8 cino=t0,(0: */