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", "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_SUBTITLES_RENDERER,
363 GCONF_CLIENT_PRELOAD_ONELEVEL,
366 g_warning("%s", error->message);
371 gconf_client_notify_add(renderer->gconf_client,
372 GCONF_MAFW_GST_SUBTITLES_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_SUBTITLES_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_SUBTITLES_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_SUBTITLES_RENDERER "/autoload_subtitles");
405 gconf_client_notify(renderer->gconf_client,
406 GCONF_MAFW_GST_SUBTITLES_RENDERER "/subtitle_encoding");
408 gconf_client_notify(renderer->gconf_client,
409 GCONF_MAFW_GST_SUBTITLES_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_SUBTITLES_RENDERER) + 1;
929 value = gconf_entry_get_value(entry);
931 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);
940 renderer->worker->subtitles.font = g_strdup(str_value);
942 renderer->worker->subtitles.font = NULL;
943 } else if (strcmp(key, "subtitle_encoding") == 0) {
944 if (renderer->worker->subtitles.encoding)
945 g_free(renderer->worker->subtitles.encoding);
948 renderer->worker->subtitles.encoding = g_strdup(str_value);
950 renderer->worker->subtitles.encoding = NULL;
952 g_warning("Wrong %s key, %s", GCONF_MAFW_GST_SUBTITLES_RENDERER, key);
956 /*----------------------------------------------------------------------------
957 Gnome VFS notifications
958 ----------------------------------------------------------------------------*/
960 static void _volume_pre_unmount_cb(GnomeVFSVolumeMonitor *monitor,
961 GnomeVFSVolume *volume,
962 MafwGstRenderer *renderer)
964 gchar *location = gnome_vfs_volume_get_activation_uri(volume);
969 mafw_gst_renderer_state_handle_pre_unmount(
970 MAFW_GST_RENDERER_STATE(
971 renderer->states[renderer->current_state]),
977 /*----------------------------------------------------------------------------
979 ----------------------------------------------------------------------------*/
983 * _signal_state_changed:
984 * @self: A #MafwGstRenderer
986 * Signals state_changed to all UIs
988 static void _signal_state_changed(MafwGstRenderer * self)
990 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
992 g_signal_emit_by_name(MAFW_RENDERER(self),
993 "state-changed", self->current_state);
997 * _signal_playlist_changed:
998 * @self: A #MafwGstRenderer
1000 * Signals playlist update to all UIs
1002 static void _signal_playlist_changed(MafwGstRenderer * self)
1004 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1006 g_signal_emit_by_name(MAFW_RENDERER(self),
1007 "playlist-changed", self->playlist);
1011 * _signal_media_changed:
1012 * @self: A #MafwGstRenderer
1014 * Signals media_changed to all UIs
1016 static void _signal_media_changed(MafwGstRenderer *self)
1019 MafwGstRendererPlaybackMode mode;
1022 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1024 mode = mafw_gst_renderer_get_playback_mode(MAFW_GST_RENDERER(self));
1025 if ((mode == MAFW_GST_RENDERER_MODE_STANDALONE) ||
1026 (self->iterator == NULL)) {
1029 index = mafw_playlist_iterator_get_current_index(self->iterator);
1032 g_signal_emit_by_name(MAFW_RENDERER(self),
1035 self->media->object_id);
1039 * _signal_transport_actions_property_changed:
1040 * @self: A #MafwGstRenderer
1042 * Signals transport_actions property_changed to all UIs
1044 static void _signal_transport_actions_property_changed(MafwGstRenderer * self)
1048 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1050 value = mafw_gst_renderer_state_get_property_value(
1051 MAFW_GST_RENDERER_STATE(
1052 self->states[self->current_state]),
1053 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS);
1056 mafw_extension_emit_property_changed(
1057 MAFW_EXTENSION(self),
1058 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS,
1060 g_value_unset(value);
1066 /*----------------------------------------------------------------------------
1067 State pattern support
1068 ----------------------------------------------------------------------------*/
1070 void mafw_gst_renderer_set_state(MafwGstRenderer *self, MafwPlayState state)
1072 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1074 self->current_state = state;
1075 _signal_state_changed(self);
1076 _signal_transport_actions_property_changed(self);
1079 void mafw_gst_renderer_play(MafwRenderer *self, MafwRendererPlaybackCB callback,
1082 MafwGstRenderer *renderer = (MafwGstRenderer*) self;
1083 GError *error = NULL;
1085 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1087 g_return_if_fail((renderer->states != 0) &&
1088 (renderer->current_state != _LastMafwPlayState) &&
1089 (renderer->states[renderer->current_state] != NULL));
1091 mafw_gst_renderer_state_play(
1092 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1095 if (callback != NULL)
1096 callback(self, user_data, error);
1098 g_error_free(error);
1101 void mafw_gst_renderer_play_object(MafwRenderer *self,
1102 const gchar *object_id,
1103 MafwRendererPlaybackCB callback,
1106 MafwGstRenderer *renderer = (MafwGstRenderer*) self;
1107 GError *error = NULL;
1109 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1110 g_return_if_fail(object_id != NULL);
1112 g_return_if_fail((renderer->states != 0) &&
1113 (renderer->current_state != _LastMafwPlayState) &&
1114 (renderer->states[renderer->current_state] != NULL));
1116 mafw_gst_renderer_state_play_object(
1117 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1121 if (callback != NULL)
1122 callback(self, user_data, error);
1124 g_error_free(error);
1127 void mafw_gst_renderer_stop(MafwRenderer *self, MafwRendererPlaybackCB callback,
1130 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1131 GError *error = NULL;
1133 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1135 g_return_if_fail((renderer->states != 0) &&
1136 (renderer->current_state != _LastMafwPlayState) &&
1137 (renderer->states[renderer->current_state] != NULL));
1139 renderer->play_failed_count = 0;
1140 mafw_gst_renderer_state_stop(
1141 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1144 if (callback != NULL)
1145 callback(self, user_data, error);
1147 g_error_free(error);
1151 void mafw_gst_renderer_pause(MafwRenderer *self, MafwRendererPlaybackCB callback,
1154 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1155 GError *error = NULL;
1157 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1159 g_return_if_fail((renderer->states != 0) &&
1160 (renderer->current_state != _LastMafwPlayState) &&
1161 (renderer->states[renderer->current_state] != NULL));
1163 mafw_gst_renderer_state_pause(
1164 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1167 if (callback != NULL)
1168 callback(self, user_data, error);
1170 g_error_free(error);
1173 void mafw_gst_renderer_resume(MafwRenderer *self, MafwRendererPlaybackCB callback,
1176 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1177 GError *error = NULL;
1179 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1181 g_return_if_fail((renderer->states != 0) &&
1182 (renderer->current_state != _LastMafwPlayState) &&
1183 (renderer->states[renderer->current_state] != NULL));
1185 mafw_gst_renderer_state_resume(
1186 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1189 if (callback != NULL)
1190 callback(self, user_data, error);
1192 g_error_free(error);
1195 void mafw_gst_renderer_next(MafwRenderer *self, MafwRendererPlaybackCB callback,
1198 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1199 GError *error = NULL;
1201 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1203 g_return_if_fail((renderer->states != 0) &&
1204 (renderer->current_state != _LastMafwPlayState) &&
1205 (renderer->states[renderer->current_state] != NULL));
1207 renderer->play_failed_count = 0;
1208 mafw_gst_renderer_state_next(
1209 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1212 if (callback != NULL)
1213 callback(self, user_data, error);
1215 g_error_free(error);
1218 void mafw_gst_renderer_previous(MafwRenderer *self, MafwRendererPlaybackCB callback,
1221 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1222 GError *error = NULL;
1224 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1226 g_return_if_fail((renderer->states != 0) &&
1227 (renderer->current_state != _LastMafwPlayState) &&
1228 (renderer->states[renderer->current_state] != NULL));
1230 renderer->play_failed_count = 0;
1231 mafw_gst_renderer_state_previous(
1232 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1235 if (callback != NULL)
1236 callback(self, user_data, error);
1238 g_error_free(error);
1241 void mafw_gst_renderer_goto_index(MafwRenderer *self, guint index,
1242 MafwRendererPlaybackCB callback,
1245 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1246 GError *error = NULL;
1248 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1250 g_return_if_fail((renderer->states != 0) &&
1251 (renderer->current_state != _LastMafwPlayState) &&
1252 (renderer->states[renderer->current_state] != NULL));
1254 renderer->play_failed_count = 0;
1255 mafw_gst_renderer_state_goto_index(
1256 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1260 if (callback != NULL)
1261 callback(self, user_data, error);
1263 g_error_free(error);
1266 void mafw_gst_renderer_get_position(MafwRenderer *self, MafwRendererPositionCB callback,
1269 MafwGstRenderer *renderer;
1271 GError *error = NULL;
1273 g_return_if_fail(callback != NULL);
1274 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1276 renderer = MAFW_GST_RENDERER(self);
1278 g_return_if_fail((renderer->states != 0) &&
1279 (renderer->current_state != _LastMafwPlayState) &&
1280 (renderer->states[renderer->current_state] != NULL));
1282 mafw_gst_renderer_state_get_position(
1283 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1287 callback(self, pos, user_data, error);
1289 g_error_free(error);
1292 void mafw_gst_renderer_set_position(MafwRenderer *self, MafwRendererSeekMode mode,
1293 gint seconds, MafwRendererPositionCB callback,
1296 MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1297 GError *error = NULL;
1299 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1301 g_return_if_fail((renderer->states != 0) &&
1302 (renderer->current_state != _LastMafwPlayState) &&
1303 (renderer->states[renderer->current_state] != NULL));
1305 mafw_gst_renderer_state_set_position(
1306 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1311 if (callback != NULL)
1312 callback(self, seconds, user_data, error);
1314 g_error_free(error);
1317 gboolean mafw_gst_renderer_manage_error_idle(gpointer data)
1319 MafwGstRendererErrorClosure *mec = (MafwGstRendererErrorClosure *) data;
1321 mafw_gst_renderer_manage_error(mec->renderer, mec->error);
1323 g_error_free(mec->error);
1329 static void _run_error_policy(MafwGstRenderer *self, const GError *in_err,
1332 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1334 gboolean play_next = FALSE;
1336 /* Check what to do on error */
1337 if (in_err->code == MAFW_EXTENSION_ERROR_OUT_OF_MEMORY) {
1340 MafwGstRendererPlaybackMode mode;
1342 mode = mafw_gst_renderer_get_playback_mode(self);
1344 if (mode == MAFW_GST_RENDERER_MODE_PLAYLIST) {
1345 /* In playlist mode we try to play next if
1346 error policy suggests so */
1348 (_get_error_policy(self) ==
1349 MAFW_RENDERER_ERROR_POLICY_CONTINUE);
1351 /* In standalone mode, then switch back to playlist
1352 mode and resume if necessary or move to Stopped
1354 mafw_gst_renderer_set_playback_mode(
1355 self, MAFW_GST_RENDERER_MODE_PLAYLIST);
1356 mafw_gst_renderer_set_media_playlist(self);
1357 if (self->resume_playlist) {
1358 mafw_gst_renderer_play(MAFW_RENDERER(self),
1361 mafw_gst_renderer_worker_stop(self->worker);
1362 mafw_gst_renderer_set_state(self, Stopped);
1364 if (out_err) *out_err = g_error_copy(in_err);
1366 /* Bail out, he have already managed the error
1367 for the case of standalone mode */
1373 if (self->playlist){
1374 MafwPlaylistIteratorMovementResult result;
1376 result = mafw_playlist_iterator_move_to_next(self->iterator,
1378 self->play_failed_count++;
1380 if (mafw_playlist_iterator_get_size(self->iterator,
1382 self->play_failed_count)
1384 mafw_gst_renderer_state_stop(
1385 MAFW_GST_RENDERER_STATE(self->states[self->current_state]),
1387 self->play_failed_count = 0;
1388 mafw_gst_renderer_set_media_playlist(self);
1389 } else if (result !=
1390 MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_OK) {
1391 mafw_playlist_iterator_reset(self->iterator, NULL);
1392 mafw_gst_renderer_set_media_playlist(self);
1393 mafw_gst_renderer_stop(MAFW_RENDERER(self), NULL, NULL);
1395 mafw_gst_renderer_set_media_playlist(self);
1396 mafw_gst_renderer_play(MAFW_RENDERER(self), NULL, NULL);
1399 if (out_err) *out_err = g_error_copy(in_err);
1402 /* We cannot move to next in the playlist or decided
1403 we do not want to do it, just stop on error */
1404 mafw_gst_renderer_stop(MAFW_RENDERER(self), NULL, NULL);
1405 if (out_err) *out_err = g_error_copy(in_err);
1409 static void _metadata_set_cb(MafwSource *self, const gchar *object_id,
1410 const gchar **failed_keys, gpointer user_data,
1411 const GError *error)
1413 if (error != NULL) {
1414 g_debug("Ignoring error received when setting metadata: "
1415 "%s (%d): %s", g_quark_to_string(error->domain),
1416 error->code, error->message);
1418 g_debug("Metadata set correctly");
1423 * _update_playcount_metadata_cb:
1424 * @cb_source: The #MafwSource that sent the metadata results
1425 * @cb_object_id: The object ID, whose metadata results were received
1426 * @cb_metadata: GHashTable containing metadata key-value pairs
1427 * @cb_user_data: Optional user data pointer (self)
1428 * @cb_error: Set if any errors occurred during metadata browsing
1430 * Receives the results of a metadata request about the playcount. It increases
1431 * it, or sets to 1, and sets the metadata to that.
1433 static void _update_playcount_metadata_cb (MafwSource *cb_source,
1434 const gchar *cb_object_id,
1435 GHashTable *cb_metadata,
1436 gpointer cb_user_data,
1437 const GError *cb_error)
1439 GValue *curval = NULL;
1440 gint curplaycount = -1;
1441 GHashTable *mdata = cb_user_data;
1443 if (cb_error == NULL) {
1445 curval = mafw_metadata_first(cb_metadata,
1446 MAFW_METADATA_KEY_PLAY_COUNT);
1447 if (curval && !G_VALUE_HOLDS(curval, G_TYPE_INT))
1451 curplaycount = g_value_get_int(curval);
1455 { /* Playing at first time, or not supported... */
1459 mdata = mafw_metadata_new();
1460 mafw_metadata_add_int(mdata,
1461 MAFW_METADATA_KEY_PLAY_COUNT,
1465 g_warning("_playcount_metadata received an error: "
1466 "%s (%d): %s", g_quark_to_string(cb_error->domain),
1467 cb_error->code, cb_error->message);
1469 g_hash_table_unref(mdata);
1476 mafw_source_set_metadata(cb_source, cb_object_id, mdata,
1477 _metadata_set_cb, NULL);
1478 g_hash_table_unref(mdata);
1483 * mafw_gst_renderer_add_lastplayed:
1484 * @mdata: Exisiting mdata, or NULL
1486 * Sets the MAFW_METADATA_KEY_LAST_PLAYED metadata in the given metadata-table,
1487 * or creates a new metadata-table, and sets the current time there.
1489 static GHashTable *mafw_gst_renderer_add_lastplayed(GHashTable *mdata)
1491 GHashTable *metadata;
1496 metadata = mafw_metadata_new();
1502 g_get_current_time(&timeval);
1504 mafw_metadata_add_long(metadata,
1505 MAFW_METADATA_KEY_LAST_PLAYED,
1511 * mafw_gst_renderer_increase_playcount:
1512 * @self: Gst renderer
1513 * @object_id: The object ID of the touched object
1514 * @mdat: Existing metadatas to add the playcount to, or NULL
1516 * Increases the playcount of the given object.
1518 static void mafw_gst_renderer_increase_playcount(MafwGstRenderer* self,
1519 const gchar *object_id, GHashTable *mdat)
1523 g_assert(self != NULL);
1524 source = _get_source(self, object_id);
1527 static const gchar * const keys[] =
1528 { MAFW_METADATA_KEY_PLAY_COUNT, NULL };
1530 mafw_source_get_metadata(source, object_id,
1532 _update_playcount_metadata_cb,
1539 * mafw_gst_renderer_update_stats:
1542 * Updates both playcount and lastplayed after a while.
1544 gboolean mafw_gst_renderer_update_stats(gpointer data)
1546 MafwGstRenderer *renderer = (MafwGstRenderer *) data;
1548 /* Update stats only for audio content */
1549 if (renderer->media->object_id &&
1550 !renderer->worker->media.has_visual_content) {
1551 GHashTable *mdata = mafw_gst_renderer_add_lastplayed(NULL);
1552 mafw_gst_renderer_increase_playcount(renderer,
1553 renderer->media->object_id,
1556 renderer->update_playcount_id = 0;
1560 void mafw_gst_renderer_update_source_duration(MafwGstRenderer *renderer,
1563 GHashTable *metadata;
1566 source = _get_source(renderer, renderer->media->object_id);
1567 g_return_if_fail(source != NULL);
1569 renderer->media->duration = duration;
1571 g_debug("updated source duration to %d", duration);
1573 metadata = mafw_metadata_new();
1574 mafw_metadata_add_int(metadata, MAFW_METADATA_KEY_DURATION, duration);
1576 mafw_source_set_metadata(source, renderer->media->object_id, metadata,
1577 _metadata_set_cb, NULL);
1578 g_hash_table_unref(metadata);
1583 * @source: The #MafwSource that sent the metadata results
1584 * @objectid: The object ID, whose metadata results were received
1585 * @metadata: GHashTable containing metadata key-value pairs
1586 * @userdata: Optional user data pointer (self)
1587 * @error: Set if any errors occurred during metadata browsing
1589 * Receives the results of a metadata request.
1591 static void _notify_metadata (MafwSource *cb_source,
1592 const gchar *cb_object_id,
1593 GHashTable *cb_metadata,
1594 gpointer cb_user_data,
1595 const GError *cb_error)
1597 MafwGstRenderer *renderer = (MafwGstRenderer*) cb_user_data;
1598 GError *mafw_error = NULL;
1599 GError *error = NULL;
1602 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1604 g_return_if_fail((renderer->states != 0) &&
1605 (renderer->current_state != _LastMafwPlayState) &&
1606 (renderer->states[renderer->current_state] != NULL));
1608 g_debug("running _notify_metadata...");
1610 mval = mafw_metadata_first(cb_metadata, MAFW_METADATA_KEY_URI);
1612 if (cb_error == NULL && mval != NULL) {
1613 mafw_gst_renderer_state_notify_metadata(
1614 MAFW_GST_RENDERER_STATE(
1615 renderer->states[renderer->current_state]),
1621 g_set_error(&mafw_error,
1622 MAFW_RENDERER_ERROR,
1623 MAFW_RENDERER_ERROR_URI_NOT_AVAILABLE, "%s",
1624 cb_error ? cb_error->message : "URI not available");
1625 mafw_gst_renderer_manage_error(renderer, mafw_error);
1626 g_error_free(mafw_error);
1630 static void _notify_play(MafwGstRendererWorker *worker, gpointer owner)
1632 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1633 GError *error = NULL;
1635 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1637 g_return_if_fail((renderer->states != 0) &&
1638 (renderer->current_state != _LastMafwPlayState) &&
1639 (renderer->states[renderer->current_state] != NULL));
1641 g_debug("running _notify_play...");
1643 mafw_gst_renderer_state_notify_play(renderer->states[renderer->current_state],
1646 if (error != NULL) {
1647 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1651 g_error_free (error);
1655 static void _notify_pause(MafwGstRendererWorker *worker, gpointer owner)
1657 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1658 GError *error = NULL;
1660 g_return_if_fail(MAFW_IS_GST_RENDERER (renderer));
1662 g_return_if_fail((renderer->states != 0) &&
1663 (renderer->current_state != _LastMafwPlayState) &&
1664 (renderer->states[renderer->current_state] != NULL));
1666 mafw_gst_renderer_state_notify_pause(renderer->states[renderer->current_state],
1669 if (error != NULL) {
1670 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1671 error->domain, error->code,
1673 g_error_free(error);
1677 static void _notify_buffer_status (MafwGstRendererWorker *worker,
1681 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1682 GError *error = NULL;
1684 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1686 g_return_if_fail((renderer->states != 0) &&
1687 (renderer->current_state != _LastMafwPlayState) &&
1688 (renderer->states[renderer->current_state] != NULL));
1690 mafw_gst_renderer_state_notify_buffer_status(
1691 renderer->states[renderer->current_state],
1695 if (error != NULL) {
1696 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1697 error->domain, error->code,
1699 g_error_free(error);
1703 static void _notify_seek(MafwGstRendererWorker *worker, gpointer owner)
1705 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1706 GError *error = NULL;
1708 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1710 g_return_if_fail((renderer->states != 0) &&
1711 (renderer->current_state != _LastMafwPlayState) &&
1712 (renderer->states[renderer->current_state] != NULL));
1714 mafw_gst_renderer_state_notify_seek(renderer->states[renderer->current_state],
1717 if (error != NULL) {
1718 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1719 error->domain, error->code,
1721 g_error_free(error);
1725 static void _playlist_changed_handler(MafwPlaylistIterator *iterator,
1726 gboolean clip_changed, GQuark domain,
1727 gint code, const gchar *message,
1730 MafwGstRenderer *renderer = (MafwGstRenderer*) user_data;
1732 g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1734 g_return_if_fail((renderer->states != 0) &&
1735 (renderer->current_state != _LastMafwPlayState) &&
1736 (renderer->states[renderer->current_state] != NULL));
1738 /* We update the current index and media here, for this is
1739 the same for all the states. Then we delegate in the state
1740 to finish the task (for example, start playback if needed) */
1742 if (renderer->playlist == NULL) {
1743 g_critical("Got iterator:contents-changed but renderer has no" \
1744 "playlist assigned!. Skipping...");
1749 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1750 domain, code, message);
1752 GError *error = NULL;
1753 MafwGstRendererPlaybackMode mode;
1755 mode = mafw_gst_renderer_get_playback_mode(renderer);
1757 /* Only in non-playobject mode */
1758 if (clip_changed && mode == MAFW_GST_RENDERER_MODE_PLAYLIST)
1759 mafw_gst_renderer_set_media_playlist(renderer);
1761 /* We let the state know if the current clip has changed as
1762 result of this operation, so it can do its work */
1763 mafw_gst_renderer_state_playlist_contents_changed_handler(
1764 renderer->states[renderer->current_state],
1768 if (error != NULL) {
1769 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1770 error->domain, error->code,
1772 g_error_free(error);
1777 static void _error_handler(MafwGstRendererWorker *worker, gpointer owner,
1778 const GError *error)
1780 MafwGstRenderer *renderer = MAFW_GST_RENDERER(owner);
1782 mafw_gst_renderer_manage_error(renderer, error);
1785 void mafw_gst_renderer_manage_error(MafwGstRenderer *self, const GError *error)
1787 GError *new_err = NULL;
1788 GError *raise_error = NULL;
1789 GQuark new_err_domain = MAFW_RENDERER_ERROR;
1790 gint new_err_code = 0;
1792 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1794 g_return_if_fail((self->states != 0) &&
1795 (self->current_state != _LastMafwPlayState) &&
1796 (self->states[self->current_state] != NULL));
1798 g_warning("Got error in renderer:\n\tdomain: %d, code: %d, message: %s",
1799 error->domain, error->code, error->message);
1801 /* Get a MAFW error */
1802 if (error->domain == GST_RESOURCE_ERROR) {
1803 /* handle RESOURCE errors */
1804 switch (error->code) {
1805 case GST_RESOURCE_ERROR_READ:
1806 if (is_current_uri_stream(self)) {
1808 if (self->connected) {
1809 new_err_code = MAFW_RENDERER_ERROR_STREAM_DISCONNECTED;
1811 new_err_domain = MAFW_EXTENSION_ERROR;
1812 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1815 /* Stream + cannot read resource ->
1817 new_err_code = MAFW_RENDERER_ERROR_STREAM_DISCONNECTED;
1820 /* This shouldn't happen */
1821 /* Unknown RESOURCE error */
1822 new_err_domain = MAFW_EXTENSION_ERROR;
1823 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1826 case GST_RESOURCE_ERROR_NOT_FOUND:
1828 if (!is_current_uri_stream(self) || self->connected) {
1830 MAFW_RENDERER_ERROR_INVALID_URI;
1832 new_err_domain = MAFW_EXTENSION_ERROR;
1833 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1837 MAFW_RENDERER_ERROR_INVALID_URI;
1840 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
1841 case GST_RESOURCE_ERROR_OPEN_READ:
1843 if (!is_current_uri_stream(self) || self->connected) {
1845 MAFW_RENDERER_ERROR_MEDIA_NOT_FOUND;
1847 new_err_domain = MAFW_EXTENSION_ERROR;
1848 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1852 MAFW_RENDERER_ERROR_MEDIA_NOT_FOUND;
1855 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
1856 new_err_domain = MAFW_EXTENSION_ERROR;
1857 new_err_code = MAFW_EXTENSION_ERROR_OUT_OF_MEMORY;
1859 case GST_RESOURCE_ERROR_WRITE:
1860 /* DSP renderers send ERROR_WRITE when they find
1862 new_err_code = MAFW_RENDERER_ERROR_CORRUPTED_FILE;
1864 case GST_RESOURCE_ERROR_SEEK:
1865 new_err_code = MAFW_RENDERER_ERROR_CANNOT_SET_POSITION;
1868 /* Unknown RESOURCE error */
1869 new_err_domain = MAFW_EXTENSION_ERROR;
1870 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1873 } else if (error->domain == GST_STREAM_ERROR) {
1874 /* handle STREAM errors */
1875 switch (error->code) {
1876 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
1877 new_err_code = MAFW_RENDERER_ERROR_TYPE_NOT_AVAILABLE;
1879 case GST_STREAM_ERROR_FORMAT:
1880 case GST_STREAM_ERROR_WRONG_TYPE:
1881 case GST_STREAM_ERROR_FAILED:
1882 new_err_code = MAFW_RENDERER_ERROR_UNSUPPORTED_TYPE;
1884 case GST_STREAM_ERROR_DECODE:
1885 case GST_STREAM_ERROR_DEMUX:
1886 new_err_code = MAFW_RENDERER_ERROR_CORRUPTED_FILE;
1888 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
1889 new_err_code = MAFW_RENDERER_ERROR_CODEC_NOT_FOUND;
1891 case GST_STREAM_ERROR_DECRYPT:
1892 case GST_STREAM_ERROR_DECRYPT_NOKEY:
1893 new_err_code = MAFW_RENDERER_ERROR_DRM;
1896 /* Unknown STREAM error */
1897 new_err_domain = MAFW_EXTENSION_ERROR;
1898 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1900 } else if (error->domain == MAFW_GST_RENDERER_ERROR) {
1901 /* Handle own errors. Errors that belong to this domain:
1902 - MAFW_GST_RENDERER_ERROR_PLUGIN_NOT_FOUND,
1903 - MAFW_GST_RENDERER_ERROR_VIDEO_CODEC_NOT_SUPPORTED,
1904 - MAFW_GST_RENDERER_ERROR_AUDIO_CODEC_NOT_SUPPORTED */
1905 new_err_code = MAFW_RENDERER_ERROR_UNSUPPORTED_TYPE;
1906 } else if (error->domain == MAFW_RENDERER_ERROR) {
1907 /* Worker may have sent MAFW_RENDERER_ERROR as well.
1908 No processing needed */
1909 new_err_code = error->code;
1913 new_err_domain = MAFW_EXTENSION_ERROR;
1914 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1917 g_set_error(&new_err, new_err_domain, new_err_code, "%s", error->message);
1919 _run_error_policy(self, new_err, &raise_error);
1920 g_error_free(new_err);
1923 g_signal_emit_by_name(MAFW_EXTENSION (self), "error",
1924 raise_error->domain,
1926 raise_error->message);
1927 g_error_free(raise_error);
1931 static void _notify_eos(MafwGstRendererWorker *worker, gpointer owner)
1933 MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1934 GError *error = NULL;
1936 g_return_if_fail(MAFW_IS_GST_RENDERER (renderer));
1938 g_return_if_fail((renderer->states != 0) &&
1939 (renderer->current_state != _LastMafwPlayState) &&
1940 (renderer->states[renderer->current_state] != NULL));
1942 mafw_gst_renderer_state_notify_eos(renderer->states[renderer->current_state],
1945 if (error != NULL) {
1946 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1947 error->domain, error->code,
1949 g_error_free(error);
1953 /*----------------------------------------------------------------------------
1955 ----------------------------------------------------------------------------*/
1957 void mafw_gst_renderer_get_status(MafwRenderer *self, MafwRendererStatusCB callback,
1960 MafwGstRenderer* renderer;
1962 MafwGstRendererPlaybackMode mode;
1964 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1965 g_return_if_fail(callback != NULL);
1966 renderer = MAFW_GST_RENDERER(self);
1968 mode = mafw_gst_renderer_get_playback_mode(MAFW_GST_RENDERER(self));
1969 if ((mode == MAFW_GST_RENDERER_MODE_STANDALONE) || (renderer->iterator == NULL)) {
1973 mafw_playlist_iterator_get_current_index(renderer->iterator);
1976 /* TODO: Set error parameter */
1977 callback(self, renderer->playlist, index, renderer->current_state,
1978 (const gchar*) renderer->media->object_id, user_data, NULL);
1981 void mafw_gst_renderer_get_current_metadata(MafwRenderer *self,
1982 MafwRendererMetadataResultCB callback,
1985 MafwGstRenderer *renderer;
1986 GHashTable *metadata;
1988 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1989 renderer = MAFW_GST_RENDERER(self);
1991 metadata = mafw_gst_renderer_worker_get_current_metadata(
1995 (const gchar*) renderer->media->object_id,
2001 /*----------------------------------------------------------------------------
2003 ----------------------------------------------------------------------------*/
2006 _playlist_contents_changed_handler(MafwPlaylist *playlist,
2007 guint from, guint nremove,
2009 MafwGstRenderer *renderer)
2011 /* Item(s) added to playlist, so new playable items could come */
2013 renderer->play_failed_count = 0;
2016 gboolean mafw_gst_renderer_assign_playlist(MafwRenderer *self,
2017 MafwPlaylist *playlist,
2020 MafwGstRenderer* renderer = (MafwGstRenderer*) self;
2022 g_return_val_if_fail(MAFW_IS_GST_RENDERER(self), FALSE);
2024 /* Get rid of previously assigned playlist */
2025 if (renderer->playlist != NULL) {
2026 g_signal_handlers_disconnect_matched(renderer->iterator,
2027 (GSignalMatchType) G_SIGNAL_MATCH_FUNC,
2029 _playlist_changed_handler,
2031 g_signal_handlers_disconnect_matched(renderer->playlist,
2032 (GSignalMatchType) G_SIGNAL_MATCH_FUNC,
2034 G_CALLBACK(_playlist_contents_changed_handler),
2036 /* Decrement the use count of the previous playlist because the
2037 renderer isn't going to use it more */
2038 mafw_playlist_decrement_use_count(renderer->playlist, NULL);
2040 g_object_unref(renderer->iterator);
2041 g_object_unref(renderer->playlist);
2044 /* Assign the new playlist */
2045 if (playlist == NULL) {
2046 renderer->playlist = NULL;
2047 renderer->iterator = NULL;
2049 GError *new_error = NULL;
2050 MafwPlaylistIterator *iterator = NULL;
2052 iterator = mafw_playlist_iterator_new();
2053 mafw_playlist_iterator_initialize(iterator, playlist,
2056 g_object_ref(playlist);
2058 if (new_error == NULL) {
2060 renderer->playlist = playlist;
2061 renderer->iterator = iterator;
2063 /* Increment the use_count to avoid the playlist destruction
2064 while the playlist is assigned to some renderer */
2065 mafw_playlist_increment_use_count(renderer->playlist, NULL);
2067 g_signal_connect(iterator,
2069 G_CALLBACK(_playlist_changed_handler),
2071 g_signal_connect(renderer->playlist,
2073 G_CALLBACK(_playlist_contents_changed_handler),
2077 g_propagate_error (error, new_error);
2081 /* Set the new media and signal playlist changed signal */
2082 _signal_playlist_changed(renderer);
2083 mafw_gst_renderer_set_media_playlist(renderer);
2087 mafw_gst_renderer_stop(MAFW_RENDERER(renderer), NULL , NULL);
2092 MafwGstRendererMovementResult mafw_gst_renderer_move(MafwGstRenderer *renderer,
2093 MafwGstRendererMovementType type,
2097 MafwGstRendererMovementResult value = MAFW_GST_RENDERER_MOVE_RESULT_OK;
2099 if (renderer->playlist == NULL) {
2100 value = MAFW_GST_RENDERER_MOVE_RESULT_NO_PLAYLIST;
2102 MafwPlaylistIteratorMovementResult result;
2105 case MAFW_GST_RENDERER_MOVE_TYPE_INDEX:
2107 mafw_playlist_iterator_move_to_index(renderer->iterator,
2111 case MAFW_GST_RENDERER_MOVE_TYPE_PREV:
2113 mafw_playlist_iterator_move_to_prev(renderer->iterator,
2116 case MAFW_GST_RENDERER_MOVE_TYPE_NEXT:
2118 mafw_playlist_iterator_move_to_next(renderer->iterator,
2124 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_OK:
2125 value = MAFW_GST_RENDERER_MOVE_RESULT_OK;
2126 mafw_gst_renderer_set_media_playlist(renderer);
2128 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_INVALID:
2129 g_critical("Iterator is invalid!");
2130 value = MAFW_GST_RENDERER_MOVE_RESULT_ERROR;
2132 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_ERROR:
2133 value = MAFW_GST_RENDERER_MOVE_RESULT_ERROR;
2135 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_LIMIT:
2136 value = MAFW_GST_RENDERER_MOVE_RESULT_PLAYLIST_LIMIT;
2144 /*----------------------------------------------------------------------------
2146 ----------------------------------------------------------------------------*/
2148 static void _set_error_policy(MafwGstRenderer *renderer, MafwRendererErrorPolicy policy)
2150 renderer->error_policy = policy;
2153 static MafwRendererErrorPolicy _get_error_policy(MafwGstRenderer *renderer)
2155 return renderer->error_policy;
2158 static void mafw_gst_renderer_get_property(MafwExtension *self,
2160 MafwExtensionPropertyCallback callback,
2163 MafwGstRenderer *renderer;
2164 GValue *value = NULL;
2165 GError *error = NULL;
2167 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
2168 g_return_if_fail(callback != NULL);
2169 g_return_if_fail(key != NULL);
2171 renderer = MAFW_GST_RENDERER(self);
2172 if (!strcmp(key, MAFW_PROPERTY_RENDERER_VOLUME)) {
2175 volume = mafw_gst_renderer_worker_get_volume(
2178 value = g_new0(GValue, 1);
2179 g_value_init(value, G_TYPE_UINT);
2180 g_value_set_uint(value, volume);
2182 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_MUTE)) {
2184 mute = mafw_gst_renderer_worker_get_mute(renderer->worker);
2185 value = g_new0(GValue, 1);
2186 g_value_init(value, G_TYPE_BOOLEAN);
2187 g_value_set_boolean(value, mute);
2189 else if (!strcmp (key, MAFW_PROPERTY_RENDERER_XID)) {
2191 xid = mafw_gst_renderer_worker_get_xid(renderer->worker);
2192 value = g_new0(GValue, 1);
2193 g_value_init(value, G_TYPE_UINT);
2194 g_value_set_uint(value, xid);
2196 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_ERROR_POLICY)) {
2198 policy = _get_error_policy(renderer);
2199 value = g_new0(GValue, 1);
2200 g_value_init(value, G_TYPE_UINT);
2201 g_value_set_uint(value, policy);
2203 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_AUTOPAINT)) {
2204 value = g_new0(GValue, 1);
2205 g_value_init(value, G_TYPE_BOOLEAN);
2206 g_value_set_boolean(
2208 mafw_gst_renderer_worker_get_autopaint(
2210 } else if (!strcmp(key, MAFW_PROPERTY_RENDERER_COLORKEY)) {
2211 value = g_new0(GValue, 1);
2212 g_value_init(value, G_TYPE_INT);
2215 mafw_gst_renderer_worker_get_colorkey(
2218 #ifdef HAVE_GDKPIXBUF
2219 else if (!strcmp(key,
2220 MAFW_PROPERTY_GST_RENDERER_CURRENT_FRAME_ON_PAUSE)) {
2221 gboolean current_frame_on_pause;
2222 current_frame_on_pause =
2223 mafw_gst_renderer_worker_get_current_frame_on_pause(renderer->worker);
2224 value = g_new0(GValue, 1);
2225 g_value_init(value, G_TYPE_BOOLEAN);
2226 g_value_set_boolean(value, current_frame_on_pause);
2229 else if (!strcmp(key,
2230 MAFW_PROPERTY_GST_RENDERER_TV_CONNECTED)) {
2231 value = g_new0(GValue, 1);
2232 g_value_init(value, G_TYPE_BOOLEAN);
2233 g_value_set_boolean(value, renderer->tv_connected);
2235 else if (!strcmp(key,
2236 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS)){
2237 /* Delegate in the state. */
2238 value = mafw_gst_renderer_state_get_property_value(
2239 MAFW_GST_RENDERER_STATE(
2240 renderer->states[renderer->current_state]),
2241 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS);
2244 /* Something goes wrong. */
2245 error = g_error_new(
2246 MAFW_GST_RENDERER_ERROR,
2247 MAFW_EXTENSION_ERROR_GET_PROPERTY,
2248 "Error while getting the property value");
2252 /* Unsupported property */
2253 error = g_error_new(MAFW_GST_RENDERER_ERROR,
2254 MAFW_EXTENSION_ERROR_GET_PROPERTY,
2255 "Unsupported property");
2258 callback(self, key, value, user_data, error);
2261 static void mafw_gst_renderer_set_property(MafwExtension *self,
2263 const GValue *value)
2265 MafwGstRenderer *renderer;
2267 g_return_if_fail(MAFW_IS_GST_RENDERER(self));
2268 g_return_if_fail(key != NULL);
2270 renderer = MAFW_GST_RENDERER(self);
2272 if (!strcmp(key, MAFW_PROPERTY_RENDERER_VOLUME)) {
2273 guint volume = g_value_get_uint(value);
2276 mafw_gst_renderer_worker_set_volume(renderer->worker,
2278 /* Property-changed emision is done by worker */
2281 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_MUTE)) {
2282 gboolean mute = g_value_get_boolean(value);
2283 mafw_gst_renderer_worker_set_mute(renderer->worker, mute);
2285 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_XID)) {
2286 XID xid = g_value_get_uint(value);
2287 mafw_gst_renderer_worker_set_xid(renderer->worker, xid);
2289 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_ERROR_POLICY)) {
2290 MafwRendererErrorPolicy policy = g_value_get_uint(value);
2291 _set_error_policy(renderer, policy);
2293 else if (!strcmp(key, MAFW_PROPERTY_RENDERER_AUTOPAINT)) {
2294 mafw_gst_renderer_worker_set_autopaint(
2296 g_value_get_boolean(value));
2298 #ifdef HAVE_GDKPIXBUF
2299 else if (!strcmp(key,
2300 MAFW_PROPERTY_GST_RENDERER_CURRENT_FRAME_ON_PAUSE)) {
2301 gboolean current_frame_on_pause = g_value_get_boolean(value);
2302 mafw_gst_renderer_worker_set_current_frame_on_pause(renderer->worker,
2303 current_frame_on_pause);
2308 /* FIXME I'm not sure when to emit property-changed signals.
2309 * Maybe we should let the worker do it, when the change
2310 * reached the hardware... */
2311 mafw_extension_emit_property_changed(self, key, value);
2314 /* vi: set noexpandtab ts=8 sw=8 cino=t0,(0: */