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