Created fork of mafw-gst-renderer with subtitles support
[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_SUBTITLE_RENDERER "/system/mafw/mafw-gst-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_SUBTITLE_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_SUBTITLE_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_SUBTITLE_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_SUBTITLE_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_SUBTITLE_RENDERER "/autoload_subtitles");
404
405                 gconf_client_notify(renderer->gconf_client,
406                                     GCONF_MAFW_GST_SUBTITLE_RENDERER "/subtitle_encoding");
407
408                 gconf_client_notify(renderer->gconf_client,
409                                     GCONF_MAFW_GST_SUBTITLE_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_SUBTITLE_RENDERER) + 1;
928
929         value = gconf_entry_get_value(entry);
930         if (value == NULL)
931                 return;
932
933         str_value = gconf_value_get_string(value);
934
935         if (strcmp(key, "subtitle_font") == 0) {
936                 if (renderer->worker->subtitles.font)
937                         g_free(renderer->worker->subtitles.font);
938
939                 renderer->worker->subtitles.font = g_strdup(str_value);
940         } else if (strcmp(key, "subtitle_encoding") == 0) {
941                 if (renderer->worker->subtitles.encoding)
942                         g_free(renderer->worker->subtitles.encoding);
943
944                 renderer->worker->subtitles.encoding = g_strdup(str_value);
945         } else {
946                 g_warning("Wrong %s key, %s", GCONF_MAFW_GST_SUBTITLE_RENDERER, key);
947         }
948 }
949
950 /*----------------------------------------------------------------------------
951   Gnome VFS notifications
952   ----------------------------------------------------------------------------*/
953
954 static void _volume_pre_unmount_cb(GnomeVFSVolumeMonitor *monitor, 
955                                    GnomeVFSVolume *volume,
956                                    MafwGstRenderer *renderer)
957 {
958         gchar *location = gnome_vfs_volume_get_activation_uri(volume);
959         if (!location) {
960                 return;
961         }
962         
963         mafw_gst_renderer_state_handle_pre_unmount(
964                 MAFW_GST_RENDERER_STATE(
965                         renderer->states[renderer->current_state]),
966                 location);
967         
968         g_free(location);
969 }
970
971 /*----------------------------------------------------------------------------
972   Signals
973   ----------------------------------------------------------------------------*/
974
975
976 /**
977  * _signal_state_changed:
978  * @self: A #MafwGstRenderer
979  *
980  * Signals state_changed to all UIs
981  **/
982 static void _signal_state_changed(MafwGstRenderer * self)
983 {
984         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
985
986         g_signal_emit_by_name(MAFW_RENDERER(self),
987                               "state-changed", self->current_state);
988 }
989
990 /**
991  * _signal_playlist_changed:
992  * @self: A #MafwGstRenderer
993  *
994  * Signals playlist update to all UIs
995  **/
996 static void _signal_playlist_changed(MafwGstRenderer * self)
997 {
998         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
999
1000         g_signal_emit_by_name(MAFW_RENDERER(self),
1001                               "playlist-changed", self->playlist);
1002 }
1003
1004 /**
1005  * _signal_media_changed:
1006  * @self: A #MafwGstRenderer
1007  *
1008  * Signals media_changed to all UIs
1009  **/
1010 static void _signal_media_changed(MafwGstRenderer *self)
1011 {
1012
1013         MafwGstRendererPlaybackMode mode;
1014         gint index;
1015
1016         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1017
1018         mode = mafw_gst_renderer_get_playback_mode(MAFW_GST_RENDERER(self));
1019         if ((mode == MAFW_GST_RENDERER_MODE_STANDALONE) ||
1020             (self->iterator == NULL)) {
1021                 index = -1;
1022         } else {
1023                 index = mafw_playlist_iterator_get_current_index(self->iterator);
1024         }
1025
1026         g_signal_emit_by_name(MAFW_RENDERER(self),
1027                               "media-changed",
1028                               index,
1029                               self->media->object_id);
1030 }
1031
1032 /**
1033  * _signal_transport_actions_property_changed:
1034  * @self: A #MafwGstRenderer
1035  *
1036  * Signals transport_actions property_changed to all UIs
1037  **/
1038 static void _signal_transport_actions_property_changed(MafwGstRenderer * self)
1039 {
1040         GValue *value;
1041
1042         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1043
1044         value = mafw_gst_renderer_state_get_property_value(
1045                 MAFW_GST_RENDERER_STATE(
1046                         self->states[self->current_state]),
1047                 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS);
1048
1049         if (value) {
1050                 mafw_extension_emit_property_changed(
1051                         MAFW_EXTENSION(self),
1052                         MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS,
1053                         value);
1054                 g_value_unset(value);
1055                 g_free(value);
1056         }
1057 }
1058
1059
1060 /*----------------------------------------------------------------------------
1061   State pattern support
1062   ----------------------------------------------------------------------------*/
1063
1064 void mafw_gst_renderer_set_state(MafwGstRenderer *self, MafwPlayState state)
1065 {
1066         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1067
1068         self->current_state = state;
1069         _signal_state_changed(self);
1070         _signal_transport_actions_property_changed(self);
1071 }
1072
1073 void mafw_gst_renderer_play(MafwRenderer *self, MafwRendererPlaybackCB callback,
1074                           gpointer user_data)
1075 {
1076         MafwGstRenderer *renderer = (MafwGstRenderer*) self;
1077         GError *error = NULL;
1078
1079         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1080
1081         g_return_if_fail((renderer->states != 0) &&
1082                          (renderer->current_state != _LastMafwPlayState) &&
1083                          (renderer->states[renderer->current_state] != NULL));
1084
1085         mafw_gst_renderer_state_play(
1086                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1087                 &error);
1088
1089         if (callback != NULL)
1090                 callback(self, user_data, error);
1091         if (error)
1092                 g_error_free(error);
1093 }
1094
1095 void mafw_gst_renderer_play_object(MafwRenderer *self,
1096                                  const gchar *object_id,
1097                                  MafwRendererPlaybackCB callback,
1098                                  gpointer user_data)
1099 {
1100         MafwGstRenderer *renderer = (MafwGstRenderer*) self;
1101         GError *error = NULL;
1102
1103         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1104         g_return_if_fail(object_id != NULL);
1105
1106         g_return_if_fail((renderer->states != 0) &&
1107                          (renderer->current_state != _LastMafwPlayState) &&
1108                          (renderer->states[renderer->current_state] != NULL));
1109
1110         mafw_gst_renderer_state_play_object(
1111                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1112                 object_id,
1113                 &error);
1114
1115         if (callback != NULL)
1116                 callback(self, user_data, error);
1117         if (error)
1118                 g_error_free(error);
1119 }
1120
1121 void mafw_gst_renderer_stop(MafwRenderer *self, MafwRendererPlaybackCB callback,
1122                           gpointer user_data)
1123 {
1124         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1125         GError *error = NULL;
1126
1127         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1128
1129         g_return_if_fail((renderer->states != 0) &&
1130                          (renderer->current_state != _LastMafwPlayState) &&
1131                          (renderer->states[renderer->current_state] != NULL));
1132
1133         renderer->play_failed_count = 0;
1134         mafw_gst_renderer_state_stop(
1135                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1136                 &error);
1137
1138         if (callback != NULL)
1139                 callback(self, user_data, error);
1140         if (error)
1141                 g_error_free(error);
1142 }
1143
1144
1145 void mafw_gst_renderer_pause(MafwRenderer *self, MafwRendererPlaybackCB callback,
1146                            gpointer user_data)
1147 {
1148         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1149         GError *error = NULL;
1150
1151         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1152
1153         g_return_if_fail((renderer->states != 0) &&
1154                          (renderer->current_state != _LastMafwPlayState) &&
1155                          (renderer->states[renderer->current_state] != NULL));
1156
1157         mafw_gst_renderer_state_pause(
1158                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1159                 &error);
1160
1161         if (callback != NULL)
1162                 callback(self, user_data, error);
1163         if (error)
1164                 g_error_free(error);
1165 }
1166
1167 void mafw_gst_renderer_resume(MafwRenderer *self, MafwRendererPlaybackCB callback,
1168                             gpointer user_data)
1169 {
1170         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1171         GError *error = NULL;
1172
1173         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1174
1175         g_return_if_fail((renderer->states != 0) &&
1176                          (renderer->current_state != _LastMafwPlayState) &&
1177                          (renderer->states[renderer->current_state] != NULL));
1178
1179         mafw_gst_renderer_state_resume(
1180                 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1181                 &error);
1182
1183         if (callback != NULL)
1184                 callback(self, user_data, error);
1185         if (error)
1186                 g_error_free(error);
1187 }
1188
1189 void mafw_gst_renderer_next(MafwRenderer *self, MafwRendererPlaybackCB callback,
1190                           gpointer user_data)
1191 {
1192         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1193         GError *error = NULL;
1194
1195         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1196
1197         g_return_if_fail((renderer->states != 0) &&
1198                          (renderer->current_state != _LastMafwPlayState) &&
1199                          (renderer->states[renderer->current_state] != NULL));
1200
1201         renderer->play_failed_count = 0;
1202         mafw_gst_renderer_state_next(
1203                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1204                 &error);
1205
1206         if (callback != NULL)
1207                 callback(self, user_data, error);
1208         if (error)
1209                 g_error_free(error);
1210 }
1211
1212 void mafw_gst_renderer_previous(MafwRenderer *self, MafwRendererPlaybackCB callback,
1213                               gpointer user_data)
1214 {
1215         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1216         GError *error = NULL;
1217
1218         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1219
1220         g_return_if_fail((renderer->states != 0) &&
1221                          (renderer->current_state != _LastMafwPlayState) &&
1222                          (renderer->states[renderer->current_state] != NULL));
1223
1224         renderer->play_failed_count = 0;
1225         mafw_gst_renderer_state_previous(
1226                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1227                 &error);
1228
1229         if (callback != NULL)
1230                 callback(self, user_data, error);
1231         if (error)
1232                 g_error_free(error);
1233 }
1234
1235 void mafw_gst_renderer_goto_index(MafwRenderer *self, guint index,
1236                                 MafwRendererPlaybackCB callback,
1237                                 gpointer user_data)
1238 {
1239         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1240         GError *error = NULL;
1241
1242         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1243
1244         g_return_if_fail((renderer->states != 0) &&
1245                          (renderer->current_state != _LastMafwPlayState) &&
1246                          (renderer->states[renderer->current_state] != NULL));
1247
1248         renderer->play_failed_count = 0;
1249         mafw_gst_renderer_state_goto_index(
1250                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1251                 index,
1252                 &error);
1253
1254         if (callback != NULL)
1255                 callback(self, user_data, error);
1256         if (error)
1257                 g_error_free(error);
1258 }
1259
1260 void mafw_gst_renderer_get_position(MafwRenderer *self, MafwRendererPositionCB callback,
1261                                   gpointer user_data)
1262 {
1263         MafwGstRenderer *renderer;
1264         gint pos;
1265         GError *error = NULL;
1266
1267         g_return_if_fail(callback != NULL);
1268         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1269
1270         renderer = MAFW_GST_RENDERER(self);
1271
1272         g_return_if_fail((renderer->states != 0) &&
1273                          (renderer->current_state != _LastMafwPlayState) &&
1274                          (renderer->states[renderer->current_state] != NULL));
1275
1276         mafw_gst_renderer_state_get_position(
1277                 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1278                 &pos,
1279                 &error);
1280         
1281         callback(self, pos, user_data, error);
1282         if (error)
1283                 g_error_free(error);
1284 }
1285
1286 void mafw_gst_renderer_set_position(MafwRenderer *self, MafwRendererSeekMode mode,
1287                                    gint seconds, MafwRendererPositionCB callback,
1288                                    gpointer user_data)
1289 {
1290         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1291         GError *error = NULL;
1292
1293         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1294
1295         g_return_if_fail((renderer->states != 0) &&
1296                          (renderer->current_state != _LastMafwPlayState) &&
1297                          (renderer->states[renderer->current_state] != NULL));
1298
1299         mafw_gst_renderer_state_set_position(
1300                 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1301                 mode,
1302                 seconds,
1303                 &error);
1304
1305         if (callback != NULL)
1306                 callback(self, seconds, user_data, error);
1307         if (error)
1308                 g_error_free(error);
1309 }
1310
1311 gboolean mafw_gst_renderer_manage_error_idle(gpointer data)
1312 {
1313         MafwGstRendererErrorClosure *mec = (MafwGstRendererErrorClosure *) data;
1314
1315         mafw_gst_renderer_manage_error(mec->renderer, mec->error);
1316         if (mec->error)
1317                 g_error_free(mec->error);
1318         g_free(mec);
1319
1320         return FALSE;
1321 }
1322
1323 static void _run_error_policy(MafwGstRenderer *self, const GError *in_err,
1324                               GError **out_err)
1325 {
1326         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1327
1328         gboolean play_next = FALSE;
1329
1330         /* Check what to do on error */
1331         if (in_err->code == MAFW_EXTENSION_ERROR_OUT_OF_MEMORY) {
1332                 play_next = FALSE;
1333         } else {
1334                 MafwGstRendererPlaybackMode mode;
1335
1336                 mode = mafw_gst_renderer_get_playback_mode(self);
1337
1338                 if (mode == MAFW_GST_RENDERER_MODE_PLAYLIST) {
1339                         /* In playlist mode we try to play next if
1340                            error policy suggests so */
1341                         play_next =
1342                                 (_get_error_policy(self) ==
1343                                  MAFW_RENDERER_ERROR_POLICY_CONTINUE);
1344                 } else {
1345                         /* In standalone mode, then switch back to playlist
1346                            mode and resume if necessary or move to Stopped
1347                            otherwise */
1348                         mafw_gst_renderer_set_playback_mode(
1349                                 self, MAFW_GST_RENDERER_MODE_PLAYLIST);
1350                         mafw_gst_renderer_set_media_playlist(self);
1351                         if (self->resume_playlist) {
1352                                 mafw_gst_renderer_play(MAFW_RENDERER(self),
1353                                                      NULL, NULL);
1354                         } else {
1355                                 mafw_gst_renderer_worker_stop(self->worker);
1356                                 mafw_gst_renderer_set_state(self, Stopped);
1357                         }
1358                         if (out_err) *out_err = g_error_copy(in_err);
1359
1360                         /* Bail out, he have already managed the error
1361                            for the case of standalone mode */
1362                         return;
1363                 }
1364         }
1365
1366         if (play_next) {
1367                 if (self->playlist){
1368                         MafwPlaylistIteratorMovementResult result;
1369
1370                         result = mafw_playlist_iterator_move_to_next(self->iterator,
1371                                                                       NULL);
1372                         self->play_failed_count++;
1373
1374                         if (mafw_playlist_iterator_get_size(self->iterator,
1375                                 NULL) <=
1376                                 self->play_failed_count)
1377                         {
1378                                 mafw_gst_renderer_state_stop(
1379                                         MAFW_GST_RENDERER_STATE(self->states[self->current_state]),
1380                                         NULL);
1381                                 self->play_failed_count = 0;
1382                                 mafw_gst_renderer_set_media_playlist(self);
1383                         } else if (result !=
1384                                    MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_OK) {
1385                                 mafw_playlist_iterator_reset(self->iterator, NULL);
1386                                 mafw_gst_renderer_set_media_playlist(self);
1387                                 mafw_gst_renderer_stop(MAFW_RENDERER(self), NULL, NULL);
1388                         } else {
1389                                 mafw_gst_renderer_set_media_playlist(self);
1390                                 mafw_gst_renderer_play(MAFW_RENDERER(self), NULL, NULL);
1391                         }
1392
1393                         if (out_err) *out_err = g_error_copy(in_err);
1394                 }
1395         } else {
1396                 /* We cannot move to next in the playlist or decided
1397                    we do not want to do it, just stop on error */
1398                 mafw_gst_renderer_stop(MAFW_RENDERER(self), NULL, NULL);
1399                 if (out_err) *out_err = g_error_copy(in_err);
1400         }
1401 }
1402
1403 static void _metadata_set_cb(MafwSource *self, const gchar *object_id,
1404                                 const gchar **failed_keys, gpointer user_data,
1405                                 const GError *error)
1406 {
1407         if (error != NULL) {
1408                 g_debug("Ignoring error received when setting metadata: "
1409                         "%s (%d): %s", g_quark_to_string(error->domain),
1410                         error->code, error->message);
1411         } else {
1412                 g_debug("Metadata set correctly");
1413         }
1414 }
1415
1416 /**
1417  * _update_playcount_metadata_cb:
1418  * @cb_source:   The #MafwSource that sent the metadata results
1419  * @cb_object_id: The object ID, whose metadata results were received
1420  * @cb_metadata: GHashTable containing metadata key-value pairs
1421  * @cb_user_data: Optional user data pointer (self)
1422  * @cb_error:    Set if any errors occurred during metadata browsing
1423  *
1424  * Receives the results of a metadata request about the playcount. It increases
1425  * it, or sets to 1, and sets the metadata to that.
1426  */
1427 static void _update_playcount_metadata_cb (MafwSource *cb_source,
1428                                            const gchar *cb_object_id,
1429                                            GHashTable *cb_metadata,
1430                                            gpointer cb_user_data,
1431                                            const GError *cb_error)
1432 {
1433         GValue *curval = NULL;
1434         gint curplaycount = -1;
1435         GHashTable *mdata = cb_user_data;
1436
1437         if (cb_error == NULL) {
1438                 if (cb_metadata)
1439                         curval = mafw_metadata_first(cb_metadata,
1440                                 MAFW_METADATA_KEY_PLAY_COUNT);
1441                 if (curval && !G_VALUE_HOLDS(curval, G_TYPE_INT))
1442                         goto set_data;
1443                 if (curval)
1444                 {
1445                         curplaycount = g_value_get_int(curval);
1446                         curplaycount++;
1447                 }
1448                 else
1449                 { /* Playing at first time, or not supported... */
1450                         curplaycount = 1;
1451                 }
1452                 if (!mdata)
1453                         mdata = mafw_metadata_new();
1454                 mafw_metadata_add_int(mdata,
1455                                         MAFW_METADATA_KEY_PLAY_COUNT,
1456                                         curplaycount);
1457
1458         } else {
1459                 g_warning("_playcount_metadata received an error: "
1460                           "%s (%d): %s", g_quark_to_string(cb_error->domain),
1461                           cb_error->code, cb_error->message);
1462                 if (mdata)
1463                         g_hash_table_unref(mdata);
1464                 return;
1465         }
1466 set_data:
1467         
1468         if (mdata)
1469         {
1470                 mafw_source_set_metadata(cb_source, cb_object_id, mdata,
1471                                                 _metadata_set_cb, NULL);
1472                 g_hash_table_unref(mdata);
1473         }
1474 }
1475
1476 /**
1477  * mafw_gst_renderer_add_lastplayed:
1478  * @mdata:   Exisiting mdata, or NULL
1479  *
1480  * Sets the MAFW_METADATA_KEY_LAST_PLAYED metadata in the given metadata-table,
1481  * or creates a new metadata-table, and sets the current time there.
1482  */
1483 static GHashTable *mafw_gst_renderer_add_lastplayed(GHashTable *mdata)
1484 {
1485         GHashTable *metadata;
1486         GTimeVal timeval;
1487
1488         
1489         if (!mdata)
1490                 metadata = mafw_metadata_new();
1491         else
1492                 metadata = mdata;
1493         
1494                 
1495
1496         g_get_current_time(&timeval);
1497                 
1498         mafw_metadata_add_long(metadata,
1499                                         MAFW_METADATA_KEY_LAST_PLAYED,
1500                                         timeval.tv_sec);
1501         return metadata;
1502 }
1503
1504 /**
1505  * mafw_gst_renderer_increase_playcount:
1506  * @self:   Gst renderer
1507  * @object_id: The object ID of the touched object
1508  * @mdat: Existing metadatas to add the playcount to, or NULL
1509  *
1510  * Increases the playcount of the given object.
1511  */
1512 static void mafw_gst_renderer_increase_playcount(MafwGstRenderer* self,
1513                                         const gchar *object_id, GHashTable *mdat)
1514 {
1515         MafwSource* source;
1516
1517         g_assert(self != NULL);
1518         source = _get_source(self, object_id);
1519         if (source != NULL)
1520         {
1521                 static const gchar * const keys[] =
1522                         { MAFW_METADATA_KEY_PLAY_COUNT, NULL };
1523
1524                 mafw_source_get_metadata(source, object_id,
1525                                          keys,
1526                                          _update_playcount_metadata_cb,
1527                                          mdat);
1528
1529         }
1530 }
1531
1532 /**
1533  * mafw_gst_renderer_update_stats:
1534  * @data: user data
1535  *
1536  * Updates both playcount and lastplayed after a while.
1537  **/
1538 gboolean mafw_gst_renderer_update_stats(gpointer data)
1539 {
1540         MafwGstRenderer *renderer = (MafwGstRenderer *) data;
1541
1542         /* Update stats only for audio content */
1543         if (renderer->media->object_id &&
1544             !renderer->worker->media.has_visual_content) {
1545                 GHashTable *mdata = mafw_gst_renderer_add_lastplayed(NULL);
1546                 mafw_gst_renderer_increase_playcount(renderer,
1547                                                      renderer->media->object_id,
1548                                                      mdata);
1549         }
1550         renderer->update_playcount_id = 0;
1551         return FALSE;
1552 }
1553
1554 void mafw_gst_renderer_update_source_duration(MafwGstRenderer *renderer,
1555                                               gint duration)
1556 {
1557         GHashTable *metadata;
1558         MafwSource* source;
1559
1560         source = _get_source(renderer, renderer->media->object_id);
1561         g_return_if_fail(source != NULL);
1562
1563         renderer->media->duration = duration;
1564
1565         g_debug("updated source duration to %d", duration);
1566
1567         metadata = mafw_metadata_new();
1568         mafw_metadata_add_int(metadata, MAFW_METADATA_KEY_DURATION, duration);
1569
1570         mafw_source_set_metadata(source, renderer->media->object_id, metadata,
1571                                  _metadata_set_cb, NULL);
1572         g_hash_table_unref(metadata);
1573 }
1574
1575 /**
1576  * _notify_metadata:
1577  * @source:   The #MafwSource that sent the metadata results
1578  * @objectid: The object ID, whose metadata results were received
1579  * @metadata: GHashTable containing metadata key-value pairs
1580  * @userdata: Optional user data pointer (self)
1581  * @error:    Set if any errors occurred during metadata browsing
1582  *
1583  * Receives the results of a metadata request.
1584  */
1585 static void _notify_metadata (MafwSource *cb_source,
1586                               const gchar *cb_object_id,
1587                               GHashTable *cb_metadata,
1588                               gpointer cb_user_data,
1589                               const GError *cb_error)
1590 {
1591         MafwGstRenderer *renderer = (MafwGstRenderer*) cb_user_data;
1592         GError *mafw_error = NULL;
1593         GError *error = NULL;
1594         GValue *mval;
1595
1596         g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1597
1598         g_return_if_fail((renderer->states != 0) &&
1599                          (renderer->current_state != _LastMafwPlayState) &&
1600                          (renderer->states[renderer->current_state] != NULL));
1601
1602         g_debug("running _notify_metadata...");
1603
1604         mval = mafw_metadata_first(cb_metadata, MAFW_METADATA_KEY_URI);
1605
1606         if (cb_error == NULL && mval != NULL) {
1607                 mafw_gst_renderer_state_notify_metadata(
1608                         MAFW_GST_RENDERER_STATE(
1609                                 renderer->states[renderer->current_state]),
1610                         cb_object_id,
1611                         cb_metadata,
1612                         &error);
1613         }
1614         else {
1615                 g_set_error(&mafw_error,
1616                             MAFW_RENDERER_ERROR,
1617                             MAFW_RENDERER_ERROR_URI_NOT_AVAILABLE, "%s",
1618                             cb_error ? cb_error->message : "URI not available");
1619                 mafw_gst_renderer_manage_error(renderer, mafw_error);
1620                 g_error_free(mafw_error);
1621         }
1622 }
1623
1624 static void _notify_play(MafwGstRendererWorker *worker, gpointer owner)
1625 {
1626         MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1627         GError *error = NULL;
1628
1629         g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1630
1631         g_return_if_fail((renderer->states != 0) &&
1632                          (renderer->current_state != _LastMafwPlayState) &&
1633                          (renderer->states[renderer->current_state] != NULL));
1634
1635         g_debug("running _notify_play...");
1636
1637         mafw_gst_renderer_state_notify_play(renderer->states[renderer->current_state],
1638                                           &error);
1639
1640         if (error != NULL) {
1641                 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1642                                       error->domain,
1643                                       error->code,
1644                                       error->message);
1645                 g_error_free (error);
1646         }
1647 }
1648
1649 static void _notify_pause(MafwGstRendererWorker *worker, gpointer owner)
1650 {
1651         MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1652         GError *error = NULL;
1653
1654         g_return_if_fail(MAFW_IS_GST_RENDERER (renderer));
1655
1656         g_return_if_fail((renderer->states != 0) &&
1657                          (renderer->current_state != _LastMafwPlayState) &&
1658                          (renderer->states[renderer->current_state] != NULL));
1659
1660         mafw_gst_renderer_state_notify_pause(renderer->states[renderer->current_state],
1661                                            &error);
1662
1663         if (error != NULL) {
1664                 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1665                                       error->domain, error->code,
1666                                       error->message);
1667                 g_error_free(error);
1668         }
1669 }
1670
1671 static void _notify_buffer_status (MafwGstRendererWorker *worker,
1672                                    gpointer owner,
1673                                    gdouble percent)
1674 {
1675         MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1676         GError *error = NULL;
1677
1678         g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1679
1680         g_return_if_fail((renderer->states != 0) &&
1681                          (renderer->current_state != _LastMafwPlayState) &&
1682                          (renderer->states[renderer->current_state] != NULL));
1683
1684         mafw_gst_renderer_state_notify_buffer_status(
1685                 renderer->states[renderer->current_state],
1686                 percent,
1687                 &error);
1688
1689         if (error != NULL) {
1690                 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1691                                       error->domain, error->code,
1692                                       error->message);
1693                 g_error_free(error);
1694         }
1695 }
1696
1697 static void _notify_seek(MafwGstRendererWorker *worker, gpointer owner)
1698 {
1699         MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1700         GError *error = NULL;
1701
1702         g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1703
1704         g_return_if_fail((renderer->states != 0) &&
1705                          (renderer->current_state != _LastMafwPlayState) &&
1706                          (renderer->states[renderer->current_state] != NULL));
1707
1708         mafw_gst_renderer_state_notify_seek(renderer->states[renderer->current_state],
1709                                           &error);
1710
1711         if (error != NULL) {
1712                 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1713                                       error->domain, error->code,
1714                                       error->message);
1715                 g_error_free(error);
1716         }
1717 }
1718
1719 static void _playlist_changed_handler(MafwPlaylistIterator *iterator,
1720                                       gboolean clip_changed, GQuark domain,
1721                                       gint code, const gchar *message,
1722                                       gpointer user_data)
1723 {
1724         MafwGstRenderer *renderer = (MafwGstRenderer*) user_data;
1725
1726         g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1727
1728         g_return_if_fail((renderer->states != 0) &&
1729                          (renderer->current_state != _LastMafwPlayState) &&
1730                          (renderer->states[renderer->current_state] != NULL));
1731
1732         /* We update the current index and media here,  for this is
1733            the same for all the states. Then we delegate in the state
1734            to finish the task (for example, start playback if needed) */
1735
1736         if (renderer->playlist == NULL) {
1737                 g_critical("Got iterator:contents-changed but renderer has no" \
1738                            "playlist assigned!. Skipping...");
1739                 return;
1740         }
1741
1742         if (domain != 0) {
1743                 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1744                                       domain, code, message);
1745         } else {
1746                 GError *error = NULL;
1747                 MafwGstRendererPlaybackMode mode;
1748                 
1749                 mode = mafw_gst_renderer_get_playback_mode(renderer);
1750
1751                 /* Only in non-playobject mode */               
1752                 if (clip_changed && mode == MAFW_GST_RENDERER_MODE_PLAYLIST)
1753                         mafw_gst_renderer_set_media_playlist(renderer);
1754
1755                 /* We let the state know if the current clip has changed as
1756                    result of this operation, so it can do its work */
1757                 mafw_gst_renderer_state_playlist_contents_changed_handler(
1758                         renderer->states[renderer->current_state],
1759                         clip_changed,
1760                         &error);
1761
1762                 if (error != NULL) {
1763                         g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1764                                               error->domain, error->code,
1765                                               error->message);
1766                         g_error_free(error);
1767                 }
1768         }
1769 }
1770
1771 static void _error_handler(MafwGstRendererWorker *worker, gpointer owner,
1772                            const GError *error)
1773 {
1774         MafwGstRenderer *renderer = MAFW_GST_RENDERER(owner);
1775
1776         mafw_gst_renderer_manage_error(renderer, error);
1777 }
1778
1779 void mafw_gst_renderer_manage_error(MafwGstRenderer *self, const GError *error)
1780 {
1781         GError *new_err = NULL;
1782         GError *raise_error = NULL;
1783         GQuark new_err_domain = MAFW_RENDERER_ERROR;
1784         gint new_err_code = 0;
1785
1786         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1787
1788         g_return_if_fail((self->states != 0) &&
1789                          (self->current_state != _LastMafwPlayState) &&
1790                          (self->states[self->current_state] != NULL));
1791
1792         g_warning("Got error in renderer:\n\tdomain: %d, code: %d, message: %s",
1793                   error->domain, error->code, error->message);
1794
1795         /* Get a MAFW error */
1796         if (error->domain == GST_RESOURCE_ERROR) {
1797                 /* handle RESOURCE errors */
1798                 switch (error->code) {
1799                 case GST_RESOURCE_ERROR_READ:
1800                         if (is_current_uri_stream(self)) {
1801 #ifdef HAVE_CONIC
1802                                 if (self->connected) {
1803                                         new_err_code = MAFW_RENDERER_ERROR_STREAM_DISCONNECTED;
1804                                 } else {
1805                                         new_err_domain = MAFW_EXTENSION_ERROR;
1806                                         new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1807                                 }
1808 #else
1809                                 /* Stream + cannot read resource ->
1810                                    disconnected */
1811                                 new_err_code = MAFW_RENDERER_ERROR_STREAM_DISCONNECTED;
1812 #endif
1813                         } else {
1814                                 /* This shouldn't happen */
1815                                 /* Unknown RESOURCE error */
1816                                 new_err_domain = MAFW_EXTENSION_ERROR;
1817                                 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1818                         }
1819                         break;
1820                 case GST_RESOURCE_ERROR_NOT_FOUND:
1821 #ifdef HAVE_CONIC
1822                         if (!is_current_uri_stream(self) || self->connected) {
1823                                 new_err_code =
1824                                         MAFW_RENDERER_ERROR_INVALID_URI;
1825                         } else {
1826                                 new_err_domain = MAFW_EXTENSION_ERROR;
1827                                 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1828                         }
1829 #else
1830                         new_err_code =
1831                                 MAFW_RENDERER_ERROR_INVALID_URI;
1832 #endif
1833                         break;
1834                 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
1835                 case GST_RESOURCE_ERROR_OPEN_READ:
1836 #ifdef HAVE_CONIC
1837                         if (!is_current_uri_stream(self) || self->connected) {
1838                                 new_err_code =
1839                                         MAFW_RENDERER_ERROR_MEDIA_NOT_FOUND;
1840                         } else {
1841                                 new_err_domain = MAFW_EXTENSION_ERROR;
1842                                 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1843                         }
1844 #else
1845                         new_err_code =
1846                                 MAFW_RENDERER_ERROR_MEDIA_NOT_FOUND;
1847 #endif
1848                         break;
1849                 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
1850                         new_err_domain = MAFW_EXTENSION_ERROR;
1851                         new_err_code = MAFW_EXTENSION_ERROR_OUT_OF_MEMORY;
1852                         break;
1853                 case GST_RESOURCE_ERROR_WRITE:
1854                         /* DSP renderers send ERROR_WRITE when they find
1855                            corrupted data */
1856                         new_err_code = MAFW_RENDERER_ERROR_CORRUPTED_FILE;
1857                         break;
1858                 case GST_RESOURCE_ERROR_SEEK:
1859                         new_err_code = MAFW_RENDERER_ERROR_CANNOT_SET_POSITION;
1860                         break;
1861                 default:
1862                         /* Unknown RESOURCE error */
1863                         new_err_domain = MAFW_EXTENSION_ERROR;
1864                         new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1865                 }
1866
1867         } else if (error->domain == GST_STREAM_ERROR) {
1868                 /* handle STREAM errors */
1869                 switch (error->code) {
1870                 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
1871                         new_err_code = MAFW_RENDERER_ERROR_TYPE_NOT_AVAILABLE;
1872                         break;
1873                 case GST_STREAM_ERROR_FORMAT:
1874                 case GST_STREAM_ERROR_WRONG_TYPE:
1875                 case GST_STREAM_ERROR_FAILED:
1876                         new_err_code = MAFW_RENDERER_ERROR_UNSUPPORTED_TYPE;
1877                         break;
1878                 case GST_STREAM_ERROR_DECODE:
1879                 case GST_STREAM_ERROR_DEMUX:
1880                         new_err_code = MAFW_RENDERER_ERROR_CORRUPTED_FILE;
1881                         break;
1882                 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
1883                         new_err_code = MAFW_RENDERER_ERROR_CODEC_NOT_FOUND;
1884                         break;
1885                 case GST_STREAM_ERROR_DECRYPT:
1886                 case GST_STREAM_ERROR_DECRYPT_NOKEY:
1887                         new_err_code = MAFW_RENDERER_ERROR_DRM;
1888                         break;
1889                 default:
1890                         /* Unknown STREAM error */
1891                         new_err_domain = MAFW_EXTENSION_ERROR;
1892                         new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1893                 }
1894         } else if (error->domain == MAFW_GST_RENDERER_ERROR) {
1895                 /* Handle own errors. Errors that belong to this domain:
1896                       - MAFW_GST_RENDERER_ERROR_PLUGIN_NOT_FOUND,
1897                       - MAFW_GST_RENDERER_ERROR_VIDEO_CODEC_NOT_SUPPORTED,
1898                       - MAFW_GST_RENDERER_ERROR_AUDIO_CODEC_NOT_SUPPORTED */
1899                 new_err_code = MAFW_RENDERER_ERROR_UNSUPPORTED_TYPE;
1900         } else if (error->domain == MAFW_RENDERER_ERROR) {
1901                 /* Worker may have sent MAFW_RENDERER_ERROR as well.
1902                    No processing needed */
1903                 new_err_code = error->code;
1904         } else {
1905                 /* default */
1906                 /* Unknown error */
1907                 new_err_domain = MAFW_EXTENSION_ERROR;
1908                 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1909         }
1910
1911         g_set_error(&new_err, new_err_domain, new_err_code, "%s", error->message);
1912
1913         _run_error_policy(self, new_err, &raise_error);
1914         g_error_free(new_err);
1915
1916         if (raise_error) {
1917                 g_signal_emit_by_name(MAFW_EXTENSION (self), "error",
1918                                       raise_error->domain,
1919                                       raise_error->code,
1920                                       raise_error->message);
1921                 g_error_free(raise_error);
1922         }
1923 }
1924
1925 static void _notify_eos(MafwGstRendererWorker *worker, gpointer owner)
1926 {
1927         MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1928         GError *error = NULL;
1929
1930         g_return_if_fail(MAFW_IS_GST_RENDERER (renderer));
1931
1932         g_return_if_fail((renderer->states != 0) &&
1933                          (renderer->current_state != _LastMafwPlayState) &&
1934                          (renderer->states[renderer->current_state] != NULL));
1935
1936         mafw_gst_renderer_state_notify_eos(renderer->states[renderer->current_state],
1937                                          &error);
1938
1939         if (error != NULL) {
1940                 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1941                                       error->domain, error->code,
1942                                       error->message);
1943                 g_error_free(error);
1944         }
1945 }
1946
1947 /*----------------------------------------------------------------------------
1948   Status
1949   ----------------------------------------------------------------------------*/
1950
1951 void mafw_gst_renderer_get_status(MafwRenderer *self, MafwRendererStatusCB callback,
1952                                 gpointer user_data)
1953 {
1954         MafwGstRenderer* renderer;
1955         gint index;
1956         MafwGstRendererPlaybackMode mode;
1957
1958         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1959         g_return_if_fail(callback != NULL);
1960         renderer = MAFW_GST_RENDERER(self);
1961
1962         mode = mafw_gst_renderer_get_playback_mode(MAFW_GST_RENDERER(self));
1963         if ((mode == MAFW_GST_RENDERER_MODE_STANDALONE) || (renderer->iterator == NULL)) {
1964                 index = -1;
1965         } else {
1966                 index =
1967                         mafw_playlist_iterator_get_current_index(renderer->iterator);
1968         }
1969
1970         /* TODO: Set error parameter */
1971         callback(self, renderer->playlist, index, renderer->current_state,
1972                  (const gchar*) renderer->media->object_id, user_data, NULL);
1973 }
1974
1975 void mafw_gst_renderer_get_current_metadata(MafwRenderer *self,
1976                                             MafwRendererMetadataResultCB callback,
1977                                             gpointer user_data)
1978 {
1979         MafwGstRenderer *renderer;
1980         GHashTable *metadata;
1981
1982         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1983         renderer = MAFW_GST_RENDERER(self);
1984
1985         metadata = mafw_gst_renderer_worker_get_current_metadata(
1986                         renderer->worker);
1987
1988         callback(self,
1989                  (const gchar*) renderer->media->object_id,
1990                  metadata,
1991                  user_data,
1992                  NULL);
1993 }
1994
1995 /*----------------------------------------------------------------------------
1996   Playlist
1997   ----------------------------------------------------------------------------*/
1998
1999 static void
2000 _playlist_contents_changed_handler(MafwPlaylist *playlist,
2001                                         guint from, guint nremove,
2002                                         guint nreplace,
2003                                         MafwGstRenderer *renderer)
2004 {
2005         /* Item(s) added to playlist, so new playable items could come */
2006         if (nreplace)
2007                 renderer->play_failed_count = 0;
2008 }
2009
2010 gboolean mafw_gst_renderer_assign_playlist(MafwRenderer *self,
2011                                            MafwPlaylist *playlist,
2012                                            GError **error)
2013 {
2014         MafwGstRenderer* renderer = (MafwGstRenderer*) self;
2015
2016         g_return_val_if_fail(MAFW_IS_GST_RENDERER(self), FALSE);
2017
2018         /* Get rid of previously assigned playlist  */
2019         if (renderer->playlist != NULL) {
2020                 g_signal_handlers_disconnect_matched(renderer->iterator,
2021                                                      (GSignalMatchType) G_SIGNAL_MATCH_FUNC,
2022                                                      0, 0, NULL,
2023                                                      _playlist_changed_handler,
2024                                                      NULL);
2025                 g_signal_handlers_disconnect_matched(renderer->playlist,
2026                                         (GSignalMatchType) G_SIGNAL_MATCH_FUNC,
2027                                         0, 0, NULL,
2028                                         G_CALLBACK(_playlist_contents_changed_handler),
2029                                         NULL);
2030                 /* Decrement the use count of the previous playlist because the
2031                    renderer isn't going to use it more */
2032                 mafw_playlist_decrement_use_count(renderer->playlist, NULL);
2033
2034                 g_object_unref(renderer->iterator);
2035                 g_object_unref(renderer->playlist);
2036         }
2037
2038         /* Assign the new playlist */
2039         if (playlist == NULL) {
2040                 renderer->playlist = NULL;
2041                 renderer->iterator = NULL;
2042         } else {
2043                 GError *new_error = NULL;
2044                 MafwPlaylistIterator *iterator = NULL;
2045
2046                 iterator = mafw_playlist_iterator_new();
2047                 mafw_playlist_iterator_initialize(iterator, playlist,
2048                                                    &new_error);
2049                 
2050                 g_object_ref(playlist);
2051
2052                 if (new_error == NULL) {
2053
2054                         renderer->playlist = playlist;
2055                         renderer->iterator = iterator;
2056
2057                         /* Increment the use_count to avoid the playlist destruction
2058                            while the playlist is assigned to some renderer */
2059                         mafw_playlist_increment_use_count(renderer->playlist, NULL);
2060
2061                         g_signal_connect(iterator,
2062                                          "playlist-changed",
2063                                          G_CALLBACK(_playlist_changed_handler),
2064                                          renderer);
2065                         g_signal_connect(renderer->playlist,
2066                                          "contents-changed",
2067                                          G_CALLBACK(_playlist_contents_changed_handler),
2068                                          renderer);
2069                 }
2070                 else {
2071                         g_propagate_error (error, new_error);
2072                 }
2073         }
2074
2075         /* Set the new media and signal playlist changed signal */
2076         _signal_playlist_changed(renderer);
2077         mafw_gst_renderer_set_media_playlist(renderer);
2078
2079
2080         /* Stop playback */
2081         mafw_gst_renderer_stop(MAFW_RENDERER(renderer), NULL , NULL);
2082
2083         return TRUE;
2084 }
2085
2086 MafwGstRendererMovementResult mafw_gst_renderer_move(MafwGstRenderer *renderer,
2087                                                    MafwGstRendererMovementType type,
2088                                                    guint index,
2089                                                    GError **error)
2090 {
2091         MafwGstRendererMovementResult value = MAFW_GST_RENDERER_MOVE_RESULT_OK;
2092
2093         if (renderer->playlist == NULL) {
2094                 value = MAFW_GST_RENDERER_MOVE_RESULT_NO_PLAYLIST;
2095         } else {
2096                 MafwPlaylistIteratorMovementResult result;
2097
2098                 switch (type) {
2099                 case MAFW_GST_RENDERER_MOVE_TYPE_INDEX:
2100                         result =
2101                                 mafw_playlist_iterator_move_to_index(renderer->iterator,
2102                                                                       index,
2103                                                                       error);
2104                         break;
2105                 case MAFW_GST_RENDERER_MOVE_TYPE_PREV:
2106                         result =
2107                                 mafw_playlist_iterator_move_to_prev(renderer->iterator,
2108                                                                      error);
2109                         break;
2110                 case MAFW_GST_RENDERER_MOVE_TYPE_NEXT:
2111                         result =
2112                                 mafw_playlist_iterator_move_to_next(renderer->iterator,
2113                                                                      error);
2114                         break;
2115                 }
2116
2117                 switch (result) {
2118                 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_OK:
2119                         value = MAFW_GST_RENDERER_MOVE_RESULT_OK;
2120                         mafw_gst_renderer_set_media_playlist(renderer);
2121                         break;
2122                 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_INVALID:
2123                         g_critical("Iterator is invalid!");
2124                         value = MAFW_GST_RENDERER_MOVE_RESULT_ERROR;
2125                         break;
2126                 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_ERROR:
2127                         value = MAFW_GST_RENDERER_MOVE_RESULT_ERROR;
2128                         break;
2129                 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_LIMIT:
2130                         value = MAFW_GST_RENDERER_MOVE_RESULT_PLAYLIST_LIMIT;
2131                         break;
2132                 }
2133         }
2134
2135         return value;
2136 }
2137
2138 /*----------------------------------------------------------------------------
2139   Properties
2140   ----------------------------------------------------------------------------*/
2141
2142 static void _set_error_policy(MafwGstRenderer *renderer, MafwRendererErrorPolicy policy)
2143 {
2144         renderer->error_policy = policy;
2145 }
2146
2147 static MafwRendererErrorPolicy _get_error_policy(MafwGstRenderer *renderer)
2148 {
2149         return renderer->error_policy;
2150 }
2151
2152 static void mafw_gst_renderer_get_property(MafwExtension *self,
2153                                          const gchar *key,
2154                                          MafwExtensionPropertyCallback callback,
2155                                          gpointer user_data)
2156 {
2157         MafwGstRenderer *renderer;
2158         GValue *value = NULL;
2159         GError *error = NULL;
2160
2161         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
2162         g_return_if_fail(callback != NULL);
2163         g_return_if_fail(key != NULL);
2164
2165         renderer = MAFW_GST_RENDERER(self);
2166         if (!strcmp(key, MAFW_PROPERTY_RENDERER_VOLUME)) {
2167                 guint volume;
2168
2169                 volume = mafw_gst_renderer_worker_get_volume(
2170                         renderer->worker);
2171
2172                 value = g_new0(GValue, 1);
2173                 g_value_init(value, G_TYPE_UINT);
2174                 g_value_set_uint(value, volume);
2175         }
2176         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_MUTE)) {
2177                 gboolean mute;
2178                 mute = mafw_gst_renderer_worker_get_mute(renderer->worker);
2179                 value = g_new0(GValue, 1);
2180                 g_value_init(value, G_TYPE_BOOLEAN);
2181                 g_value_set_boolean(value, mute);
2182         }
2183         else if (!strcmp (key, MAFW_PROPERTY_RENDERER_XID)) {
2184                 guint xid;
2185                 xid = mafw_gst_renderer_worker_get_xid(renderer->worker);
2186                 value = g_new0(GValue, 1);
2187                 g_value_init(value, G_TYPE_UINT);
2188                 g_value_set_uint(value, xid);
2189         }
2190         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_ERROR_POLICY)) {
2191                 guint policy;
2192                 policy = _get_error_policy(renderer);
2193                 value = g_new0(GValue, 1);
2194                 g_value_init(value, G_TYPE_UINT);
2195                 g_value_set_uint(value, policy);
2196         }
2197         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_AUTOPAINT)) {
2198                 value = g_new0(GValue, 1);
2199                 g_value_init(value, G_TYPE_BOOLEAN);
2200                 g_value_set_boolean(
2201                         value,
2202                         mafw_gst_renderer_worker_get_autopaint(
2203                                 renderer->worker));
2204         } else if (!strcmp(key, MAFW_PROPERTY_RENDERER_COLORKEY)) {
2205                 value = g_new0(GValue, 1);
2206                 g_value_init(value, G_TYPE_INT);
2207                 g_value_set_int(
2208                         value,
2209                         mafw_gst_renderer_worker_get_colorkey(
2210                                 renderer->worker));
2211         }
2212 #ifdef HAVE_GDKPIXBUF
2213         else if (!strcmp(key,
2214                          MAFW_PROPERTY_GST_RENDERER_CURRENT_FRAME_ON_PAUSE)) {
2215                 gboolean current_frame_on_pause;
2216                 current_frame_on_pause =
2217                         mafw_gst_renderer_worker_get_current_frame_on_pause(renderer->worker);
2218                 value = g_new0(GValue, 1);
2219                 g_value_init(value, G_TYPE_BOOLEAN);
2220                 g_value_set_boolean(value, current_frame_on_pause);
2221         }
2222 #endif
2223         else if (!strcmp(key,
2224                          MAFW_PROPERTY_GST_RENDERER_TV_CONNECTED)) {
2225                 value = g_new0(GValue, 1);
2226                 g_value_init(value, G_TYPE_BOOLEAN);
2227                 g_value_set_boolean(value, renderer->tv_connected);
2228         }
2229         else if (!strcmp(key,
2230                          MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS)){
2231                 /* Delegate in the state. */
2232                 value = mafw_gst_renderer_state_get_property_value(
2233                         MAFW_GST_RENDERER_STATE(
2234                                 renderer->states[renderer->current_state]),
2235                         MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS);
2236
2237                 if (!value) {
2238                         /* Something goes wrong. */
2239                         error = g_error_new(
2240                                 MAFW_GST_RENDERER_ERROR,
2241                                 MAFW_EXTENSION_ERROR_GET_PROPERTY,
2242                                 "Error while getting the property value");
2243                 }
2244         }
2245         else {
2246                 /* Unsupported property */
2247                 error = g_error_new(MAFW_GST_RENDERER_ERROR,
2248                                     MAFW_EXTENSION_ERROR_GET_PROPERTY,
2249                                     "Unsupported property");
2250         }
2251
2252         callback(self, key, value, user_data, error);
2253 }
2254
2255 static void mafw_gst_renderer_set_property(MafwExtension *self,
2256                                          const gchar *key,
2257                                          const GValue *value)
2258 {
2259         MafwGstRenderer *renderer;
2260
2261         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
2262         g_return_if_fail(key != NULL);
2263
2264         renderer = MAFW_GST_RENDERER(self);
2265
2266         if (!strcmp(key, MAFW_PROPERTY_RENDERER_VOLUME)) {
2267                 guint volume = g_value_get_uint(value);
2268                 if (volume > 100)
2269                         volume = 100;
2270                 mafw_gst_renderer_worker_set_volume(renderer->worker,
2271                                                            volume);
2272                 /* Property-changed emision is done by worker */
2273                 return;
2274         }
2275         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_MUTE)) {
2276                 gboolean mute = g_value_get_boolean(value);
2277                 mafw_gst_renderer_worker_set_mute(renderer->worker, mute);
2278         }
2279         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_XID)) {
2280                 XID xid = g_value_get_uint(value);
2281                 mafw_gst_renderer_worker_set_xid(renderer->worker, xid);
2282         }
2283         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_ERROR_POLICY)) {
2284                 MafwRendererErrorPolicy policy = g_value_get_uint(value);
2285                 _set_error_policy(renderer, policy);
2286         }
2287         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_AUTOPAINT)) {
2288                 mafw_gst_renderer_worker_set_autopaint(
2289                         renderer->worker,
2290                         g_value_get_boolean(value));
2291         }
2292 #ifdef HAVE_GDKPIXBUF
2293         else if (!strcmp(key,
2294                          MAFW_PROPERTY_GST_RENDERER_CURRENT_FRAME_ON_PAUSE)) {
2295                 gboolean current_frame_on_pause = g_value_get_boolean(value);
2296                 mafw_gst_renderer_worker_set_current_frame_on_pause(renderer->worker,
2297                                                                            current_frame_on_pause);
2298         }
2299 #endif
2300         else return;
2301
2302         /* FIXME I'm not sure when to emit property-changed signals.
2303          * Maybe we should let the worker do it, when the change
2304          * reached the hardware... */
2305         mafw_extension_emit_property_changed(self, key, value);
2306 }
2307
2308 /* vi: set noexpandtab ts=8 sw=8 cino=t0,(0: */