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_SUBTITLE_RENDERER "/system/mafw/mafw-gst-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", "omx", "selector",
212 "autodetect", "pulseaudio", "audioconvert", "audioresample",
213 "xvimagesink", "ffmpegcolorspace", "videoscale", NULL};
217 gclass = G_OBJECT_CLASS(klass);
218 g_return_if_fail(gclass != NULL);
220 renderer_class = MAFW_RENDERER_CLASS(klass);
221 g_return_if_fail(renderer_class != NULL);
225 gclass->dispose = mafw_gst_renderer_dispose;
226 gclass->finalize = mafw_gst_renderer_finalize;
230 renderer_class->play = mafw_gst_renderer_play;
231 renderer_class->play_object = mafw_gst_renderer_play_object;
232 renderer_class->stop = mafw_gst_renderer_stop;
233 renderer_class->pause = mafw_gst_renderer_pause;
234 renderer_class->resume = mafw_gst_renderer_resume;
235 renderer_class->get_status = mafw_gst_renderer_get_status;
237 /* Playlist operations */
239 renderer_class->assign_playlist = mafw_gst_renderer_assign_playlist;
240 renderer_class->next = mafw_gst_renderer_next;
241 renderer_class->previous = mafw_gst_renderer_previous;
242 renderer_class->goto_index = mafw_gst_renderer_goto_index;
244 /* Playback position */
246 renderer_class->set_position = mafw_gst_renderer_set_position;
247 renderer_class->get_position = mafw_gst_renderer_get_position;
251 renderer_class->get_current_metadata =
252 mafw_gst_renderer_get_current_metadata;
256 MAFW_EXTENSION_CLASS(klass)->get_extension_property =
257 (gpointer) mafw_gst_renderer_get_property;
258 MAFW_EXTENSION_CLASS(klass)->set_extension_property =
259 (gpointer) mafw_gst_renderer_set_property;
261 gst_init(NULL, NULL);
264 /* Pre-load some common plugins */
265 while (preloaded_plugins[i])
267 plugin = G_OBJECT(gst_plugin_load_by_name(preloaded_plugins[i]));
269 g_object_unref(plugin);
271 g_debug("Can not load plugin: %s", preloaded_plugins[i]);
276 static void mafw_gst_renderer_init(MafwGstRenderer *self)
278 MafwGstRenderer *renderer = NULL;
279 GError *error = NULL;
281 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
283 renderer = MAFW_GST_RENDERER(self);
284 g_return_if_fail(renderer != NULL);
286 mafw_extension_add_property(MAFW_EXTENSION(self), "volume", G_TYPE_UINT);
287 mafw_extension_add_property(MAFW_EXTENSION(self), "mute", G_TYPE_BOOLEAN);
288 mafw_extension_add_property(MAFW_EXTENSION(self), "xid", G_TYPE_UINT);
289 mafw_extension_add_property(MAFW_EXTENSION(self), "error-policy", G_TYPE_UINT);
290 MAFW_EXTENSION_SUPPORTS_AUTOPAINT(self);
291 MAFW_EXTENSION_SUPPORTS_COLORKEY(self);
292 #ifdef HAVE_GDKPIXBUF
293 mafw_extension_add_property(MAFW_EXTENSION(self),
294 "current-frame-on-pause",
297 mafw_extension_add_property(MAFW_EXTENSION(self),
298 MAFW_PROPERTY_GST_RENDERER_TV_CONNECTED,
300 MAFW_EXTENSION_SUPPORTS_TRANSPORT_ACTIONS(self);
301 renderer->media = g_new0(MafwGstRendererMedia, 1);
302 renderer->media->seekability = SEEKABILITY_UNKNOWN;
303 renderer->current_state = Stopped;
305 renderer->playlist = NULL;
306 renderer->iterator = NULL;
307 renderer->seeking_to = -1;
308 renderer->update_playcount_id = 0;
310 self->worker = mafw_gst_renderer_worker_new(self);
312 /* Set notification handlers for worker */
313 renderer->worker->notify_play_handler = _notify_play;
314 renderer->worker->notify_pause_handler = _notify_pause;
315 renderer->worker->notify_seek_handler = _notify_seek;
316 renderer->worker->notify_error_handler = _error_handler;
317 renderer->worker->notify_eos_handler = _notify_eos;
318 renderer->worker->notify_buffer_status_handler = _notify_buffer_status;
320 renderer->states = g_new0 (MafwGstRendererState*, _LastMafwPlayState);
321 renderer->states[Stopped] =
322 MAFW_GST_RENDERER_STATE(mafw_gst_renderer_state_stopped_new(self));
323 renderer->states[Transitioning] =
324 MAFW_GST_RENDERER_STATE(
325 mafw_gst_renderer_state_transitioning_new(self));
326 renderer->states[Playing] =
327 MAFW_GST_RENDERER_STATE(mafw_gst_renderer_state_playing_new(self));
328 renderer->states[Paused] =
329 MAFW_GST_RENDERER_STATE(mafw_gst_renderer_state_paused_new(self));
331 renderer->current_state = Stopped;
332 renderer->resume_playlist = FALSE;
333 renderer->playback_mode = MAFW_GST_RENDERER_MODE_PLAYLIST;
336 renderer->connected = FALSE;
337 renderer->connection = NULL;
339 _connection_init(renderer);
341 renderer->gconf_client = gconf_client_get_default();
342 gconf_client_add_dir(renderer->gconf_client, GCONF_OSSO_AF,
343 GCONF_CLIENT_PRELOAD_ONELEVEL, &error);
345 g_warning("%s", error->message);
350 gconf_client_notify_add(renderer->gconf_client,
351 GCONF_BATTERY_COVER_OPEN,
352 (GConfClientNotifyFunc) _battery_cover_open_cb,
357 g_warning("%s", error->message);
361 gconf_client_add_dir(renderer->gconf_client,
362 GCONF_MAFW_GST_SUBTITLE_RENDERER,
363 GCONF_CLIENT_PRELOAD_ONELEVEL,
366 g_warning("%s", error->message);
371 gconf_client_notify_add(renderer->gconf_client,
372 GCONF_MAFW_GST_SUBTITLE_RENDERER "/autoload_subtitles",
373 (GConfClientNotifyFunc) _autoload_subtitles_changed_cb,
377 g_warning("%s", error->message);
381 gconf_client_notify_add(renderer->gconf_client,
382 GCONF_MAFW_GST_SUBTITLE_RENDERER "/subtitle_encoding",
383 (GConfClientNotifyFunc) _subtitle_font_changed_cb,
387 g_warning("%s", error->message);
391 gconf_client_notify_add(renderer->gconf_client,
392 GCONF_MAFW_GST_SUBTITLE_RENDERER "/subtitle_font",
393 (GConfClientNotifyFunc) _subtitle_font_changed_cb,
397 g_warning("%s", error->message);
401 if (self->worker->pipeline) {
402 gconf_client_notify(renderer->gconf_client,
403 GCONF_MAFW_GST_SUBTITLE_RENDERER "/autoload_subtitles");
405 gconf_client_notify(renderer->gconf_client,
406 GCONF_MAFW_GST_SUBTITLE_RENDERER "/subtitle_encoding");
408 gconf_client_notify(renderer->gconf_client,
409 GCONF_MAFW_GST_SUBTITLE_RENDERER "/subtitle_font");
412 if (gnome_vfs_init()) {
413 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
414 g_signal_connect(monitor, "volume-pre-unmount",
415 G_CALLBACK(_volume_pre_unmount_cb), renderer);
417 g_warning("Failed to initialize gnome-vfs");
421 static void mafw_gst_renderer_dispose(GObject *object)
423 MafwGstRenderer *renderer;
425 g_return_if_fail(MAFW_IS_GST_RENDERER(object));
427 renderer = MAFW_GST_RENDERER(object);
429 if (renderer->worker != NULL) {
430 mafw_gst_renderer_worker_exit(renderer->worker);
431 renderer->seek_pending = FALSE;
432 g_free(renderer->worker);
433 renderer->worker = NULL;
436 if (renderer->registry != NULL) {
437 g_object_unref(renderer->registry);
438 renderer->registry = NULL;
441 if (renderer->states != NULL) {
444 for (i = 0; i < _LastMafwPlayState; i++) {
445 if (renderer->states[i] != NULL)
446 g_object_unref(renderer->states[i]);
448 g_free(renderer->states);
449 renderer->states = NULL;
452 if (renderer->hal_ctx != NULL) {
453 libhal_device_remove_property_watch(renderer->hal_ctx,
456 libhal_ctx_shutdown(renderer->hal_ctx, NULL);
457 libhal_ctx_free(renderer->hal_ctx);
461 if (renderer->connection != NULL) {
462 g_object_unref(renderer->connection);
463 renderer->connection = NULL;
467 if (renderer->gconf_client != NULL) {
468 g_object_unref(renderer->gconf_client);
469 renderer->gconf_client = NULL;
472 G_OBJECT_CLASS(mafw_gst_renderer_parent_class)->dispose(object);
475 static void mafw_gst_renderer_finalize(GObject *object)
477 MafwGstRenderer *self = (MafwGstRenderer*) object;
479 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
481 mafw_gst_renderer_clear_media(self);
489 G_OBJECT_CLASS(mafw_gst_renderer_parent_class)->finalize(object);
493 * mafw_gst_renderer_new:
494 * @registry: The registry that owns this renderer.
496 * Creates a new MafwGstRenderer object
498 GObject *mafw_gst_renderer_new(MafwRegistry* registry)
502 DBusConnection *conn;
508 object = g_object_new(MAFW_TYPE_GST_RENDERER,
509 "uuid", MAFW_GST_RENDERER_UUID,
510 "name", MAFW_GST_RENDERER_NAME,
511 "plugin", MAFW_GST_RENDERER_PLUGIN_NAME,
513 g_assert(object != NULL);
514 MAFW_GST_RENDERER(object)->registry = g_object_ref(registry);
516 /* Set default error policy */
517 MAFW_GST_RENDERER(object)->error_policy =
518 MAFW_RENDERER_ERROR_POLICY_CONTINUE;
520 MAFW_GST_RENDERER(object)->tv_connected = FALSE;
522 /* Setup hal connection for reacting usb cable connected event */
523 dbus_error_init(&err);
524 conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
526 if (dbus_error_is_set(&err)) {
527 g_warning("Couldn't setup HAL connection: %s", err.message);
528 dbus_error_free(&err);
532 ctx = libhal_ctx_new();
533 libhal_ctx_set_dbus_connection(ctx, conn);
534 libhal_ctx_set_user_data(ctx, object);
536 if (libhal_ctx_init(ctx, &err) == FALSE) {
537 if (dbus_error_is_set(&err)) {
538 g_warning("Could not initialize hal: %s", err.message);
539 dbus_error_free(&err);
541 g_warning("Could not initialize hal");
546 libhal_device_add_property_watch(ctx, HAL_VIDEOOUT_UDI, &err);
548 if (dbus_error_is_set(&err)) {
549 g_warning("Could not start watching usb device: %s",
551 dbus_error_free(&err);
555 libhal_ctx_set_device_property_modified(ctx, _property_modified);
557 /* Initializes blanking policy */
558 jackets = libhal_find_device_by_capability(ctx,
559 "input.jack.video-out",
561 if (jackets != NULL) {
564 if (_tv_out_is_connected(ctx, *jack)) {
565 MAFW_GST_RENDERER(object)->tv_connected = TRUE;
571 blanking_control(*jack == NULL);
572 libhal_free_string_array(jackets);
575 MAFW_GST_RENDERER(object)->hal_ctx = ctx;
579 libhal_ctx_shutdown(ctx, NULL);
581 libhal_ctx_free(ctx);
587 * mafw_gst_renderer_error_quark:
589 * Fetches the quark representing the domain of the errors in the
592 * Return value: a quark identifying the error domain of the
593 * #MafwGstRenderer objects.
596 GQuark mafw_gst_renderer_error_quark(void)
598 return g_quark_from_static_string("mafw-gst-renderer-error-quark");
601 void mafw_gst_renderer_set_playback_mode(MafwGstRenderer *self,
602 MafwGstRendererPlaybackMode mode)
604 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
605 self->playback_mode = mode;
608 MafwGstRendererPlaybackMode mafw_gst_renderer_get_playback_mode(
609 MafwGstRenderer *self)
611 g_return_val_if_fail(MAFW_IS_GST_RENDERER(self),
612 MAFW_GST_RENDERER_MODE_STANDALONE);
613 return self->playback_mode;
616 /*----------------------------------------------------------------------------
618 ----------------------------------------------------------------------------*/
620 static MafwSource* _get_source(MafwGstRenderer *renderer,
621 const gchar *object_id)
624 gchar* sourceid = NULL;
626 g_assert(object_id != NULL);
628 /* Attempt to find a source that provided the object ID */
629 mafw_source_split_objectid(object_id, &sourceid, NULL);
630 source = MAFW_SOURCE(mafw_registry_get_extension_by_uuid(
631 renderer->registry, sourceid));
637 void mafw_gst_renderer_get_metadata(MafwGstRenderer* self,
638 const gchar* objectid,
643 g_assert(self != NULL);
646 * Any error here is an error when trying to Play, so
647 * it must be handled by error policy.
648 * Problem: if we get an error here and we are not in
649 * Transitioning yet (maybe we are still in Stopped state)
650 * then the policy may move to next and stay Stopped (instead of
651 * trying to play), so errors need to be handled by the policy
652 * in an idle callback, so that any error that may happen here
653 * is not processed until we have moved to Transitioning state
656 source = _get_source(self, objectid);
659 /* List of metadata keys that we are interested in when going to
660 Transitioning state */
661 static const gchar * const keys[] =
662 { MAFW_METADATA_KEY_URI,
663 MAFW_METADATA_KEY_IS_SEEKABLE,
664 MAFW_METADATA_KEY_DURATION,
667 /* Source found, get metadata */
668 mafw_source_get_metadata(source, objectid,
676 /* This is a playback error: execute error policy */
677 MafwGstRendererErrorClosure *error_closure;
678 error_closure = g_new0(MafwGstRendererErrorClosure, 1);
679 error_closure->renderer = self;
680 g_set_error (&(error_closure->error),
681 MAFW_EXTENSION_ERROR,
682 MAFW_EXTENSION_ERROR_EXTENSION_NOT_AVAILABLE,
683 "Unable to find source for current object ID");
684 g_idle_add(mafw_gst_renderer_manage_error_idle, error_closure);
688 void mafw_gst_renderer_set_object(MafwGstRenderer *self, const gchar *object_id)
690 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
692 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
693 g_return_if_fail(object_id != NULL);
695 /* This is intended to be called only when using play_object(),
696 * as for playlists we use set_media_playlist()
699 /* Stop any ongoing playback */
700 mafw_gst_renderer_clear_media(renderer);
703 renderer->media->object_id = g_strdup(object_id);
705 /* Signal media changed */
706 _signal_media_changed(renderer);
711 * mafw_gst_renderer_clear_media:
713 * @renderer A #MafwGstRenderer whose media to clear
715 * Clears & frees the renderer's current media details
717 void mafw_gst_renderer_clear_media(MafwGstRenderer *self)
719 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
720 g_return_if_fail(self->media != NULL);
722 g_free(self->media->object_id);
723 self->media->object_id = NULL;
725 g_free(self->media->uri);
726 self->media->uri = NULL;
728 g_free(self->media->title);
729 self->media->title = NULL;
731 g_free(self->media->artist);
732 self->media->artist = NULL;
734 g_free(self->media->album);
735 self->media->album = NULL;
737 self->media->duration = 0;
738 self->media->position = 0;
743 * mafw_gst_renderer_set_media_playlist:
745 * @self A #MafwGstRenderer, whose media to set
747 * Set current media from the renderer's playlist, using the current playlist index.
749 void mafw_gst_renderer_set_media_playlist(MafwGstRenderer* self)
751 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
753 /* Get rid of old media details */
754 mafw_gst_renderer_clear_media(self);
756 if (self->playlist != NULL &&
757 mafw_playlist_iterator_get_size(self->iterator, NULL) > 0) {
758 /* Get the current item from playlist */
759 self->media->object_id =
760 g_strdup(mafw_playlist_iterator_get_current_objectid(self->iterator));
762 self->media->object_id = NULL;
765 _signal_media_changed(self);
769 /*----------------------------------------------------------------------------
771 ----------------------------------------------------------------------------*/
774 _con_ic_status_handler(ConIcConnection *conn, ConIcConnectionEvent *event,
777 MafwGstRenderer *renderer = (MafwGstRenderer *) data;
779 g_assert(MAFW_IS_GST_RENDERER(renderer));
781 renderer->connected =
782 con_ic_connection_event_get_status(event) ==
783 CON_IC_STATUS_CONNECTED;
787 _connection_init(MafwGstRenderer *renderer)
789 g_assert (MAFW_IS_GST_RENDERER(renderer));
791 if (renderer->connection == NULL) {
792 renderer->connection = con_ic_connection_new();
793 renderer->connected = FALSE;
795 g_assert(renderer->connection != NULL);
798 g_object_set(renderer->connection, "automatic-connection-events",
800 g_signal_connect(renderer->connection, "connection-event",
801 G_CALLBACK (_con_ic_status_handler), renderer);
803 con_ic_connection_connect(renderer->connection,
804 CON_IC_CONNECT_FLAG_AUTOMATICALLY_TRIGGERED);
808 /*----------------------------------------------------------------------------
810 ----------------------------------------------------------------------------*/
812 static gboolean _tv_out_is_connected(LibHalContext *ctx, const char *udi)
814 gboolean is_tv_out_jack = FALSE;
822 jack_types = libhal_device_get_property_strlist(ctx, udi,
825 if (jack_types == NULL) {
831 if (strcmp(*jack, "video-out") == 0) {
832 is_tv_out_jack = TRUE;
839 libhal_free_string_array(jack_types);
841 return is_tv_out_jack;
844 static void _property_modified(LibHalContext *ctx, const char *udi,
845 const char *key, dbus_bool_t is_removed,
846 dbus_bool_t is_added)
848 MafwGstRenderer *renderer;
850 GValue value = { 0 };
852 g_debug("HAL property modified! jack changed\n");
853 connected = _tv_out_is_connected(ctx, udi);
854 renderer = MAFW_GST_RENDERER(libhal_ctx_get_user_data(ctx));
855 if (renderer->tv_connected != connected) {
856 /* Notify the change */
857 renderer->tv_connected = connected;
858 g_value_init(&value, G_TYPE_BOOLEAN);
859 g_value_set_boolean(&value, renderer->tv_connected);
860 mafw_extension_emit_property_changed(
861 MAFW_EXTENSION(renderer),
862 MAFW_PROPERTY_GST_RENDERER_TV_CONNECTED,
864 g_value_unset(&value);
866 blanking_control(connected == FALSE);
869 /*----------------------------------------------------------------------------
871 ----------------------------------------------------------------------------*/
873 static void _battery_cover_open_cb(GConfClient *client,
876 MafwGstRenderer *renderer)
878 GConfValue *value = NULL;
879 gboolean is_cover_open;
881 value = gconf_entry_get_value(entry);
882 is_cover_open = gconf_value_get_bool(value);
885 /* External mmc could be removed!. */
886 const gchar *emmc_path = g_getenv("MMC_MOUNTPOINT");
888 mafw_gst_renderer_state_handle_pre_unmount(
889 MAFW_GST_RENDERER_STATE(
890 renderer->states[renderer->current_state]),
895 static void _autoload_subtitles_changed_cb(GConfClient *client,
898 MafwGstRenderer *renderer)
900 GConfValue *value = NULL;
901 gboolean enabled = FALSE;
903 value = gconf_entry_get_value(entry);
907 enabled = gconf_value_get_bool(value);
910 renderer->worker->subtitles.enabled = TRUE;
912 renderer->worker->subtitles.enabled = FALSE;
915 static void _subtitle_font_changed_cb(GConfClient *client,
918 MafwGstRenderer *renderer)
920 const gchar *key = NULL;
921 GConfValue *value = NULL;
922 const gchar *str_value = NULL;
924 key = gconf_entry_get_key(entry);
926 /* Only key without absolute path is required */
927 key += strlen(GCONF_MAFW_GST_SUBTITLE_RENDERER) + 1;
929 value = gconf_entry_get_value(entry);
933 str_value = gconf_value_get_string(value);
935 if (strcmp(key, "subtitle_font") == 0) {
936 if (renderer->worker->subtitles.font)
937 g_free(renderer->worker->subtitles.font);
939 renderer->worker->subtitles.font = g_strdup(str_value);
940 } else if (strcmp(key, "subtitle_encoding") == 0) {
941 if (renderer->worker->subtitles.encoding)
942 g_free(renderer->worker->subtitles.encoding);
944 renderer->worker->subtitles.encoding = g_strdup(str_value);
946 g_warning("Wrong %s key, %s", GCONF_MAFW_GST_SUBTITLE_RENDERER, key);
950 /*----------------------------------------------------------------------------
951 Gnome VFS notifications
952 ----------------------------------------------------------------------------*/
954 static void _volume_pre_unmount_cb(GnomeVFSVolumeMonitor *monitor,
955 GnomeVFSVolume *volume,
956 MafwGstRenderer *renderer)
958 gchar *location = gnome_vfs_volume_get_activation_uri(volume);
963 mafw_gst_renderer_state_handle_pre_unmount(
964 MAFW_GST_RENDERER_STATE(
965 renderer->states[renderer->current_state]),
971 /*----------------------------------------------------------------------------
973 ----------------------------------------------------------------------------*/
977 * _signal_state_changed:
978 * @self: A #MafwGstRenderer
980 * Signals state_changed to all UIs
982 static void _signal_state_changed(MafwGstRenderer * self)
984 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
986 g_signal_emit_by_name(MAFW_RENDERER(self),
987 "state-changed", self->current_state);
991 * _signal_playlist_changed:
992 * @self: A #MafwGstRenderer
994 * Signals playlist update to all UIs
996 static void _signal_playlist_changed(MafwGstRenderer * self)
998 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1000 g_signal_emit_by_name(MAFW_RENDERER(self),
1001 "playlist-changed", self->playlist);
1005 * _signal_media_changed:
1006 * @self: A #MafwGstRenderer
1008 * Signals media_changed to all UIs
1010 static void _signal_media_changed(MafwGstRenderer *self)
1013 MafwGstRendererPlaybackMode mode;
1016 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1018 mode = mafw_gst_renderer_get_playback_mode(MAFW_GST_RENDERER(self));
1019 if ((mode == MAFW_GST_RENDERER_MODE_STANDALONE) ||
1020 (self->iterator == NULL)) {
1023 index = mafw_playlist_iterator_get_current_index(self->iterator);
1026 g_signal_emit_by_name(MAFW_RENDERER(self),
1029 self->media->object_id);
1033 * _signal_transport_actions_property_changed:
1034 * @self: A #MafwGstRenderer
1036 * Signals transport_actions property_changed to all UIs
1038 static void _signal_transport_actions_property_changed(MafwGstRenderer * self)
1042 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1044 value = mafw_gst_renderer_state_get_property_value(
1045 MAFW_GST_RENDERER_STATE(
1046 self->states[self->current_state]),
1047 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS);
1050 mafw_extension_emit_property_changed(
1051 MAFW_EXTENSION(self),
1052 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS,
1054 g_value_unset(value);
1060 /*----------------------------------------------------------------------------
1061 State pattern support
1062 ----------------------------------------------------------------------------*/
1064 void mafw_gst_renderer_set_state(MafwGstRenderer *self, MafwPlayState state)
1066 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1068 self->current_state = state;
1069 _signal_state_changed(self);
1070 _signal_transport_actions_property_changed(self);
1073 void mafw_gst_renderer_play(MafwRenderer *self, MafwRendererPlaybackCB callback,
1076 MafwGstRenderer *renderer = (MafwGstRenderer*) self;
1077 GError *error = NULL;
1079 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1081 g_return_if_fail((renderer->states != 0) &&
1082 (renderer->current_state != _LastMafwPlayState) &&
1083 (renderer->states[renderer->current_state] != NULL));
1085 mafw_gst_renderer_state_play(
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_play_object(MafwRenderer *self,
1096 const gchar *object_id,
1097 MafwRendererPlaybackCB callback,
1100 MafwGstRenderer *renderer = (MafwGstRenderer*) self;
1101 GError *error = NULL;
1103 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1104 g_return_if_fail(object_id != NULL);
1106 g_return_if_fail((renderer->states != 0) &&
1107 (renderer->current_state != _LastMafwPlayState) &&
1108 (renderer->states[renderer->current_state] != NULL));
1110 mafw_gst_renderer_state_play_object(
1111 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1115 if (callback != NULL)
1116 callback(self, user_data, error);
1118 g_error_free(error);
1121 void mafw_gst_renderer_stop(MafwRenderer *self, MafwRendererPlaybackCB callback,
1124 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1125 GError *error = NULL;
1127 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1129 g_return_if_fail((renderer->states != 0) &&
1130 (renderer->current_state != _LastMafwPlayState) &&
1131 (renderer->states[renderer->current_state] != NULL));
1133 renderer->play_failed_count = 0;
1134 mafw_gst_renderer_state_stop(
1135 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1138 if (callback != NULL)
1139 callback(self, user_data, error);
1141 g_error_free(error);
1145 void mafw_gst_renderer_pause(MafwRenderer *self, MafwRendererPlaybackCB callback,
1148 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1149 GError *error = NULL;
1151 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1153 g_return_if_fail((renderer->states != 0) &&
1154 (renderer->current_state != _LastMafwPlayState) &&
1155 (renderer->states[renderer->current_state] != NULL));
1157 mafw_gst_renderer_state_pause(
1158 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1161 if (callback != NULL)
1162 callback(self, user_data, error);
1164 g_error_free(error);
1167 void mafw_gst_renderer_resume(MafwRenderer *self, MafwRendererPlaybackCB callback,
1170 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1171 GError *error = NULL;
1173 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1175 g_return_if_fail((renderer->states != 0) &&
1176 (renderer->current_state != _LastMafwPlayState) &&
1177 (renderer->states[renderer->current_state] != NULL));
1179 mafw_gst_renderer_state_resume(
1180 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1183 if (callback != NULL)
1184 callback(self, user_data, error);
1186 g_error_free(error);
1189 void mafw_gst_renderer_next(MafwRenderer *self, MafwRendererPlaybackCB callback,
1192 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1193 GError *error = NULL;
1195 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1197 g_return_if_fail((renderer->states != 0) &&
1198 (renderer->current_state != _LastMafwPlayState) &&
1199 (renderer->states[renderer->current_state] != NULL));
1201 renderer->play_failed_count = 0;
1202 mafw_gst_renderer_state_next(
1203 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1206 if (callback != NULL)
1207 callback(self, user_data, error);
1209 g_error_free(error);
1212 void mafw_gst_renderer_previous(MafwRenderer *self, MafwRendererPlaybackCB callback,
1215 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1216 GError *error = NULL;
1218 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1220 g_return_if_fail((renderer->states != 0) &&
1221 (renderer->current_state != _LastMafwPlayState) &&
1222 (renderer->states[renderer->current_state] != NULL));
1224 renderer->play_failed_count = 0;
1225 mafw_gst_renderer_state_previous(
1226 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1229 if (callback != NULL)
1230 callback(self, user_data, error);
1232 g_error_free(error);
1235 void mafw_gst_renderer_goto_index(MafwRenderer *self, guint index,
1236 MafwRendererPlaybackCB callback,
1239 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1240 GError *error = NULL;
1242 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1244 g_return_if_fail((renderer->states != 0) &&
1245 (renderer->current_state != _LastMafwPlayState) &&
1246 (renderer->states[renderer->current_state] != NULL));
1248 renderer->play_failed_count = 0;
1249 mafw_gst_renderer_state_goto_index(
1250 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1254 if (callback != NULL)
1255 callback(self, user_data, error);
1257 g_error_free(error);
1260 void mafw_gst_renderer_get_position(MafwRenderer *self, MafwRendererPositionCB callback,
1263 MafwGstRenderer *renderer;
1265 GError *error = NULL;
1267 g_return_if_fail(callback != NULL);
1268 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1270 renderer = MAFW_GST_RENDERER(self);
1272 g_return_if_fail((renderer->states != 0) &&
1273 (renderer->current_state != _LastMafwPlayState) &&
1274 (renderer->states[renderer->current_state] != NULL));
1276 mafw_gst_renderer_state_get_position(
1277 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1281 callback(self, pos, user_data, error);
1283 g_error_free(error);
1286 void mafw_gst_renderer_set_position(MafwRenderer *self, MafwRendererSeekMode mode,
1287 gint seconds, MafwRendererPositionCB callback,
1290 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1291 GError *error = NULL;
1293 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1295 g_return_if_fail((renderer->states != 0) &&
1296 (renderer->current_state != _LastMafwPlayState) &&
1297 (renderer->states[renderer->current_state] != NULL));
1299 mafw_gst_renderer_state_set_position(
1300 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1305 if (callback != NULL)
1306 callback(self, seconds, user_data, error);
1308 g_error_free(error);
1311 gboolean mafw_gst_renderer_manage_error_idle(gpointer data)
1313 MafwGstRendererErrorClosure *mec = (MafwGstRendererErrorClosure *) data;
1315 mafw_gst_renderer_manage_error(mec->renderer, mec->error);
1317 g_error_free(mec->error);
1323 static void _run_error_policy(MafwGstRenderer *self, const GError *in_err,
1326 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1328 gboolean play_next = FALSE;
1330 /* Check what to do on error */
1331 if (in_err->code == MAFW_EXTENSION_ERROR_OUT_OF_MEMORY) {
1334 MafwGstRendererPlaybackMode mode;
1336 mode = mafw_gst_renderer_get_playback_mode(self);
1338 if (mode == MAFW_GST_RENDERER_MODE_PLAYLIST) {
1339 /* In playlist mode we try to play next if
1340 error policy suggests so */
1342 (_get_error_policy(self) ==
1343 MAFW_RENDERER_ERROR_POLICY_CONTINUE);
1345 /* In standalone mode, then switch back to playlist
1346 mode and resume if necessary or move to Stopped
1348 mafw_gst_renderer_set_playback_mode(
1349 self, MAFW_GST_RENDERER_MODE_PLAYLIST);
1350 mafw_gst_renderer_set_media_playlist(self);
1351 if (self->resume_playlist) {
1352 mafw_gst_renderer_play(MAFW_RENDERER(self),
1355 mafw_gst_renderer_worker_stop(self->worker);
1356 mafw_gst_renderer_set_state(self, Stopped);
1358 if (out_err) *out_err = g_error_copy(in_err);
1360 /* Bail out, he have already managed the error
1361 for the case of standalone mode */
1367 if (self->playlist){
1368 MafwPlaylistIteratorMovementResult result;
1370 result = mafw_playlist_iterator_move_to_next(self->iterator,
1372 self->play_failed_count++;
1374 if (mafw_playlist_iterator_get_size(self->iterator,
1376 self->play_failed_count)
1378 mafw_gst_renderer_state_stop(
1379 MAFW_GST_RENDERER_STATE(self->states[self->current_state]),
1381 self->play_failed_count = 0;
1382 mafw_gst_renderer_set_media_playlist(self);
1383 } else if (result !=
1384 MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_OK) {
1385 mafw_playlist_iterator_reset(self->iterator, NULL);
1386 mafw_gst_renderer_set_media_playlist(self);
1387 mafw_gst_renderer_stop(MAFW_RENDERER(self), NULL, NULL);
1389 mafw_gst_renderer_set_media_playlist(self);
1390 mafw_gst_renderer_play(MAFW_RENDERER(self), NULL, NULL);
1393 if (out_err) *out_err = g_error_copy(in_err);
1396 /* We cannot move to next in the playlist or decided
1397 we do not want to do it, just stop on error */
1398 mafw_gst_renderer_stop(MAFW_RENDERER(self), NULL, NULL);
1399 if (out_err) *out_err = g_error_copy(in_err);
1403 static void _metadata_set_cb(MafwSource *self, const gchar *object_id,
1404 const gchar **failed_keys, gpointer user_data,
1405 const GError *error)
1407 if (error != NULL) {
1408 g_debug("Ignoring error received when setting metadata: "
1409 "%s (%d): %s", g_quark_to_string(error->domain),
1410 error->code, error->message);
1412 g_debug("Metadata set correctly");
1417 * _update_playcount_metadata_cb:
1418 * @cb_source: The #MafwSource that sent the metadata results
1419 * @cb_object_id: The object ID, whose metadata results were received
1420 * @cb_metadata: GHashTable containing metadata key-value pairs
1421 * @cb_user_data: Optional user data pointer (self)
1422 * @cb_error: Set if any errors occurred during metadata browsing
1424 * Receives the results of a metadata request about the playcount. It increases
1425 * it, or sets to 1, and sets the metadata to that.
1427 static void _update_playcount_metadata_cb (MafwSource *cb_source,
1428 const gchar *cb_object_id,
1429 GHashTable *cb_metadata,
1430 gpointer cb_user_data,
1431 const GError *cb_error)
1433 GValue *curval = NULL;
1434 gint curplaycount = -1;
1435 GHashTable *mdata = cb_user_data;
1437 if (cb_error == NULL) {
1439 curval = mafw_metadata_first(cb_metadata,
1440 MAFW_METADATA_KEY_PLAY_COUNT);
1441 if (curval && !G_VALUE_HOLDS(curval, G_TYPE_INT))
1445 curplaycount = g_value_get_int(curval);
1449 { /* Playing at first time, or not supported... */
1453 mdata = mafw_metadata_new();
1454 mafw_metadata_add_int(mdata,
1455 MAFW_METADATA_KEY_PLAY_COUNT,
1459 g_warning("_playcount_metadata received an error: "
1460 "%s (%d): %s", g_quark_to_string(cb_error->domain),
1461 cb_error->code, cb_error->message);
1463 g_hash_table_unref(mdata);
1470 mafw_source_set_metadata(cb_source, cb_object_id, mdata,
1471 _metadata_set_cb, NULL);
1472 g_hash_table_unref(mdata);
1477 * mafw_gst_renderer_add_lastplayed:
1478 * @mdata: Exisiting mdata, or NULL
1480 * Sets the MAFW_METADATA_KEY_LAST_PLAYED metadata in the given metadata-table,
1481 * or creates a new metadata-table, and sets the current time there.
1483 static GHashTable *mafw_gst_renderer_add_lastplayed(GHashTable *mdata)
1485 GHashTable *metadata;
1490 metadata = mafw_metadata_new();
1496 g_get_current_time(&timeval);
1498 mafw_metadata_add_long(metadata,
1499 MAFW_METADATA_KEY_LAST_PLAYED,
1505 * mafw_gst_renderer_increase_playcount:
1506 * @self: Gst renderer
1507 * @object_id: The object ID of the touched object
1508 * @mdat: Existing metadatas to add the playcount to, or NULL
1510 * Increases the playcount of the given object.
1512 static void mafw_gst_renderer_increase_playcount(MafwGstRenderer* self,
1513 const gchar *object_id, GHashTable *mdat)
1517 g_assert(self != NULL);
1518 source = _get_source(self, object_id);
1521 static const gchar * const keys[] =
1522 { MAFW_METADATA_KEY_PLAY_COUNT, NULL };
1524 mafw_source_get_metadata(source, object_id,
1526 _update_playcount_metadata_cb,
1533 * mafw_gst_renderer_update_stats:
1536 * Updates both playcount and lastplayed after a while.
1538 gboolean mafw_gst_renderer_update_stats(gpointer data)
1540 MafwGstRenderer *renderer = (MafwGstRenderer *) data;
1542 /* Update stats only for audio content */
1543 if (renderer->media->object_id &&
1544 !renderer->worker->media.has_visual_content) {
1545 GHashTable *mdata = mafw_gst_renderer_add_lastplayed(NULL);
1546 mafw_gst_renderer_increase_playcount(renderer,
1547 renderer->media->object_id,
1550 renderer->update_playcount_id = 0;
1554 void mafw_gst_renderer_update_source_duration(MafwGstRenderer *renderer,
1557 GHashTable *metadata;
1560 source = _get_source(renderer, renderer->media->object_id);
1561 g_return_if_fail(source != NULL);
1563 renderer->media->duration = duration;
1565 g_debug("updated source duration to %d", duration);
1567 metadata = mafw_metadata_new();
1568 mafw_metadata_add_int(metadata, MAFW_METADATA_KEY_DURATION, duration);
1570 mafw_source_set_metadata(source, renderer->media->object_id, metadata,
1571 _metadata_set_cb, NULL);
1572 g_hash_table_unref(metadata);
1577 * @source: The #MafwSource that sent the metadata results
1578 * @objectid: The object ID, whose metadata results were received
1579 * @metadata: GHashTable containing metadata key-value pairs
1580 * @userdata: Optional user data pointer (self)
1581 * @error: Set if any errors occurred during metadata browsing
1583 * Receives the results of a metadata request.
1585 static void _notify_metadata (MafwSource *cb_source,
1586 const gchar *cb_object_id,
1587 GHashTable *cb_metadata,
1588 gpointer cb_user_data,
1589 const GError *cb_error)
1591 MafwGstRenderer *renderer = (MafwGstRenderer*) cb_user_data;
1592 GError *mafw_error = NULL;
1593 GError *error = NULL;
1596 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1598 g_return_if_fail((renderer->states != 0) &&
1599 (renderer->current_state != _LastMafwPlayState) &&
1600 (renderer->states[renderer->current_state] != NULL));
1602 g_debug("running _notify_metadata...");
1604 mval = mafw_metadata_first(cb_metadata, MAFW_METADATA_KEY_URI);
1606 if (cb_error == NULL && mval != NULL) {
1607 mafw_gst_renderer_state_notify_metadata(
1608 MAFW_GST_RENDERER_STATE(
1609 renderer->states[renderer->current_state]),
1615 g_set_error(&mafw_error,
1616 MAFW_RENDERER_ERROR,
1617 MAFW_RENDERER_ERROR_URI_NOT_AVAILABLE, "%s",
1618 cb_error ? cb_error->message : "URI not available");
1619 mafw_gst_renderer_manage_error(renderer, mafw_error);
1620 g_error_free(mafw_error);
1624 static void _notify_play(MafwGstRendererWorker *worker, gpointer owner)
1626 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1627 GError *error = NULL;
1629 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1631 g_return_if_fail((renderer->states != 0) &&
1632 (renderer->current_state != _LastMafwPlayState) &&
1633 (renderer->states[renderer->current_state] != NULL));
1635 g_debug("running _notify_play...");
1637 mafw_gst_renderer_state_notify_play(renderer->states[renderer->current_state],
1640 if (error != NULL) {
1641 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1645 g_error_free (error);
1649 static void _notify_pause(MafwGstRendererWorker *worker, gpointer owner)
1651 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1652 GError *error = NULL;
1654 g_return_if_fail(MAFW_IS_GST_RENDERER (renderer));
1656 g_return_if_fail((renderer->states != 0) &&
1657 (renderer->current_state != _LastMafwPlayState) &&
1658 (renderer->states[renderer->current_state] != NULL));
1660 mafw_gst_renderer_state_notify_pause(renderer->states[renderer->current_state],
1663 if (error != NULL) {
1664 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1665 error->domain, error->code,
1667 g_error_free(error);
1671 static void _notify_buffer_status (MafwGstRendererWorker *worker,
1675 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1676 GError *error = NULL;
1678 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1680 g_return_if_fail((renderer->states != 0) &&
1681 (renderer->current_state != _LastMafwPlayState) &&
1682 (renderer->states[renderer->current_state] != NULL));
1684 mafw_gst_renderer_state_notify_buffer_status(
1685 renderer->states[renderer->current_state],
1689 if (error != NULL) {
1690 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1691 error->domain, error->code,
1693 g_error_free(error);
1697 static void _notify_seek(MafwGstRendererWorker *worker, gpointer owner)
1699 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1700 GError *error = NULL;
1702 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1704 g_return_if_fail((renderer->states != 0) &&
1705 (renderer->current_state != _LastMafwPlayState) &&
1706 (renderer->states[renderer->current_state] != NULL));
1708 mafw_gst_renderer_state_notify_seek(renderer->states[renderer->current_state],
1711 if (error != NULL) {
1712 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1713 error->domain, error->code,
1715 g_error_free(error);
1719 static void _playlist_changed_handler(MafwPlaylistIterator *iterator,
1720 gboolean clip_changed, GQuark domain,
1721 gint code, const gchar *message,
1724 MafwGstRenderer *renderer = (MafwGstRenderer*) user_data;
1726 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1728 g_return_if_fail((renderer->states != 0) &&
1729 (renderer->current_state != _LastMafwPlayState) &&
1730 (renderer->states[renderer->current_state] != NULL));
1732 /* We update the current index and media here, for this is
1733 the same for all the states. Then we delegate in the state
1734 to finish the task (for example, start playback if needed) */
1736 if (renderer->playlist == NULL) {
1737 g_critical("Got iterator:contents-changed but renderer has no" \
1738 "playlist assigned!. Skipping...");
1743 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1744 domain, code, message);
1746 GError *error = NULL;
1747 MafwGstRendererPlaybackMode mode;
1749 mode = mafw_gst_renderer_get_playback_mode(renderer);
1751 /* Only in non-playobject mode */
1752 if (clip_changed && mode == MAFW_GST_RENDERER_MODE_PLAYLIST)
1753 mafw_gst_renderer_set_media_playlist(renderer);
1755 /* We let the state know if the current clip has changed as
1756 result of this operation, so it can do its work */
1757 mafw_gst_renderer_state_playlist_contents_changed_handler(
1758 renderer->states[renderer->current_state],
1762 if (error != NULL) {
1763 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1764 error->domain, error->code,
1766 g_error_free(error);
1771 static void _error_handler(MafwGstRendererWorker *worker, gpointer owner,
1772 const GError *error)
1774 MafwGstRenderer *renderer = MAFW_GST_RENDERER(owner);
1776 mafw_gst_renderer_manage_error(renderer, error);
1779 void mafw_gst_renderer_manage_error(MafwGstRenderer *self, const GError *error)
1781 GError *new_err = NULL;
1782 GError *raise_error = NULL;
1783 GQuark new_err_domain = MAFW_RENDERER_ERROR;
1784 gint new_err_code = 0;
1786 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1788 g_return_if_fail((self->states != 0) &&
1789 (self->current_state != _LastMafwPlayState) &&
1790 (self->states[self->current_state] != NULL));
1792 g_warning("Got error in renderer:\n\tdomain: %d, code: %d, message: %s",
1793 error->domain, error->code, error->message);
1795 /* Get a MAFW error */
1796 if (error->domain == GST_RESOURCE_ERROR) {
1797 /* handle RESOURCE errors */
1798 switch (error->code) {
1799 case GST_RESOURCE_ERROR_READ:
1800 if (is_current_uri_stream(self)) {
1802 if (self->connected) {
1803 new_err_code = MAFW_RENDERER_ERROR_STREAM_DISCONNECTED;
1805 new_err_domain = MAFW_EXTENSION_ERROR;
1806 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1809 /* Stream + cannot read resource ->
1811 new_err_code = MAFW_RENDERER_ERROR_STREAM_DISCONNECTED;
1814 /* This shouldn't happen */
1815 /* Unknown RESOURCE error */
1816 new_err_domain = MAFW_EXTENSION_ERROR;
1817 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1820 case GST_RESOURCE_ERROR_NOT_FOUND:
1822 if (!is_current_uri_stream(self) || self->connected) {
1824 MAFW_RENDERER_ERROR_INVALID_URI;
1826 new_err_domain = MAFW_EXTENSION_ERROR;
1827 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1831 MAFW_RENDERER_ERROR_INVALID_URI;
1834 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
1835 case GST_RESOURCE_ERROR_OPEN_READ:
1837 if (!is_current_uri_stream(self) || self->connected) {
1839 MAFW_RENDERER_ERROR_MEDIA_NOT_FOUND;
1841 new_err_domain = MAFW_EXTENSION_ERROR;
1842 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1846 MAFW_RENDERER_ERROR_MEDIA_NOT_FOUND;
1849 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
1850 new_err_domain = MAFW_EXTENSION_ERROR;
1851 new_err_code = MAFW_EXTENSION_ERROR_OUT_OF_MEMORY;
1853 case GST_RESOURCE_ERROR_WRITE:
1854 /* DSP renderers send ERROR_WRITE when they find
1856 new_err_code = MAFW_RENDERER_ERROR_CORRUPTED_FILE;
1858 case GST_RESOURCE_ERROR_SEEK:
1859 new_err_code = MAFW_RENDERER_ERROR_CANNOT_SET_POSITION;
1862 /* Unknown RESOURCE error */
1863 new_err_domain = MAFW_EXTENSION_ERROR;
1864 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1867 } else if (error->domain == GST_STREAM_ERROR) {
1868 /* handle STREAM errors */
1869 switch (error->code) {
1870 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
1871 new_err_code = MAFW_RENDERER_ERROR_TYPE_NOT_AVAILABLE;
1873 case GST_STREAM_ERROR_FORMAT:
1874 case GST_STREAM_ERROR_WRONG_TYPE:
1875 case GST_STREAM_ERROR_FAILED:
1876 new_err_code = MAFW_RENDERER_ERROR_UNSUPPORTED_TYPE;
1878 case GST_STREAM_ERROR_DECODE:
1879 case GST_STREAM_ERROR_DEMUX:
1880 new_err_code = MAFW_RENDERER_ERROR_CORRUPTED_FILE;
1882 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
1883 new_err_code = MAFW_RENDERER_ERROR_CODEC_NOT_FOUND;
1885 case GST_STREAM_ERROR_DECRYPT:
1886 case GST_STREAM_ERROR_DECRYPT_NOKEY:
1887 new_err_code = MAFW_RENDERER_ERROR_DRM;
1890 /* Unknown STREAM error */
1891 new_err_domain = MAFW_EXTENSION_ERROR;
1892 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1894 } else if (error->domain == MAFW_GST_RENDERER_ERROR) {
1895 /* Handle own errors. Errors that belong to this domain:
1896 - MAFW_GST_RENDERER_ERROR_PLUGIN_NOT_FOUND,
1897 - MAFW_GST_RENDERER_ERROR_VIDEO_CODEC_NOT_SUPPORTED,
1898 - MAFW_GST_RENDERER_ERROR_AUDIO_CODEC_NOT_SUPPORTED */
1899 new_err_code = MAFW_RENDERER_ERROR_UNSUPPORTED_TYPE;
1900 } else if (error->domain == MAFW_RENDERER_ERROR) {
1901 /* Worker may have sent MAFW_RENDERER_ERROR as well.
1902 No processing needed */
1903 new_err_code = error->code;
1907 new_err_domain = MAFW_EXTENSION_ERROR;
1908 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1911 g_set_error(&new_err, new_err_domain, new_err_code, "%s", error->message);
1913 _run_error_policy(self, new_err, &raise_error);
1914 g_error_free(new_err);
1917 g_signal_emit_by_name(MAFW_EXTENSION (self), "error",
1918 raise_error->domain,
1920 raise_error->message);
1921 g_error_free(raise_error);
1925 static void _notify_eos(MafwGstRendererWorker *worker, gpointer owner)
1927 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1928 GError *error = NULL;
1930 g_return_if_fail(MAFW_IS_GST_RENDERER (renderer));
1932 g_return_if_fail((renderer->states != 0) &&
1933 (renderer->current_state != _LastMafwPlayState) &&
1934 (renderer->states[renderer->current_state] != NULL));
1936 mafw_gst_renderer_state_notify_eos(renderer->states[renderer->current_state],
1939 if (error != NULL) {
1940 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1941 error->domain, error->code,
1943 g_error_free(error);
1947 /*----------------------------------------------------------------------------
1949 ----------------------------------------------------------------------------*/
1951 void mafw_gst_renderer_get_status(MafwRenderer *self, MafwRendererStatusCB callback,
1954 MafwGstRenderer* renderer;
1956 MafwGstRendererPlaybackMode mode;
1958 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1959 g_return_if_fail(callback != NULL);
1960 renderer = MAFW_GST_RENDERER(self);
1962 mode = mafw_gst_renderer_get_playback_mode(MAFW_GST_RENDERER(self));
1963 if ((mode == MAFW_GST_RENDERER_MODE_STANDALONE) || (renderer->iterator == NULL)) {
1967 mafw_playlist_iterator_get_current_index(renderer->iterator);
1970 /* TODO: Set error parameter */
1971 callback(self, renderer->playlist, index, renderer->current_state,
1972 (const gchar*) renderer->media->object_id, user_data, NULL);
1975 void mafw_gst_renderer_get_current_metadata(MafwRenderer *self,
1976 MafwRendererMetadataResultCB callback,
1979 MafwGstRenderer *renderer;
1980 GHashTable *metadata;
1982 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1983 renderer = MAFW_GST_RENDERER(self);
1985 metadata = mafw_gst_renderer_worker_get_current_metadata(
1989 (const gchar*) renderer->media->object_id,
1995 /*----------------------------------------------------------------------------
1997 ----------------------------------------------------------------------------*/
2000 _playlist_contents_changed_handler(MafwPlaylist *playlist,
2001 guint from, guint nremove,
2003 MafwGstRenderer *renderer)
2005 /* Item(s) added to playlist, so new playable items could come */
2007 renderer->play_failed_count = 0;
2010 gboolean mafw_gst_renderer_assign_playlist(MafwRenderer *self,
2011 MafwPlaylist *playlist,
2014 MafwGstRenderer* renderer = (MafwGstRenderer*) self;
2016 g_return_val_if_fail(MAFW_IS_GST_RENDERER(self), FALSE);
2018 /* Get rid of previously assigned playlist */
2019 if (renderer->playlist != NULL) {
2020 g_signal_handlers_disconnect_matched(renderer->iterator,
2021 (GSignalMatchType) G_SIGNAL_MATCH_FUNC,
2023 _playlist_changed_handler,
2025 g_signal_handlers_disconnect_matched(renderer->playlist,
2026 (GSignalMatchType) G_SIGNAL_MATCH_FUNC,
2028 G_CALLBACK(_playlist_contents_changed_handler),
2030 /* Decrement the use count of the previous playlist because the
2031 renderer isn't going to use it more */
2032 mafw_playlist_decrement_use_count(renderer->playlist, NULL);
2034 g_object_unref(renderer->iterator);
2035 g_object_unref(renderer->playlist);
2038 /* Assign the new playlist */
2039 if (playlist == NULL) {
2040 renderer->playlist = NULL;
2041 renderer->iterator = NULL;
2043 GError *new_error = NULL;
2044 MafwPlaylistIterator *iterator = NULL;
2046 iterator = mafw_playlist_iterator_new();
2047 mafw_playlist_iterator_initialize(iterator, playlist,
2050 g_object_ref(playlist);
2052 if (new_error == NULL) {
2054 renderer->playlist = playlist;
2055 renderer->iterator = iterator;
2057 /* Increment the use_count to avoid the playlist destruction
2058 while the playlist is assigned to some renderer */
2059 mafw_playlist_increment_use_count(renderer->playlist, NULL);
2061 g_signal_connect(iterator,
2063 G_CALLBACK(_playlist_changed_handler),
2065 g_signal_connect(renderer->playlist,
2067 G_CALLBACK(_playlist_contents_changed_handler),
2071 g_propagate_error (error, new_error);
2075 /* Set the new media and signal playlist changed signal */
2076 _signal_playlist_changed(renderer);
2077 mafw_gst_renderer_set_media_playlist(renderer);
2081 mafw_gst_renderer_stop(MAFW_RENDERER(renderer), NULL , NULL);
2086 MafwGstRendererMovementResult mafw_gst_renderer_move(MafwGstRenderer *renderer,
2087 MafwGstRendererMovementType type,
2091 MafwGstRendererMovementResult value = MAFW_GST_RENDERER_MOVE_RESULT_OK;
2093 if (renderer->playlist == NULL) {
2094 value = MAFW_GST_RENDERER_MOVE_RESULT_NO_PLAYLIST;
2096 MafwPlaylistIteratorMovementResult result;
2099 case MAFW_GST_RENDERER_MOVE_TYPE_INDEX:
2101 mafw_playlist_iterator_move_to_index(renderer->iterator,
2105 case MAFW_GST_RENDERER_MOVE_TYPE_PREV:
2107 mafw_playlist_iterator_move_to_prev(renderer->iterator,
2110 case MAFW_GST_RENDERER_MOVE_TYPE_NEXT:
2112 mafw_playlist_iterator_move_to_next(renderer->iterator,
2118 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_OK:
2119 value = MAFW_GST_RENDERER_MOVE_RESULT_OK;
2120 mafw_gst_renderer_set_media_playlist(renderer);
2122 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_INVALID:
2123 g_critical("Iterator is invalid!");
2124 value = MAFW_GST_RENDERER_MOVE_RESULT_ERROR;
2126 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_ERROR:
2127 value = MAFW_GST_RENDERER_MOVE_RESULT_ERROR;
2129 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_LIMIT:
2130 value = MAFW_GST_RENDERER_MOVE_RESULT_PLAYLIST_LIMIT;
2138 /*----------------------------------------------------------------------------
2140 ----------------------------------------------------------------------------*/
2142 static void _set_error_policy(MafwGstRenderer *renderer, MafwRendererErrorPolicy policy)
2144 renderer->error_policy = policy;
2147 static MafwRendererErrorPolicy _get_error_policy(MafwGstRenderer *renderer)
2149 return renderer->error_policy;
2152 static void mafw_gst_renderer_get_property(MafwExtension *self,
2154 MafwExtensionPropertyCallback callback,
2157 MafwGstRenderer *renderer;
2158 GValue *value = NULL;
2159 GError *error = NULL;
2161 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
2162 g_return_if_fail(callback != NULL);
2163 g_return_if_fail(key != NULL);
2165 renderer = MAFW_GST_RENDERER(self);
2166 if (!strcmp(key, MAFW_PROPERTY_RENDERER_VOLUME)) {
2169 volume = mafw_gst_renderer_worker_get_volume(
2172 value = g_new0(GValue, 1);
2173 g_value_init(value, G_TYPE_UINT);
2174 g_value_set_uint(value, volume);
2176 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_MUTE)) {
2178 mute = mafw_gst_renderer_worker_get_mute(renderer->worker);
2179 value = g_new0(GValue, 1);
2180 g_value_init(value, G_TYPE_BOOLEAN);
2181 g_value_set_boolean(value, mute);
2183 else if (!strcmp (key, MAFW_PROPERTY_RENDERER_XID)) {
2185 xid = mafw_gst_renderer_worker_get_xid(renderer->worker);
2186 value = g_new0(GValue, 1);
2187 g_value_init(value, G_TYPE_UINT);
2188 g_value_set_uint(value, xid);
2190 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_ERROR_POLICY)) {
2192 policy = _get_error_policy(renderer);
2193 value = g_new0(GValue, 1);
2194 g_value_init(value, G_TYPE_UINT);
2195 g_value_set_uint(value, policy);
2197 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_AUTOPAINT)) {
2198 value = g_new0(GValue, 1);
2199 g_value_init(value, G_TYPE_BOOLEAN);
2200 g_value_set_boolean(
2202 mafw_gst_renderer_worker_get_autopaint(
2204 } else if (!strcmp(key, MAFW_PROPERTY_RENDERER_COLORKEY)) {
2205 value = g_new0(GValue, 1);
2206 g_value_init(value, G_TYPE_INT);
2209 mafw_gst_renderer_worker_get_colorkey(
2212 #ifdef HAVE_GDKPIXBUF
2213 else if (!strcmp(key,
2214 MAFW_PROPERTY_GST_RENDERER_CURRENT_FRAME_ON_PAUSE)) {
2215 gboolean current_frame_on_pause;
2216 current_frame_on_pause =
2217 mafw_gst_renderer_worker_get_current_frame_on_pause(renderer->worker);
2218 value = g_new0(GValue, 1);
2219 g_value_init(value, G_TYPE_BOOLEAN);
2220 g_value_set_boolean(value, current_frame_on_pause);
2223 else if (!strcmp(key,
2224 MAFW_PROPERTY_GST_RENDERER_TV_CONNECTED)) {
2225 value = g_new0(GValue, 1);
2226 g_value_init(value, G_TYPE_BOOLEAN);
2227 g_value_set_boolean(value, renderer->tv_connected);
2229 else if (!strcmp(key,
2230 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS)){
2231 /* Delegate in the state. */
2232 value = mafw_gst_renderer_state_get_property_value(
2233 MAFW_GST_RENDERER_STATE(
2234 renderer->states[renderer->current_state]),
2235 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS);
2238 /* Something goes wrong. */
2239 error = g_error_new(
2240 MAFW_GST_RENDERER_ERROR,
2241 MAFW_EXTENSION_ERROR_GET_PROPERTY,
2242 "Error while getting the property value");
2246 /* Unsupported property */
2247 error = g_error_new(MAFW_GST_RENDERER_ERROR,
2248 MAFW_EXTENSION_ERROR_GET_PROPERTY,
2249 "Unsupported property");
2252 callback(self, key, value, user_data, error);
2255 static void mafw_gst_renderer_set_property(MafwExtension *self,
2257 const GValue *value)
2259 MafwGstRenderer *renderer;
2261 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
2262 g_return_if_fail(key != NULL);
2264 renderer = MAFW_GST_RENDERER(self);
2266 if (!strcmp(key, MAFW_PROPERTY_RENDERER_VOLUME)) {
2267 guint volume = g_value_get_uint(value);
2270 mafw_gst_renderer_worker_set_volume(renderer->worker,
2272 /* Property-changed emision is done by worker */
2275 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_MUTE)) {
2276 gboolean mute = g_value_get_boolean(value);
2277 mafw_gst_renderer_worker_set_mute(renderer->worker, mute);
2279 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_XID)) {
2280 XID xid = g_value_get_uint(value);
2281 mafw_gst_renderer_worker_set_xid(renderer->worker, xid);
2283 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_ERROR_POLICY)) {
2284 MafwRendererErrorPolicy policy = g_value_get_uint(value);
2285 _set_error_policy(renderer, policy);
2287 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_AUTOPAINT)) {
2288 mafw_gst_renderer_worker_set_autopaint(
2290 g_value_get_boolean(value));
2292 #ifdef HAVE_GDKPIXBUF
2293 else if (!strcmp(key,
2294 MAFW_PROPERTY_GST_RENDERER_CURRENT_FRAME_ON_PAUSE)) {
2295 gboolean current_frame_on_pause = g_value_get_boolean(value);
2296 mafw_gst_renderer_worker_set_current_frame_on_pause(renderer->worker,
2297 current_frame_on_pause);
2302 /* FIXME I'm not sure when to emit property-changed signals.
2303 * Maybe we should let the worker do it, when the change
2304 * reached the hardware... */
2305 mafw_extension_emit_property_changed(self, key, value);
2308 /* vi: set noexpandtab ts=8 sw=8 cino=t0,(0: */