hythmbox-2.98/backends/gstreamer/rb-player-gst.c

No issues found

   1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
   2  *
   3  *  Copyright (C) 2003 Jorn Baayen <jorn@nl.linux.org>
   4  *  Copyright (C) 2003,2004 Colin Walters <walters@debian.org>
   5  *  Copyright (C) 2009 Jonathan Matthew  <jonathan@d14n.org>
   6  *
   7  *  This program is free software; you can redistribute it and/or modify
   8  *  it under the terms of the GNU General Public License as published by
   9  *  the Free Software Foundation; either version 2 of the License, or
  10  *  (at your option) any later version.
  11  *
  12  *  The Rhythmbox authors hereby grant permission for non-GPL compatible
  13  *  GStreamer plugins to be used and distributed together with GStreamer
  14  *  and Rhythmbox. This permission is above and beyond the permissions granted
  15  *  by the GPL license by which Rhythmbox is covered. If you modify this code
  16  *  you may extend this exception to your version of the code, but you are not
  17  *  obligated to do so. If you do not wish to do so, delete this exception
  18  *  statement from your version.
  19  *
  20  *  This program is distributed in the hope that it will be useful,
  21  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23  *  GNU General Public License for more details.
  24  *
  25  *  You should have received a copy of the GNU General Public License
  26  *  along with this program; if not, write to the Free Software
  27  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
  28  *
  29  */
  30 
  31 #include <config.h>
  32 #include <math.h>
  33 #include <string.h>
  34 #include <stdlib.h>
  35 
  36 #include <glib/gi18n.h>
  37 #include <gdk/gdk.h>
  38 #include <gst/tag/tag.h>
  39 #include <gst/interfaces/streamvolume.h>
  40 #include <gst/pbutils/pbutils.h>
  41 
  42 #include "rb-debug.h"
  43 #include "rb-marshal.h"
  44 #include "rb-util.h"
  45 
  46 #include "rb-player.h"
  47 #include "rb-player-gst.h"
  48 #include "rb-player-gst-helper.h"
  49 #include "rb-player-gst-filter.h"
  50 #include "rb-player-gst-tee.h"
  51 
  52 static void rb_player_init (RBPlayerIface *iface);
  53 static void rb_player_gst_filter_init (RBPlayerGstFilterIface *iface);
  54 static void rb_player_gst_tee_init (RBPlayerGstTeeIface *iface);
  55 
  56 static void state_change_finished (RBPlayerGst *mp, GError *error);
  57 
  58 G_DEFINE_TYPE_WITH_CODE(RBPlayerGst, rb_player_gst, G_TYPE_OBJECT,
  59 			G_IMPLEMENT_INTERFACE(RB_TYPE_PLAYER, rb_player_init)
  60 			G_IMPLEMENT_INTERFACE(RB_TYPE_PLAYER_GST_FILTER, rb_player_gst_filter_init)
  61 			G_IMPLEMENT_INTERFACE(RB_TYPE_PLAYER_GST_TEE, rb_player_gst_tee_init)
  62 			)
  63 
  64 #define RB_PLAYER_GST_TICK_HZ 5
  65 #define STATE_CHANGE_MESSAGE_TIMEOUT 5
  66 
  67 enum
  68 {
  69 	PROP_0,
  70 	PROP_PLAYBIN,
  71 	PROP_BUS
  72 };
  73 
  74 enum
  75 {
  76 	PREPARE_SOURCE,
  77 	CAN_REUSE_STREAM,
  78 	REUSE_STREAM,
  79 	MISSING_PLUGINS,
  80 	LAST_SIGNAL
  81 };
  82 
  83 enum StateChangeAction {
  84 	DO_NOTHING,
  85 	PLAYER_SHUTDOWN,
  86 	SET_NEXT_URI,
  87 	STOP_TICK_TIMER,
  88 	FINISH_TRACK_CHANGE
  89 };
  90 
  91 static guint signals[LAST_SIGNAL] = { 0 };
  92 
  93 struct _RBPlayerGstPrivate
  94 {
  95 	char *prev_uri;
  96 	char *uri;
  97 	gpointer stream_data;
  98 	GDestroyNotify stream_data_destroy;
  99 	gpointer next_stream_data;
 100 	GDestroyNotify next_stream_data_destroy;
 101 
 102 	GstElement *playbin;
 103 	GstElement *audio_sink;
 104 	enum StateChangeAction state_change_action;
 105 
 106 	gboolean playing;
 107 	gboolean buffering;
 108 
 109 	gboolean stream_change_pending;
 110 	gboolean current_track_finishing;
 111 	gboolean playbin_stream_changing;
 112 	gboolean track_change;
 113 
 114 	gboolean emitted_error;
 115 
 116 	GList *stream_tags;
 117 
 118 	gint volume_changed;
 119 	gint volume_applied;
 120 	float cur_volume;
 121 
 122 	guint tick_timeout_id;
 123 
 124 	GList *waiting_tees;
 125 	GstElement *sinkbin;
 126 	GstElement *tee;
 127 
 128 	GList *waiting_filters; /* in reverse order */
 129 	GstElement *filterbin;
 130 };
 131 
 132 static void
 133 _destroy_stream_data (RBPlayerGst *player)
 134 {
 135 	if (player->priv->stream_data && player->priv->stream_data_destroy) {
 136 		player->priv->stream_data_destroy (player->priv->stream_data);
 137 	}
 138 	player->priv->stream_data = NULL;
 139 	player->priv->stream_data_destroy = NULL;
 140 }
 141 
 142 static void
 143 _destroy_next_stream_data (RBPlayerGst *player)
 144 {
 145 	if (player->priv->next_stream_data && player->priv->next_stream_data_destroy) {
 146 		player->priv->next_stream_data_destroy (player->priv->next_stream_data);
 147 	}
 148 	player->priv->next_stream_data = NULL;
 149 	player->priv->next_stream_data_destroy = NULL;
 150 }
 151 
 152 static void
 153 about_to_finish_cb (GstElement *playbin, RBPlayerGst *player)
 154 {
 155 	if (player->priv->stream_change_pending == TRUE) {
 156 		/* this probably shouldn't happen, but it's OK if it does, I think */
 157 		rb_debug ("got about-to-finish, but we already have a stream change pending.");
 158 		return;
 159 	}
 160 
 161 	/* don't handle about-to-finish for cdda */
 162 	if (g_str_has_prefix (player->priv->uri, "cdda://")) {
 163 		rb_debug ("ignoring about-to-finish for %s", player->priv->uri);
 164 		return;
 165 	}
 166 
 167 	/* emit EOS now and hope we get something to play */
 168 	player->priv->current_track_finishing = TRUE;
 169 
 170 	_rb_player_emit_eos (RB_PLAYER (player), player->priv->stream_data, TRUE);
 171 }
 172 
 173 static gboolean
 174 emit_volume_changed_idle (RBPlayerGst *player)
 175 {
 176 	double vol;
 177 
 178 	if (gst_element_implements_interface (player->priv->playbin, GST_TYPE_STREAM_VOLUME)) {
 179 		vol = gst_stream_volume_get_volume (GST_STREAM_VOLUME (player->priv->playbin),
 180 						    GST_STREAM_VOLUME_FORMAT_CUBIC);
 181 	} else {
 182 		vol = player->priv->cur_volume;
 183 	}
 184 
 185 	_rb_player_emit_volume_changed (RB_PLAYER (player), vol);
 186 	return FALSE;
 187 }
 188 
 189 static void
 190 volume_notify_cb (GObject *element, GstObject *prop_object, GParamSpec *pspec, RBPlayerGst *player)
 191 {
 192 	gdouble v;
 193 	g_object_get (element, "volume", &v, NULL);
 194 	player->priv->cur_volume = v;
 195 
 196 	g_idle_add ((GSourceFunc) emit_volume_changed_idle, player);
 197 }
 198 
 199 static void
 200 process_tag (const GstTagList *list, const gchar *tag, RBPlayerGst *player)
 201 {
 202 	RBMetaDataField field;
 203 	GValue value = {0,};
 204 
 205 	/* process embedded images */
 206 	if (!g_strcmp0 (tag, GST_TAG_IMAGE) || !g_strcmp0 (tag, GST_TAG_PREVIEW_IMAGE)) {
 207 		GdkPixbuf *pixbuf;
 208 		pixbuf = rb_gst_process_embedded_image (list, tag);
 209 		if (pixbuf != NULL) {
 210 			_rb_player_emit_image (RB_PLAYER (player),
 211 					       player->priv->stream_data,
 212 					       pixbuf);
 213 			g_object_unref (pixbuf);
 214 		}
 215 	} else if (rb_gst_process_tag_string (list, tag, &field, &value)) {
 216 		rb_debug ("emitting info field %d", field);
 217 		_rb_player_emit_info (RB_PLAYER (player),
 218 				      player->priv->stream_data,
 219 				      field,
 220 				      &value);
 221 		g_value_unset (&value);
 222 	}
 223 }
 224 
 225 static void
 226 emit_playing_stream_and_tags (RBPlayerGst *player, gboolean track_change)
 227 {
 228 	GList *t;
 229 
 230 	if (track_change) {
 231 		/* swap stream data */
 232 		_destroy_stream_data (player);
 233 		player->priv->stream_data = player->priv->next_stream_data;
 234 		player->priv->stream_data_destroy = player->priv->next_stream_data_destroy;
 235 		player->priv->next_stream_data = NULL;
 236 		player->priv->next_stream_data_destroy = NULL;
 237 	}
 238 
 239 	_rb_player_emit_playing_stream (RB_PLAYER (player), player->priv->stream_data);
 240 
 241 	/* process any tag lists we received while starting the stream */
 242 	for (t = player->priv->stream_tags; t != NULL; t = t->next) {
 243 		GstTagList *tags;
 244 
 245 		tags = (GstTagList *)t->data;
 246 		rb_debug ("processing buffered taglist");
 247 		gst_tag_list_foreach (tags, (GstTagForeachFunc) process_tag, player);
 248 		gst_tag_list_free (tags);
 249 	}
 250 	g_list_free (player->priv->stream_tags);
 251 	player->priv->stream_tags = NULL;
 252 }
 253 
 254 static void
 255 handle_missing_plugin_message (RBPlayerGst *player, GstMessage *message)
 256 {
 257 	char **details;
 258 	char **descriptions;
 259 	char *detail;
 260 	char *description;
 261 	int count;
 262 
 263 	rb_debug ("got missing-plugin message from %s: %s",
 264 		  GST_OBJECT_NAME (GST_MESSAGE_SRC (message)),
 265 		  gst_missing_plugin_message_get_installer_detail (message));
 266 
 267 	/* probably need to wait to collect any subsequent missing-plugin
 268 	 * messages, but I think we'd need to wait for state changes to do
 269 	 * that.  for now, we can only handle a single message.
 270 	 */
 271 	count = 1;
 272 
 273 	details = g_new0 (char *, count + 1);
 274 	descriptions = g_new0 (char *, count + 1);
 275 
 276 	detail = gst_missing_plugin_message_get_installer_detail (message);
 277 	description = gst_missing_plugin_message_get_description (message);
 278 	details[0] = g_strdup (detail);
 279 	descriptions[0] = g_strdup (description);
 280 
 281 	g_signal_emit (player, signals[MISSING_PLUGINS], 0, player->priv->stream_data, details, descriptions);
 282 	g_strfreev (details);
 283 	g_strfreev (descriptions);
 284 }
 285 
 286 static gboolean
 287 tick_timeout (RBPlayerGst *mp)
 288 {
 289 	if (mp->priv->playing) {
 290 		gint64 position;
 291 
 292 		position = rb_player_get_time (RB_PLAYER (mp));
 293 
 294 		/* if we don't have stream-changed messages, do the track change when
 295 		 * the playback position is less than one second into the current track,
 296 		 * which pretty much has to be the new one.
 297 		 */
 298 		if (mp->priv->playbin_stream_changing && (position < GST_SECOND)) {
 299 			emit_playing_stream_and_tags (mp, TRUE);
 300 			mp->priv->playbin_stream_changing = FALSE;
 301 		}
 302 
 303 		_rb_player_emit_tick (RB_PLAYER (mp),
 304 				      mp->priv->stream_data,
 305 				      position,
 306 				      -1);
 307 	}
 308 	return TRUE;
 309 }
 310 
 311 static void
 312 set_playbin_volume (RBPlayerGst *player, float volume)
 313 {
 314 	/* ignore the deep-notify we get directly from the sink, as it causes deadlock.
 315 	 * we still get another one anyway.
 316 	 */
 317 	g_signal_handlers_block_by_func (player->priv->playbin, volume_notify_cb, player);
 318 	if (gst_element_implements_interface (player->priv->playbin, GST_TYPE_STREAM_VOLUME))
 319 		gst_stream_volume_set_volume (GST_STREAM_VOLUME (player->priv->playbin),
 320 					      GST_STREAM_VOLUME_FORMAT_CUBIC, volume);
 321 	else
 322 		g_object_set (player->priv->playbin, "volume", volume, NULL);
 323 	g_signal_handlers_unblock_by_func (player->priv->playbin, volume_notify_cb, player);
 324 }
 325 
 326 
 327 
 328 static void
 329 track_change_done (RBPlayerGst *mp, GError *error)
 330 {
 331 	mp->priv->stream_change_pending = FALSE;
 332 
 333 	if (error != NULL) {
 334 		rb_debug ("track change failed: %s", error->message);
 335 		return;
 336 	}
 337 	rb_debug ("track change finished");
 338 
 339 	mp->priv->current_track_finishing = FALSE;
 340 	mp->priv->buffering = FALSE;
 341 	mp->priv->playing = TRUE;
 342 
 343 	if (mp->priv->playbin_stream_changing == FALSE) {
 344 		emit_playing_stream_and_tags (mp, mp->priv->track_change);
 345 	}
 346 
 347 	if (mp->priv->tick_timeout_id == 0) {
 348 		mp->priv->tick_timeout_id =
 349 			g_timeout_add (1000 / RB_PLAYER_GST_TICK_HZ,
 350 				       (GSourceFunc) tick_timeout,
 351 				       mp);
 352 	}
 353 
 354 	if (mp->priv->volume_applied == 0) {
 355 		GstElement *e;
 356 
 357 		/* if the sink provides volume control, ignore the first
 358 		 * volume setting, allowing the sink to restore its own
 359 		 * volume.
 360 		 */
 361 		e = rb_player_gst_find_element_with_property (mp->priv->audio_sink, "volume");
 362 		if (e != NULL) {
 363 			mp->priv->volume_applied = 1;
 364 			gst_object_unref (e);
 365 		}
 366 
 367 		if (mp->priv->volume_applied < mp->priv->volume_changed) {
 368 			rb_debug ("applying initial volume: %f", mp->priv->cur_volume);
 369 			set_playbin_volume (mp, mp->priv->cur_volume);
 370 		}
 371 
 372 		mp->priv->volume_applied = mp->priv->volume_changed;
 373 	}
 374 }
 375 
 376 static void
 377 start_state_change (RBPlayerGst *mp, GstState state, enum StateChangeAction action)
 378 {
 379 	GstStateChangeReturn scr;
 380 
 381 	rb_debug ("changing state to %s", gst_element_state_get_name (state));
 382 	mp->priv->state_change_action = action;
 383 	scr = gst_element_set_state (mp->priv->playbin, state);
 384 	if (scr == GST_STATE_CHANGE_SUCCESS) {
 385 		rb_debug ("state change succeeded synchronously");
 386 		state_change_finished (mp, NULL);
 387 	}
 388 }
 389 
 390 static void
 391 state_change_finished (RBPlayerGst *mp, GError *error)
 392 {
 393 	enum StateChangeAction action = mp->priv->state_change_action;
 394 	mp->priv->state_change_action = DO_NOTHING;
 395 
 396 	switch (action) {
 397 	case DO_NOTHING:
 398 		break;
 399 
 400 	case PLAYER_SHUTDOWN:
 401 		if (error != NULL) {
 402 			g_warning ("unable to shut down player pipeline: %s\n", error->message);
 403 		}
 404 		break;
 405 
 406 	case SET_NEXT_URI:
 407 		if (error != NULL) {
 408 			g_warning ("unable to stop playback: %s\n", error->message);
 409 		} else {
 410 			rb_debug ("setting new playback URI %s", mp->priv->uri);
 411 			g_object_set (mp->priv->playbin, "uri", mp->priv->uri, NULL);
 412 			start_state_change (mp, GST_STATE_PLAYING, FINISH_TRACK_CHANGE);
 413 		}
 414 		break;
 415 
 416 	case STOP_TICK_TIMER:
 417 		if (error != NULL) {
 418 			g_warning ("unable to pause playback: %s\n", error->message);
 419 		} else {
 420 			if (mp->priv->tick_timeout_id != 0) {
 421 				g_source_remove (mp->priv->tick_timeout_id);
 422 				mp->priv->tick_timeout_id = 0;
 423 			}
 424 		}
 425 		break;
 426 
 427 	case FINISH_TRACK_CHANGE:
 428 		track_change_done (mp, error);
 429 		break;
 430 	}
 431 }
 432 
 433 static gboolean
 434 message_from_sink (GstElement *sink, GstMessage *message)
 435 {
 436 	GstElement *src;
 437 	GstElement *match;
 438 	char *name;
 439 
 440 	src = GST_ELEMENT (GST_MESSAGE_SRC (message));
 441 
 442 	if (GST_IS_BIN (sink) == FALSE) {
 443 		return (src == sink);
 444 	}
 445 
 446 	name = gst_element_get_name (src);
 447 	match = gst_bin_get_by_name (GST_BIN (sink), name);
 448 	g_free (name);
 449 
 450 	if (match != NULL) {
 451 		g_object_unref (match);
 452 		return (match == src);
 453 	}
 454 
 455 	return FALSE;
 456 }
 457 
 458 static gboolean
 459 bus_cb (GstBus *bus, GstMessage *message, RBPlayerGst *mp)
 460 {
 461 	const GstStructure *structure;
 462 	g_return_val_if_fail (mp != NULL, FALSE);
 463 
 464 	switch (GST_MESSAGE_TYPE (message)) {
 465 	case GST_MESSAGE_ERROR: {
 466 		char *debug;
 467 		GError *error = NULL;
 468 		GError *sig_error = NULL;
 469 		int code;
 470 		gboolean emit = TRUE;
 471 
 472 		gst_message_parse_error (message, &error, &debug);
 473 
 474 		/* If we've already got an error, ignore 'internal data flow error'
 475 		 * type messages, as they're too generic to be helpful.
 476 		 */
 477 		if (mp->priv->emitted_error &&
 478 		    error->domain == GST_STREAM_ERROR &&
 479 		    error->code == GST_STREAM_ERROR_FAILED) {
 480 			rb_debug ("Ignoring generic error \"%s\"", error->message);
 481 			emit = FALSE;
 482 		}
 483 
 484 		code = rb_gst_error_get_error_code (error);
 485 
 486 		if (emit) {
 487 			if (message_from_sink (mp->priv->audio_sink, message)) {
 488 				rb_debug ("got error from sink: %s (%s)", error->message, debug);
 489 				/* Translators: the parameter here is an error message */
 490 				g_set_error (&sig_error,
 491 					     RB_PLAYER_ERROR,
 492 					     code,
 493 					     _("Failed to open output device: %s"),
 494 					     error->message);
 495 			} else {
 496 				rb_debug ("got error from stream: %s (%s)", error->message, debug);
 497 				g_set_error (&sig_error,
 498 					     RB_PLAYER_ERROR,
 499 					     code,
 500 					     "%s",
 501 					     error->message);
 502 			}
 503 			state_change_finished (mp, sig_error);
 504 			mp->priv->emitted_error = TRUE;
 505 			if (mp->priv->playbin_stream_changing) {
 506 				emit_playing_stream_and_tags (mp, TRUE);
 507 			}
 508 			_rb_player_emit_error (RB_PLAYER (mp), mp->priv->stream_data, sig_error);
 509 		}
 510 
 511 		/* close if not already closing */
 512 		if (mp->priv->uri != NULL)
 513 			rb_player_close (RB_PLAYER (mp), NULL, NULL);
 514 
 515 		g_error_free (error);
 516 		g_free (debug);
 517 		break;
 518 	}
 519 
 520 	case GST_MESSAGE_EOS:
 521 		_rb_player_emit_eos (RB_PLAYER (mp), mp->priv->stream_data, FALSE);
 522 		break;
 523 
 524 	case GST_MESSAGE_STATE_CHANGED:
 525 		{
 526 			GstState oldstate;
 527 			GstState newstate;
 528 			GstState pending;
 529 			gst_message_parse_state_changed (message, &oldstate, &newstate, &pending);
 530 			if (GST_MESSAGE_SRC (message) == GST_OBJECT (mp->priv->playbin)) {
 531 				if (pending == GST_STATE_VOID_PENDING) {
 532 					rb_debug ("playbin reached state %s", gst_element_state_get_name (newstate));
 533 					state_change_finished (mp, NULL);
 534 				}
 535 			}
 536 			break;
 537 		}
 538 
 539 	case GST_MESSAGE_TAG: {
 540 		GstTagList *tags;
 541 		gst_message_parse_tag (message, &tags);
 542 
 543 		if (mp->priv->stream_change_pending || mp->priv->playbin_stream_changing) {
 544 			mp->priv->stream_tags = g_list_append (mp->priv->stream_tags, tags);
 545 		} else {
 546 			gst_tag_list_foreach (tags, (GstTagForeachFunc) process_tag, mp);
 547 			gst_tag_list_free (tags);
 548 		}
 549 		break;
 550 	}
 551 
 552 
 553 	case GST_MESSAGE_BUFFERING: {
 554 		gint progress;
 555 
 556 		structure = gst_message_get_structure (message);
 557 		if (!gst_structure_get_int (structure, "buffer-percent", &progress)) {
 558 			g_warning ("Could not get value from BUFFERING message");
 559 			break;
 560 		}
 561 
 562 		if (progress >= 100) {
 563 			mp->priv->buffering = FALSE;
 564 			if (mp->priv->playing) {
 565 				rb_debug ("buffering done, setting pipeline back to PLAYING");
 566 				gst_element_set_state (mp->priv->playbin, GST_STATE_PLAYING);
 567 			} else {
 568 				rb_debug ("buffering done, leaving pipeline PAUSED");
 569 			}
 570 		} else if (mp->priv->buffering == FALSE && mp->priv->playing) {
 571 
 572 			rb_debug ("buffering - temporarily pausing playback");
 573 			gst_element_set_state (mp->priv->playbin, GST_STATE_PAUSED);
 574 			mp->priv->buffering = TRUE;
 575 		}
 576 
 577 		_rb_player_emit_buffering (RB_PLAYER (mp), mp->priv->stream_data, progress);
 578 		break;
 579 	}
 580 
 581 	case GST_MESSAGE_APPLICATION:
 582 		structure = gst_message_get_structure (message);
 583 		_rb_player_emit_event (RB_PLAYER (mp), mp->priv->stream_data, gst_structure_get_name (structure), NULL);
 584 		break;
 585 
 586 	case GST_MESSAGE_ELEMENT:
 587 		structure = gst_message_get_structure (message);
 588 		if (gst_is_missing_plugin_message (message)) {
 589 			handle_missing_plugin_message (mp, message);
 590 		} else if (mp->priv->playbin_stream_changing &&
 591 			   gst_structure_has_name (structure, "playbin2-stream-changed")) {
 592 			rb_debug ("got playbin2-stream-changed message");
 593 			mp->priv->playbin_stream_changing = FALSE;
 594 			emit_playing_stream_and_tags (mp, TRUE);
 595 		} else if (gst_structure_has_name (structure, "redirect")) {
 596 			const char *uri = gst_structure_get_string (structure, "new-location");
 597 			_rb_player_emit_redirect (RB_PLAYER (mp), mp->priv->stream_data, uri);
 598 		}
 599 		break;
 600 
 601 	default:
 602 		break;
 603 	}
 604 
 605 	/* emit message signals too, so plugins can process messages */
 606 	gst_bus_async_signal_func (bus, message, NULL);
 607 
 608 	return TRUE;
 609 }
 610 
 611 static void
 612 source_notify_cb (GObject *object, GParamSpec *pspec, RBPlayerGst *player)
 613 {
 614 	GstElement *source;
 615 
 616 	if (player->priv->uri == NULL) {
 617 		rb_debug ("got notify::source while changing to NULL");
 618 		return;
 619 	}
 620 
 621 	g_object_get (object, "source", &source, NULL);
 622 
 623 	g_signal_emit (player, signals[PREPARE_SOURCE], 0, player->priv->uri, source);
 624 
 625 	g_object_unref (source);
 626 }
 627 
 628 static gboolean
 629 construct_pipeline (RBPlayerGst *mp, GError **error)
 630 {
 631 	GstElement *sink;
 632 
 633 	mp->priv->playbin = gst_element_factory_make ("playbin2", NULL);
 634 	if (mp->priv->playbin == NULL) {
 635 		g_set_error (error,
 636 			     RB_PLAYER_ERROR,
 637 			     RB_PLAYER_ERROR_GENERAL,
 638 			     _("Failed to create %s element; check your GStreamer installation"),
 639 			     "playbin2");
 640 		return FALSE;
 641 	}
 642 	g_signal_connect_object (G_OBJECT (mp->priv->playbin),
 643 				 "about-to-finish",
 644 				 G_CALLBACK (about_to_finish_cb),
 645 				 mp, 0);
 646 	g_signal_connect_object (G_OBJECT (mp->priv->playbin),
 647 				 "deep-notify::volume",
 648 				 G_CALLBACK (volume_notify_cb),
 649 				 mp, 0);
 650 	g_signal_connect_object (G_OBJECT (mp->priv->playbin),
 651 				 "notify::source",
 652 				 G_CALLBACK (source_notify_cb),
 653 				 mp, 0);
 654 
 655 	gst_bus_add_watch (gst_element_get_bus (mp->priv->playbin),
 656 			   (GstBusFunc) bus_cb,
 657 			   mp);
 658 
 659 	/* let plugins add bits to playbin */
 660 	g_object_notify (G_OBJECT (mp), "playbin");
 661 	g_object_notify (G_OBJECT (mp), "bus");
 662 
 663 	/* Use gsettingsaudiosink for audio if there's no audio sink yet */
 664 	g_object_get (mp->priv->playbin, "audio-sink", &mp->priv->audio_sink, NULL);
 665 	if (mp->priv->audio_sink == NULL) {
 666 		const char *try_sinks[] = { "gsettingsaudiosink", "gconfaudiosink", "autoaudiosink" };
 667 		int i;
 668 
 669 		for (i = 0; i < G_N_ELEMENTS (try_sinks); i++) {
 670 			mp->priv->audio_sink = rb_player_gst_try_audio_sink (try_sinks[i], NULL);
 671 			if (mp->priv->audio_sink != NULL) {
 672 				g_object_set (mp->priv->playbin, "audio-sink", mp->priv->audio_sink, NULL);
 673 				break;
 674 			}
 675 		}
 676 		if (mp->priv->audio_sink == NULL) {
 677 			g_set_error (error,
 678 				     RB_PLAYER_ERROR,
 679 				     RB_PLAYER_ERROR_GENERAL,
 680 				     _("Failed to create %s element; check your GStreamer installation"),
 681 				     "autoaudiosink");
 682 			return FALSE;
 683 		}
 684 	} else {
 685 		rb_debug ("existing audio sink found");
 686 		g_object_unref (mp->priv->audio_sink);
 687 	}
 688 
 689 	{
 690 		GstPad *pad;
 691 		GList *l;
 692 		GstElement *queue;
 693 		GstPad *ghostpad;
 694 
 695 		/* setup filterbin */
 696 		mp->priv->filterbin = rb_gst_create_filter_bin ();
 697 
 698 		/* set up the sinkbin with its tee element */
 699 		mp->priv->sinkbin = gst_bin_new (NULL);
 700 		mp->priv->tee = gst_element_factory_make ("tee", NULL);
 701 		queue = gst_element_factory_make ("queue", NULL);
 702 
 703 		/* link it all together and insert */
 704 		gst_bin_add_many (GST_BIN (mp->priv->sinkbin), mp->priv->filterbin, mp->priv->tee, queue, mp->priv->audio_sink, NULL);
 705 		gst_element_link_many (mp->priv->filterbin, mp->priv->tee, queue, mp->priv->audio_sink, NULL);
 706 
 707 		pad = gst_element_get_pad (mp->priv->filterbin, "sink");
 708 		ghostpad = gst_ghost_pad_new ("sink", pad);
 709 		gst_element_add_pad (mp->priv->sinkbin, ghostpad);
 710 		gst_object_unref (pad);
 711 
 712 		g_object_set (G_OBJECT (mp->priv->playbin), "audio-sink", mp->priv->sinkbin, NULL);
 713 
 714 		/* add any tees and filters that were waiting for us */
 715 		for (l = mp->priv->waiting_tees; l != NULL; l = g_list_next (l)) {
 716 			rb_player_gst_tee_add_tee (RB_PLAYER_GST_TEE (mp), GST_ELEMENT (l->data));
 717 		}
 718 		g_list_free (mp->priv->waiting_tees);
 719 		mp->priv->waiting_tees = NULL;
 720 
 721 		for (l = mp->priv->waiting_filters; l != NULL; l = g_list_next (l)) {
 722 			rb_player_gst_filter_add_filter (RB_PLAYER_GST_FILTER(mp), GST_ELEMENT (l->data));
 723 		}
 724 		g_list_free (mp->priv->waiting_filters);
 725 		mp->priv->waiting_filters = NULL;
 726 	}
 727 
 728 	/* Use fakesink for video if there's no video sink yet */
 729 	g_object_get (mp->priv->playbin, "video-sink", &sink, NULL);
 730 	if (sink == NULL) {
 731 		sink = gst_element_factory_make ("fakesink", NULL);
 732 		g_object_set (mp->priv->playbin, "video-sink", sink, NULL);
 733 	} else {
 734 		g_object_unref (sink);
 735 	}
 736 
 737 	if (mp->priv->cur_volume > 1.0)
 738 		mp->priv->cur_volume = 1.0;
 739 	if (mp->priv->cur_volume < 0.0)
 740 		mp->priv->cur_volume = 0;
 741 
 742 	rb_debug ("pipeline construction complete");
 743 	return TRUE;
 744 }
 745 
 746 static gboolean
 747 impl_close (RBPlayer *player, const char *uri, GError **error)
 748 {
 749 	RBPlayerGst *mp = RB_PLAYER_GST (player);
 750 
 751 	if ((uri != NULL) && (mp->priv->uri != NULL) && strcmp (mp->priv->uri, uri) == 0) {
 752 		rb_debug ("URI doesn't match current playing URI; ignoring");
 753 		return TRUE;
 754 	}
 755 
 756 	mp->priv->playing = FALSE;
 757 	mp->priv->buffering = FALSE;
 758 	mp->priv->current_track_finishing = FALSE;
 759 
 760 	_destroy_stream_data (mp);
 761 	if (uri == NULL) {
 762 		_destroy_next_stream_data (mp);
 763 	}
 764 	g_free (mp->priv->uri);
 765 	g_free (mp->priv->prev_uri);
 766 	mp->priv->uri = NULL;
 767 	mp->priv->prev_uri = NULL;
 768 
 769 	if (mp->priv->tick_timeout_id != 0) {
 770 		g_source_remove (mp->priv->tick_timeout_id);
 771 		mp->priv->tick_timeout_id = 0;
 772 	}
 773 
 774 	if (mp->priv->playbin != NULL) {
 775 		start_state_change (mp, GST_STATE_NULL, PLAYER_SHUTDOWN);
 776 	}
 777 	return TRUE;
 778 }
 779 
 780 static gboolean
 781 impl_open (RBPlayer *player,
 782 	   const char *uri,
 783 	   gpointer stream_data,
 784 	   GDestroyNotify stream_data_destroy,
 785 	   GError **error)
 786 {
 787 	RBPlayerGst *mp = RB_PLAYER_GST (player);
 788 
 789 	if (mp->priv->playbin == NULL) {
 790 		if (!construct_pipeline (mp, error))
 791 			return FALSE;
 792 	}
 793 
 794 	g_assert (mp->priv->playbin != NULL);
 795 
 796 	if (uri == NULL) {
 797 		return impl_close (player, NULL, error);
 798 	}
 799 
 800 	rb_debug ("setting new uri to %s", uri);
 801 	_destroy_next_stream_data (mp);
 802 	g_free (mp->priv->prev_uri);
 803 	mp->priv->prev_uri = mp->priv->uri;
 804 	mp->priv->uri = g_strdup (uri);
 805 	mp->priv->next_stream_data = stream_data;
 806 	mp->priv->next_stream_data_destroy = stream_data_destroy;
 807 	mp->priv->emitted_error = FALSE;
 808 	mp->priv->stream_change_pending = TRUE;
 809 
 810 	return TRUE;
 811 }
 812 
 813 static gboolean
 814 impl_opened (RBPlayer *player)
 815 {
 816 	RBPlayerGst *mp = RB_PLAYER_GST (player);
 817 
 818 	return mp->priv->uri != NULL;
 819 }
 820 
 821 static gboolean
 822 impl_play (RBPlayer *player, RBPlayerPlayType play_type, gint64 crossfade, GError **error)
 823 {
 824 	RBPlayerGst *mp = RB_PLAYER_GST (player);
 825 
 826 	g_return_val_if_fail (mp->priv->playbin != NULL, FALSE);
 827 
 828 	mp->priv->track_change = TRUE;
 829 
 830 	if (mp->priv->stream_change_pending == FALSE) {
 831 		rb_debug ("no stream change pending, just restarting playback");
 832 		mp->priv->track_change = FALSE;
 833 		start_state_change (mp, GST_STATE_PLAYING, FINISH_TRACK_CHANGE);
 834 	} else if (mp->priv->current_track_finishing) {
 835 		rb_debug ("current track finishing -> just setting URI on playbin");
 836 		g_object_set (mp->priv->playbin, "uri", mp->priv->uri, NULL);
 837 
 838 		mp->priv->playbin_stream_changing = TRUE;
 839 
 840 		track_change_done (mp, NULL);
 841 	} else {
 842 		gboolean reused = FALSE;
 843 
 844 		/* try to reuse the stream */
 845 		if (mp->priv->prev_uri != NULL) {
 846 			g_signal_emit (mp,
 847 				       signals[CAN_REUSE_STREAM], 0,
 848 				       mp->priv->uri, mp->priv->prev_uri, mp->priv->playbin,
 849 				       &reused);
 850 
 851 			if (reused) {
 852 				rb_debug ("reusing stream to switch from %s to %s", mp->priv->prev_uri, mp->priv->uri);
 853 				g_signal_emit (player,
 854 					       signals[REUSE_STREAM], 0,
 855 					       mp->priv->uri, mp->priv->prev_uri, mp->priv->playbin);
 856 				track_change_done (mp, *error);
 857 			}
 858 		}
 859 
 860 		/* no stream reuse, so stop, set the new URI, then start */
 861 		if (reused == FALSE) {
 862 			rb_debug ("not in transition, stopping current track to start the new one");
 863 			start_state_change (mp, GST_STATE_READY, SET_NEXT_URI);
 864 		}
 865 
 866 	}
 867 
 868 	return TRUE;
 869 }
 870 
 871 static void
 872 impl_pause (RBPlayer *player)
 873 {
 874 	RBPlayerGst *mp = RB_PLAYER_GST (player);
 875 
 876 	if (!mp->priv->playing)
 877 		return;
 878 
 879 	mp->priv->playing = FALSE;
 880 
 881 	g_return_if_fail (mp->priv->playbin != NULL);
 882 
 883 	start_state_change (mp, GST_STATE_PAUSED, STOP_TICK_TIMER);
 884 }
 885 
 886 static gboolean
 887 impl_playing (RBPlayer *player)
 888 {
 889 	RBPlayerGst *mp = RB_PLAYER_GST (player);
 890 
 891 	return mp->priv->playing;
 892 }
 893 
 894 static void
 895 impl_set_volume (RBPlayer *player,
 896 		 float volume)
 897 {
 898 	RBPlayerGst *mp = RB_PLAYER_GST (player);
 899 	g_return_if_fail (volume >= 0.0 && volume <= 1.0);
 900 
 901 	mp->priv->volume_changed++;
 902 	if (mp->priv->volume_applied > 0) {
 903 		set_playbin_volume (mp, volume);
 904 		mp->priv->volume_applied = mp->priv->volume_changed;
 905 	} else {
 906 		/* volume will be applied in the first call to impl_play */
 907 	}
 908 
 909 	mp->priv->cur_volume = volume;
 910 }
 911 
 912 static float
 913 impl_get_volume (RBPlayer *player)
 914 {
 915 	RBPlayerGst *mp = RB_PLAYER_GST (player);
 916 
 917 	return mp->priv->cur_volume;
 918 }
 919 
 920 static gboolean
 921 impl_seekable (RBPlayer *player)
 922 {
 923 	RBPlayerGst *mp = RB_PLAYER_GST (player);
 924 	gboolean can_seek = TRUE;
 925 	GstQuery *query;
 926 
 927 	if (mp->priv->playbin == NULL)
 928 		return FALSE;
 929 
 930 	query = gst_query_new_seeking (GST_FORMAT_TIME);
 931 	if (gst_element_query (mp->priv->playbin, query)) {
 932 		gst_query_parse_seeking (query, NULL, &can_seek, NULL, NULL);
 933 	} else {
 934 		gst_query_unref (query);
 935 
 936 		query = gst_query_new_duration (GST_FORMAT_TIME);
 937 		can_seek = gst_element_query (mp->priv->playbin, query);
 938 	}
 939 	gst_query_unref (query);
 940 
 941 	return can_seek;
 942 }
 943 
 944 static void
 945 impl_set_time (RBPlayer *player, gint64 time)
 946 {
 947 	RBPlayerGst *mp = RB_PLAYER_GST (player);
 948 
 949 	rb_debug ("seeking to %" G_GINT64_FORMAT, time);
 950 	gst_element_seek (mp->priv->playbin, 1.0,
 951 			  GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
 952 			  GST_SEEK_TYPE_SET, time,
 953 			  GST_SEEK_TYPE_NONE, -1);
 954 
 955 	gst_element_get_state (mp->priv->playbin, NULL, NULL, 100 * GST_MSECOND);
 956 }
 957 
 958 static gint64
 959 impl_get_time (RBPlayer *player)
 960 {
 961 	RBPlayerGst *mp = RB_PLAYER_GST (player);
 962 
 963 	if (mp->priv->playbin != NULL) {
 964 		gint64 position = -1;
 965 		GstFormat fmt = GST_FORMAT_TIME;
 966 
 967 		gst_element_query_position (mp->priv->playbin, &fmt, &position);
 968 		return position;
 969 	} else {
 970 		return -1;
 971 	}
 972 }
 973 
 974 static gboolean
 975 need_pad_blocking (RBPlayerGst *mp)
 976 {
 977 	return (mp->priv->playing || (mp->priv->uri != NULL));
 978 }
 979 
 980 static gboolean
 981 impl_add_tee (RBPlayerGstTee *player, GstElement *element)
 982 {
 983 	RBPlayerGst *mp = RB_PLAYER_GST (player);
 984 
 985 	if (mp->priv->tee == NULL) {
 986 		mp->priv->waiting_tees = g_list_prepend (mp->priv->waiting_tees, element);
 987 		return TRUE;
 988 	}
 989 
 990 	return rb_gst_add_tee (RB_PLAYER (player), mp->priv->tee, element, need_pad_blocking (mp));
 991 }
 992 
 993 static gboolean
 994 impl_remove_tee (RBPlayerGstTee *player, GstElement *element)
 995 {
 996 	RBPlayerGst *mp = RB_PLAYER_GST (player);
 997 
 998 	if (mp->priv->tee == NULL) {
 999 		gst_object_sink (element);
1000 		mp->priv->waiting_tees = g_list_remove (mp->priv->waiting_tees, element);
1001 		return TRUE;
1002 	}
1003 
1004 	return rb_gst_remove_tee (RB_PLAYER (mp), mp->priv->tee, element, need_pad_blocking (mp));
1005 }
1006 
1007 static gboolean
1008 impl_add_filter (RBPlayerGstFilter *player, GstElement *element)
1009 {
1010 	RBPlayerGst *mp = RB_PLAYER_GST (player);
1011 
1012 	if (mp->priv->filterbin == NULL) {
1013 		mp->priv->waiting_filters = g_list_prepend (mp->priv->waiting_filters, element);
1014 		return TRUE;
1015 	}
1016 	return rb_gst_add_filter (RB_PLAYER (mp), mp->priv->filterbin, element, need_pad_blocking (mp));
1017 }
1018 
1019 static gboolean
1020 impl_remove_filter (RBPlayerGstFilter *player, GstElement *element)
1021 {
1022 	RBPlayerGst *mp = RB_PLAYER_GST (player);
1023 
1024 	if (mp->priv->filterbin == NULL) {
1025 		gst_object_sink (element);
1026 		mp->priv->waiting_filters = g_list_remove (mp->priv->waiting_filters, element);
1027 		return TRUE;
1028 	}
1029 
1030 	return rb_gst_remove_filter (RB_PLAYER (mp), mp->priv->filterbin, element, need_pad_blocking (mp));
1031 }
1032 
1033 static void
1034 rb_player_gst_filter_init (RBPlayerGstFilterIface *iface)
1035 {
1036 	iface->add_filter = impl_add_filter;
1037 	iface->remove_filter = impl_remove_filter;
1038 }
1039 
1040 static void
1041 rb_player_gst_tee_init (RBPlayerGstTeeIface *iface)
1042 {
1043 	iface->add_tee = impl_add_tee;
1044 	iface->remove_tee = impl_remove_tee;
1045 }
1046 
1047 
1048 
1049 RBPlayer *
1050 rb_player_gst_new (GError **error)
1051 {
1052 	return RB_PLAYER (g_object_new (RB_TYPE_PLAYER_GST, NULL, NULL));
1053 }
1054 
1055 
1056 static void
1057 rb_player_gst_init (RBPlayerGst *mp)
1058 {
1059 	mp->priv = (G_TYPE_INSTANCE_GET_PRIVATE ((mp),
1060 		    RB_TYPE_PLAYER_GST,
1061 		    RBPlayerGstPrivate));
1062 }
1063 
1064 static void
1065 impl_get_property (GObject *object,
1066 		   guint prop_id,
1067 		   GValue *value,
1068 		   GParamSpec *pspec)
1069 {
1070 	RBPlayerGst *mp = RB_PLAYER_GST (object);
1071 
1072 	switch (prop_id) {
1073 	case PROP_PLAYBIN:
1074 		g_value_set_object (value, mp->priv->playbin);
1075 		break;
1076 	case PROP_BUS:
1077 		if (mp->priv->playbin) {
1078 			GstBus *bus;
1079 			bus = gst_element_get_bus (mp->priv->playbin);
1080 			g_value_set_object (value, bus);
1081 			gst_object_unref (bus);
1082 		}
1083 		break;
1084 	default:
1085 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1086 		break;
1087 	}
1088 }
1089 
1090 static void
1091 impl_set_property (GObject *object,
1092 		   guint prop_id,
1093 		   const GValue *value,
1094 		   GParamSpec *pspec)
1095 {
1096 	/*RBPlayerGst *mp = RB_PLAYER_GST (object);*/
1097 
1098 	switch (prop_id) {
1099 	default:
1100 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1101 		break;
1102 	}
1103 }
1104 
1105 static void
1106 impl_dispose (GObject *object)
1107 {
1108 	RBPlayerGst *mp;
1109 
1110 	mp = RB_PLAYER_GST (object);
1111 
1112 	if (mp->priv->tick_timeout_id != 0) {
1113 		g_source_remove (mp->priv->tick_timeout_id);
1114 		mp->priv->tick_timeout_id = 0;
1115 	}
1116 
1117 	if (mp->priv->playbin != NULL) {
1118 		gst_element_set_state (mp->priv->playbin, GST_STATE_NULL);
1119 		g_object_unref (mp->priv->playbin);
1120 		mp->priv->playbin = NULL;
1121 		mp->priv->audio_sink = NULL;
1122 	}
1123 
1124 	if (mp->priv->waiting_tees != NULL) {
1125 		g_list_foreach (mp->priv->waiting_tees, (GFunc)gst_object_sink, NULL);
1126 		g_list_free (mp->priv->waiting_tees);
1127 		mp->priv->waiting_tees = NULL;
1128 	}
1129 
1130 	if (mp->priv->waiting_filters != NULL) {
1131 		g_list_foreach (mp->priv->waiting_filters, (GFunc)gst_object_sink, NULL);
1132 		g_list_free (mp->priv->waiting_filters);
1133 		mp->priv->waiting_filters = NULL;
1134 	}
1135 
1136 	G_OBJECT_CLASS (rb_player_gst_parent_class)->dispose (object);
1137 }
1138 
1139 static void
1140 rb_player_init (RBPlayerIface *iface)
1141 {
1142 	iface->open = impl_open;
1143 	iface->opened = impl_opened;
1144 	iface->close = impl_close;
1145 	iface->play = impl_play;
1146 	iface->pause = impl_pause;
1147 	iface->playing = impl_playing;
1148 	iface->set_volume = impl_set_volume;
1149 	iface->get_volume = impl_get_volume;
1150 	iface->seekable = impl_seekable;
1151 	iface->set_time = impl_set_time;
1152 	iface->get_time = impl_get_time;
1153 	iface->multiple_open = (RBPlayerFeatureFunc) rb_false_function;
1154 }
1155 
1156 static void
1157 rb_player_gst_class_init (RBPlayerGstClass *klass)
1158 {
1159 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
1160 
1161 	object_class->dispose = impl_dispose;
1162 	object_class->get_property = impl_get_property;
1163 	object_class->set_property = impl_set_property;
1164 
1165 	g_object_class_install_property (object_class,
1166 					 PROP_PLAYBIN,
1167 					 g_param_spec_object ("playbin",
1168 							      "playbin",
1169 							      "playbin element",
1170 							      GST_TYPE_ELEMENT,
1171 							      G_PARAM_READABLE));
1172 	g_object_class_install_property (object_class,
1173 					 PROP_BUS,
1174 					 g_param_spec_object ("bus",
1175 							      "bus",
1176 							      "GStreamer message bus",
1177 							      GST_TYPE_BUS,
1178 							      G_PARAM_READABLE));
1179 
1180 	signals[PREPARE_SOURCE] =
1181 		g_signal_new ("prepare-source",
1182 			      G_OBJECT_CLASS_TYPE (object_class),
1183 			      G_SIGNAL_RUN_LAST,
1184 			      G_STRUCT_OFFSET (RBPlayerGstClass, prepare_source),
1185 			      NULL, NULL,
1186 			      rb_marshal_VOID__STRING_OBJECT,
1187 			      G_TYPE_NONE,
1188 			      2,
1189 			      G_TYPE_STRING, GST_TYPE_ELEMENT);
1190 	signals[CAN_REUSE_STREAM] =
1191 		g_signal_new ("can-reuse-stream",
1192 			      G_OBJECT_CLASS_TYPE (object_class),
1193 			      G_SIGNAL_RUN_LAST,
1194 			      G_STRUCT_OFFSET (RBPlayerGstClass, can_reuse_stream),
1195 			      NULL, NULL,
1196 			      rb_marshal_BOOLEAN__STRING_STRING_OBJECT,
1197 			      G_TYPE_BOOLEAN,
1198 			      3,
1199 			      G_TYPE_STRING, G_TYPE_STRING, GST_TYPE_ELEMENT);
1200 	signals[REUSE_STREAM] =
1201 		g_signal_new ("reuse-stream",
1202 			      G_OBJECT_CLASS_TYPE (object_class),
1203 			      G_SIGNAL_RUN_LAST,
1204 			      G_STRUCT_OFFSET (RBPlayerGstClass, reuse_stream),
1205 			      NULL, NULL,
1206 			      rb_marshal_VOID__STRING_STRING_OBJECT,
1207 			      G_TYPE_NONE,
1208 			      3,
1209 			      G_TYPE_STRING, G_TYPE_STRING, GST_TYPE_ELEMENT);
1210 	signals[MISSING_PLUGINS] =
1211 		g_signal_new ("missing-plugins",
1212 			      G_OBJECT_CLASS_TYPE (object_class),
1213 			      G_SIGNAL_RUN_LAST,
1214 			      0,	/* no point handling this internally */
1215 			      NULL, NULL,
1216 			      rb_marshal_VOID__POINTER_POINTER_POINTER,
1217 			      G_TYPE_NONE,
1218 			      3,
1219 			      G_TYPE_POINTER, G_TYPE_STRV, G_TYPE_STRV);
1220 
1221 	g_type_class_add_private (klass, sizeof (RBPlayerGstPrivate));
1222 }