2 * Copyright (C) 2008 OpenedHand Ltd.
3 * Copyright (C) 2009,2010,2011,2012 Nokia Corporation.
4 * Copyright (C) 2012 Openismus GmbH
5 * Copyright (C) 2012 Intel Corporation.
7 * Author: Jorn Baayen <jorn@openedhand.com>
8 * Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
9 * <zeeshan.ali@nokia.com>
10 * Jens Georg <jensg@openismus.com>
12 * Rygel is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * Rygel is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this program; if not, write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 #include "rygel-playbin-player.h"
28 #include <libgupnp-av/gupnp-av.h>
29 #include <rygel-renderer.h>
33 static void rygel_playbin_player_rygel_media_player_interface_init (RygelMediaPlayerIface *iface);
36 * Implementation of RygelMediaPlayer for GStreamer.
38 * This class is useful only when implementing Rygel plugins.
41 G_DEFINE_TYPE_WITH_CODE (RygelPlaybinPlayer,
44 G_IMPLEMENT_INTERFACE (RYGEL_TYPE_MEDIA_PLAYER,
45 rygel_playbin_player_rygel_media_player_interface_init))
47 #define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
49 struct _RygelPlaybinPlayerPrivate {
50 gboolean duration_hint;
55 gchar *_playback_state;
56 gchar **_allowed_playback_speeds;
57 gint _allowed_playback_speeds_length;
58 gint __allowed_playback_speeds_size_;
59 gchar *_playback_speed;
61 gboolean uri_update_hint;
65 gchar *_content_features;
66 GUPnPProtocolInfo *protocol_info;
69 static RygelMediaPlayerIface* rygel_playbin_player_rygel_media_player_parent_iface = NULL;
71 #define RYGEL_PLAYBIN_PLAYER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RYGEL_TYPE_PLAYBIN_PLAYER, RygelPlaybinPlayerPrivate))
73 RYGEL_PLAYBIN_PLAYER_DUMMY_PROPERTY,
74 RYGEL_PLAYBIN_PLAYER_PLAYBIN,
75 RYGEL_PLAYBIN_PLAYER_PLAYBACK_STATE,
76 RYGEL_PLAYBIN_PLAYER_ALLOWED_PLAYBACK_SPEEDS,
77 RYGEL_PLAYBIN_PLAYER_PLAYBACK_SPEED,
78 RYGEL_PLAYBIN_PLAYER_URI,
79 RYGEL_PLAYBIN_PLAYER_MIME_TYPE,
80 RYGEL_PLAYBIN_PLAYER_METADATA,
81 RYGEL_PLAYBIN_PLAYER_CAN_SEEK,
82 RYGEL_PLAYBIN_PLAYER_CONTENT_FEATURES,
83 RYGEL_PLAYBIN_PLAYER_VOLUME,
84 RYGEL_PLAYBIN_PLAYER_DURATION,
85 RYGEL_PLAYBIN_PLAYER_POSITION
88 #define RYGEL_PLAYBIN_PLAYER_TRANSFER_MODE_STREAMING "Streaming"
89 #define RYGEL_PLAYBIN_PLAYER_TRANSFER_MODE_INTERACTIVE "Interactive"
90 #define RYGEL_PLAYBIN_PLAYER_PROTOCOL_INFO_TEMPLATE "http-get:%s:*:%s"
92 static void rygel_playbin_player_set_playbin (RygelPlaybinPlayer *self, GstElement *value);
93 static void rygel_playbin_player_setup_playbin (RygelPlaybinPlayer *self);
94 static gboolean rygel_playbin_player_real_seek (RygelMediaPlayer *base, gint64 time);
95 static gchar **rygel_playbin_player_real_get_protocols (RygelMediaPlayer *base, int *result_length1);
96 static gchar **rygel_playbin_player_real_get_mime_types (RygelMediaPlayer *base, int *result_length1);
97 static gboolean rygel_playbin_player_is_rendering_image (RygelPlaybinPlayer *self);
98 static void rygel_playbin_player_bus_handler (GstBus *bus, GstMessage *message, gpointer user_data);
99 static gchar *rygel_playbin_player_generate_basic_didl (RygelPlaybinPlayer *self);
100 static void rygel_playbin_player_on_source_setup (GstElement *sender, GstElement *source, gpointer user_data);
101 static void rygel_playbin_player_on_uri_notify (GObject *sender, GParamSpec *pspec, gpointer user_data);
102 static void rygel_playbin_player_finalize (GObject *obj);
103 static void _vala_rygel_playbin_player_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
104 static void _vala_rygel_playbin_player_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
106 static const gchar *RYGEL_PLAYBIN_PLAYER_PROTOCOLS[2] = {"http-get", "rtsp"};
107 static const gchar *RYGEL_PLAYBIN_PLAYER_MIME_TYPES[40] = {"audio/mpeg", "application/ogg", "audio/x-vorbis", "audio/x-vorbis+ogg", "audio/ogg", "audio/x-ms-wma", "audio/x-ms-asf", "audio/x-flac", "audio/x-flac+ogg", "audio/flac", "audio/mp4", "audio/vnd.dlna.adts", "audio/x-mod", "audio/x-wav", "audio/x-ac3", "audio/x-m4a", "audio/L16;rate=44100;channels=2", "audio/L16;rate=44100;channels=1", "audio/L16;channels=2;rate=44100", "audio/L16;channels=1;rate=44100", "audio/L16;rate=44100", "image/jpeg", "image/png", "video/x-theora", "video/x-theora+ogg", "video/x-oggm", "video/ogg", "video/x-dirac", "video/x-wmv", "video/x-wma", "video/x-msvideo", "video/x-3ivx", "video/x-3ivx", "video/x-matroska", "video/x-mkv", "video/mpeg", "video/mp4", "video/x-ms-asf", "video/x-xvid", "video/x-ms-wmv"};
110 static RygelPlaybinPlayer*
111 rygel_playbin_player_new (void) {
112 RygelPlaybinPlayer *self;
114 self = RYGEL_PLAYBIN_PLAYER (g_object_new (RYGEL_TYPE_PLAYBIN_PLAYER, NULL));
116 /* TODO: This should really be done via a construct property. */
117 GstElement *playbin = gst_element_factory_make ("playbin2", NULL);
119 gst_object_ref_sink (playbin);
122 rygel_playbin_player_set_playbin (self, playbin);
123 gst_object_unref (playbin);
125 self->priv->foreign = FALSE;
126 rygel_playbin_player_setup_playbin (self);
131 static RygelPlaybinPlayer* rygel_playbin_player_player = NULL;
134 rygel_playbin_player_get_default (void) {
135 if (!rygel_playbin_player_player) {
136 rygel_playbin_player_player = rygel_playbin_player_new ();
139 g_object_ref (rygel_playbin_player_player);
140 return rygel_playbin_player_player;
145 rygel_playbin_player_real_seek (RygelMediaPlayer *base, gint64 time) {
146 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
147 g_return_val_if_fail (self, FALSE);
148 g_return_val_if_fail (self->priv->_playbin, FALSE);
150 return gst_element_seek (self->priv->_playbin, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, time * GST_USECOND, GST_SEEK_TYPE_NONE, (gint64) (-1));
155 rygel_playbin_player_real_get_protocols (RygelMediaPlayer *base, int *result_length) {
156 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
158 gchar **result = NULL;
161 g_return_val_if_fail (self, NULL);
163 length = G_N_ELEMENTS (RYGEL_PLAYBIN_PLAYER_PROTOCOLS);
166 *result_length = length;
169 result = g_new0 (gchar*, length + 1);
170 for (i = 0; i < length; i++) {
171 result[i] = g_strdup (RYGEL_PLAYBIN_PLAYER_PROTOCOLS[i]);
178 rygel_playbin_player_real_get_mime_types (RygelMediaPlayer *base, int *result_length) {
179 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
181 gchar **result = NULL;
184 g_return_val_if_fail (self, NULL);
186 length = G_N_ELEMENTS (RYGEL_PLAYBIN_PLAYER_MIME_TYPES);
189 *result_length = length;
192 result = g_new0 (gchar*, length + 1);
193 for (i = 0; i < length; i++) {
194 result[i] = g_strdup (RYGEL_PLAYBIN_PLAYER_MIME_TYPES[i]);
202 rygel_playbin_player_is_rendering_image (RygelPlaybinPlayer *self) {
203 GstElement* typefind = NULL;
204 GstCaps *caps = NULL;
205 GstStructure *structure = NULL;
206 const gchar *name = NULL;
209 g_return_val_if_fail (self, FALSE);
210 g_return_val_if_fail (self->priv->_playbin, FALSE);
212 typefind = gst_bin_get_by_name (GST_BIN (self->priv->_playbin), "typefind");
213 g_return_val_if_fail (typefind, FALSE);
215 g_object_get (typefind, "caps", &caps, NULL);
216 g_return_val_if_fail (caps, FALSE);
218 structure = gst_caps_get_structure (caps, 0);
219 g_return_val_if_fail (structure, FALSE);
221 name = gst_structure_get_name (structure);
222 result = (g_strcmp0 (name, "image/jpeg") == 0) ||
223 (g_strcmp0 (name, "image/png") == 0);
225 gst_caps_unref (caps);
226 gst_object_unref (typefind);
232 rygel_playbin_player_bus_handler (GstBus *bus, GstMessage *message, gpointer user_data) {
233 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (user_data);
234 g_return_if_fail (self);
236 g_return_if_fail (bus);
237 g_return_if_fail (message);
239 switch (message->type) {
240 case GST_MESSAGE_DURATION:
242 GstFormat format = GST_FORMAT_TIME;
243 if (gst_element_query_duration (self->priv->_playbin, &format, NULL)) {
244 g_object_notify (G_OBJECT (self), "duration");
249 case GST_MESSAGE_STATE_CHANGED:
251 if (message->src == GST_OBJECT (self->priv->_playbin)) {
252 GstState old_state = 0;
253 GstState new_state = 0;
254 GstState pending = 0;
255 gst_message_parse_state_changed (message, &old_state, &new_state, &pending);
256 if (old_state == GST_STATE_READY && new_state == GST_STATE_PAUSED) {
257 if (self->priv->uri_update_hint) {
258 self->priv->uri_update_hint = FALSE;
260 gchar *current_uri = NULL;
261 g_object_get (self->priv->_playbin, "uri", ¤t_uri, NULL);
263 if (g_strcmp0 (self->priv->_uri, current_uri) != 0
264 && g_strcmp0 (current_uri, "") != 0) {
266 // uri changed externally
267 if (self->priv->_uri)
268 g_free (self->priv->_uri);
271 g_object_get (self->priv->_playbin, "uri", &uri, NULL);
272 self->priv->_uri = uri;
273 g_object_notify (G_OBJECT (self), "uri");
275 gchar *metadata = rygel_playbin_player_generate_basic_didl (self);
276 rygel_media_player_set_metadata (RYGEL_MEDIA_PLAYER (self), metadata);
280 g_free (current_uri);
284 if (pending == GST_STATE_VOID_PENDING
285 && !self->priv->buffering) {
287 case GST_STATE_PAUSED:
289 rygel_media_player_set_playback_state (RYGEL_MEDIA_PLAYER (self), "PAUSED_PLAYBACK");
294 rygel_media_player_set_playback_state (RYGEL_MEDIA_PLAYER (self), "STOPPED");
297 case GST_STATE_PLAYING:
299 rygel_media_player_set_playback_state (RYGEL_MEDIA_PLAYER (self), "PLAYING");
309 if (old_state == GST_STATE_PAUSED
310 && new_state == GST_STATE_PLAYING) {
311 self->priv->buffering = FALSE;
312 rygel_media_player_set_playback_state (RYGEL_MEDIA_PLAYER (self), "PLAYING");
318 case GST_MESSAGE_BUFFERING:
320 // Assume the original application takes care of this.
321 if (!self->priv->is_live || self->priv->foreign) {
323 gst_message_parse_buffering (message, &percent);
326 self->priv->buffering = TRUE;
327 gst_element_set_state (self->priv->_playbin, GST_STATE_PAUSED);
329 gst_element_set_state (self->priv->_playbin, GST_STATE_PLAYING);
335 case GST_MESSAGE_CLOCK_LOST:
337 // Assume the original application takes care of this.
338 if (!self->priv->foreign) {
339 gst_element_set_state (self->priv->_playbin, GST_STATE_PAUSED);
340 gst_element_set_state (self->priv->_playbin, GST_STATE_PLAYING);
345 case GST_MESSAGE_EOS:
347 if(!rygel_playbin_player_is_rendering_image (self)) {
348 g_debug ("rygel-playbin-player.c: EOS");
349 rygel_media_player_set_playback_state (RYGEL_MEDIA_PLAYER (self), "STOPPED");
351 g_debug ("rygel-playbin-player.c: Content is image. Ignoring EOS");
356 case GST_MESSAGE_ERROR:
358 GError *error = NULL;
359 gchar *error_message = NULL;
360 gchar *name = gst_object_get_name (GST_OBJECT (self->priv->_playbin));
362 gst_message_parse_error (message, &error, &error_message);
363 g_warning ("Error from GStreamer element %s: %s (%s)",
368 g_error_free (error);
369 g_free (error_message);
370 g_warning ("Going to STOPPED state");
372 rygel_media_player_set_playback_state (RYGEL_MEDIA_PLAYER (self), "STOPPED");
383 * Generate basic DIDLLite information.
385 * This is used when the URI gets changed externally. DLNA requires that a
386 * minimum DIDLLite is always present if the URI is not empty.
389 rygel_playbin_player_generate_basic_didl (RygelPlaybinPlayer *self) {
390 GUPnPDIDLLiteWriter *writer = NULL;
391 GUPnPDIDLLiteItem *item = NULL;
392 GUPnPDIDLLiteResource *resource = NULL;
394 gchar *basename = NULL;
395 gchar *result = NULL;
397 g_return_val_if_fail (self, NULL);
399 writer = gupnp_didl_lite_writer_new (NULL);
401 item = gupnp_didl_lite_writer_add_item (writer);
402 gupnp_didl_lite_object_set_id ((GUPnPDIDLLiteObject*) item, "1");
403 gupnp_didl_lite_object_set_parent_id ((GUPnPDIDLLiteObject*) item, "-1");
404 gupnp_didl_lite_object_set_upnp_class ((GUPnPDIDLLiteObject*) item, "object.item");
406 resource = gupnp_didl_lite_object_add_resource ((GUPnPDIDLLiteObject*) item);
407 gupnp_didl_lite_resource_set_uri (resource, self->priv->_uri);
409 file = g_file_new_for_uri (self->priv->_uri);
410 basename = g_file_get_basename (file);
411 gupnp_didl_lite_object_set_title ((GUPnPDIDLLiteObject*) item, basename);
414 result = gupnp_didl_lite_writer_get_string (writer);
416 g_object_unref (file);
417 g_object_unref (resource);
418 g_object_unref (item);
419 g_object_unref (writer);
426 rygel_playbin_player_on_source_setup (GstElement *sender G_GNUC_UNUSED, GstElement *source, gpointer user_data) {
427 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (user_data);
429 GstStructure *structure = NULL;
431 g_return_if_fail (self);
432 g_return_if_fail (source);
434 //We do not use GST_IS_SOUP_HTTP_SRC(), to avoid a build-time dependency on gst-plugins-good,
435 //though it will be needed at runtime.
436 if ((g_strcmp0 (G_OBJECT_TYPE_NAME (source), "GstSoupHTTPSrc") == 0) &&
437 self->priv->transfer_mode) {
438 g_debug ("rygel-playbin-player.c: Setting transfer mode to %s", self->priv->transfer_mode);
440 structure = gst_structure_empty_new ("Extra Headers");
441 gst_structure_set (structure, "transferMode.dlna.org", G_TYPE_STRING, self->priv->transfer_mode, NULL);
443 g_object_set (source, "extra-headers", structure, NULL);
445 gst_structure_free (structure);
450 rygel_playbin_player_on_uri_notify (GObject *sender G_GNUC_UNUSED, GParamSpec *pspec, gpointer user_data) {
451 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (user_data);
453 g_return_if_fail (self);
454 g_return_if_fail (pspec);
456 self->priv->uri_update_hint = TRUE;
460 rygel_playbin_player_setup_playbin (RygelPlaybinPlayer *self) {
463 g_return_if_fail (self);
464 g_return_if_fail (self->priv->_playbin);
466 self->priv->duration_hint = FALSE;
468 /* Needed to get "Stop" events from the playbin.
469 * We can do this because we have a bus watch.
471 self->priv->is_live = FALSE;
473 g_object_set (self->priv->_playbin, "auto-flush-bus", FALSE, NULL);
474 g_assert (self->priv->_playbin);
476 g_signal_connect_object (self->priv->_playbin, "source_setup", (GCallback) rygel_playbin_player_on_source_setup, self, 0);
477 g_signal_connect_object (self->priv->_playbin, "notify::uri", (GCallback) rygel_playbin_player_on_uri_notify, self, 0);
480 bus = gst_element_get_bus (self->priv->_playbin);
481 g_return_if_fail (bus);
483 gst_bus_add_signal_watch (bus);
484 g_signal_connect_object (bus, "message", (GCallback) rygel_playbin_player_bus_handler, self, 0);
486 gst_object_unref (bus);
491 rygel_playbin_player_get_playbin (RygelPlaybinPlayer *self) {
492 g_return_val_if_fail (self, NULL);
494 /* TODO: Shouldn't we ref this, like other GStreamer getters? */
495 return self->priv->_playbin;
499 rygel_playbin_player_set_playbin (RygelPlaybinPlayer *self, GstElement *value) {
500 g_return_if_fail (self);
502 if(self->priv->_playbin)
503 gst_object_unref (self->priv->_playbin);
505 gst_object_ref (value);
506 self->priv->_playbin = value;
508 g_object_notify (G_OBJECT (self), "playbin");
513 rygel_playbin_player_real_get_playback_state (RygelMediaPlayer *base) {
514 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
516 g_return_val_if_fail (self, NULL);
518 return g_strdup (self->priv->_playback_state);
523 rygel_playbin_player_real_set_playback_state (RygelMediaPlayer *base, const gchar *value) {
525 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
527 g_return_if_fail (self);
530 GstState pending = 0;
531 gst_element_get_state (self->priv->_playbin, &state, &pending, (GstClockTime) GST_MSECOND);
533 g_debug ("rygel-playbin-player.c: Changing playback state to %s.", value);
535 if (g_strcmp0 (value, "STOPPED") == 0) {
536 if (self->priv->_playback_state)
537 g_free (self->priv->_playback_state);
539 if (state != GST_STATE_NULL ||
540 pending != GST_STATE_VOID_PENDING) {
541 self->priv->_playback_state = g_strdup ("TRANSITIONING");
542 gst_element_set_state (self->priv->_playbin, GST_STATE_NULL);
544 self->priv->_playback_state = g_strdup (value);
546 } else if (g_strcmp0 (value, "PAUSED_PLAYBACK") == 0) {
547 if (self->priv->_playback_state)
548 g_free (self->priv->_playback_state);
550 if (state != GST_STATE_PAUSED ||
551 pending != GST_STATE_VOID_PENDING) {
552 self->priv->_playback_state = g_strdup ("TRANSITIONING");
553 gst_element_set_state (self->priv->_playbin, GST_STATE_PAUSED);
555 self->priv->_playback_state = g_strdup (value);
557 } else if (g_strcmp0 (value, "PLAYING") == 0) {
558 if (self->priv->_playback_state)
559 g_free (self->priv->_playback_state);
561 if (state != GST_STATE_PLAYING ||
562 pending != GST_STATE_VOID_PENDING) {
564 bin = gst_element_factory_make ("pulsesink", NULL);
566 g_object_set (self->priv->_playbin, "audio-sink", bin, NULL);
568 self->priv->_playback_state = g_strdup ("TRANSITIONING");
570 /* This needs a check if GStreamer and DLNA agree on
571 * the "liveness" of the source (s0/sn increase in
574 self->priv->is_live =
575 (gst_element_set_state (self->priv->_playbin, GST_STATE_PLAYING) == GST_STATE_CHANGE_NO_PREROLL);
577 self->priv->_playback_state = g_strdup (value);
579 } else if (g_strcmp0 (value, "EOS") == 0) {
580 if (self->priv->_playback_state)
581 g_free (self->priv->_playback_state);
583 self->priv->_playback_state = g_strdup (value);
586 g_object_notify (G_OBJECT (self), "playback-state");
591 rygel_playbin_player_real_get_allowed_playback_speeds (RygelMediaPlayer *base, int *result_length) {
592 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
593 gchar **result = NULL;
596 g_return_val_if_fail (self, NULL);
599 *result_length = self->priv->_allowed_playback_speeds_length;
602 result = g_new0 (gchar*, self->priv->_allowed_playback_speeds_length + 1);
603 for (i = 0; i < self->priv->_allowed_playback_speeds_length; i++) {
604 result[i] = g_strdup (self->priv->_allowed_playback_speeds[i]);
612 rygel_playbin_player_real_get_playback_speed (RygelMediaPlayer *base) {
613 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
615 g_return_val_if_fail (self, NULL);
617 return g_strdup (self->priv->_playback_speed);
621 static void rygel_playbin_player_real_set_playback_speed (RygelMediaPlayer *base, const gchar *value) {
622 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
624 g_return_if_fail (self);
626 if (self->priv->_playback_speed)
627 g_free (self->priv->_playback_speed);
629 self->priv->_playback_speed = g_strdup (value);
631 g_object_notify (G_OBJECT (self), "playback-speed");
636 rygel_playbin_player_real_get_uri (RygelMediaPlayer *base) {
637 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
639 g_return_val_if_fail (self, NULL);
641 return g_strdup (self->priv->_uri);
646 rygel_playbin_player_real_set_uri (RygelMediaPlayer *base, const gchar *value) {
647 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
649 g_return_if_fail (self);
651 if (self->priv->_uri)
652 g_free (self->priv->_uri);
653 self->priv->_uri = g_strdup (value);
655 gst_element_set_state (self->priv->_playbin, GST_STATE_READY);
656 g_object_set (self->priv->_playbin, "uri", value, NULL);
658 if (g_strcmp0 (value, "") != 0) {
659 if (g_strcmp0 (self->priv->_playback_state, "NO_MEDIA_PRESENT") != 0) {
660 if (self->priv->_playback_state)
661 g_free (self->priv->_playback_state);
663 self->priv->_playback_state = g_strdup ("STOPPED");
664 g_object_notify (G_OBJECT (self), "playback-state");
665 } else if (g_strcmp0 (self->priv->_playback_state, "STOPPED") != 0) {
666 } else if (g_strcmp0 (self->priv->_playback_state, "PAUSED_PLAYBACK") != 0) {
667 self->priv->is_live =
668 (gst_element_set_state (self->priv->_playbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_NO_PREROLL);
669 } else if (g_strcmp0 (self->priv->_playback_state, "EOS") != 0 ||
670 g_strcmp0 (self->priv->_playback_state, "PLAYING") != 0) {
671 /* This needs a check if GStreamer and DLNA agree on
672 * the "liveness" of the source (s0/sn increase in
675 self->priv->is_live =
676 (gst_element_set_state (self->priv->_playbin, GST_STATE_PLAYING) == GST_STATE_CHANGE_NO_PREROLL);
679 if (self->priv->_playback_state)
680 g_free (self->priv->_playback_state);
682 self->priv->_playback_state = g_strdup ("NO_MEDIA_PRESENT");
683 g_object_notify (G_OBJECT (self), "playback-state");
686 g_debug ("rygel-playbin-player.c: URI set to %s.", value);
691 rygel_playbin_player_real_get_mime_type (RygelMediaPlayer *base) {
692 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
694 g_return_val_if_fail (self, NULL);
696 return g_strdup (self->priv->_mime_type);
701 rygel_playbin_player_real_set_mime_type (RygelMediaPlayer *base, const gchar *value) {
702 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
704 g_return_if_fail (self);
706 if (self->priv->_mime_type)
707 g_free (self->priv->_mime_type);
709 self->priv->_mime_type = g_strdup (value);
711 g_object_notify (G_OBJECT (self), "mime-type");
716 rygel_playbin_player_real_get_metadata (RygelMediaPlayer *base) {
717 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
719 g_return_val_if_fail (self, NULL);
721 return g_strdup (self->priv->_metadata);
726 rygel_playbin_player_real_set_metadata (RygelMediaPlayer *base, const gchar *value) {
727 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
729 g_return_if_fail (self);
731 if (self->priv->_metadata)
732 g_free (self->priv->_metadata);
734 self->priv->_metadata = g_strdup (value);
736 g_object_notify (G_OBJECT (self), "metadata");
741 rygel_playbin_player_real_get_can_seek (RygelMediaPlayer *base) {
742 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
744 g_return_val_if_fail (self, FALSE);
746 return (g_strcmp0 (self->priv->transfer_mode, RYGEL_PLAYBIN_PLAYER_TRANSFER_MODE_INTERACTIVE) != 0) &&
747 g_str_has_prefix (self->priv->_mime_type, "image/");
752 rygel_playbin_player_real_get_content_features (RygelMediaPlayer *base) {
753 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
755 g_return_val_if_fail (self, NULL);
757 return g_strdup (self->priv->_content_features);
762 rygel_playbin_player_real_set_content_features (RygelMediaPlayer *base, const gchar *value) {
763 GError *inner_error = NULL;
764 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
766 g_return_if_fail (self);
768 gchar *mime_type = rygel_media_player_get_mime_type (RYGEL_MEDIA_PLAYER (self));
769 gchar *pi_string = g_strdup_printf (RYGEL_PLAYBIN_PLAYER_PROTOCOL_INFO_TEMPLATE,
773 if (self->priv->protocol_info)
774 g_object_unref (self->priv->protocol_info);
776 self->priv->protocol_info = gupnp_protocol_info_new_from_string (pi_string, &inner_error);
778 if (self->priv->protocol_info)
779 g_object_unref (self->priv->protocol_info);
780 self->priv->protocol_info = NULL;
782 if (self->priv->transfer_mode)
783 g_free (self->priv->transfer_mode);
784 self->priv->transfer_mode = NULL;
786 g_error_free (inner_error);
789 if (self->priv->transfer_mode)
790 g_free (self->priv->transfer_mode);
792 GUPnPDLNAFlags flags = gupnp_protocol_info_get_dlna_flags (self->priv->protocol_info);
793 if ((flags & GUPNP_DLNA_FLAGS_INTERACTIVE_TRANSFER_MODE) == GUPNP_DLNA_FLAGS_INTERACTIVE_TRANSFER_MODE) {
794 self->priv->transfer_mode = g_strdup (RYGEL_PLAYBIN_PLAYER_TRANSFER_MODE_INTERACTIVE);
795 } else if ((flags & GUPNP_DLNA_FLAGS_STREAMING_TRANSFER_MODE) == GUPNP_DLNA_FLAGS_STREAMING_TRANSFER_MODE) {
796 self->priv->transfer_mode = g_strdup (RYGEL_PLAYBIN_PLAYER_TRANSFER_MODE_STREAMING);
798 self->priv->transfer_mode = NULL;
801 if (self->priv->_content_features)
802 g_free (self->priv->_content_features);
803 self->priv->_content_features = g_strdup (value);
806 g_object_notify (G_OBJECT (self), "content-features");
810 rygel_playbin_player_real_get_volume (RygelMediaPlayer *base) {
811 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
813 g_return_val_if_fail (self, 0);
814 g_return_val_if_fail (self->priv->_playbin, 0);
817 g_object_get (self->priv->_playbin, "volume", &result, NULL);
823 rygel_playbin_player_real_set_volume (RygelMediaPlayer *base, gdouble value) {
824 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
826 g_return_if_fail (self);
828 g_object_set (self->priv->_playbin, "volume", value, NULL);
830 g_debug ("rygel-playbin-player.c: volume set to %f.", value);
831 g_object_notify (G_OBJECT (self), "volume");
836 rygel_playbin_player_real_get_duration (RygelMediaPlayer *base) {
837 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
838 GstFormat format = GST_FORMAT_TIME;
841 g_return_val_if_fail (self, 0LL);
842 g_return_val_if_fail (self->priv->_playbin, 0LL);
844 if (gst_element_query_duration (self->priv->_playbin, &format, &pos)) {
845 return pos / GST_USECOND;
853 rygel_playbin_player_real_get_position (RygelMediaPlayer *base) {
854 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (base);
855 GstFormat format = GST_FORMAT_TIME;
858 g_return_val_if_fail (self, 0LL);
859 g_return_val_if_fail (self->priv->_playbin, 0LL);
861 if (gst_element_query_position (self->priv->_playbin, &format, &pos)) {
862 return pos / GST_USECOND;
869 static void rygel_playbin_player_class_init (RygelPlaybinPlayerClass *klass) {
870 rygel_playbin_player_parent_class = g_type_class_peek_parent (klass);
871 g_type_class_add_private (klass, sizeof (RygelPlaybinPlayerPrivate));
873 G_OBJECT_CLASS (klass)->get_property = _vala_rygel_playbin_player_get_property;
874 G_OBJECT_CLASS (klass)->set_property = _vala_rygel_playbin_player_set_property;
875 G_OBJECT_CLASS (klass)->finalize = rygel_playbin_player_finalize;
877 g_object_class_install_property (G_OBJECT_CLASS (klass),
878 RYGEL_PLAYBIN_PLAYER_PLAYBIN,
879 g_param_spec_object ("playbin", "playbin", "playbin", GST_TYPE_ELEMENT,
880 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
882 g_object_class_install_property (G_OBJECT_CLASS (klass),
883 RYGEL_PLAYBIN_PLAYER_PLAYBACK_STATE,
884 g_param_spec_string ("playback-state", "playback-state", "playback-state", NULL,
885 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE));
887 g_object_class_install_property (G_OBJECT_CLASS (klass),
888 RYGEL_PLAYBIN_PLAYER_ALLOWED_PLAYBACK_SPEEDS,
889 g_param_spec_boxed ("allowed-playback-speeds", "allowed-playback-speeds", "allowed-playback-speeds",
890 G_TYPE_STRV, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
892 g_object_class_install_property (G_OBJECT_CLASS (klass),
893 RYGEL_PLAYBIN_PLAYER_PLAYBACK_SPEED,
894 g_param_spec_string ("playback-speed", "playback-speed", "playback-speed", NULL,
895 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE));
897 g_object_class_install_property (G_OBJECT_CLASS (klass),
898 RYGEL_PLAYBIN_PLAYER_URI,
899 g_param_spec_string ("uri", "uri", "uri", NULL,
900 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE));
902 g_object_class_install_property (G_OBJECT_CLASS (klass),
903 RYGEL_PLAYBIN_PLAYER_MIME_TYPE,
904 g_param_spec_string ("mime-type", "mime-type", "mime-type", NULL,
905 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE));
907 g_object_class_install_property (G_OBJECT_CLASS (klass),
908 RYGEL_PLAYBIN_PLAYER_METADATA,
909 g_param_spec_string ("metadata", "metadata", "metadata", NULL,
910 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE));
912 g_object_class_install_property (G_OBJECT_CLASS (klass),
913 RYGEL_PLAYBIN_PLAYER_CAN_SEEK,
914 g_param_spec_boolean ("can-seek", "can-seek", "can-seek", FALSE,
915 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
917 g_object_class_install_property (G_OBJECT_CLASS (klass),
918 RYGEL_PLAYBIN_PLAYER_CONTENT_FEATURES,
919 g_param_spec_string ("content-features", "content-features", "content-features", NULL,
920 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE));
922 g_object_class_install_property (G_OBJECT_CLASS (klass),
923 RYGEL_PLAYBIN_PLAYER_VOLUME,
924 g_param_spec_double ("volume", "volume", "volume", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
925 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE | G_PARAM_WRITABLE));
927 g_object_class_install_property (G_OBJECT_CLASS (klass),
928 RYGEL_PLAYBIN_PLAYER_DURATION,
929 g_param_spec_int64 ("duration", "duration", "duration", G_MININT64, G_MAXINT64, 0,
930 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
932 g_object_class_install_property (G_OBJECT_CLASS (klass),
933 RYGEL_PLAYBIN_PLAYER_POSITION,
934 g_param_spec_int64 ("position", "position", "position", G_MININT64, G_MAXINT64, 0,
935 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
939 static void rygel_playbin_player_rygel_media_player_interface_init (RygelMediaPlayerIface *iface) {
940 rygel_playbin_player_rygel_media_player_parent_iface = g_type_interface_peek_parent (iface);
942 iface->seek = (gboolean (*)(RygelMediaPlayer*, gint64)) rygel_playbin_player_real_seek;
943 iface->get_protocols = (gchar **(*)(RygelMediaPlayer*, int*)) rygel_playbin_player_real_get_protocols;
944 iface->get_mime_types = (gchar **(*)(RygelMediaPlayer*, int*)) rygel_playbin_player_real_get_mime_types;
945 iface->get_playback_state = rygel_playbin_player_real_get_playback_state;
946 iface->set_playback_state = rygel_playbin_player_real_set_playback_state;
947 iface->get_allowed_playback_speeds = rygel_playbin_player_real_get_allowed_playback_speeds;
948 iface->get_playback_speed = rygel_playbin_player_real_get_playback_speed;
949 iface->set_playback_speed = rygel_playbin_player_real_set_playback_speed;
950 iface->get_uri = rygel_playbin_player_real_get_uri;
951 iface->set_uri = rygel_playbin_player_real_set_uri;
952 iface->get_mime_type = rygel_playbin_player_real_get_mime_type;
953 iface->set_mime_type = rygel_playbin_player_real_set_mime_type;
954 iface->get_metadata = rygel_playbin_player_real_get_metadata;
955 iface->set_metadata = rygel_playbin_player_real_set_metadata;
956 iface->get_can_seek = rygel_playbin_player_real_get_can_seek;
957 iface->get_content_features = rygel_playbin_player_real_get_content_features;
958 iface->set_content_features = rygel_playbin_player_real_set_content_features;
959 iface->get_volume = rygel_playbin_player_real_get_volume;
960 iface->set_volume = rygel_playbin_player_real_set_volume;
961 iface->get_duration = rygel_playbin_player_real_get_duration;
962 iface->get_position = rygel_playbin_player_real_get_position;
966 static void rygel_playbin_player_init (RygelPlaybinPlayer *self) {
967 g_return_if_fail (self);
969 self->priv = RYGEL_PLAYBIN_PLAYER_GET_PRIVATE (self);
971 self->priv->_playback_state = g_strdup ("NO_MEDIA_PRESENT");
972 self->priv->transfer_mode = NULL;
973 self->priv->uri_update_hint = FALSE;
974 self->priv->_uri = NULL;
975 self->priv->_mime_type = NULL;
976 self->priv->_metadata = NULL;
977 self->priv->_content_features = NULL;
978 self->priv->_allowed_playback_speeds = g_strsplit ("1", ",", -1);
979 self->priv->_allowed_playback_speeds_length = 1;
980 self->priv->_playback_speed = g_strdup ("1");
984 static void rygel_playbin_player_finalize (GObject *obj) {
985 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (obj);
987 g_return_if_fail (self);
989 gst_object_unref (self->priv->_playbin);
991 if (self->priv->_playback_state)
992 g_free (self->priv->_playback_state);
994 if (self->priv->_allowed_playback_speeds) {
996 for (i = 0; i < self->priv->_allowed_playback_speeds_length; i = i + 1) {
997 g_free (self->priv->_allowed_playback_speeds[i]);
999 g_free (self->priv->_allowed_playback_speeds);
1002 if (self->priv->_playback_speed)
1003 g_free (self->priv->_playback_speed);
1005 if (self->priv->transfer_mode)
1006 g_free (self->priv->transfer_mode);
1008 if (self->priv->_uri)
1009 g_free (self->priv->_uri);
1011 if (self->priv->_mime_type)
1012 g_free (self->priv->_mime_type);
1014 if (self->priv->_metadata)
1015 g_free (self->priv->_metadata);
1017 if (self->priv->_content_features)
1018 g_free (self->priv->_content_features);
1020 if (self->priv->protocol_info)
1021 g_object_unref (self->priv->protocol_info);
1023 G_OBJECT_CLASS (rygel_playbin_player_parent_class)->finalize (obj);
1027 static void _vala_rygel_playbin_player_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) {
1028 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (object);
1030 g_return_if_fail (self);
1032 switch (property_id) {
1033 case RYGEL_PLAYBIN_PLAYER_PLAYBIN:
1034 g_value_set_object (value, rygel_playbin_player_get_playbin (self));
1036 case RYGEL_PLAYBIN_PLAYER_PLAYBACK_STATE:
1037 g_value_take_string (value, rygel_media_player_get_playback_state (RYGEL_MEDIA_PLAYER (self)));
1039 case RYGEL_PLAYBIN_PLAYER_ALLOWED_PLAYBACK_SPEEDS:
1042 g_value_take_boxed (value, rygel_media_player_get_allowed_playback_speeds (RYGEL_MEDIA_PLAYER (self), &length));
1045 case RYGEL_PLAYBIN_PLAYER_PLAYBACK_SPEED:
1046 g_value_take_string (value, rygel_media_player_get_playback_speed (RYGEL_MEDIA_PLAYER (self)));
1048 case RYGEL_PLAYBIN_PLAYER_URI:
1049 g_value_take_string (value, rygel_media_player_get_uri (RYGEL_MEDIA_PLAYER (self)));
1051 case RYGEL_PLAYBIN_PLAYER_MIME_TYPE:
1052 g_value_take_string (value, rygel_media_player_get_mime_type (RYGEL_MEDIA_PLAYER (self)));
1054 case RYGEL_PLAYBIN_PLAYER_METADATA:
1055 g_value_take_string (value, rygel_media_player_get_metadata (RYGEL_MEDIA_PLAYER (self)));
1057 case RYGEL_PLAYBIN_PLAYER_CAN_SEEK:
1058 g_value_set_boolean (value, rygel_media_player_get_can_seek (RYGEL_MEDIA_PLAYER (self)));
1060 case RYGEL_PLAYBIN_PLAYER_CONTENT_FEATURES:
1061 g_value_take_string (value, rygel_media_player_get_content_features (RYGEL_MEDIA_PLAYER (self)));
1063 case RYGEL_PLAYBIN_PLAYER_VOLUME:
1064 g_value_set_double (value, rygel_media_player_get_volume (RYGEL_MEDIA_PLAYER (self)));
1066 case RYGEL_PLAYBIN_PLAYER_DURATION:
1067 g_value_set_int64 (value, rygel_media_player_get_duration (RYGEL_MEDIA_PLAYER (self)));
1069 case RYGEL_PLAYBIN_PLAYER_POSITION:
1070 g_value_set_int64 (value, rygel_media_player_get_position (RYGEL_MEDIA_PLAYER (self)));
1073 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1079 static void _vala_rygel_playbin_player_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) {
1080 RygelPlaybinPlayer *self = RYGEL_PLAYBIN_PLAYER (object);
1082 g_return_if_fail (self);
1084 switch (property_id) {
1085 case RYGEL_PLAYBIN_PLAYER_PLAYBIN:
1086 rygel_playbin_player_set_playbin (self, g_value_get_object (value));
1088 case RYGEL_PLAYBIN_PLAYER_PLAYBACK_STATE:
1089 rygel_media_player_set_playback_state (RYGEL_MEDIA_PLAYER (self), g_value_get_string (value));
1091 case RYGEL_PLAYBIN_PLAYER_PLAYBACK_SPEED:
1092 rygel_media_player_set_playback_speed (RYGEL_MEDIA_PLAYER (self), g_value_get_string (value));
1094 case RYGEL_PLAYBIN_PLAYER_URI:
1095 rygel_media_player_set_uri (RYGEL_MEDIA_PLAYER (self), g_value_get_string (value));
1097 case RYGEL_PLAYBIN_PLAYER_MIME_TYPE:
1098 rygel_media_player_set_mime_type (RYGEL_MEDIA_PLAYER (self), g_value_get_string (value));
1100 case RYGEL_PLAYBIN_PLAYER_METADATA:
1101 rygel_media_player_set_metadata (RYGEL_MEDIA_PLAYER (self), g_value_get_string (value));
1103 case RYGEL_PLAYBIN_PLAYER_CONTENT_FEATURES:
1104 rygel_media_player_set_content_features (RYGEL_MEDIA_PLAYER (self), g_value_get_string (value));
1106 case RYGEL_PLAYBIN_PLAYER_VOLUME:
1107 rygel_media_player_set_volume (RYGEL_MEDIA_PLAYER (self), g_value_get_double (value));
1110 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);