6412b13be4df82d3d45263cdc1fdddbd1bafd514
[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 HAL_VIDEOOUT_UDI "/org/freedesktop/Hal/devices" \
60         "/platform_soc_audio_logicaldev_input"
61
62 /*----------------------------------------------------------------------------
63   Static variable definitions
64   ----------------------------------------------------------------------------*/
65
66 /*----------------------------------------------------------------------------
67   Plugin initialization
68   ----------------------------------------------------------------------------*/
69
70 static gboolean mafw_gst_renderer_initialize(MafwRegistry *registry,
71                                            GError **error);
72 static void mafw_gst_renderer_deinitialize(GError **error);
73
74 /*----------------------------------------------------------------------------
75   GObject initialization
76   ----------------------------------------------------------------------------*/
77
78 static void mafw_gst_renderer_dispose(GObject *object);
79 static void mafw_gst_renderer_finalize(GObject *object);
80
81 /*----------------------------------------------------------------------------
82   Hal callbacks
83   ----------------------------------------------------------------------------*/
84 static void _property_modified(LibHalContext *ctx, const char *udi,
85                                const char *key, dbus_bool_t is_removed,
86                                dbus_bool_t is_added);
87 static gboolean _tv_out_is_connected(LibHalContext *ctx, const char *udi);
88
89 /*----------------------------------------------------------------------------
90   GConf notifications
91   ----------------------------------------------------------------------------*/
92
93 static void _battery_cover_open_cb(GConfClient *client,
94                                    guint cnxn_id,
95                                    GConfEntry *entry,
96                                    MafwGstRenderer *renderer);
97
98 /*----------------------------------------------------------------------------
99   Gnome VFS notifications
100   ----------------------------------------------------------------------------*/
101
102 static void _volume_pre_unmount_cb(GnomeVFSVolumeMonitor *monitor,
103                                    GnomeVFSVolume *volume,
104                                    MafwGstRenderer *renderer);
105
106 /*----------------------------------------------------------------------------
107   Playback
108   ----------------------------------------------------------------------------*/
109
110 static void _signal_state_changed(MafwGstRenderer * self);
111 static void _signal_media_changed(MafwGstRenderer * self);
112 static void _signal_playlist_changed(MafwGstRenderer * self);
113 static void _signal_transport_actions_property_changed(MafwGstRenderer * self);
114
115 /*----------------------------------------------------------------------------
116   Properties
117   ----------------------------------------------------------------------------*/
118
119 static void _set_error_policy(MafwGstRenderer *renderer, MafwRendererErrorPolicy policy);
120 static MafwRendererErrorPolicy _get_error_policy(MafwGstRenderer *renderer);
121
122 static void mafw_gst_renderer_set_property(MafwExtension *self, const gchar *key,
123                                          const GValue *value);
124 static void mafw_gst_renderer_get_property(MafwExtension *self, const gchar *key,
125                                          MafwExtensionPropertyCallback callback,
126                                          gpointer user_data);
127
128 /*----------------------------------------------------------------------------
129   Metadata
130   ----------------------------------------------------------------------------*/
131
132 static void _notify_metadata(MafwSource *cb_source,
133                              const gchar *cb_object_id,
134                              GHashTable *cb_metadata,
135                              gpointer cb_user_data,
136                              const GError *cb_error);
137
138 /*----------------------------------------------------------------------------
139   Notification operations
140   ----------------------------------------------------------------------------*/
141
142 static void _notify_play(MafwGstRendererWorker *worker, gpointer owner);
143 static void _notify_pause(MafwGstRendererWorker *worker, gpointer owner);
144 static void _notify_seek(MafwGstRendererWorker *worker, gpointer owner);
145 static void _notify_buffer_status(MafwGstRendererWorker *worker, gpointer owner,
146                                   gdouble percent);
147 static void _notify_eos(MafwGstRendererWorker *worker, gpointer owner);
148 static void _error_handler(MafwGstRendererWorker *worker, gpointer owner,
149                            const GError *error);
150
151 #ifdef HAVE_CONIC
152 /*----------------------------------------------------------------------------
153   Connection
154   ----------------------------------------------------------------------------*/
155
156 static void _connection_init(MafwGstRenderer *renderer);
157 #endif
158
159 /*----------------------------------------------------------------------------
160   Plugin initialization
161   ----------------------------------------------------------------------------*/
162
163 /*
164  * Registers the plugin descriptor making this plugin available to the
165  * framework and applications
166  */
167 G_MODULE_EXPORT MafwPluginDescriptor mafw_gst_renderer_plugin_description = {
168         { .name         = MAFW_GST_RENDERER_PLUGIN_NAME },
169         .initialize     = mafw_gst_renderer_initialize,
170         .deinitialize   = mafw_gst_renderer_deinitialize,
171 };
172
173 static gboolean mafw_gst_renderer_initialize(MafwRegistry *registry,
174                                            GError **error)
175 {
176         MafwGstRenderer *self;
177
178         g_assert(registry != NULL);
179         self = MAFW_GST_RENDERER(mafw_gst_renderer_new(registry));
180         mafw_registry_add_extension(registry, MAFW_EXTENSION(self));
181
182         return TRUE;
183 }
184
185 static void mafw_gst_renderer_deinitialize(GError **error)
186 {
187 }
188
189 /*----------------------------------------------------------------------------
190   GObject initialization
191   ----------------------------------------------------------------------------*/
192
193 G_DEFINE_TYPE(MafwGstRenderer, mafw_gst_renderer, MAFW_TYPE_RENDERER);
194
195 static void mafw_gst_renderer_class_init(MafwGstRendererClass *klass)
196 {
197         GObjectClass *gclass = NULL;
198         MafwRendererClass *renderer_class = NULL;
199         const gchar *preloaded_plugins[] = {"playback", "uridecodebin",
200                 "coreelements", "typefindfunctions", "omx", "selector",
201                 "autodetect", "pulseaudio", "audioconvert", "audioresample",
202                 "xvimagesink", "ffmpegcolorspace", "videoscale", NULL};
203         gint i = 0;
204         GObject *plugin;
205
206         gclass = G_OBJECT_CLASS(klass);
207         g_return_if_fail(gclass != NULL);
208
209         renderer_class = MAFW_RENDERER_CLASS(klass);
210         g_return_if_fail(renderer_class != NULL);
211
212         /* GObject */
213
214         gclass->dispose = mafw_gst_renderer_dispose;
215         gclass->finalize = mafw_gst_renderer_finalize;
216
217         /* Playback */
218
219         renderer_class->play = mafw_gst_renderer_play;
220         renderer_class->play_object = mafw_gst_renderer_play_object;
221         renderer_class->stop = mafw_gst_renderer_stop;
222         renderer_class->pause = mafw_gst_renderer_pause;
223         renderer_class->resume = mafw_gst_renderer_resume;
224         renderer_class->get_status = mafw_gst_renderer_get_status;
225
226         /* Playlist operations */
227
228         renderer_class->assign_playlist = mafw_gst_renderer_assign_playlist;
229         renderer_class->next = mafw_gst_renderer_next;
230         renderer_class->previous = mafw_gst_renderer_previous;
231         renderer_class->goto_index = mafw_gst_renderer_goto_index;
232
233         /* Playback position */
234
235         renderer_class->set_position = mafw_gst_renderer_set_position;
236         renderer_class->get_position = mafw_gst_renderer_get_position;
237
238         /* Metadata */
239
240         renderer_class->get_current_metadata =
241                 mafw_gst_renderer_get_current_metadata;
242
243         /* Properties */
244
245         MAFW_EXTENSION_CLASS(klass)->get_extension_property =
246                 (gpointer) mafw_gst_renderer_get_property;
247         MAFW_EXTENSION_CLASS(klass)->set_extension_property =
248                 (gpointer) mafw_gst_renderer_set_property;
249
250         gst_init(NULL, NULL);
251         gst_pb_utils_init();
252
253         /* Pre-load some common plugins */
254         while (preloaded_plugins[i])
255         {
256                 plugin = G_OBJECT(gst_plugin_load_by_name(preloaded_plugins[i]));
257                 if (plugin)
258                         g_object_unref(plugin);
259                 else
260                         g_debug("Can not load plugin: %s", preloaded_plugins[i]);
261                 i++;
262         }
263 }
264
265 static void mafw_gst_renderer_init(MafwGstRenderer *self)
266 {
267         MafwGstRenderer *renderer = NULL;
268         GError *error = NULL;
269
270         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
271
272         renderer = MAFW_GST_RENDERER(self);
273         g_return_if_fail(renderer != NULL);
274
275         mafw_extension_add_property(MAFW_EXTENSION(self), "volume", G_TYPE_UINT);
276         mafw_extension_add_property(MAFW_EXTENSION(self), "mute", G_TYPE_BOOLEAN);
277         mafw_extension_add_property(MAFW_EXTENSION(self), "xid", G_TYPE_UINT);
278         mafw_extension_add_property(MAFW_EXTENSION(self), "error-policy", G_TYPE_UINT);
279         MAFW_EXTENSION_SUPPORTS_AUTOPAINT(self);
280         MAFW_EXTENSION_SUPPORTS_COLORKEY(self);
281 #ifdef HAVE_GDKPIXBUF
282         mafw_extension_add_property(MAFW_EXTENSION(self),
283                                      "current-frame-on-pause",
284                                      G_TYPE_BOOLEAN);
285 #endif
286         mafw_extension_add_property(MAFW_EXTENSION(self),
287                                     MAFW_PROPERTY_GST_RENDERER_TV_CONNECTED,
288                                     G_TYPE_BOOLEAN);
289         MAFW_EXTENSION_SUPPORTS_TRANSPORT_ACTIONS(self);
290         renderer->media = g_new0(MafwGstRendererMedia, 1);
291         renderer->media->seekability = SEEKABILITY_UNKNOWN;
292         renderer->current_state = Stopped;
293
294         renderer->playlist = NULL;
295         renderer->iterator = NULL;
296         renderer->seeking_to = -1;
297         renderer->update_playcount_id = 0;
298
299         self->worker = mafw_gst_renderer_worker_new(self);
300
301         /* Set notification handlers for worker */
302         renderer->worker->notify_play_handler = _notify_play;
303         renderer->worker->notify_pause_handler = _notify_pause;
304         renderer->worker->notify_seek_handler = _notify_seek;
305         renderer->worker->notify_error_handler = _error_handler;
306         renderer->worker->notify_eos_handler = _notify_eos;
307         renderer->worker->notify_buffer_status_handler = _notify_buffer_status;
308
309         renderer->states = g_new0 (MafwGstRendererState*, _LastMafwPlayState);
310         renderer->states[Stopped] =
311                 MAFW_GST_RENDERER_STATE(mafw_gst_renderer_state_stopped_new(self));
312         renderer->states[Transitioning] =
313                 MAFW_GST_RENDERER_STATE(
314                         mafw_gst_renderer_state_transitioning_new(self));
315         renderer->states[Playing] =
316                 MAFW_GST_RENDERER_STATE(mafw_gst_renderer_state_playing_new(self));
317         renderer->states[Paused] =
318                 MAFW_GST_RENDERER_STATE(mafw_gst_renderer_state_paused_new(self));
319
320         renderer->current_state = Stopped;
321         renderer->resume_playlist = FALSE;
322         renderer->playback_mode = MAFW_GST_RENDERER_MODE_PLAYLIST;
323
324 #ifdef HAVE_CONIC
325         renderer->connected = FALSE;
326         renderer->connection = NULL;
327
328         _connection_init(renderer);
329 #endif
330         renderer->gconf_client = gconf_client_get_default();
331         gconf_client_add_dir(renderer->gconf_client, GCONF_OSSO_AF,
332                              GCONF_CLIENT_PRELOAD_ONELEVEL, &error);
333         if (error) {
334                 g_warning("%s", error->message);
335                 g_error_free(error);
336                 error = NULL;
337         }
338
339         gconf_client_notify_add(renderer->gconf_client,
340                                 GCONF_BATTERY_COVER_OPEN,
341                                 (GConfClientNotifyFunc) _battery_cover_open_cb,
342                                 renderer,
343                                 NULL, &error);
344
345         if (error) {
346                 g_warning("%s", error->message);
347                 g_error_free(error);
348         }
349
350         if (gnome_vfs_init()) {
351                 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
352                 g_signal_connect(monitor, "volume-pre-unmount", 
353                                  G_CALLBACK(_volume_pre_unmount_cb), renderer);
354         } else {
355                 g_warning("Failed to initialize gnome-vfs");
356         }
357 }
358
359 static void mafw_gst_renderer_dispose(GObject *object)
360 {
361         MafwGstRenderer *renderer;
362
363         g_return_if_fail(MAFW_IS_GST_RENDERER(object));
364
365         renderer = MAFW_GST_RENDERER(object);
366
367         if (renderer->worker != NULL) {
368                 mafw_gst_renderer_worker_exit(renderer->worker);
369                 renderer->seek_pending = FALSE;
370                 g_free(renderer->worker);
371                 renderer->worker = NULL;
372         }
373
374         if (renderer->registry != NULL) {
375                 g_object_unref(renderer->registry);
376                 renderer->registry = NULL;
377         }
378
379         if (renderer->states != NULL) {
380                 guint i = 0;
381
382                 for (i = 0; i < _LastMafwPlayState; i++) {
383                         if (renderer->states[i] != NULL)
384                                 g_object_unref(renderer->states[i]);
385                 }
386                 g_free(renderer->states);
387                 renderer->states = NULL;
388         }
389
390         if (renderer->hal_ctx != NULL) {
391                 libhal_device_remove_property_watch(renderer->hal_ctx,
392                                                     HAL_VIDEOOUT_UDI,
393                                                     NULL);
394                 libhal_ctx_shutdown(renderer->hal_ctx, NULL);
395                 libhal_ctx_free(renderer->hal_ctx);
396         }
397
398 #ifdef HAVE_CONIC
399         if (renderer->connection != NULL) {
400                 g_object_unref(renderer->connection);
401                 renderer->connection = NULL;
402         }
403 #endif
404
405         if (renderer->gconf_client != NULL) {
406                 g_object_unref(renderer->gconf_client);
407                 renderer->gconf_client = NULL;
408         }
409
410         G_OBJECT_CLASS(mafw_gst_renderer_parent_class)->dispose(object);
411 }
412
413 static void mafw_gst_renderer_finalize(GObject *object)
414 {
415         MafwGstRenderer *self = (MafwGstRenderer*) object;
416
417         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
418
419         mafw_gst_renderer_clear_media(self);
420
421         if (self->media)
422         {
423                 g_free(self->media);
424                 self->media = NULL;
425         }
426
427         G_OBJECT_CLASS(mafw_gst_renderer_parent_class)->finalize(object);
428 }
429
430 /**
431  * mafw_gst_renderer_new:
432  * @registry: The registry that owns this renderer.
433  *
434  * Creates a new MafwGstRenderer object
435  */
436 GObject *mafw_gst_renderer_new(MafwRegistry* registry)
437 {
438         GObject* object;
439         LibHalContext *ctx;
440         DBusConnection *conn;
441         DBusError err;
442         char **jackets;
443         char **jack;
444         gint num_jacks;
445
446         object = g_object_new(MAFW_TYPE_GST_RENDERER,
447                               "uuid", MAFW_GST_RENDERER_UUID,
448                               "name", MAFW_GST_RENDERER_NAME,
449                               "plugin", MAFW_GST_RENDERER_PLUGIN_NAME,
450                               NULL);
451         g_assert(object != NULL);
452         MAFW_GST_RENDERER(object)->registry = g_object_ref(registry);
453
454         /* Set default error policy */
455         MAFW_GST_RENDERER(object)->error_policy =
456                 MAFW_RENDERER_ERROR_POLICY_CONTINUE;
457
458         MAFW_GST_RENDERER(object)->tv_connected = FALSE;
459
460         /* Setup hal connection for reacting usb cable connected event */
461         dbus_error_init(&err);
462         conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
463
464         if (dbus_error_is_set(&err)) {
465                 g_warning("Couldn't setup HAL connection: %s", err.message);
466                 dbus_error_free(&err);
467
468                 goto err1;
469         }
470         ctx = libhal_ctx_new();
471         libhal_ctx_set_dbus_connection(ctx, conn);
472         libhal_ctx_set_user_data(ctx, object);
473
474         if (libhal_ctx_init(ctx, &err) == FALSE) {
475                 if (dbus_error_is_set(&err)) {
476                         g_warning("Could not initialize hal: %s", err.message);
477                         dbus_error_free(&err);
478                 } else {
479                         g_warning("Could not initialize hal");
480                 }
481                 goto err2;
482         }
483
484         libhal_device_add_property_watch(ctx, HAL_VIDEOOUT_UDI, &err);
485
486         if (dbus_error_is_set(&err)) {
487                 g_warning("Could not start watching usb device: %s",
488                           err.message);
489                 dbus_error_free(&err);
490
491                 goto err3;
492         }
493         libhal_ctx_set_device_property_modified(ctx, _property_modified);
494
495         /* Initializes blanking policy */
496         jackets = libhal_find_device_by_capability(ctx,
497                                                    "input.jack.video-out",
498                                                    &num_jacks, NULL);
499         if (jackets != NULL) {
500                 jack = jackets;
501                 while (*jack) {
502                         if (_tv_out_is_connected(ctx, *jack)) {
503                                 MAFW_GST_RENDERER(object)->tv_connected = TRUE;
504                                 break;
505                         }
506                         jack++;
507                 }
508
509                 blanking_control(*jack == NULL);
510                 libhal_free_string_array(jackets);
511         }
512
513         MAFW_GST_RENDERER(object)->hal_ctx = ctx;
514
515         return object;
516 err3:
517         libhal_ctx_shutdown(ctx, NULL);
518 err2:
519         libhal_ctx_free(ctx);
520 err1:
521         return object;
522 }
523
524 /**
525  * mafw_gst_renderer_error_quark:
526  *
527  * Fetches the quark representing the domain of the errors in the
528  * gst renderer
529  *
530  * Return value: a quark identifying the error domain of the
531  * #MafwGstRenderer objects.
532  *
533  **/
534 GQuark mafw_gst_renderer_error_quark(void)
535 {
536         return g_quark_from_static_string("mafw-gst-renderer-error-quark");
537 }
538
539 void mafw_gst_renderer_set_playback_mode(MafwGstRenderer *self,
540                                        MafwGstRendererPlaybackMode mode)
541 {
542         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
543         self->playback_mode = mode;
544 }
545
546 MafwGstRendererPlaybackMode mafw_gst_renderer_get_playback_mode(
547         MafwGstRenderer *self)
548 {
549         g_return_val_if_fail(MAFW_IS_GST_RENDERER(self),
550                              MAFW_GST_RENDERER_MODE_STANDALONE);
551         return self->playback_mode;
552 }
553
554 /*----------------------------------------------------------------------------
555   Set Media
556   ----------------------------------------------------------------------------*/
557
558 static MafwSource* _get_source(MafwGstRenderer *renderer,
559                                const gchar *object_id)
560 {
561         MafwSource* source;
562         gchar* sourceid = NULL;
563
564         g_assert(object_id != NULL);
565
566         /* Attempt to find a source that provided the object ID */
567         mafw_source_split_objectid(object_id, &sourceid, NULL);
568         source = MAFW_SOURCE(mafw_registry_get_extension_by_uuid(
569                                      renderer->registry, sourceid));
570         g_free(sourceid);
571
572         return source;
573 }
574
575 void mafw_gst_renderer_get_metadata(MafwGstRenderer* self,
576                                   const gchar* objectid,
577                                   GError **error)
578 {
579         MafwSource* source;
580
581         g_assert(self != NULL);
582
583         /*
584          * Any error here is an error when trying to Play, so
585          * it must be handled by error policy.
586          * Problem: if we get an error here and we are not in
587          * Transitioning yet (maybe we are still in Stopped state)
588          * then the policy may move to next and stay Stopped (instead of
589          * trying to play), so  errors need to be handled by the policy
590          * in an idle callback, so that any error that may happen here
591          * is not processed until we have moved to Transitioning state
592          */
593
594         source = _get_source(self, objectid);
595         if (source != NULL)
596         {
597                 /* List of metadata keys that we are interested in when going to
598                    Transitioning state */
599                 static const gchar * const keys[] =
600                         { MAFW_METADATA_KEY_URI,
601                           MAFW_METADATA_KEY_IS_SEEKABLE,
602                           MAFW_METADATA_KEY_DURATION,
603                                 NULL };
604
605                 /* Source found, get metadata */
606                 mafw_source_get_metadata(source, objectid,
607                                          keys,
608                                          _notify_metadata,
609                                          self);
610
611         }
612         else
613         {
614                 /* This is a playback error: execute error policy */
615                 MafwGstRendererErrorClosure *error_closure;
616                 error_closure = g_new0(MafwGstRendererErrorClosure, 1);
617                 error_closure->renderer = self;
618                 g_set_error (&(error_closure->error),
619                              MAFW_EXTENSION_ERROR,
620                              MAFW_EXTENSION_ERROR_EXTENSION_NOT_AVAILABLE,
621                              "Unable to find source for current object ID");
622                 g_idle_add(mafw_gst_renderer_manage_error_idle, error_closure);
623         }
624 }
625
626 void mafw_gst_renderer_set_object(MafwGstRenderer *self, const gchar *object_id)
627 {
628         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
629
630         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
631         g_return_if_fail(object_id != NULL);
632
633         /* This is intended to be called only when using play_object(),
634          * as for playlists we use set_media_playlist()
635          */
636
637         /* Stop any ongoing playback */
638         mafw_gst_renderer_clear_media(renderer);
639
640         /* Set new object */
641         renderer->media->object_id = g_strdup(object_id);
642
643         /* Signal media changed */
644         _signal_media_changed(renderer);
645 }
646
647
648 /**
649  * mafw_gst_renderer_clear_media:
650  *
651  * @renderer A #MafwGstRenderer whose media to clear
652  *
653  * Clears & frees the renderer's current media details
654  **/
655 void mafw_gst_renderer_clear_media(MafwGstRenderer *self)
656 {
657         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
658         g_return_if_fail(self->media != NULL);
659
660         g_free(self->media->object_id);
661         self->media->object_id = NULL;
662
663         g_free(self->media->uri);
664         self->media->uri = NULL;
665
666         g_free(self->media->title);
667         self->media->title = NULL;
668
669         g_free(self->media->artist);
670         self->media->artist = NULL;
671
672         g_free(self->media->album);
673         self->media->album = NULL;
674
675         self->media->duration = 0;
676         self->media->position = 0;
677 }
678
679
680 /**
681  * mafw_gst_renderer_set_media_playlist:
682  *
683  * @self A #MafwGstRenderer, whose media to set
684  *
685  * Set current media from the renderer's playlist, using the current playlist index.
686  **/
687 void mafw_gst_renderer_set_media_playlist(MafwGstRenderer* self)
688 {
689         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
690
691         /* Get rid of old media details */
692         mafw_gst_renderer_clear_media(self);
693
694         if (self->playlist != NULL &&
695             mafw_playlist_iterator_get_size(self->iterator, NULL) > 0) {
696                 /* Get the current item from playlist */
697                 self->media->object_id =
698                         g_strdup(mafw_playlist_iterator_get_current_objectid(self->iterator));
699         } else {
700                 self->media->object_id = NULL;
701         }
702
703         _signal_media_changed(self);
704 }
705
706 #ifdef HAVE_CONIC
707 /*----------------------------------------------------------------------------
708   Connection
709   ----------------------------------------------------------------------------*/
710
711 static void
712 _con_ic_status_handler(ConIcConnection *conn, ConIcConnectionEvent *event,
713                        gpointer data)
714 {
715         MafwGstRenderer *renderer = (MafwGstRenderer *) data;
716
717         g_assert(MAFW_IS_GST_RENDERER(renderer));
718
719         renderer->connected =
720                 con_ic_connection_event_get_status(event) ==
721                 CON_IC_STATUS_CONNECTED;
722 }
723
724 static void
725 _connection_init(MafwGstRenderer *renderer)
726 {
727         g_assert (MAFW_IS_GST_RENDERER(renderer));
728
729         if (renderer->connection == NULL) {
730                 renderer->connection = con_ic_connection_new();
731                 renderer->connected = FALSE;
732
733                 g_assert(renderer->connection != NULL);
734         }
735
736         g_object_set(renderer->connection, "automatic-connection-events",
737                      TRUE, NULL);
738         g_signal_connect(renderer->connection, "connection-event",
739                          G_CALLBACK (_con_ic_status_handler), renderer);
740
741         con_ic_connection_connect(renderer->connection,
742                                   CON_IC_CONNECT_FLAG_AUTOMATICALLY_TRIGGERED);
743 }
744 #endif
745
746 /*----------------------------------------------------------------------------
747   Hal callbacks
748   ----------------------------------------------------------------------------*/
749
750 static gboolean _tv_out_is_connected(LibHalContext *ctx, const char *udi)
751 {
752         gboolean is_tv_out_jack = FALSE;
753         char **jack_types;
754         char **jack;
755
756         if (udi == NULL) {
757                 return FALSE;
758         }
759
760         jack_types = libhal_device_get_property_strlist(ctx, udi,
761                                                         "input.jack.type",
762                                                         NULL);
763         if (jack_types == NULL) {
764                 return FALSE;
765         }
766
767         jack = jack_types;
768         while (*jack) {
769                 if (strcmp(*jack, "video-out") == 0) {
770                         is_tv_out_jack = TRUE;
771                         break;
772                 } else {
773                         jack++;
774                 }
775         }
776
777         libhal_free_string_array(jack_types);
778
779         return is_tv_out_jack;
780 }
781
782 static void _property_modified(LibHalContext *ctx, const char *udi,
783                                const char *key, dbus_bool_t is_removed,
784                                dbus_bool_t is_added)
785 {
786         MafwGstRenderer *renderer;
787         gboolean connected;
788         GValue value = { 0 };
789
790         g_debug("HAL property modified! jack changed\n");
791         connected = _tv_out_is_connected(ctx, udi);
792         renderer = MAFW_GST_RENDERER(libhal_ctx_get_user_data(ctx));
793         if (renderer->tv_connected != connected) {
794                 /* Notify the change */
795                 renderer->tv_connected = connected;
796                 g_value_init(&value, G_TYPE_BOOLEAN);
797                 g_value_set_boolean(&value, renderer->tv_connected);
798                 mafw_extension_emit_property_changed(
799                         MAFW_EXTENSION(renderer),
800                         MAFW_PROPERTY_GST_RENDERER_TV_CONNECTED,
801                         &value);
802                 g_value_unset(&value);
803         }
804         blanking_control(connected == FALSE);
805 }
806
807 /*----------------------------------------------------------------------------
808   GConf notifications
809   ----------------------------------------------------------------------------*/
810
811 static void _battery_cover_open_cb(GConfClient *client,
812                                    guint cnxn_id,
813                                    GConfEntry *entry,
814                                    MafwGstRenderer *renderer)
815 {
816         GConfValue *value = NULL;
817         gboolean is_cover_open;
818
819         value = gconf_entry_get_value(entry);
820         is_cover_open = gconf_value_get_bool(value);
821
822         if (is_cover_open) {
823                 /* External mmc could be removed!. */
824                 const gchar *emmc_path = g_getenv("MMC_MOUNTPOINT");
825
826                 mafw_gst_renderer_state_handle_pre_unmount(
827                         MAFW_GST_RENDERER_STATE(
828                                 renderer->states[renderer->current_state]),
829                                  emmc_path);
830         }
831 }
832
833 /*----------------------------------------------------------------------------
834   Gnome VFS notifications
835   ----------------------------------------------------------------------------*/
836
837 static void _volume_pre_unmount_cb(GnomeVFSVolumeMonitor *monitor, 
838                                    GnomeVFSVolume *volume,
839                                    MafwGstRenderer *renderer)
840 {
841         gchar *location = gnome_vfs_volume_get_activation_uri(volume);
842         if (!location) {
843                 return;
844         }
845         
846         mafw_gst_renderer_state_handle_pre_unmount(
847                 MAFW_GST_RENDERER_STATE(
848                         renderer->states[renderer->current_state]),
849                 location);
850         
851         g_free(location);
852 }
853
854 /*----------------------------------------------------------------------------
855   Signals
856   ----------------------------------------------------------------------------*/
857
858
859 /**
860  * _signal_state_changed:
861  * @self: A #MafwGstRenderer
862  *
863  * Signals state_changed to all UIs
864  **/
865 static void _signal_state_changed(MafwGstRenderer * self)
866 {
867         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
868
869         g_signal_emit_by_name(MAFW_RENDERER(self),
870                               "state-changed", self->current_state);
871 }
872
873 /**
874  * _signal_playlist_changed:
875  * @self: A #MafwGstRenderer
876  *
877  * Signals playlist update to all UIs
878  **/
879 static void _signal_playlist_changed(MafwGstRenderer * self)
880 {
881         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
882
883         g_signal_emit_by_name(MAFW_RENDERER(self),
884                               "playlist-changed", self->playlist);
885 }
886
887 /**
888  * _signal_media_changed:
889  * @self: A #MafwGstRenderer
890  *
891  * Signals media_changed to all UIs
892  **/
893 static void _signal_media_changed(MafwGstRenderer *self)
894 {
895
896         MafwGstRendererPlaybackMode mode;
897         gint index;
898
899         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
900
901         mode = mafw_gst_renderer_get_playback_mode(MAFW_GST_RENDERER(self));
902         if ((mode == MAFW_GST_RENDERER_MODE_STANDALONE) ||
903             (self->iterator == NULL)) {
904                 index = -1;
905         } else {
906                 index = mafw_playlist_iterator_get_current_index(self->iterator);
907         }
908
909         g_signal_emit_by_name(MAFW_RENDERER(self),
910                               "media-changed",
911                               index,
912                               self->media->object_id);
913 }
914
915 /**
916  * _signal_transport_actions_property_changed:
917  * @self: A #MafwGstRenderer
918  *
919  * Signals transport_actions property_changed to all UIs
920  **/
921 static void _signal_transport_actions_property_changed(MafwGstRenderer * self)
922 {
923         GValue *value;
924
925         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
926
927         value = mafw_gst_renderer_state_get_property_value(
928                 MAFW_GST_RENDERER_STATE(
929                         self->states[self->current_state]),
930                 MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS);
931
932         if (value) {
933                 mafw_extension_emit_property_changed(
934                         MAFW_EXTENSION(self),
935                         MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS,
936                         value);
937                 g_value_unset(value);
938                 g_free(value);
939         }
940 }
941
942
943 /*----------------------------------------------------------------------------
944   State pattern support
945   ----------------------------------------------------------------------------*/
946
947 void mafw_gst_renderer_set_state(MafwGstRenderer *self, MafwPlayState state)
948 {
949         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
950
951         self->current_state = state;
952         _signal_state_changed(self);
953         _signal_transport_actions_property_changed(self);
954 }
955
956 void mafw_gst_renderer_play(MafwRenderer *self, MafwRendererPlaybackCB callback,
957                           gpointer user_data)
958 {
959         MafwGstRenderer *renderer = (MafwGstRenderer*) self;
960         GError *error = NULL;
961
962         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
963
964         g_return_if_fail((renderer->states != 0) &&
965                          (renderer->current_state != _LastMafwPlayState) &&
966                          (renderer->states[renderer->current_state] != NULL));
967
968         mafw_gst_renderer_state_play(
969                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
970                 &error);
971
972         if (callback != NULL)
973                 callback(self, user_data, error);
974         if (error)
975                 g_error_free(error);
976 }
977
978 void mafw_gst_renderer_play_object(MafwRenderer *self,
979                                  const gchar *object_id,
980                                  MafwRendererPlaybackCB callback,
981                                  gpointer user_data)
982 {
983         MafwGstRenderer *renderer = (MafwGstRenderer*) self;
984         GError *error = NULL;
985
986         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
987         g_return_if_fail(object_id != NULL);
988
989         g_return_if_fail((renderer->states != 0) &&
990                          (renderer->current_state != _LastMafwPlayState) &&
991                          (renderer->states[renderer->current_state] != NULL));
992
993         mafw_gst_renderer_state_play_object(
994                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
995                 object_id,
996                 &error);
997
998         if (callback != NULL)
999                 callback(self, user_data, error);
1000         if (error)
1001                 g_error_free(error);
1002 }
1003
1004 void mafw_gst_renderer_stop(MafwRenderer *self, MafwRendererPlaybackCB callback,
1005                           gpointer user_data)
1006 {
1007         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1008         GError *error = NULL;
1009
1010         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1011
1012         g_return_if_fail((renderer->states != 0) &&
1013                          (renderer->current_state != _LastMafwPlayState) &&
1014                          (renderer->states[renderer->current_state] != NULL));
1015
1016         renderer->play_failed_count = 0;
1017         mafw_gst_renderer_state_stop(
1018                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1019                 &error);
1020
1021         if (callback != NULL)
1022                 callback(self, user_data, error);
1023         if (error)
1024                 g_error_free(error);
1025 }
1026
1027
1028 void mafw_gst_renderer_pause(MafwRenderer *self, MafwRendererPlaybackCB callback,
1029                            gpointer user_data)
1030 {
1031         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1032         GError *error = NULL;
1033
1034         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1035
1036         g_return_if_fail((renderer->states != 0) &&
1037                          (renderer->current_state != _LastMafwPlayState) &&
1038                          (renderer->states[renderer->current_state] != NULL));
1039
1040         mafw_gst_renderer_state_pause(
1041                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1042                 &error);
1043
1044         if (callback != NULL)
1045                 callback(self, user_data, error);
1046         if (error)
1047                 g_error_free(error);
1048 }
1049
1050 void mafw_gst_renderer_resume(MafwRenderer *self, MafwRendererPlaybackCB callback,
1051                             gpointer user_data)
1052 {
1053         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1054         GError *error = NULL;
1055
1056         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1057
1058         g_return_if_fail((renderer->states != 0) &&
1059                          (renderer->current_state != _LastMafwPlayState) &&
1060                          (renderer->states[renderer->current_state] != NULL));
1061
1062         mafw_gst_renderer_state_resume(
1063                 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1064                 &error);
1065
1066         if (callback != NULL)
1067                 callback(self, user_data, error);
1068         if (error)
1069                 g_error_free(error);
1070 }
1071
1072 void mafw_gst_renderer_next(MafwRenderer *self, MafwRendererPlaybackCB callback,
1073                           gpointer user_data)
1074 {
1075         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1076         GError *error = NULL;
1077
1078         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1079
1080         g_return_if_fail((renderer->states != 0) &&
1081                          (renderer->current_state != _LastMafwPlayState) &&
1082                          (renderer->states[renderer->current_state] != NULL));
1083
1084         renderer->play_failed_count = 0;
1085         mafw_gst_renderer_state_next(
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_previous(MafwRenderer *self, MafwRendererPlaybackCB callback,
1096                               gpointer user_data)
1097 {
1098         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1099         GError *error = NULL;
1100
1101         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1102
1103         g_return_if_fail((renderer->states != 0) &&
1104                          (renderer->current_state != _LastMafwPlayState) &&
1105                          (renderer->states[renderer->current_state] != NULL));
1106
1107         renderer->play_failed_count = 0;
1108         mafw_gst_renderer_state_previous(
1109                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1110                 &error);
1111
1112         if (callback != NULL)
1113                 callback(self, user_data, error);
1114         if (error)
1115                 g_error_free(error);
1116 }
1117
1118 void mafw_gst_renderer_goto_index(MafwRenderer *self, guint index,
1119                                 MafwRendererPlaybackCB callback,
1120                                 gpointer user_data)
1121 {
1122         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1123         GError *error = NULL;
1124
1125         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1126
1127         g_return_if_fail((renderer->states != 0) &&
1128                          (renderer->current_state != _LastMafwPlayState) &&
1129                          (renderer->states[renderer->current_state] != NULL));
1130
1131         renderer->play_failed_count = 0;
1132         mafw_gst_renderer_state_goto_index(
1133                 MAFW_GST_RENDERER_STATE(renderer->states[renderer->current_state]),
1134                 index,
1135                 &error);
1136
1137         if (callback != NULL)
1138                 callback(self, user_data, error);
1139         if (error)
1140                 g_error_free(error);
1141 }
1142
1143 void mafw_gst_renderer_get_position(MafwRenderer *self, MafwRendererPositionCB callback,
1144                                   gpointer user_data)
1145 {
1146         MafwGstRenderer *renderer;
1147         gint pos;
1148         GError *error = NULL;
1149
1150         g_return_if_fail(callback != NULL);
1151         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1152
1153         renderer = MAFW_GST_RENDERER(self);
1154
1155         g_return_if_fail((renderer->states != 0) &&
1156                          (renderer->current_state != _LastMafwPlayState) &&
1157                          (renderer->states[renderer->current_state] != NULL));
1158
1159         mafw_gst_renderer_state_get_position(
1160                 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1161                 &pos,
1162                 &error);
1163         
1164         callback(self, pos, user_data, error);
1165         if (error)
1166                 g_error_free(error);
1167 }
1168
1169 void mafw_gst_renderer_set_position(MafwRenderer *self, MafwRendererSeekMode mode,
1170                                    gint seconds, MafwRendererPositionCB callback,
1171                                    gpointer user_data)
1172 {
1173         MafwGstRenderer *renderer = (MafwGstRenderer *) self;
1174         GError *error = NULL;
1175
1176         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1177
1178         g_return_if_fail((renderer->states != 0) &&
1179                          (renderer->current_state != _LastMafwPlayState) &&
1180                          (renderer->states[renderer->current_state] != NULL));
1181
1182         mafw_gst_renderer_state_set_position(
1183                 MAFW_GST_RENDERER_STATE (renderer->states[renderer->current_state]),
1184                 mode,
1185                 seconds,
1186                 &error);
1187
1188         if (callback != NULL)
1189                 callback(self, seconds, user_data, error);
1190         if (error)
1191                 g_error_free(error);
1192 }
1193
1194 gboolean mafw_gst_renderer_manage_error_idle(gpointer data)
1195 {
1196         MafwGstRendererErrorClosure *mec = (MafwGstRendererErrorClosure *) data;
1197
1198         mafw_gst_renderer_manage_error(mec->renderer, mec->error);
1199         if (mec->error)
1200                 g_error_free(mec->error);
1201         g_free(mec);
1202
1203         return FALSE;
1204 }
1205
1206 static void _run_error_policy(MafwGstRenderer *self, const GError *in_err,
1207                               GError **out_err)
1208 {
1209         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1210
1211         gboolean play_next = FALSE;
1212
1213         /* Check what to do on error */
1214         if (in_err->code == MAFW_EXTENSION_ERROR_OUT_OF_MEMORY) {
1215                 play_next = FALSE;
1216         } else {
1217                 MafwGstRendererPlaybackMode mode;
1218
1219                 mode = mafw_gst_renderer_get_playback_mode(self);
1220
1221                 if (mode == MAFW_GST_RENDERER_MODE_PLAYLIST) {
1222                         /* In playlist mode we try to play next if
1223                            error policy suggests so */
1224                         play_next =
1225                                 (_get_error_policy(self) ==
1226                                  MAFW_RENDERER_ERROR_POLICY_CONTINUE);
1227                 } else {
1228                         /* In standalone mode, then switch back to playlist
1229                            mode and resume if necessary or move to Stopped
1230                            otherwise */
1231                         mafw_gst_renderer_set_playback_mode(
1232                                 self, MAFW_GST_RENDERER_MODE_PLAYLIST);
1233                         mafw_gst_renderer_set_media_playlist(self);
1234                         if (self->resume_playlist) {
1235                                 mafw_gst_renderer_play(MAFW_RENDERER(self),
1236                                                      NULL, NULL);
1237                         } else {
1238                                 mafw_gst_renderer_worker_stop(self->worker);
1239                                 mafw_gst_renderer_set_state(self, Stopped);
1240                         }
1241                         if (out_err) *out_err = g_error_copy(in_err);
1242
1243                         /* Bail out, he have already managed the error
1244                            for the case of standalone mode */
1245                         return;
1246                 }
1247         }
1248
1249         if (play_next) {
1250                 if (self->playlist){
1251                         MafwPlaylistIteratorMovementResult result;
1252
1253                         result = mafw_playlist_iterator_move_to_next(self->iterator,
1254                                                                       NULL);
1255                         self->play_failed_count++;
1256
1257                         if (mafw_playlist_iterator_get_size(self->iterator,
1258                                 NULL) <=
1259                                 self->play_failed_count)
1260                         {
1261                                 mafw_gst_renderer_state_stop(
1262                                         MAFW_GST_RENDERER_STATE(self->states[self->current_state]),
1263                                         NULL);
1264                                 self->play_failed_count = 0;
1265                                 mafw_gst_renderer_set_media_playlist(self);
1266                         } else if (result !=
1267                                    MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_OK) {
1268                                 mafw_playlist_iterator_reset(self->iterator, NULL);
1269                                 mafw_gst_renderer_set_media_playlist(self);
1270                                 mafw_gst_renderer_stop(MAFW_RENDERER(self), NULL, NULL);
1271                         } else {
1272                                 mafw_gst_renderer_set_media_playlist(self);
1273                                 mafw_gst_renderer_play(MAFW_RENDERER(self), NULL, NULL);
1274                         }
1275
1276                         if (out_err) *out_err = g_error_copy(in_err);
1277                 }
1278         } else {
1279                 /* We cannot move to next in the playlist or decided
1280                    we do not want to do it, just stop on error */
1281                 mafw_gst_renderer_stop(MAFW_RENDERER(self), NULL, NULL);
1282                 if (out_err) *out_err = g_error_copy(in_err);
1283         }
1284 }
1285
1286 static void _metadata_set_cb(MafwSource *self, const gchar *object_id,
1287                                 const gchar **failed_keys, gpointer user_data,
1288                                 const GError *error)
1289 {
1290         if (error != NULL) {
1291                 g_debug("Ignoring error received when setting metadata: "
1292                         "%s (%d): %s", g_quark_to_string(error->domain),
1293                         error->code, error->message);
1294         } else {
1295                 g_debug("Metadata set correctly");
1296         }
1297 }
1298
1299 /**
1300  * _update_playcount_metadata_cb:
1301  * @cb_source:   The #MafwSource that sent the metadata results
1302  * @cb_object_id: The object ID, whose metadata results were received
1303  * @cb_metadata: GHashTable containing metadata key-value pairs
1304  * @cb_user_data: Optional user data pointer (self)
1305  * @cb_error:    Set if any errors occurred during metadata browsing
1306  *
1307  * Receives the results of a metadata request about the playcount. It increases
1308  * it, or sets to 1, and sets the metadata to that.
1309  */
1310 static void _update_playcount_metadata_cb (MafwSource *cb_source,
1311                                            const gchar *cb_object_id,
1312                                            GHashTable *cb_metadata,
1313                                            gpointer cb_user_data,
1314                                            const GError *cb_error)
1315 {
1316         GValue *curval = NULL;
1317         gint curplaycount = -1;
1318         GHashTable *mdata = cb_user_data;
1319
1320         if (cb_error == NULL) {
1321                 if (cb_metadata)
1322                         curval = mafw_metadata_first(cb_metadata,
1323                                 MAFW_METADATA_KEY_PLAY_COUNT);
1324                 if (curval && !G_VALUE_HOLDS(curval, G_TYPE_INT))
1325                         goto set_data;
1326                 if (curval)
1327                 {
1328                         curplaycount = g_value_get_int(curval);
1329                         curplaycount++;
1330                 }
1331                 else
1332                 { /* Playing at first time, or not supported... */
1333                         curplaycount = 1;
1334                 }
1335                 if (!mdata)
1336                         mdata = mafw_metadata_new();
1337                 mafw_metadata_add_int(mdata,
1338                                         MAFW_METADATA_KEY_PLAY_COUNT,
1339                                         curplaycount);
1340
1341         } else {
1342                 g_warning("_playcount_metadata received an error: "
1343                           "%s (%d): %s", g_quark_to_string(cb_error->domain),
1344                           cb_error->code, cb_error->message);
1345                 if (mdata)
1346                         g_hash_table_unref(mdata);
1347                 return;
1348         }
1349 set_data:
1350         
1351         if (mdata)
1352         {
1353                 mafw_source_set_metadata(cb_source, cb_object_id, mdata,
1354                                                 _metadata_set_cb, NULL);
1355                 g_hash_table_unref(mdata);
1356         }
1357 }
1358
1359 /**
1360  * mafw_gst_renderer_add_lastplayed:
1361  * @mdata:   Exisiting mdata, or NULL
1362  *
1363  * Sets the MAFW_METADATA_KEY_LAST_PLAYED metadata in the given metadata-table,
1364  * or creates a new metadata-table, and sets the current time there.
1365  */
1366 static GHashTable *mafw_gst_renderer_add_lastplayed(GHashTable *mdata)
1367 {
1368         GHashTable *metadata;
1369         GTimeVal timeval;
1370
1371         
1372         if (!mdata)
1373                 metadata = mafw_metadata_new();
1374         else
1375                 metadata = mdata;
1376         
1377                 
1378
1379         g_get_current_time(&timeval);
1380                 
1381         mafw_metadata_add_long(metadata,
1382                                         MAFW_METADATA_KEY_LAST_PLAYED,
1383                                         timeval.tv_sec);
1384         return metadata;
1385 }
1386
1387 /**
1388  * mafw_gst_renderer_increase_playcount:
1389  * @self:   Gst renderer
1390  * @object_id: The object ID of the touched object
1391  * @mdat: Existing metadatas to add the playcount to, or NULL
1392  *
1393  * Increases the playcount of the given object.
1394  */
1395 static void mafw_gst_renderer_increase_playcount(MafwGstRenderer* self,
1396                                         const gchar *object_id, GHashTable *mdat)
1397 {
1398         MafwSource* source;
1399
1400         g_assert(self != NULL);
1401         source = _get_source(self, object_id);
1402         if (source != NULL)
1403         {
1404                 static const gchar * const keys[] =
1405                         { MAFW_METADATA_KEY_PLAY_COUNT, NULL };
1406
1407                 mafw_source_get_metadata(source, object_id,
1408                                          keys,
1409                                          _update_playcount_metadata_cb,
1410                                          mdat);
1411
1412         }
1413 }
1414
1415 /**
1416  * mafw_gst_renderer_update_stats:
1417  * @data: user data
1418  *
1419  * Updates both playcount and lastplayed after a while.
1420  **/
1421 gboolean mafw_gst_renderer_update_stats(gpointer data)
1422 {
1423         MafwGstRenderer *renderer = (MafwGstRenderer *) data;
1424
1425         /* Update stats only for audio content */
1426         if (renderer->media->object_id &&
1427             !renderer->worker->media.has_visual_content) {
1428                 GHashTable *mdata = mafw_gst_renderer_add_lastplayed(NULL);
1429                 mafw_gst_renderer_increase_playcount(renderer,
1430                                                      renderer->media->object_id,
1431                                                      mdata);
1432         }
1433         renderer->update_playcount_id = 0;
1434         return FALSE;
1435 }
1436
1437 void mafw_gst_renderer_update_source_duration(MafwGstRenderer *renderer,
1438                                               gint duration)
1439 {
1440         GHashTable *metadata;
1441         MafwSource* source;
1442
1443         source = _get_source(renderer, renderer->media->object_id);
1444         g_return_if_fail(source != NULL);
1445
1446         renderer->media->duration = duration;
1447
1448         g_debug("updated source duration to %d", duration);
1449
1450         metadata = mafw_metadata_new();
1451         mafw_metadata_add_int(metadata, MAFW_METADATA_KEY_DURATION, duration);
1452
1453         mafw_source_set_metadata(source, renderer->media->object_id, metadata,
1454                                  _metadata_set_cb, NULL);
1455         g_hash_table_unref(metadata);
1456 }
1457
1458 /**
1459  * _notify_metadata:
1460  * @source:   The #MafwSource that sent the metadata results
1461  * @objectid: The object ID, whose metadata results were received
1462  * @metadata: GHashTable containing metadata key-value pairs
1463  * @userdata: Optional user data pointer (self)
1464  * @error:    Set if any errors occurred during metadata browsing
1465  *
1466  * Receives the results of a metadata request.
1467  */
1468 static void _notify_metadata (MafwSource *cb_source,
1469                               const gchar *cb_object_id,
1470                               GHashTable *cb_metadata,
1471                               gpointer cb_user_data,
1472                               const GError *cb_error)
1473 {
1474         MafwGstRenderer *renderer = (MafwGstRenderer*) cb_user_data;
1475         GError *mafw_error = NULL;
1476         GError *error = NULL;
1477         GValue *mval;
1478
1479         g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1480
1481         g_return_if_fail((renderer->states != 0) &&
1482                          (renderer->current_state != _LastMafwPlayState) &&
1483                          (renderer->states[renderer->current_state] != NULL));
1484
1485         g_debug("running _notify_metadata...");
1486
1487         mval = mafw_metadata_first(cb_metadata, MAFW_METADATA_KEY_URI);
1488
1489         if (cb_error == NULL && mval != NULL) {
1490                 mafw_gst_renderer_state_notify_metadata(
1491                         MAFW_GST_RENDERER_STATE(
1492                                 renderer->states[renderer->current_state]),
1493                         cb_object_id,
1494                         cb_metadata,
1495                         &error);
1496         }
1497         else {
1498                 g_set_error(&mafw_error,
1499                             MAFW_RENDERER_ERROR,
1500                             MAFW_RENDERER_ERROR_URI_NOT_AVAILABLE, "%s",
1501                             cb_error ? cb_error->message : "URI not available");
1502                 mafw_gst_renderer_manage_error(renderer, mafw_error);
1503                 g_error_free(mafw_error);
1504         }
1505 }
1506
1507 static void _notify_play(MafwGstRendererWorker *worker, gpointer owner)
1508 {
1509         MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1510         GError *error = NULL;
1511
1512         g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1513
1514         g_return_if_fail((renderer->states != 0) &&
1515                          (renderer->current_state != _LastMafwPlayState) &&
1516                          (renderer->states[renderer->current_state] != NULL));
1517
1518         g_debug("running _notify_play...");
1519
1520         mafw_gst_renderer_state_notify_play(renderer->states[renderer->current_state],
1521                                           &error);
1522
1523         if (error != NULL) {
1524                 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1525                                       error->domain,
1526                                       error->code,
1527                                       error->message);
1528                 g_error_free (error);
1529         }
1530 }
1531
1532 static void _notify_pause(MafwGstRendererWorker *worker, gpointer owner)
1533 {
1534         MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1535         GError *error = NULL;
1536
1537         g_return_if_fail(MAFW_IS_GST_RENDERER (renderer));
1538
1539         g_return_if_fail((renderer->states != 0) &&
1540                          (renderer->current_state != _LastMafwPlayState) &&
1541                          (renderer->states[renderer->current_state] != NULL));
1542
1543         mafw_gst_renderer_state_notify_pause(renderer->states[renderer->current_state],
1544                                            &error);
1545
1546         if (error != NULL) {
1547                 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1548                                       error->domain, error->code,
1549                                       error->message);
1550                 g_error_free(error);
1551         }
1552 }
1553
1554 static void _notify_buffer_status (MafwGstRendererWorker *worker,
1555                                    gpointer owner,
1556                                    gdouble percent)
1557 {
1558         MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1559         GError *error = NULL;
1560
1561         g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1562
1563         g_return_if_fail((renderer->states != 0) &&
1564                          (renderer->current_state != _LastMafwPlayState) &&
1565                          (renderer->states[renderer->current_state] != NULL));
1566
1567         mafw_gst_renderer_state_notify_buffer_status(
1568                 renderer->states[renderer->current_state],
1569                 percent,
1570                 &error);
1571
1572         if (error != NULL) {
1573                 g_signal_emit_by_name(MAFW_EXTENSION (renderer), "error",
1574                                       error->domain, error->code,
1575                                       error->message);
1576                 g_error_free(error);
1577         }
1578 }
1579
1580 static void _notify_seek(MafwGstRendererWorker *worker, gpointer owner)
1581 {
1582         MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1583         GError *error = NULL;
1584
1585         g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1586
1587         g_return_if_fail((renderer->states != 0) &&
1588                          (renderer->current_state != _LastMafwPlayState) &&
1589                          (renderer->states[renderer->current_state] != NULL));
1590
1591         mafw_gst_renderer_state_notify_seek(renderer->states[renderer->current_state],
1592                                           &error);
1593
1594         if (error != NULL) {
1595                 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1596                                       error->domain, error->code,
1597                                       error->message);
1598                 g_error_free(error);
1599         }
1600 }
1601
1602 static void _playlist_changed_handler(MafwPlaylistIterator *iterator,
1603                                       gboolean clip_changed, GQuark domain,
1604                                       gint code, const gchar *message,
1605                                       gpointer user_data)
1606 {
1607         MafwGstRenderer *renderer = (MafwGstRenderer*) user_data;
1608
1609         g_return_if_fail(MAFW_IS_GST_RENDERER(renderer));
1610
1611         g_return_if_fail((renderer->states != 0) &&
1612                          (renderer->current_state != _LastMafwPlayState) &&
1613                          (renderer->states[renderer->current_state] != NULL));
1614
1615         /* We update the current index and media here,  for this is
1616            the same for all the states. Then we delegate in the state
1617            to finish the task (for example, start playback if needed) */
1618
1619         if (renderer->playlist == NULL) {
1620                 g_critical("Got iterator:contents-changed but renderer has no" \
1621                            "playlist assigned!. Skipping...");
1622                 return;
1623         }
1624
1625         if (domain != 0) {
1626                 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1627                                       domain, code, message);
1628         } else {
1629                 GError *error = NULL;
1630                 MafwGstRendererPlaybackMode mode;
1631                 
1632                 mode = mafw_gst_renderer_get_playback_mode(renderer);
1633
1634                 /* Only in non-playobject mode */               
1635                 if (clip_changed && mode == MAFW_GST_RENDERER_MODE_PLAYLIST)
1636                         mafw_gst_renderer_set_media_playlist(renderer);
1637
1638                 /* We let the state know if the current clip has changed as
1639                    result of this operation, so it can do its work */
1640                 mafw_gst_renderer_state_playlist_contents_changed_handler(
1641                         renderer->states[renderer->current_state],
1642                         clip_changed,
1643                         &error);
1644
1645                 if (error != NULL) {
1646                         g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1647                                               error->domain, error->code,
1648                                               error->message);
1649                         g_error_free(error);
1650                 }
1651         }
1652 }
1653
1654 static void _error_handler(MafwGstRendererWorker *worker, gpointer owner,
1655                            const GError *error)
1656 {
1657         MafwGstRenderer *renderer = MAFW_GST_RENDERER(owner);
1658
1659         mafw_gst_renderer_manage_error(renderer, error);
1660 }
1661
1662 void mafw_gst_renderer_manage_error(MafwGstRenderer *self, const GError *error)
1663 {
1664         GError *new_err = NULL;
1665         GError *raise_error = NULL;
1666         GQuark new_err_domain = MAFW_RENDERER_ERROR;
1667         gint new_err_code = 0;
1668
1669         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1670
1671         g_return_if_fail((self->states != 0) &&
1672                          (self->current_state != _LastMafwPlayState) &&
1673                          (self->states[self->current_state] != NULL));
1674
1675         g_warning("Got error in renderer:\n\tdomain: %d, code: %d, message: %s",
1676                   error->domain, error->code, error->message);
1677
1678         /* Get a MAFW error */
1679         if (error->domain == GST_RESOURCE_ERROR) {
1680                 /* handle RESOURCE errors */
1681                 switch (error->code) {
1682                 case GST_RESOURCE_ERROR_READ:
1683                         if (is_current_uri_stream(self)) {
1684 #ifdef HAVE_CONIC
1685                                 if (self->connected) {
1686                                         new_err_code = MAFW_RENDERER_ERROR_STREAM_DISCONNECTED;
1687                                 } else {
1688                                         new_err_domain = MAFW_EXTENSION_ERROR;
1689                                         new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1690                                 }
1691 #else
1692                                 /* Stream + cannot read resource ->
1693                                    disconnected */
1694                                 new_err_code = MAFW_RENDERER_ERROR_STREAM_DISCONNECTED;
1695 #endif
1696                         } else {
1697                                 /* This shouldn't happen */
1698                                 /* Unknown RESOURCE error */
1699                                 new_err_domain = MAFW_EXTENSION_ERROR;
1700                                 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1701                         }
1702                         break;
1703                 case GST_RESOURCE_ERROR_NOT_FOUND:
1704 #ifdef HAVE_CONIC
1705                         if (!is_current_uri_stream(self) || self->connected) {
1706                                 new_err_code =
1707                                         MAFW_RENDERER_ERROR_INVALID_URI;
1708                         } else {
1709                                 new_err_domain = MAFW_EXTENSION_ERROR;
1710                                 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1711                         }
1712 #else
1713                         new_err_code =
1714                                 MAFW_RENDERER_ERROR_INVALID_URI;
1715 #endif
1716                         break;
1717                 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
1718                 case GST_RESOURCE_ERROR_OPEN_READ:
1719 #ifdef HAVE_CONIC
1720                         if (!is_current_uri_stream(self) || self->connected) {
1721                                 new_err_code =
1722                                         MAFW_RENDERER_ERROR_MEDIA_NOT_FOUND;
1723                         } else {
1724                                 new_err_domain = MAFW_EXTENSION_ERROR;
1725                                 new_err_code = MAFW_EXTENSION_ERROR_NETWORK_DOWN;
1726                         }
1727 #else
1728                         new_err_code =
1729                                 MAFW_RENDERER_ERROR_MEDIA_NOT_FOUND;
1730 #endif
1731                         break;
1732                 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
1733                         new_err_domain = MAFW_EXTENSION_ERROR;
1734                         new_err_code = MAFW_EXTENSION_ERROR_OUT_OF_MEMORY;
1735                         break;
1736                 case GST_RESOURCE_ERROR_WRITE:
1737                         /* DSP renderers send ERROR_WRITE when they find
1738                            corrupted data */
1739                         new_err_code = MAFW_RENDERER_ERROR_CORRUPTED_FILE;
1740                         break;
1741                 case GST_RESOURCE_ERROR_SEEK:
1742                         new_err_code = MAFW_RENDERER_ERROR_CANNOT_SET_POSITION;
1743                         break;
1744                 default:
1745                         /* Unknown RESOURCE error */
1746                         new_err_domain = MAFW_EXTENSION_ERROR;
1747                         new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1748                 }
1749
1750         } else if (error->domain == GST_STREAM_ERROR) {
1751                 /* handle STREAM errors */
1752                 switch (error->code) {
1753                 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
1754                         new_err_code = MAFW_RENDERER_ERROR_TYPE_NOT_AVAILABLE;
1755                         break;
1756                 case GST_STREAM_ERROR_FORMAT:
1757                 case GST_STREAM_ERROR_WRONG_TYPE:
1758                 case GST_STREAM_ERROR_FAILED:
1759                         new_err_code = MAFW_RENDERER_ERROR_UNSUPPORTED_TYPE;
1760                         break;
1761                 case GST_STREAM_ERROR_DECODE:
1762                 case GST_STREAM_ERROR_DEMUX:
1763                         new_err_code = MAFW_RENDERER_ERROR_CORRUPTED_FILE;
1764                         break;
1765                 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
1766                         new_err_code = MAFW_RENDERER_ERROR_CODEC_NOT_FOUND;
1767                         break;
1768                 case GST_STREAM_ERROR_DECRYPT:
1769                 case GST_STREAM_ERROR_DECRYPT_NOKEY:
1770                         new_err_code = MAFW_RENDERER_ERROR_DRM;
1771                         break;
1772                 default:
1773                         /* Unknown STREAM error */
1774                         new_err_domain = MAFW_EXTENSION_ERROR;
1775                         new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1776                 }
1777         } else if (error->domain == MAFW_GST_RENDERER_ERROR) {
1778                 /* Handle own errors. Errors that belong to this domain:
1779                       - MAFW_GST_RENDERER_ERROR_PLUGIN_NOT_FOUND,
1780                       - MAFW_GST_RENDERER_ERROR_VIDEO_CODEC_NOT_SUPPORTED,
1781                       - MAFW_GST_RENDERER_ERROR_AUDIO_CODEC_NOT_SUPPORTED */
1782                 new_err_code = MAFW_RENDERER_ERROR_UNSUPPORTED_TYPE;
1783         } else if (error->domain == MAFW_RENDERER_ERROR) {
1784                 /* Worker may have sent MAFW_RENDERER_ERROR as well.
1785                    No processing needed */
1786                 new_err_code = error->code;
1787         } else {
1788                 /* default */
1789                 /* Unknown error */
1790                 new_err_domain = MAFW_EXTENSION_ERROR;
1791                 new_err_code = MAFW_EXTENSION_ERROR_FAILED;
1792         }
1793
1794         g_set_error(&new_err, new_err_domain, new_err_code, "%s", error->message);
1795
1796         _run_error_policy(self, new_err, &raise_error);
1797         g_error_free(new_err);
1798
1799         if (raise_error) {
1800                 g_signal_emit_by_name(MAFW_EXTENSION (self), "error",
1801                                       raise_error->domain,
1802                                       raise_error->code,
1803                                       raise_error->message);
1804                 g_error_free(raise_error);
1805         }
1806 }
1807
1808 static void _notify_eos(MafwGstRendererWorker *worker, gpointer owner)
1809 {
1810         MafwGstRenderer *renderer = (MafwGstRenderer*) owner;
1811         GError *error = NULL;
1812
1813         g_return_if_fail(MAFW_IS_GST_RENDERER (renderer));
1814
1815         g_return_if_fail((renderer->states != 0) &&
1816                          (renderer->current_state != _LastMafwPlayState) &&
1817                          (renderer->states[renderer->current_state] != NULL));
1818
1819         mafw_gst_renderer_state_notify_eos(renderer->states[renderer->current_state],
1820                                          &error);
1821
1822         if (error != NULL) {
1823                 g_signal_emit_by_name(MAFW_EXTENSION(renderer), "error",
1824                                       error->domain, error->code,
1825                                       error->message);
1826                 g_error_free(error);
1827         }
1828 }
1829
1830 /*----------------------------------------------------------------------------
1831   Status
1832   ----------------------------------------------------------------------------*/
1833
1834 void mafw_gst_renderer_get_status(MafwRenderer *self, MafwRendererStatusCB callback,
1835                                 gpointer user_data)
1836 {
1837         MafwGstRenderer* renderer;
1838         gint index;
1839         MafwGstRendererPlaybackMode mode;
1840
1841         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1842         g_return_if_fail(callback != NULL);
1843         renderer = MAFW_GST_RENDERER(self);
1844
1845         mode = mafw_gst_renderer_get_playback_mode(MAFW_GST_RENDERER(self));
1846         if ((mode == MAFW_GST_RENDERER_MODE_STANDALONE) || (renderer->iterator == NULL)) {
1847                 index = -1;
1848         } else {
1849                 index =
1850                         mafw_playlist_iterator_get_current_index(renderer->iterator);
1851         }
1852
1853         /* TODO: Set error parameter */
1854         callback(self, renderer->playlist, index, renderer->current_state,
1855                  (const gchar*) renderer->media->object_id, user_data, NULL);
1856 }
1857
1858 void mafw_gst_renderer_get_current_metadata(MafwRenderer *self,
1859                                             MafwRendererMetadataResultCB callback,
1860                                             gpointer user_data)
1861 {
1862         MafwGstRenderer *renderer;
1863         GHashTable *metadata;
1864
1865         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
1866         renderer = MAFW_GST_RENDERER(self);
1867
1868         metadata = mafw_gst_renderer_worker_get_current_metadata(
1869                         renderer->worker);
1870
1871         callback(self,
1872                  (const gchar*) renderer->media->object_id,
1873                  metadata,
1874                  user_data,
1875                  NULL);
1876 }
1877
1878 /*----------------------------------------------------------------------------
1879   Playlist
1880   ----------------------------------------------------------------------------*/
1881
1882 static void
1883 _playlist_contents_changed_handler(MafwPlaylist *playlist,
1884                                         guint from, guint nremove,
1885                                         guint nreplace,
1886                                         MafwGstRenderer *renderer)
1887 {
1888         /* Item(s) added to playlist, so new playable items could come */
1889         if (nreplace)
1890                 renderer->play_failed_count = 0;
1891 }
1892
1893 gboolean mafw_gst_renderer_assign_playlist(MafwRenderer *self,
1894                                            MafwPlaylist *playlist,
1895                                            GError **error)
1896 {
1897         MafwGstRenderer* renderer = (MafwGstRenderer*) self;
1898
1899         g_return_val_if_fail(MAFW_IS_GST_RENDERER(self), FALSE);
1900
1901         /* Get rid of previously assigned playlist  */
1902         if (renderer->playlist != NULL) {
1903                 g_signal_handlers_disconnect_matched(renderer->iterator,
1904                                                      (GSignalMatchType) G_SIGNAL_MATCH_FUNC,
1905                                                      0, 0, NULL,
1906                                                      _playlist_changed_handler,
1907                                                      NULL);
1908                 g_signal_handlers_disconnect_matched(renderer->playlist,
1909                                         (GSignalMatchType) G_SIGNAL_MATCH_FUNC,
1910                                         0, 0, NULL,
1911                                         G_CALLBACK(_playlist_contents_changed_handler),
1912                                         NULL);
1913                 /* Decrement the use count of the previous playlist because the
1914                    renderer isn't going to use it more */
1915                 mafw_playlist_decrement_use_count(renderer->playlist, NULL);
1916
1917                 g_object_unref(renderer->iterator);
1918                 g_object_unref(renderer->playlist);
1919         }
1920
1921         /* Assign the new playlist */
1922         if (playlist == NULL) {
1923                 renderer->playlist = NULL;
1924                 renderer->iterator = NULL;
1925         } else {
1926                 GError *new_error = NULL;
1927                 MafwPlaylistIterator *iterator = NULL;
1928
1929                 iterator = mafw_playlist_iterator_new();
1930                 mafw_playlist_iterator_initialize(iterator, playlist,
1931                                                    &new_error);
1932                 
1933                 g_object_ref(playlist);
1934
1935                 if (new_error == NULL) {
1936
1937                         renderer->playlist = playlist;
1938                         renderer->iterator = iterator;
1939
1940                         /* Increment the use_count to avoid the playlist destruction
1941                            while the playlist is assigned to some renderer */
1942                         mafw_playlist_increment_use_count(renderer->playlist, NULL);
1943
1944                         g_signal_connect(iterator,
1945                                          "playlist-changed",
1946                                          G_CALLBACK(_playlist_changed_handler),
1947                                          renderer);
1948                         g_signal_connect(renderer->playlist,
1949                                          "contents-changed",
1950                                          G_CALLBACK(_playlist_contents_changed_handler),
1951                                          renderer);
1952                 }
1953                 else {
1954                         g_propagate_error (error, new_error);
1955                 }
1956         }
1957
1958         /* Set the new media and signal playlist changed signal */
1959         _signal_playlist_changed(renderer);
1960         mafw_gst_renderer_set_media_playlist(renderer);
1961
1962
1963         /* Stop playback */
1964         mafw_gst_renderer_stop(MAFW_RENDERER(renderer), NULL , NULL);
1965
1966         return TRUE;
1967 }
1968
1969 MafwGstRendererMovementResult mafw_gst_renderer_move(MafwGstRenderer *renderer,
1970                                                    MafwGstRendererMovementType type,
1971                                                    guint index,
1972                                                    GError **error)
1973 {
1974         MafwGstRendererMovementResult value = MAFW_GST_RENDERER_MOVE_RESULT_OK;
1975
1976         if (renderer->playlist == NULL) {
1977                 value = MAFW_GST_RENDERER_MOVE_RESULT_NO_PLAYLIST;
1978         } else {
1979                 MafwPlaylistIteratorMovementResult result;
1980
1981                 switch (type) {
1982                 case MAFW_GST_RENDERER_MOVE_TYPE_INDEX:
1983                         result =
1984                                 mafw_playlist_iterator_move_to_index(renderer->iterator,
1985                                                                       index,
1986                                                                       error);
1987                         break;
1988                 case MAFW_GST_RENDERER_MOVE_TYPE_PREV:
1989                         result =
1990                                 mafw_playlist_iterator_move_to_prev(renderer->iterator,
1991                                                                      error);
1992                         break;
1993                 case MAFW_GST_RENDERER_MOVE_TYPE_NEXT:
1994                         result =
1995                                 mafw_playlist_iterator_move_to_next(renderer->iterator,
1996                                                                      error);
1997                         break;
1998                 }
1999
2000                 switch (result) {
2001                 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_OK:
2002                         value = MAFW_GST_RENDERER_MOVE_RESULT_OK;
2003                         mafw_gst_renderer_set_media_playlist(renderer);
2004                         break;
2005                 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_INVALID:
2006                         g_critical("Iterator is invalid!");
2007                         value = MAFW_GST_RENDERER_MOVE_RESULT_ERROR;
2008                         break;
2009                 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_ERROR:
2010                         value = MAFW_GST_RENDERER_MOVE_RESULT_ERROR;
2011                         break;
2012                 case MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_LIMIT:
2013                         value = MAFW_GST_RENDERER_MOVE_RESULT_PLAYLIST_LIMIT;
2014                         break;
2015                 }
2016         }
2017
2018         return value;
2019 }
2020
2021 /*----------------------------------------------------------------------------
2022   Properties
2023   ----------------------------------------------------------------------------*/
2024
2025 static void _set_error_policy(MafwGstRenderer *renderer, MafwRendererErrorPolicy policy)
2026 {
2027         renderer->error_policy = policy;
2028 }
2029
2030 static MafwRendererErrorPolicy _get_error_policy(MafwGstRenderer *renderer)
2031 {
2032         return renderer->error_policy;
2033 }
2034
2035 static void mafw_gst_renderer_get_property(MafwExtension *self,
2036                                          const gchar *key,
2037                                          MafwExtensionPropertyCallback callback,
2038                                          gpointer user_data)
2039 {
2040         MafwGstRenderer *renderer;
2041         GValue *value = NULL;
2042         GError *error = NULL;
2043
2044         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
2045         g_return_if_fail(callback != NULL);
2046         g_return_if_fail(key != NULL);
2047
2048         renderer = MAFW_GST_RENDERER(self);
2049         if (!strcmp(key, MAFW_PROPERTY_RENDERER_VOLUME)) {
2050                 guint volume;
2051
2052                 volume = mafw_gst_renderer_worker_get_volume(
2053                         renderer->worker);
2054
2055                 value = g_new0(GValue, 1);
2056                 g_value_init(value, G_TYPE_UINT);
2057                 g_value_set_uint(value, volume);
2058         }
2059         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_MUTE)) {
2060                 gboolean mute;
2061                 mute = mafw_gst_renderer_worker_get_mute(renderer->worker);
2062                 value = g_new0(GValue, 1);
2063                 g_value_init(value, G_TYPE_BOOLEAN);
2064                 g_value_set_boolean(value, mute);
2065         }
2066         else if (!strcmp (key, MAFW_PROPERTY_RENDERER_XID)) {
2067                 guint xid;
2068                 xid = mafw_gst_renderer_worker_get_xid(renderer->worker);
2069                 value = g_new0(GValue, 1);
2070                 g_value_init(value, G_TYPE_UINT);
2071                 g_value_set_uint(value, xid);
2072         }
2073         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_ERROR_POLICY)) {
2074                 guint policy;
2075                 policy = _get_error_policy(renderer);
2076                 value = g_new0(GValue, 1);
2077                 g_value_init(value, G_TYPE_UINT);
2078                 g_value_set_uint(value, policy);
2079         }
2080         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_AUTOPAINT)) {
2081                 value = g_new0(GValue, 1);
2082                 g_value_init(value, G_TYPE_BOOLEAN);
2083                 g_value_set_boolean(
2084                         value,
2085                         mafw_gst_renderer_worker_get_autopaint(
2086                                 renderer->worker));
2087         } else if (!strcmp(key, MAFW_PROPERTY_RENDERER_COLORKEY)) {
2088                 value = g_new0(GValue, 1);
2089                 g_value_init(value, G_TYPE_INT);
2090                 g_value_set_int(
2091                         value,
2092                         mafw_gst_renderer_worker_get_colorkey(
2093                                 renderer->worker));
2094         }
2095 #ifdef HAVE_GDKPIXBUF
2096         else if (!strcmp(key,
2097                          MAFW_PROPERTY_GST_RENDERER_CURRENT_FRAME_ON_PAUSE)) {
2098                 gboolean current_frame_on_pause;
2099                 current_frame_on_pause =
2100                         mafw_gst_renderer_worker_get_current_frame_on_pause(renderer->worker);
2101                 value = g_new0(GValue, 1);
2102                 g_value_init(value, G_TYPE_BOOLEAN);
2103                 g_value_set_boolean(value, current_frame_on_pause);
2104         }
2105 #endif
2106         else if (!strcmp(key,
2107                          MAFW_PROPERTY_GST_RENDERER_TV_CONNECTED)) {
2108                 value = g_new0(GValue, 1);
2109                 g_value_init(value, G_TYPE_BOOLEAN);
2110                 g_value_set_boolean(value, renderer->tv_connected);
2111         }
2112         else if (!strcmp(key,
2113                          MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS)){
2114                 /* Delegate in the state. */
2115                 value = mafw_gst_renderer_state_get_property_value(
2116                         MAFW_GST_RENDERER_STATE(
2117                                 renderer->states[renderer->current_state]),
2118                         MAFW_PROPERTY_RENDERER_TRANSPORT_ACTIONS);
2119
2120                 if (!value) {
2121                         /* Something goes wrong. */
2122                         error = g_error_new(
2123                                 MAFW_GST_RENDERER_ERROR,
2124                                 MAFW_EXTENSION_ERROR_GET_PROPERTY,
2125                                 "Error while getting the property value");
2126                 }
2127         }
2128         else {
2129                 /* Unsupported property */
2130                 error = g_error_new(MAFW_GST_RENDERER_ERROR,
2131                                     MAFW_EXTENSION_ERROR_GET_PROPERTY,
2132                                     "Unsupported property");
2133         }
2134
2135         callback(self, key, value, user_data, error);
2136 }
2137
2138 static void mafw_gst_renderer_set_property(MafwExtension *self,
2139                                          const gchar *key,
2140                                          const GValue *value)
2141 {
2142         MafwGstRenderer *renderer;
2143
2144         g_return_if_fail(MAFW_IS_GST_RENDERER(self));
2145         g_return_if_fail(key != NULL);
2146
2147         renderer = MAFW_GST_RENDERER(self);
2148
2149         if (!strcmp(key, MAFW_PROPERTY_RENDERER_VOLUME)) {
2150                 guint volume = g_value_get_uint(value);
2151                 if (volume > 100)
2152                         volume = 100;
2153                 mafw_gst_renderer_worker_set_volume(renderer->worker,
2154                                                            volume);
2155                 /* Property-changed emision is done by worker */
2156                 return;
2157         }
2158         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_MUTE)) {
2159                 gboolean mute = g_value_get_boolean(value);
2160                 mafw_gst_renderer_worker_set_mute(renderer->worker, mute);
2161         }
2162         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_XID)) {
2163                 XID xid = g_value_get_uint(value);
2164                 mafw_gst_renderer_worker_set_xid(renderer->worker, xid);
2165         }
2166         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_ERROR_POLICY)) {
2167                 MafwRendererErrorPolicy policy = g_value_get_uint(value);
2168                 _set_error_policy(renderer, policy);
2169         }
2170         else if (!strcmp(key, MAFW_PROPERTY_RENDERER_AUTOPAINT)) {
2171                 mafw_gst_renderer_worker_set_autopaint(
2172                         renderer->worker,
2173                         g_value_get_boolean(value));
2174         }
2175 #ifdef HAVE_GDKPIXBUF
2176         else if (!strcmp(key,
2177                          MAFW_PROPERTY_GST_RENDERER_CURRENT_FRAME_ON_PAUSE)) {
2178                 gboolean current_frame_on_pause = g_value_get_boolean(value);
2179                 mafw_gst_renderer_worker_set_current_frame_on_pause(renderer->worker,
2180                                                                            current_frame_on_pause);
2181         }
2182 #endif
2183         else return;
2184
2185         /* FIXME I'm not sure when to emit property-changed signals.
2186          * Maybe we should let the worker do it, when the change
2187          * reached the hardware... */
2188         mafw_extension_emit_property_changed(self, key, value);
2189 }
2190
2191 /* vi: set noexpandtab ts=8 sw=8 cino=t0,(0: */