Added missing build dependency to hildon-control-panel-dev
[mafwsubrenderer] / libmafw-gst-renderer / mafw-gst-renderer.c
1 /*
2  * This file is a part of MAFW
3  *
4  * Copyright (C) 2007, 2008, 2009 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Visa Smolander <visa.smolander@nokia.com>
7  *
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.
12  *
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.
17  *
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
21  * 02110-1301 USA
22  *
23  */
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <glib.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <dbus/dbus.h>
32 #include <libgnomevfs/gnome-vfs.h>
33
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"
38
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"
43
44 #include "blanking.h"
45
46 #ifdef HAVE_CONIC
47 #include <conicconnectionevent.h>
48 #endif
49
50 #undef  G_LOG_DOMAIN
51 #define G_LOG_DOMAIN "mafw-gst-renderer"
52
53 #define is_current_uri_stream(self) \
54         (((self)->media != NULL) && ((self)->media->uri != NULL) &&     \
55          uri_is_stream((self)->media->uri))
56
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"
62
63 /*----------------------------------------------------------------------------
64   Static variable definitions
65   ----------------------------------------------------------------------------*/
66
67 /*----------------------------------------------------------------------------
68   Plugin initialization
69   ----------------------------------------------------------------------------*/
70
71 static gboolean mafw_gst_renderer_initialize(MafwRegistry *registry,
72                                            GError **error);
73 static void mafw_gst_renderer_deinitialize(GError **error);
74
75 /*----------------------------------------------------------------------------
76   GObject initialization
77   ----------------------------------------------------------------------------*/
78
79 static void mafw_gst_renderer_dispose(GObject *object);
80 static void mafw_gst_renderer_finalize(GObject *object);
81
82 /*----------------------------------------------------------------------------
83   Hal callbacks
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);
89
90 /*----------------------------------------------------------------------------
91   GConf notifications
92   ----------------------------------------------------------------------------*/
93
94 static void _battery_cover_open_cb(GConfClient *client,
95                                    guint cnxn_id,
96                                    GConfEntry *entry,
97                                    MafwGstRenderer *renderer);
98
99 static void _autoload_subtitles_changed_cb(GConfClient *client,
100                                            guint cnxn_id,
101                                            GConfEntry *entry,
102                                            MafwGstRenderer *renderer);
103
104 static void _subtitle_font_changed_cb(GConfClient *client,
105                                       guint cnxn_id,
106                                       GConfEntry *entry,
107                                       MafwGstRenderer *renderer);
108
109 /*----------------------------------------------------------------------------
110   Gnome VFS notifications
111   ----------------------------------------------------------------------------*/
112
113 static void _volume_pre_unmount_cb(GnomeVFSVolumeMonitor *monitor,
114                                    GnomeVFSVolume *volume,
115                                    MafwGstRenderer *renderer);
116
117 /*----------------------------------------------------------------------------
118   Playback
119   ----------------------------------------------------------------------------*/
120
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);
125
126 /*----------------------------------------------------------------------------
127   Properties
128   ----------------------------------------------------------------------------*/
129
130 static void _set_error_policy(MafwGstRenderer *renderer, MafwRendererErrorPolicy policy);
131 static MafwRendererErrorPolicy _get_error_policy(MafwGstRenderer *renderer);
132
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,
137                                          gpointer user_data);
138
139 /*----------------------------------------------------------------------------
140   Metadata
141   ----------------------------------------------------------------------------*/
142
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);
148
149 /*----------------------------------------------------------------------------
150   Notification operations
151   ----------------------------------------------------------------------------*/
152
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,
157                                   gdouble percent);
158 static void _notify_eos(MafwGstRendererWorker *worker, gpointer owner);
159 static void _error_handler(MafwGstRendererWorker *worker, gpointer owner,
160                            const GError *error);
161
162 #ifdef HAVE_CONIC
163 /*----------------------------------------------------------------------------
164   Connection
165   ----------------------------------------------------------------------------*/
166
167 static void _connection_init(MafwGstRenderer *renderer);
168 #endif
169
170 /*----------------------------------------------------------------------------
171   Plugin initialization
172   ----------------------------------------------------------------------------*/
173
174 /*
175  * Registers the plugin descriptor making this plugin available to the
176  * framework and applications
177  */
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,
182 };
183
184 static gboolean mafw_gst_renderer_initialize(MafwRegistry *registry,
185                                            GError **error)
186 {
187         MafwGstRenderer *self;
188
189         g_assert(registry != NULL);
190         self = MAFW_GST_RENDERER(mafw_gst_renderer_new(registry));
191         mafw_registry_add_extension(registry, MAFW_EXTENSION(self));
192
193         return TRUE;
194 }
195
196 static void mafw_gst_renderer_deinitialize(GError **error)
197 {
198 }
199
200 /*----------------------------------------------------------------------------
201   GObject initialization
202   ----------------------------------------------------------------------------*/
203
204 G_DEFINE_TYPE(MafwGstRenderer, mafw_gst_renderer, MAFW_TYPE_RENDERER);
205
206 static void mafw_gst_renderer_class_init(MafwGstRendererClass *klass)
207 {
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};
214         gint i = 0;
215         GObject *plugin;
216
217         gclass = G_OBJECT_CLASS(klass);
218         g_return_if_fail(gclass != NULL);
219
220         renderer_class = MAFW_RENDERER_CLASS(klass);
221         g_return_if_fail(renderer_class != NULL);
222
223         /* GObject */
224
225         gclass->dispose = mafw_gst_renderer_dispose;
226         gclass->finalize = mafw_gst_renderer_finalize;
227
228         /* Playback */
229
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;
236
237         /* Playlist operations */
238
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;
243
244         /* Playback position */
245
246         renderer_class->set_position = mafw_gst_renderer_set_position;
247         renderer_class->get_position = mafw_gst_renderer_get_position;
248
249         /* Metadata */
250
251         renderer_class->get_current_metadata =
252                 mafw_gst_renderer_get_current_metadata;
253
254         /* Properties */
255
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;
260
261         gst_init(NULL, NULL);
262         gst_pb_utils_init();
263
264         /* Pre-load some common plugins */
265         while (preloaded_plugins[i])
266         {
267                 plugin = G_OBJECT(gst_plugin_load_by_name(preloaded_plugins[i]));
268                 if (plugin)
269                         g_object_unref(plugin);
270                 else
271                         g_debug("Can not load plugin: %s", preloaded_plugins[i]);
272                 i++;
273         }
274 }
275
276 static void mafw_gst_renderer_init(MafwGstRenderer *self)
277 {
278         MafwGstRenderer *renderer = NULL;
279         GError *error = NULL;
280
281         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
282
283         renderer = MAFW_GST_RENDERER(self);
284         g_return_if_fail(renderer != NULL);
285
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",
295                                      G_TYPE_BOOLEAN);
296 #endif
297         mafw_extension_add_property(MAFW_EXTENSION(self),
298                                     MAFW_PROPERTY_GST_RENDERER_TV_CONNECTED,
299                                     G_TYPE_BOOLEAN);
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;
304
305         renderer->playlist = NULL;
306         renderer->iterator = NULL;
307         renderer->seeking_to = -1;
308         renderer->update_playcount_id = 0;
309
310         self->worker = mafw_gst_renderer_worker_new(self);
311
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;
319
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));
330
331         renderer->current_state = Stopped;
332         renderer->resume_playlist = FALSE;
333         renderer->playback_mode = MAFW_GST_RENDERER_MODE_PLAYLIST;
334
335 #ifdef HAVE_CONIC
336         renderer->connected = FALSE;
337         renderer->connection = NULL;
338
339         _connection_init(renderer);
340 #endif
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);
344         if (error) {
345                 g_warning("%s", error->message);
346                 g_error_free(error);
347                 error = NULL;
348         }
349
350         gconf_client_notify_add(renderer->gconf_client,
351                                 GCONF_BATTERY_COVER_OPEN,
352                                 (GConfClientNotifyFunc) _battery_cover_open_cb,
353                                 renderer,
354                                 NULL, &error);
355
356         if (error) {
357                 g_warning("%s", error->message);
358                 g_error_free(error);
359         }
360
361         gconf_client_add_dir(renderer->gconf_client,
362                              GCONF_MAFW_GST_SUBTITLES_RENDERER,
363                              GCONF_CLIENT_PRELOAD_ONELEVEL,
364                              &error);
365         if (error) {
366                 g_warning("%s", error->message);
367                 g_error_free(error);
368                 error = NULL;
369         }
370
371         gconf_client_notify_add(renderer->gconf_client,
372                                 GCONF_MAFW_GST_SUBTITLES_RENDERER "/autoload_subtitles",
373                                 (GConfClientNotifyFunc) _autoload_subtitles_changed_cb,
374                                 renderer,
375                                 NULL, &error);
376         if (error) {
377                 g_warning("%s", error->message);
378                 g_error_free(error);
379         }
380
381         gconf_client_notify_add(renderer->gconf_client,
382                                 GCONF_MAFW_GST_SUBTITLES_RENDERER "/subtitle_encoding",
383                                 (GConfClientNotifyFunc) _subtitle_font_changed_cb,
384                                 renderer,
385                                 NULL, &error);
386         if (error) {
387                 g_warning("%s", error->message);
388                 g_error_free(error);
389         }
390
391         gconf_client_notify_add(renderer->gconf_client,
392                                 GCONF_MAFW_GST_SUBTITLES_RENDERER "/subtitle_font",
393                                 (GConfClientNotifyFunc) _subtitle_font_changed_cb,
394                                 renderer,
395                                 NULL, &error);
396         if (error) {
397                 g_warning("%s", error->message);
398                 g_error_free(error);
399         }
400
401         if (self->worker->pipeline) {
402                 gconf_client_notify(renderer->gconf_client,
403                                     GCONF_MAFW_GST_SUBTITLES_RENDERER "/autoload_subtitles");
404
405                 gconf_client_notify(renderer->gconf_client,
406                                     GCONF_MAFW_GST_SUBTITLES_RENDERER "/subtitle_encoding");
407
408                 gconf_client_notify(renderer->gconf_client,
409                                     GCONF_MAFW_GST_SUBTITLES_RENDERER "/subtitle_font");
410         }
411
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);
416         } else {
417                 g_warning("Failed to initialize gnome-vfs");
418         }
419 }
420
421 static void mafw_gst_renderer_dispose(GObject *object)
422 {
423         MafwGstRenderer *renderer;
424
425         g_return_if_fail(MAFW_IS_GST_RENDERER(object));
426
427         renderer = MAFW_GST_RENDERER(object);
428
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;
434         }
435
436         if (renderer->registry != NULL) {
437                 g_object_unref(renderer->registry);
438                 renderer->registry = NULL;
439         }
440
441         if (renderer->states != NULL) {
442                 guint i = 0;
443
444                 for (i = 0; i < _LastMafwPlayState; i++) {
445                         if (renderer->states[i] != NULL)
446                                 g_object_unref(renderer->states[i]);
447                 }
448                 g_free(renderer->states);
449                 renderer->states = NULL;
450         }
451
452         if (renderer->hal_ctx != NULL) {
453                 libhal_device_remove_property_watch(renderer->hal_ctx,
454                                                     HAL_VIDEOOUT_UDI,
455                                                     NULL);
456                 libhal_ctx_shutdown(renderer->hal_ctx, NULL);
457                 libhal_ctx_free(renderer->hal_ctx);
458         }
459
460 #ifdef HAVE_CONIC
461         if (renderer->connection != NULL) {
462                 g_object_unref(renderer->connection);
463                 renderer->connection = NULL;
464         }
465 #endif
466
467         if (renderer->gconf_client != NULL) {
468                 g_object_unref(renderer->gconf_client);
469                 renderer->gconf_client = NULL;
470         }
471
472         G_OBJECT_CLASS(mafw_gst_renderer_parent_class)->dispose(object);
473 }
474
475 static void mafw_gst_renderer_finalize(GObject *object)
476 {
477         MafwGstRenderer *self = (MafwGstRenderer*) object;
478
479         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
480
481         mafw_gst_renderer_clear_media(self);
482
483         if (self->media)
484         {
485                 g_free(self->media);
486                 self->media = NULL;
487         }
488
489         G_OBJECT_CLASS(mafw_gst_renderer_parent_class)->finalize(object);
490 }
491
492 /**
493  * mafw_gst_renderer_new:
494  * @registry: The registry that owns this renderer.
495  *
496  * Creates a new MafwGstRenderer object
497  */
498 GObject *mafw_gst_renderer_new(MafwRegistry* registry)
499 {
500         GObject* object;
501         LibHalContext *ctx;
502         DBusConnection *conn;
503         DBusError err;
504         char **jackets;
505         char **jack;
506         gint num_jacks;
507
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,
512                               NULL);
513         g_assert(object != NULL);
514         MAFW_GST_RENDERER(object)->registry = g_object_ref(registry);
515
516         /* Set default error policy */
517         MAFW_GST_RENDERER(object)->error_policy =
518                 MAFW_RENDERER_ERROR_POLICY_CONTINUE;
519
520         MAFW_GST_RENDERER(object)->tv_connected = FALSE;
521
522         /* Setup hal connection for reacting usb cable connected event */
523         dbus_error_init(&err);
524         conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
525
526         if (dbus_error_is_set(&err)) {
527                 g_warning("Couldn't setup HAL connection: %s", err.message);
528                 dbus_error_free(&err);
529
530                 goto err1;
531         }
532         ctx = libhal_ctx_new();
533         libhal_ctx_set_dbus_connection(ctx, conn);
534         libhal_ctx_set_user_data(ctx, object);
535
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);
540                 } else {
541                         g_warning("Could not initialize hal");
542                 }
543                 goto err2;
544         }
545
546         libhal_device_add_property_watch(ctx, HAL_VIDEOOUT_UDI, &err);
547
548         if (dbus_error_is_set(&err)) {
549                 g_warning("Could not start watching usb device: %s",
550                           err.message);
551                 dbus_error_free(&err);
552
553                 goto err3;
554         }
555         libhal_ctx_set_device_property_modified(ctx, _property_modified);
556
557         /* Initializes blanking policy */
558         jackets = libhal_find_device_by_capability(ctx,
559                                                    "input.jack.video-out",
560                                                    &num_jacks, NULL);
561         if (jackets != NULL) {
562                 jack = jackets;
563                 while (*jack) {
564                         if (_tv_out_is_connected(ctx, *jack)) {
565                                 MAFW_GST_RENDERER(object)->tv_connected = TRUE;
566                                 break;
567                         }
568                         jack++;
569                 }
570
571                 blanking_control(*jack == NULL);
572                 libhal_free_string_array(jackets);
573         }
574
575         MAFW_GST_RENDERER(object)->hal_ctx = ctx;
576
577         return object;
578 err3:
579         libhal_ctx_shutdown(ctx, NULL);
580 err2:
581         libhal_ctx_free(ctx);
582 err1:
583         return object;
584 }
585
586 /**
587  * mafw_gst_renderer_error_quark:
588  *
589  * Fetches the quark representing the domain of the errors in the
590  * gst renderer
591  *
592  * Return value: a quark identifying the error domain of the
593  * #MafwGstRenderer objects.
594  *
595  **/
596 GQuark mafw_gst_renderer_error_quark(void)
597 {
598         return g_quark_from_static_string("mafw-gst-renderer-error-quark");
599 }
600
601 void mafw_gst_renderer_set_playback_mode(MafwGstRenderer *self,
602                                        MafwGstRendererPlaybackMode mode)
603 {
604         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
605         self->playback_mode = mode;
606 }
607
608 MafwGstRendererPlaybackMode mafw_gst_renderer_get_playback_mode(
609         MafwGstRenderer *self)
610 {
611         g_return_val_if_fail(MAFW_IS_GST_RENDERER(self),
612                              MAFW_GST_RENDERER_MODE_STANDALONE);
613         return self->playback_mode;
614 }
615
616 /*----------------------------------------------------------------------------
617   Set Media
618   ----------------------------------------------------------------------------*/
619
620 static MafwSource* _get_source(MafwGstRenderer *renderer,
621                                const gchar *object_id)
622 {
623         MafwSource* source;
624         gchar* sourceid = NULL;
625
626         g_assert(object_id != NULL);
627
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));
632         g_free(sourceid);
633
634         return source;
635 }
636
637 void mafw_gst_renderer_get_metadata(MafwGstRenderer* self,
638                                   const gchar* objectid,
639                                   GError **error)
640 {
641         MafwSource* source;
642
643         g_assert(self != NULL);
644
645         /*
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
654          */
655
656         source = _get_source(self, objectid);
657         if (source != NULL)
658         {
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,
665                                 NULL };
666
667                 /* Source found, get metadata */
668                 mafw_source_get_metadata(source, objectid,
669                                          keys,
670                                          _notify_metadata,
671                                          self);
672
673         }
674         else
675         {
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);
685         }
686 }
687
688 void mafw_gst_renderer_set_object(MafwGstRenderer *self, const gchar *object_id)
689 {
690         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
691
692         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
693         g_return_if_fail(object_id != NULL);
694
695         /* This is intended to be called only when using play_object(),
696          * as for playlists we use set_media_playlist()
697          */
698
699         /* Stop any ongoing playback */
700         mafw_gst_renderer_clear_media(renderer);
701
702         /* Set new object */
703         renderer->media->object_id = g_strdup(object_id);
704
705         /* Signal media changed */
706         _signal_media_changed(renderer);
707 }
708
709
710 /**
711  * mafw_gst_renderer_clear_media:
712  *
713  * @renderer A #MafwGstRenderer whose media to clear
714  *
715  * Clears & frees the renderer's current media details
716  **/
717 void mafw_gst_renderer_clear_media(MafwGstRenderer *self)
718 {
719         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
720         g_return_if_fail(self->media != NULL);
721
722         g_free(self->media->object_id);
723         self->media->object_id = NULL;
724
725         g_free(self->media->uri);
726         self->media->uri = NULL;
727
728         g_free(self->media->title);
729         self->media->title = NULL;
730
731         g_free(self->media->artist);
732         self->media->artist = NULL;
733
734         g_free(self->media->album);
735         self->media->album = NULL;
736
737         self->media->duration = 0;
738         self->media->position = 0;
739 }
740
741
742 /**
743  * mafw_gst_renderer_set_media_playlist:
744  *
745  * @self A #MafwGstRenderer, whose media to set
746  *
747  * Set current media from the renderer's playlist, using the current playlist index.
748  **/
749 void mafw_gst_renderer_set_media_playlist(MafwGstRenderer* self)
750 {
751         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
752
753         /* Get rid of old media details */
754         mafw_gst_renderer_clear_media(self);
755
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));
761         } else {
762                 self->media->object_id = NULL;
763         }
764
765         _signal_media_changed(self);
766 }
767
768 #ifdef HAVE_CONIC
769 /*----------------------------------------------------------------------------
770   Connection
771   ----------------------------------------------------------------------------*/
772
773 static void
774 _con_ic_status_handler(ConIcConnection *conn, ConIcConnectionEvent *event,
775                        gpointer data)
776 {
777         MafwGstRenderer *renderer = (MafwGstRenderer *) data;
778
779         g_assert(MAFW_IS_GST_RENDERER(renderer));
780
781         renderer->connected =
782                 con_ic_connection_event_get_status(event) ==
783                 CON_IC_STATUS_CONNECTED;
784 }
785
786 static void
787 _connection_init(MafwGstRenderer *renderer)
788 {
789         g_assert (MAFW_IS_GST_RENDERER(renderer));
790
791         if (renderer->connection == NULL) {
792                 renderer->connection = con_ic_connection_new();
793                 renderer->connected = FALSE;
794
795                 g_assert(renderer->connection != NULL);
796         }
797
798         g_object_set(renderer->connection, "automatic-connection-events",
799                      TRUE, NULL);
800         g_signal_connect(renderer->connection, "connection-event",
801                          G_CALLBACK (_con_ic_status_handler), renderer);
802
803         con_ic_connection_connect(renderer->connection,
804                                   CON_IC_CONNECT_FLAG_AUTOMATICALLY_TRIGGERED);
805 }
806 #endif
807
808 /*----------------------------------------------------------------------------
809   Hal callbacks
810   ----------------------------------------------------------------------------*/
811
812 static gboolean _tv_out_is_connected(LibHalContext *ctx, const char *udi)
813 {
814         gboolean is_tv_out_jack = FALSE;
815         char **jack_types;
816         char **jack;
817
818         if (udi == NULL) {
819                 return FALSE;
820         }
821
822         jack_types = libhal_device_get_property_strlist(ctx, udi,
823                                                         "input.jack.type",
824                                                         NULL);
825         if (jack_types == NULL) {
826                 return FALSE;
827         }
828
829         jack = jack_types;
830         while (*jack) {
831                 if (strcmp(*jack, "video-out") == 0) {
832                         is_tv_out_jack = TRUE;
833                         break;
834                 } else {
835                         jack++;
836                 }
837         }
838
839         libhal_free_string_array(jack_types);
840
841         return is_tv_out_jack;
842 }
843
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)
847 {
848         MafwGstRenderer *renderer;
849         gboolean connected;
850         GValue value = { 0 };
851
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,
863                         &value);
864                 g_value_unset(&value);
865         }
866         blanking_control(connected == FALSE);
867 }
868
869 /*----------------------------------------------------------------------------
870   GConf notifications
871   ----------------------------------------------------------------------------*/
872
873 static void _battery_cover_open_cb(GConfClient *client,
874                                    guint cnxn_id,
875                                    GConfEntry *entry,
876                                    MafwGstRenderer *renderer)
877 {
878         GConfValue *value = NULL;
879         gboolean is_cover_open;
880
881         value = gconf_entry_get_value(entry);
882         is_cover_open = gconf_value_get_bool(value);
883
884         if (is_cover_open) {
885                 /* External mmc could be removed!. */
886                 const gchar *emmc_path = g_getenv("MMC_MOUNTPOINT");
887
888                 mafw_gst_renderer_state_handle_pre_unmount(
889                         MAFW_GST_RENDERER_STATE(
890                                 renderer->states[renderer->current_state]),
891                                  emmc_path);
892         }
893 }
894
895 static void _autoload_subtitles_changed_cb(GConfClient *client,
896                                            guint cnxn_id,
897                                            GConfEntry *entry,
898                                            MafwGstRenderer *renderer)
899 {
900         GConfValue *value = NULL;
901         gboolean enabled = FALSE;
902
903         value = gconf_entry_get_value(entry);
904         if (value == NULL)
905                 return;
906
907         enabled = gconf_value_get_bool(value);
908
909         if (enabled)
910                 renderer->worker->subtitles.enabled = TRUE;
911         else
912                 renderer->worker->subtitles.enabled = FALSE;
913 }
914
915 static void _subtitle_font_changed_cb(GConfClient *client,
916                                       guint cnxn_id,
917                                       GConfEntry *entry,
918                                       MafwGstRenderer *renderer)
919 {
920         const gchar *key = NULL;
921         GConfValue *value = NULL;
922         const gchar *str_value = NULL;
923
924         key = gconf_entry_get_key(entry);
925
926         /* Only key without absolute path is required */
927         key += strlen(GCONF_MAFW_GST_SUBTITLES_RENDERER) + 1;
928
929         value = gconf_entry_get_value(entry);
930         if (value)
931                 str_value = gconf_value_get_string(value);
932         else
933                 str_value = NULL;
934
935         if (strcmp(key, "subtitle_font") == 0) {
936                 if (renderer->worker->subtitles.font)
937                         g_free(renderer->worker->subtitles.font);
938
939                 if (str_value)
940                         renderer->worker->subtitles.font = g_strdup(str_value);
941                 else
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);
946
947                 if (str_value)
948                         renderer->worker->subtitles.encoding = g_strdup(str_value);
949                 else
950                         renderer->worker->subtitles.encoding = NULL;
951         } else {
952                 g_warning("Wrong %s key, %s", GCONF_MAFW_GST_SUBTITLES_RENDERER, key);
953         }
954 }
955
956 /*----------------------------------------------------------------------------
957   Gnome VFS notifications
958   ----------------------------------------------------------------------------*/
959
960 static void _volume_pre_unmount_cb(GnomeVFSVolumeMonitor *monitor, 
961                                    GnomeVFSVolume *volume,
962                                    MafwGstRenderer *renderer)
963 {
964         gchar *location = gnome_vfs_volume_get_activation_uri(volume);
965         if (!location) {
966                 return;
967         }
968         
969         mafw_gst_renderer_state_handle_pre_unmount(
970                 MAFW_GST_RENDERER_STATE(
971                         renderer->states[renderer->current_state]),
972                 location);
973         
974         g_free(location);
975 }
976
977 /*----------------------------------------------------------------------------
978   Signals
979   ----------------------------------------------------------------------------*/
980
981
982 /**
983  * _signal_state_changed:
984  * @self: A #MafwGstRenderer
985  *
986  * Signals state_changed to all UIs
987  **/
988 static void _signal_state_changed(MafwGstRenderer * self)
989 {
990         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
991
992         g_signal_emit_by_name(MAFW_RENDERER(self),
993                               "state-changed", self->current_state);
994 }
995
996 /**
997  * _signal_playlist_changed:
998  * @self: A #MafwGstRenderer
999  *
1000  * Signals playlist update to all UIs
1001  **/
1002 static void _signal_playlist_changed(MafwGstRenderer * self)
1003 {
1004         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1005
1006         g_signal_emit_by_name(MAFW_RENDERER(self),
1007                               "playlist-changed", self->playlist);
1008 }
1009
1010 /**
1011  * _signal_media_changed:
1012  * @self: A #MafwGstRenderer
1013  *
1014  * Signals media_changed to all UIs
1015  **/
1016 static void _signal_media_changed(MafwGstRenderer *self)
1017 {
1018
1019         MafwGstRendererPlaybackMode mode;
1020         gint index;
1021
1022         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1023
1024         mode = mafw_gst_renderer_get_playback_mode(MAFW_GST_RENDERER(self));
1025         if ((mode == MAFW_GST_RENDERER_MODE_STANDALONE) ||
1026             (self->iterator == NULL)) {
1027                 index = -1;
1028         } else {
1029                 index = mafw_playlist_iterator_get_current_index(self->iterator);
1030         }
1031
1032         g_signal_emit_by_name(MAFW_RENDERER(self),
1033                               "media-changed",
1034                               index,
1035                               self->media->object_id);
1036 }
1037
1038 /**
1039  * _signal_transport_actions_property_changed:
1040  * @self: A #MafwGstRenderer
1041  *
1042  * Signals transport_actions property_changed to all UIs
1043  **/
1044 static void _signal_transport_actions_property_changed(MafwGstRenderer * self)
1045 {
1046         GValue *value;
1047
1048         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1049
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);
1054
1055         if (value) {
1056                 mafw_extension_emit_property_changed(
1057                         MAFW_EXTENSION(self),
1058                         MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS,
1059                         value);
1060                 g_value_unset(value);
1061                 g_free(value);
1062         }
1063 }
1064
1065
1066 /*----------------------------------------------------------------------------
1067   State pattern support
1068   ----------------------------------------------------------------------------*/
1069
1070 void mafw_gst_renderer_set_state(MafwGstRenderer *self, MafwPlayState state)
1071 {
1072         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1073
1074         self->current_state = state;
1075         _signal_state_changed(self);
1076         _signal_transport_actions_property_changed(self);
1077 }
1078
1079 void mafw_gst_renderer_play(MafwRenderer *self, MafwRendererPlaybackCB callback,
1080                           gpointer user_data)
1081 {
1082         MafwGstRenderer *renderer = (MafwGstRenderer*) self;
1083         GError *error = NULL;
1084
1085         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1086
1087         g_return_if_fail((renderer->states != 0) &&
1088                          (renderer->current_state != _LastMafwPlayState) &&
1089                          (renderer->states[renderer->current_state] != NULL));
1090
1091         mafw_gst_renderer_state_play(
1092                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1093                 &error);
1094
1095         if (callback != NULL)
1096                 callback(self, user_data, error);
1097         if (error)
1098                 g_error_free(error);
1099 }
1100
1101 void mafw_gst_renderer_play_object(MafwRenderer *self,
1102                                  const gchar *object_id,
1103                                  MafwRendererPlaybackCB callback,
1104                                  gpointer user_data)
1105 {
1106         MafwGstRenderer *renderer = (MafwGstRenderer*) self;
1107         GError *error = NULL;
1108
1109         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1110         g_return_if_fail(object_id != NULL);
1111
1112         g_return_if_fail((renderer->states != 0) &&
1113                          (renderer->current_state != _LastMafwPlayState) &&
1114                          (renderer->states[renderer->current_state] != NULL));
1115
1116         mafw_gst_renderer_state_play_object(
1117                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1118                 object_id,
1119                 &error);
1120
1121         if (callback != NULL)
1122                 callback(self, user_data, error);
1123         if (error)
1124                 g_error_free(error);
1125 }
1126
1127 void mafw_gst_renderer_stop(MafwRenderer *self, MafwRendererPlaybackCB callback,
1128                           gpointer user_data)
1129 {
1130         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1131         GError *error = NULL;
1132
1133         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1134
1135         g_return_if_fail((renderer->states != 0) &&
1136                          (renderer->current_state != _LastMafwPlayState) &&
1137                          (renderer->states[renderer->current_state] != NULL));
1138
1139         renderer->play_failed_count = 0;
1140         mafw_gst_renderer_state_stop(
1141                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1142                 &error);
1143
1144         if (callback != NULL)
1145                 callback(self, user_data, error);
1146         if (error)
1147                 g_error_free(error);
1148 }
1149
1150
1151 void mafw_gst_renderer_pause(MafwRenderer *self, MafwRendererPlaybackCB callback,
1152                            gpointer user_data)
1153 {
1154         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1155         GError *error = NULL;
1156
1157         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1158
1159         g_return_if_fail((renderer->states != 0) &&
1160                          (renderer->current_state != _LastMafwPlayState) &&
1161                          (renderer->states[renderer->current_state] != NULL));
1162
1163         mafw_gst_renderer_state_pause(
1164                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1165                 &error);
1166
1167         if (callback != NULL)
1168                 callback(self, user_data, error);
1169         if (error)
1170                 g_error_free(error);
1171 }
1172
1173 void mafw_gst_renderer_resume(MafwRenderer *self, MafwRendererPlaybackCB callback,
1174                             gpointer user_data)
1175 {
1176         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1177         GError *error = NULL;
1178
1179         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1180
1181         g_return_if_fail((renderer->states != 0) &&
1182                          (renderer->current_state != _LastMafwPlayState) &&
1183                          (renderer->states[renderer->current_state] != NULL));
1184
1185         mafw_gst_renderer_state_resume(
1186                 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1187                 &error);
1188
1189         if (callback != NULL)
1190                 callback(self, user_data, error);
1191         if (error)
1192                 g_error_free(error);
1193 }
1194
1195 void mafw_gst_renderer_next(MafwRenderer *self, MafwRendererPlaybackCB callback,
1196                           gpointer user_data)
1197 {
1198         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1199         GError *error = NULL;
1200
1201         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1202
1203         g_return_if_fail((renderer->states != 0) &&
1204                          (renderer->current_state != _LastMafwPlayState) &&
1205                          (renderer->states[renderer->current_state] != NULL));
1206
1207         renderer->play_failed_count = 0;
1208         mafw_gst_renderer_state_next(
1209                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1210                 &error);
1211
1212         if (callback != NULL)
1213                 callback(self, user_data, error);
1214         if (error)
1215                 g_error_free(error);
1216 }
1217
1218 void mafw_gst_renderer_previous(MafwRenderer *self, MafwRendererPlaybackCB callback,
1219                               gpointer user_data)
1220 {
1221         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1222         GError *error = NULL;
1223
1224         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1225
1226         g_return_if_fail((renderer->states != 0) &&
1227                          (renderer->current_state != _LastMafwPlayState) &&
1228                          (renderer->states[renderer->current_state] != NULL));
1229
1230         renderer->play_failed_count = 0;
1231         mafw_gst_renderer_state_previous(
1232                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1233                 &error);
1234
1235         if (callback != NULL)
1236                 callback(self, user_data, error);
1237         if (error)
1238                 g_error_free(error);
1239 }
1240
1241 void mafw_gst_renderer_goto_index(MafwRenderer *self, guint index,
1242                                 MafwRendererPlaybackCB callback,
1243                                 gpointer user_data)
1244 {
1245         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1246         GError *error = NULL;
1247
1248         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1249
1250         g_return_if_fail((renderer->states != 0) &&
1251                          (renderer->current_state != _LastMafwPlayState) &&
1252                          (renderer->states[renderer->current_state] != NULL));
1253
1254         renderer->play_failed_count = 0;
1255         mafw_gst_renderer_state_goto_index(
1256                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1257                 index,
1258                 &error);
1259
1260         if (callback != NULL)
1261                 callback(self, user_data, error);
1262         if (error)
1263                 g_error_free(error);
1264 }
1265
1266 void mafw_gst_renderer_get_position(MafwRenderer *self, MafwRendererPositionCB callback,
1267                                   gpointer user_data)
1268 {
1269         MafwGstRenderer *renderer;
1270         gint pos;
1271         GError *error = NULL;
1272
1273         g_return_if_fail(callback != NULL);
1274         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1275
1276         renderer = MAFW_GST_RENDERER(self);
1277
1278         g_return_if_fail((renderer->states != 0) &&
1279                          (renderer->current_state != _LastMafwPlayState) &&
1280                          (renderer->states[renderer->current_state] != NULL));
1281
1282         mafw_gst_renderer_state_get_position(
1283                 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1284                 &pos,
1285                 &error);
1286         
1287         callback(self, pos, user_data, error);
1288         if (error)
1289                 g_error_free(error);
1290 }
1291
1292 void mafw_gst_renderer_set_position(MafwRenderer *self, MafwRendererSeekMode mode,
1293                                    gint seconds, MafwRendererPositionCB callback,
1294                                    gpointer user_data)
1295 {
1296         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1297         GError *error = NULL;
1298
1299         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1300
1301         g_return_if_fail((renderer->states != 0) &&
1302                          (renderer->current_state != _LastMafwPlayState) &&
1303                          (renderer->states[renderer->current_state] != NULL));
1304
1305         mafw_gst_renderer_state_set_position(
1306                 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1307                 mode,
1308                 seconds,
1309                 &error);
1310
1311         if (callback != NULL)
1312                 callback(self, seconds, user_data, error);
1313         if (error)
1314                 g_error_free(error);
1315 }
1316
1317 gboolean mafw_gst_renderer_manage_error_idle(gpointer data)
1318 {
1319         MafwGstRendererErrorClosure *mec = (MafwGstRendererErrorClosure *) data;
1320
1321         mafw_gst_renderer_manage_error(mec->renderer, mec->error);
1322         if (mec->error)
1323                 g_error_free(mec->error);
1324         g_free(mec);
1325
1326         return FALSE;
1327 }
1328
1329 static void _run_error_policy(MafwGstRenderer *self, const GError *in_err,
1330                               GError **out_err)
1331 {
1332         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1333
1334         gboolean play_next = FALSE;
1335
1336         /* Check what to do on error */
1337         if (in_err->code == MAFW_EXTENSION_ERROR_OUT_OF_MEMORY) {
1338                 play_next = FALSE;
1339         } else {
1340                 MafwGstRendererPlaybackMode mode;
1341
1342                 mode = mafw_gst_renderer_get_playback_mode(self);
1343
1344                 if (mode == MAFW_GST_RENDERER_MODE_PLAYLIST) {
1345                         /* In playlist mode we try to play next if
1346                            error policy suggests so */
1347                         play_next =
1348                                 (_get_error_policy(self) ==
1349                                  MAFW_RENDERER_ERROR_POLICY_CONTINUE);
1350                 } else {
1351                         /* In standalone mode, then switch back to playlist
1352                            mode and resume if necessary or move to Stopped
1353                            otherwise */
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),
1359                                                      NULL, NULL);
1360                         } else {
1361                                 mafw_gst_renderer_worker_stop(self->worker);
1362                                 mafw_gst_renderer_set_state(self, Stopped);
1363                         }
1364                         if (out_err) *out_err = g_error_copy(in_err);
1365
1366                         /* Bail out, he have already managed the error
1367                            for the case of standalone mode */
1368                         return;
1369                 }
1370         }
1371
1372         if (play_next) {
1373                 if (self->playlist){
1374                         MafwPlaylistIteratorMovementResult result;
1375
1376                         result = mafw_playlist_iterator_move_to_next(self->iterator,
1377                                                                       NULL);
1378                         self->play_failed_count++;
1379
1380                         if (mafw_playlist_iterator_get_size(self->iterator,
1381                                 NULL) <=
1382                                 self->play_failed_count)
1383                         {
1384                                 mafw_gst_renderer_state_stop(
1385                                         MAFW_GST_RENDERER_STATE(self->states[self->current_state]),
1386                                         NULL);
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);
1394                         } else {
1395                                 mafw_gst_renderer_set_media_playlist(self);
1396                                 mafw_gst_renderer_play(MAFW_RENDERER(self), NULL, NULL);
1397                         }
1398
1399                         if (out_err) *out_err = g_error_copy(in_err);
1400                 }
1401         } else {
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);
1406         }
1407 }
1408
1409 static void _metadata_set_cb(MafwSource *self, const gchar *object_id,
1410                                 const gchar **failed_keys, gpointer user_data,
1411                                 const GError *error)
1412 {
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);
1417         } else {
1418                 g_debug("Metadata set correctly");
1419         }
1420 }
1421
1422 /**
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
1429  *
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.
1432  */
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)
1438 {
1439         GValue *curval = NULL;
1440         gint curplaycount = -1;
1441         GHashTable *mdata = cb_user_data;
1442
1443         if (cb_error == NULL) {
1444                 if (cb_metadata)
1445                         curval = mafw_metadata_first(cb_metadata,
1446                                 MAFW_METADATA_KEY_PLAY_COUNT);
1447                 if (curval && !G_VALUE_HOLDS(curval, G_TYPE_INT))
1448                         goto set_data;
1449                 if (curval)
1450                 {
1451                         curplaycount = g_value_get_int(curval);
1452                         curplaycount++;
1453                 }
1454                 else
1455                 { /* Playing at first time, or not supported... */
1456                         curplaycount = 1;
1457                 }
1458                 if (!mdata)
1459                         mdata = mafw_metadata_new();
1460                 mafw_metadata_add_int(mdata,
1461                                         MAFW_METADATA_KEY_PLAY_COUNT,
1462                                         curplaycount);
1463
1464         } else {
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);
1468                 if (mdata)
1469                         g_hash_table_unref(mdata);
1470                 return;
1471         }
1472 set_data:
1473         
1474         if (mdata)
1475         {
1476                 mafw_source_set_metadata(cb_source, cb_object_id, mdata,
1477                                                 _metadata_set_cb, NULL);
1478                 g_hash_table_unref(mdata);
1479         }
1480 }
1481
1482 /**
1483  * mafw_gst_renderer_add_lastplayed:
1484  * @mdata:   Exisiting mdata, or NULL
1485  *
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.
1488  */
1489 static GHashTable *mafw_gst_renderer_add_lastplayed(GHashTable *mdata)
1490 {
1491         GHashTable *metadata;
1492         GTimeVal timeval;
1493
1494         
1495         if (!mdata)
1496                 metadata = mafw_metadata_new();
1497         else
1498                 metadata = mdata;
1499         
1500                 
1501
1502         g_get_current_time(&timeval);
1503                 
1504         mafw_metadata_add_long(metadata,
1505                                         MAFW_METADATA_KEY_LAST_PLAYED,
1506                                         timeval.tv_sec);
1507         return metadata;
1508 }
1509
1510 /**
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
1515  *
1516  * Increases the playcount of the given object.
1517  */
1518 static void mafw_gst_renderer_increase_playcount(MafwGstRenderer* self,
1519                                         const gchar *object_id, GHashTable *mdat)
1520 {
1521         MafwSource* source;
1522
1523         g_assert(self != NULL);
1524         source = _get_source(self, object_id);
1525         if (source != NULL)
1526         {
1527                 static const gchar * const keys[] =
1528                         { MAFW_METADATA_KEY_PLAY_COUNT, NULL };
1529
1530                 mafw_source_get_metadata(source, object_id,
1531                                          keys,
1532                                          _update_playcount_metadata_cb,
1533                                          mdat);
1534
1535         }
1536 }
1537
1538 /**
1539  * mafw_gst_renderer_update_stats:
1540  * @data: user data
1541  *
1542  * Updates both playcount and lastplayed after a while.
1543  **/
1544 gboolean mafw_gst_renderer_update_stats(gpointer data)
1545 {
1546         MafwGstRenderer *renderer = (MafwGstRenderer *) data;
1547
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,
1554                                                      mdata);
1555         }
1556         renderer->update_playcount_id = 0;
1557         return FALSE;
1558 }
1559
1560 void mafw_gst_renderer_update_source_duration(MafwGstRenderer *renderer,
1561                                               gint duration)
1562 {
1563         GHashTable *metadata;
1564         MafwSource* source;
1565
1566         source = _get_source(renderer, renderer->media->object_id);
1567         g_return_if_fail(source != NULL);
1568
1569         renderer->media->duration = duration;
1570
1571         g_debug("updated source duration to %d", duration);
1572
1573         metadata = mafw_metadata_new();
1574         mafw_metadata_add_int(metadata, MAFW_METADATA_KEY_DURATION, duration);
1575
1576         mafw_source_set_metadata(source, renderer->media->object_id, metadata,
1577                                  _metadata_set_cb, NULL);
1578         g_hash_table_unref(metadata);
1579 }
1580
1581 /**
1582  * _notify_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
1588  *
1589  * Receives the results of a metadata request.
1590  */
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)
1596 {
1597         MafwGstRenderer *renderer = (MafwGstRenderer*) cb_user_data;
1598         GError *mafw_error = NULL;
1599         GError *error = NULL;
1600         GValue *mval;
1601
1602         g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1603
1604         g_return_if_fail((renderer->states != 0) &&
1605                          (renderer->current_state != _LastMafwPlayState) &&
1606                          (renderer->states[renderer->current_state] != NULL));
1607
1608         g_debug("running _notify_metadata...");
1609
1610         mval = mafw_metadata_first(cb_metadata, MAFW_METADATA_KEY_URI);
1611
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]),
1616                         cb_object_id,
1617                         cb_metadata,
1618                         &error);
1619         }
1620         else {
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);
1627         }
1628 }
1629
1630 static void _notify_play(MafwGstRendererWorker *worker, gpointer owner)
1631 {
1632         MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1633         GError *error = NULL;
1634
1635         g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1636
1637         g_return_if_fail((renderer->states != 0) &&
1638                          (renderer->current_state != _LastMafwPlayState) &&
1639                          (renderer->states[renderer->current_state] != NULL));
1640
1641         g_debug("running _notify_play...");
1642
1643         mafw_gst_renderer_state_notify_play(renderer->states[renderer->current_state],
1644                                           &error);
1645
1646         if (error != NULL) {
1647                 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1648                                       error->domain,
1649                                       error->code,
1650                                       error->message);
1651                 g_error_free (error);
1652         }
1653 }
1654
1655 static void _notify_pause(MafwGstRendererWorker *worker, gpointer owner)
1656 {
1657         MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1658         GError *error = NULL;
1659
1660         g_return_if_fail(MAFW_IS_GST_RENDERER (renderer));
1661
1662         g_return_if_fail((renderer->states != 0) &&
1663                          (renderer->current_state != _LastMafwPlayState) &&
1664                          (renderer->states[renderer->current_state] != NULL));
1665
1666         mafw_gst_renderer_state_notify_pause(renderer->states[renderer->current_state],
1667                                            &error);
1668
1669         if (error != NULL) {
1670                 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1671                                       error->domain, error->code,
1672                                       error->message);
1673                 g_error_free(error);
1674         }
1675 }
1676
1677 static void _notify_buffer_status (MafwGstRendererWorker *worker,
1678                                    gpointer owner,
1679                                    gdouble percent)
1680 {
1681         MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1682         GError *error = NULL;
1683
1684         g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1685
1686         g_return_if_fail((renderer->states != 0) &&
1687                          (renderer->current_state != _LastMafwPlayState) &&
1688                          (renderer->states[renderer->current_state] != NULL));
1689
1690         mafw_gst_renderer_state_notify_buffer_status(
1691                 renderer->states[renderer->current_state],
1692                 percent,
1693                 &error);
1694
1695         if (error != NULL) {
1696                 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1697                                       error->domain, error->code,
1698                                       error->message);
1699                 g_error_free(error);
1700         }
1701 }
1702
1703 static void _notify_seek(MafwGstRendererWorker *worker, gpointer owner)
1704 {
1705         MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1706         GError *error = NULL;
1707
1708         g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1709
1710         g_return_if_fail((renderer->states != 0) &&
1711                          (renderer->current_state != _LastMafwPlayState) &&
1712                          (renderer->states[renderer->current_state] != NULL));
1713
1714         mafw_gst_renderer_state_notify_seek(renderer->states[renderer->current_state],
1715                                           &error);
1716
1717         if (error != NULL) {
1718                 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1719                                       error->domain, error->code,
1720                                       error->message);
1721                 g_error_free(error);
1722         }
1723 }
1724
1725 static void _playlist_changed_handler(MafwPlaylistIterator *iterator,
1726                                       gboolean clip_changed, GQuark domain,
1727                                       gint code, const gchar *message,
1728                                       gpointer user_data)
1729 {
1730         MafwGstRenderer *renderer = (MafwGstRenderer*) user_data;
1731
1732         g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1733
1734         g_return_if_fail((renderer->states != 0) &&
1735                          (renderer->current_state != _LastMafwPlayState) &&
1736                          (renderer->states[renderer->current_state] != NULL));
1737
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) */
1741
1742         if (renderer->playlist == NULL) {
1743                 g_critical("Got iterator:contents-changed but renderer has no" \
1744                            "playlist assigned!. Skipping...");
1745                 return;
1746         }
1747
1748         if (domain != 0) {
1749                 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1750                                       domain, code, message);
1751         } else {
1752                 GError *error = NULL;
1753                 MafwGstRendererPlaybackMode mode;
1754                 
1755                 mode = mafw_gst_renderer_get_playback_mode(renderer);
1756
1757                 /* Only in non-playobject mode */               
1758                 if (clip_changed && mode == MAFW_GST_RENDERER_MODE_PLAYLIST)
1759                         mafw_gst_renderer_set_media_playlist(renderer);
1760
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],
1765                         clip_changed,
1766                         &error);
1767
1768                 if (error != NULL) {
1769                         g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1770                                               error->domain, error->code,
1771                                               error->message);
1772                         g_error_free(error);
1773                 }
1774         }
1775 }
1776
1777 static void _error_handler(MafwGstRendererWorker *worker, gpointer owner,
1778                            const GError *error)
1779 {
1780         MafwGstRenderer *renderer = MAFW_GST_RENDERER(owner);
1781
1782         mafw_gst_renderer_manage_error(renderer, error);
1783 }
1784
1785 void mafw_gst_renderer_manage_error(MafwGstRenderer *self, const GError *error)
1786 {
1787         GError *new_err = NULL;
1788         GError *raise_error = NULL;
1789         GQuark new_err_domain = MAFW_RENDERER_ERROR;
1790         gint new_err_code = 0;
1791
1792         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1793
1794         g_return_if_fail((self->states != 0) &&
1795                          (self->current_state != _LastMafwPlayState) &&
1796                          (self->states[self->current_state] != NULL));
1797
1798         g_warning("Got error in renderer:\n\tdomain: %d, code: %d, message: %s",
1799                   error->domain, error->code, error->message);
1800
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)) {
1807 #ifdef HAVE_CONIC
1808                                 if (self->connected) {
1809                                         new_err_code = MAFW_RENDERER_ERROR_STREAM_DISCONNECTED;
1810                                 } else {
1811                                         new_err_domain = MAFW_EXTENSION_ERROR;
1812                                         new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1813                                 }
1814 #else
1815                                 /* Stream + cannot read resource ->
1816                                    disconnected */
1817                                 new_err_code = MAFW_RENDERER_ERROR_STREAM_DISCONNECTED;
1818 #endif
1819                         } else {
1820                                 /* This shouldn't happen */
1821                                 /* Unknown RESOURCE error */
1822                                 new_err_domain = MAFW_EXTENSION_ERROR;
1823                                 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1824                         }
1825                         break;
1826                 case GST_RESOURCE_ERROR_NOT_FOUND:
1827 #ifdef HAVE_CONIC
1828                         if (!is_current_uri_stream(self) || self->connected) {
1829                                 new_err_code =
1830                                         MAFW_RENDERER_ERROR_INVALID_URI;
1831                         } else {
1832                                 new_err_domain = MAFW_EXTENSION_ERROR;
1833                                 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1834                         }
1835 #else
1836                         new_err_code =
1837                                 MAFW_RENDERER_ERROR_INVALID_URI;
1838 #endif
1839                         break;
1840                 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
1841                 case GST_RESOURCE_ERROR_OPEN_READ:
1842 #ifdef HAVE_CONIC
1843                         if (!is_current_uri_stream(self) || self->connected) {
1844                                 new_err_code =
1845                                         MAFW_RENDERER_ERROR_MEDIA_NOT_FOUND;
1846                         } else {
1847                                 new_err_domain = MAFW_EXTENSION_ERROR;
1848                                 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1849                         }
1850 #else
1851                         new_err_code =
1852                                 MAFW_RENDERER_ERROR_MEDIA_NOT_FOUND;
1853 #endif
1854                         break;
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;
1858                         break;
1859                 case GST_RESOURCE_ERROR_WRITE:
1860                         /* DSP renderers send ERROR_WRITE when they find
1861                            corrupted data */
1862                         new_err_code = MAFW_RENDERER_ERROR_CORRUPTED_FILE;
1863                         break;
1864                 case GST_RESOURCE_ERROR_SEEK:
1865                         new_err_code = MAFW_RENDERER_ERROR_CANNOT_SET_POSITION;
1866                         break;
1867                 default:
1868                         /* Unknown RESOURCE error */
1869                         new_err_domain = MAFW_EXTENSION_ERROR;
1870                         new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1871                 }
1872
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;
1878                         break;
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;
1883                         break;
1884                 case GST_STREAM_ERROR_DECODE:
1885                 case GST_STREAM_ERROR_DEMUX:
1886                         new_err_code = MAFW_RENDERER_ERROR_CORRUPTED_FILE;
1887                         break;
1888                 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
1889                         new_err_code = MAFW_RENDERER_ERROR_CODEC_NOT_FOUND;
1890                         break;
1891                 case GST_STREAM_ERROR_DECRYPT:
1892                 case GST_STREAM_ERROR_DECRYPT_NOKEY:
1893                         new_err_code = MAFW_RENDERER_ERROR_DRM;
1894                         break;
1895                 default:
1896                         /* Unknown STREAM error */
1897                         new_err_domain = MAFW_EXTENSION_ERROR;
1898                         new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1899                 }
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;
1910         } else {
1911                 /* default */
1912                 /* Unknown error */
1913                 new_err_domain = MAFW_EXTENSION_ERROR;
1914                 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1915         }
1916
1917         g_set_error(&new_err, new_err_domain, new_err_code, "%s", error->message);
1918
1919         _run_error_policy(self, new_err, &raise_error);
1920         g_error_free(new_err);
1921
1922         if (raise_error) {
1923                 g_signal_emit_by_name(MAFW_EXTENSION (self), "error",
1924                                       raise_error->domain,
1925                                       raise_error->code,
1926                                       raise_error->message);
1927                 g_error_free(raise_error);
1928         }
1929 }
1930
1931 static void _notify_eos(MafwGstRendererWorker *worker, gpointer owner)
1932 {
1933         MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1934         GError *error = NULL;
1935
1936         g_return_if_fail(MAFW_IS_GST_RENDERER (renderer));
1937
1938         g_return_if_fail((renderer->states != 0) &&
1939                          (renderer->current_state != _LastMafwPlayState) &&
1940                          (renderer->states[renderer->current_state] != NULL));
1941
1942         mafw_gst_renderer_state_notify_eos(renderer->states[renderer->current_state],
1943                                          &error);
1944
1945         if (error != NULL) {
1946                 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1947                                       error->domain, error->code,
1948                                       error->message);
1949                 g_error_free(error);
1950         }
1951 }
1952
1953 /*----------------------------------------------------------------------------
1954   Status
1955   ----------------------------------------------------------------------------*/
1956
1957 void mafw_gst_renderer_get_status(MafwRenderer *self, MafwRendererStatusCB callback,
1958                                 gpointer user_data)
1959 {
1960         MafwGstRenderer* renderer;
1961         gint index;
1962         MafwGstRendererPlaybackMode mode;
1963
1964         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1965         g_return_if_fail(callback != NULL);
1966         renderer = MAFW_GST_RENDERER(self);
1967
1968         mode = mafw_gst_renderer_get_playback_mode(MAFW_GST_RENDERER(self));
1969         if ((mode == MAFW_GST_RENDERER_MODE_STANDALONE) || (renderer->iterator == NULL)) {
1970                 index = -1;
1971         } else {
1972                 index =
1973                         mafw_playlist_iterator_get_current_index(renderer->iterator);
1974         }
1975
1976         /* TODO: Set error parameter */
1977         callback(self, renderer->playlist, index, renderer->current_state,
1978                  (const gchar*) renderer->media->object_id, user_data, NULL);
1979 }
1980
1981 void mafw_gst_renderer_get_current_metadata(MafwRenderer *self,
1982                                             MafwRendererMetadataResultCB callback,
1983                                             gpointer user_data)
1984 {
1985         MafwGstRenderer *renderer;
1986         GHashTable *metadata;
1987
1988         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1989         renderer = MAFW_GST_RENDERER(self);
1990
1991         metadata = mafw_gst_renderer_worker_get_current_metadata(
1992                         renderer->worker);
1993
1994         callback(self,
1995                  (const gchar*) renderer->media->object_id,
1996                  metadata,
1997                  user_data,
1998                  NULL);
1999 }
2000
2001 /*----------------------------------------------------------------------------
2002   Playlist
2003   ----------------------------------------------------------------------------*/
2004
2005 static void
2006 _playlist_contents_changed_handler(MafwPlaylist *playlist,
2007                                         guint from, guint nremove,
2008                                         guint nreplace,
2009                                         MafwGstRenderer *renderer)
2010 {
2011         /* Item(s) added to playlist, so new playable items could come */
2012         if (nreplace)
2013                 renderer->play_failed_count = 0;
2014 }
2015
2016 gboolean mafw_gst_renderer_assign_playlist(MafwRenderer *self,
2017                                            MafwPlaylist *playlist,
2018                                            GError **error)
2019 {
2020         MafwGstRenderer* renderer = (MafwGstRenderer*) self;
2021
2022         g_return_val_if_fail(MAFW_IS_GST_RENDERER(self), FALSE);
2023
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,
2028                                                      0, 0, NULL,
2029                                                      _playlist_changed_handler,
2030                                                      NULL);
2031                 g_signal_handlers_disconnect_matched(renderer->playlist,
2032                                         (GSignalMatchType) G_SIGNAL_MATCH_FUNC,
2033                                         0, 0, NULL,
2034                                         G_CALLBACK(_playlist_contents_changed_handler),
2035                                         NULL);
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);
2039
2040                 g_object_unref(renderer->iterator);
2041                 g_object_unref(renderer->playlist);
2042         }
2043
2044         /* Assign the new playlist */
2045         if (playlist == NULL) {
2046                 renderer->playlist = NULL;
2047                 renderer->iterator = NULL;
2048         } else {
2049                 GError *new_error = NULL;
2050                 MafwPlaylistIterator *iterator = NULL;
2051
2052                 iterator = mafw_playlist_iterator_new();
2053                 mafw_playlist_iterator_initialize(iterator, playlist,
2054                                                    &new_error);
2055                 
2056                 g_object_ref(playlist);
2057
2058                 if (new_error == NULL) {
2059
2060                         renderer->playlist = playlist;
2061                         renderer->iterator = iterator;
2062
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);
2066
2067                         g_signal_connect(iterator,
2068                                          "playlist-changed",
2069                                          G_CALLBACK(_playlist_changed_handler),
2070                                          renderer);
2071                         g_signal_connect(renderer->playlist,
2072                                          "contents-changed",
2073                                          G_CALLBACK(_playlist_contents_changed_handler),
2074                                          renderer);
2075                 }
2076                 else {
2077                         g_propagate_error (error, new_error);
2078                 }
2079         }
2080
2081         /* Set the new media and signal playlist changed signal */
2082         _signal_playlist_changed(renderer);
2083         mafw_gst_renderer_set_media_playlist(renderer);
2084
2085
2086         /* Stop playback */
2087         mafw_gst_renderer_stop(MAFW_RENDERER(renderer), NULL , NULL);
2088
2089         return TRUE;
2090 }
2091
2092 MafwGstRendererMovementResult mafw_gst_renderer_move(MafwGstRenderer *renderer,
2093                                                    MafwGstRendererMovementType type,
2094                                                    guint index,
2095                                                    GError **error)
2096 {
2097         MafwGstRendererMovementResult value = MAFW_GST_RENDERER_MOVE_RESULT_OK;
2098
2099         if (renderer->playlist == NULL) {
2100                 value = MAFW_GST_RENDERER_MOVE_RESULT_NO_PLAYLIST;
2101         } else {
2102                 MafwPlaylistIteratorMovementResult result;
2103
2104                 switch (type) {
2105                 case MAFW_GST_RENDERER_MOVE_TYPE_INDEX:
2106                         result =
2107                                 mafw_playlist_iterator_move_to_index(renderer->iterator,
2108                                                                       index,
2109                                                                       error);
2110                         break;
2111                 case MAFW_GST_RENDERER_MOVE_TYPE_PREV:
2112                         result =
2113                                 mafw_playlist_iterator_move_to_prev(renderer->iterator,
2114                                                                      error);
2115                         break;
2116                 case MAFW_GST_RENDERER_MOVE_TYPE_NEXT:
2117                         result =
2118                                 mafw_playlist_iterator_move_to_next(renderer->iterator,
2119                                                                      error);
2120                         break;
2121                 }
2122
2123                 switch (result) {
2124                 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_OK:
2125                         value = MAFW_GST_RENDERER_MOVE_RESULT_OK;
2126                         mafw_gst_renderer_set_media_playlist(renderer);
2127                         break;
2128                 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_INVALID:
2129                         g_critical("Iterator is invalid!");
2130                         value = MAFW_GST_RENDERER_MOVE_RESULT_ERROR;
2131                         break;
2132                 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_ERROR:
2133                         value = MAFW_GST_RENDERER_MOVE_RESULT_ERROR;
2134                         break;
2135                 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_LIMIT:
2136                         value = MAFW_GST_RENDERER_MOVE_RESULT_PLAYLIST_LIMIT;
2137                         break;
2138                 }
2139         }
2140
2141         return value;
2142 }
2143
2144 /*----------------------------------------------------------------------------
2145   Properties
2146   ----------------------------------------------------------------------------*/
2147
2148 static void _set_error_policy(MafwGstRenderer *renderer, MafwRendererErrorPolicy policy)
2149 {
2150         renderer->error_policy = policy;
2151 }
2152
2153 static MafwRendererErrorPolicy _get_error_policy(MafwGstRenderer *renderer)
2154 {
2155         return renderer->error_policy;
2156 }
2157
2158 static void mafw_gst_renderer_get_property(MafwExtension *self,
2159                                          const gchar *key,
2160                                          MafwExtensionPropertyCallback callback,
2161                                          gpointer user_data)
2162 {
2163         MafwGstRenderer *renderer;
2164         GValue *value = NULL;
2165         GError *error = NULL;
2166
2167         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
2168         g_return_if_fail(callback != NULL);
2169         g_return_if_fail(key != NULL);
2170
2171         renderer = MAFW_GST_RENDERER(self);
2172         if (!strcmp(key, MAFW_PROPERTY_RENDERER_VOLUME)) {
2173                 guint volume;
2174
2175                 volume = mafw_gst_renderer_worker_get_volume(
2176                         renderer->worker);
2177
2178                 value = g_new0(GValue, 1);
2179                 g_value_init(value, G_TYPE_UINT);
2180                 g_value_set_uint(value, volume);
2181         }
2182         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_MUTE)) {
2183                 gboolean 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);
2188         }
2189         else if (!strcmp (key, MAFW_PROPERTY_RENDERER_XID)) {
2190                 guint 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);
2195         }
2196         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_ERROR_POLICY)) {
2197                 guint 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);
2202         }
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(
2207                         value,
2208                         mafw_gst_renderer_worker_get_autopaint(
2209                                 renderer->worker));
2210         } else if (!strcmp(key, MAFW_PROPERTY_RENDERER_COLORKEY)) {
2211                 value = g_new0(GValue, 1);
2212                 g_value_init(value, G_TYPE_INT);
2213                 g_value_set_int(
2214                         value,
2215                         mafw_gst_renderer_worker_get_colorkey(
2216                                 renderer->worker));
2217         }
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);
2227         }
2228 #endif
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);
2234         }
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);
2242
2243                 if (!value) {
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");
2249                 }
2250         }
2251         else {
2252                 /* Unsupported property */
2253                 error = g_error_new(MAFW_GST_RENDERER_ERROR,
2254                                     MAFW_EXTENSION_ERROR_GET_PROPERTY,
2255                                     "Unsupported property");
2256         }
2257
2258         callback(self, key, value, user_data, error);
2259 }
2260
2261 static void mafw_gst_renderer_set_property(MafwExtension *self,
2262                                          const gchar *key,
2263                                          const GValue *value)
2264 {
2265         MafwGstRenderer *renderer;
2266
2267         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
2268         g_return_if_fail(key != NULL);
2269
2270         renderer = MAFW_GST_RENDERER(self);
2271
2272         if (!strcmp(key, MAFW_PROPERTY_RENDERER_VOLUME)) {
2273                 guint volume = g_value_get_uint(value);
2274                 if (volume > 100)
2275                         volume = 100;
2276                 mafw_gst_renderer_worker_set_volume(renderer->worker,
2277                                                            volume);
2278                 /* Property-changed emision is done by worker */
2279                 return;
2280         }
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);
2284         }
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);
2288         }
2289         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_ERROR_POLICY)) {
2290                 MafwRendererErrorPolicy policy = g_value_get_uint(value);
2291                 _set_error_policy(renderer, policy);
2292         }
2293         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_AUTOPAINT)) {
2294                 mafw_gst_renderer_worker_set_autopaint(
2295                         renderer->worker,
2296                         g_value_get_boolean(value));
2297         }
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);
2304         }
2305 #endif
2306         else return;
2307
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);
2312 }
2313
2314 /* vi: set noexpandtab ts=8 sw=8 cino=t0,(0: */