static void start_state_change (RBPlayerGst *mp, GstState state, enum StateChangeAction action) { GstStateChangeReturn scr; mp->priv->state_change_action = action; scr = gst_element_set_state (mp->priv->playbin, state); if (scr == GST_STATE_CHANGE_SUCCESS) { rb_debug ("state change succeeded synchronously"); state_change_finished (mp, NULL); } }
static gboolean bus_cb(GstBus *bus, GstMessage *message, XmrPlayer *player) { XmrPlayerPrivate *priv; g_return_val_if_fail (player != NULL, FALSE); priv = player->priv; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: { gchar *debug; GError *error; gst_message_parse_error(message, &error, &debug); g_signal_emit(player, signals[ERROR], 0, error); g_free(debug); g_error_free(error); } break; case GST_MESSAGE_EOS: g_signal_emit(player, signals[EOS], 0, FALSE); break; case GST_MESSAGE_BUFFERING: { gint progress; gst_message_parse_buffering(message, &progress); if (progress >= 100) { priv->buffering = FALSE; if (priv->playing) { xmr_debug("buffering done, setting pipeline back to PLAYING"); gst_element_set_state (priv->playbin, GST_STATE_PLAYING); } else { xmr_debug("buffering done, leaving pipeline PAUSED"); } } else if (priv->buffering == FALSE && priv->playing) { xmr_debug ("buffering - temporarily pausing playback"); gst_element_set_state (priv->playbin, GST_STATE_PAUSED); priv->buffering = TRUE; } g_signal_emit(player, signals[BUFFERING], 0, progress); break; } case GST_MESSAGE_STATE_CHANGED: { GstState oldstate; GstState newstate; GstState pending; gst_message_parse_state_changed (message, &oldstate, &newstate, &pending); if (GST_MESSAGE_SRC(message) == GST_OBJECT(priv->playbin)) { if (pending == GST_STATE_VOID_PENDING) { xmr_debug("playbin reached state %s", gst_element_state_get_name(newstate)); state_change_finished(player, NULL); } g_signal_emit(player, signals[STATE_CHANGED], 0, oldstate, newstate); } break; } default: break; } return TRUE; }
static gboolean bus_cb (GstBus *bus, GstMessage *message, RBPlayerGst *mp) { const GstStructure *structure; g_return_val_if_fail (mp != NULL, FALSE); switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: { char *debug; GError *error = NULL; GError *sig_error = NULL; int code; gboolean emit = TRUE; gst_message_parse_error (message, &error, &debug); /* If we've already got an error, ignore 'internal data flow error' * type messages, as they're too generic to be helpful. */ if (mp->priv->emitted_error && error->domain == GST_STREAM_ERROR && error->code == GST_STREAM_ERROR_FAILED) { rb_debug ("Ignoring generic error \"%s\"", error->message); emit = FALSE; } code = rb_gst_error_get_error_code (error); if (emit) { if (message_from_sink (mp->priv->audio_sink, message)) { rb_debug ("got error from sink: %s (%s)", error->message, debug); /* Translators: the parameter here is an error message */ g_set_error (&sig_error, RB_PLAYER_ERROR, code, _("Failed to open output device: %s"), error->message); } else { rb_debug ("got error from stream: %s (%s)", error->message, debug); g_set_error (&sig_error, RB_PLAYER_ERROR, code, "%s", error->message); } state_change_finished (mp, sig_error); mp->priv->emitted_error = TRUE; _rb_player_emit_error (RB_PLAYER (mp), mp->priv->stream_data, sig_error); } /* close if not already closing */ if (mp->priv->uri != NULL) rb_player_close (RB_PLAYER (mp), NULL, NULL); g_error_free (error); g_free (debug); break; } case GST_MESSAGE_EOS: _rb_player_emit_eos (RB_PLAYER (mp), mp->priv->stream_data, FALSE); break; case GST_MESSAGE_STATE_CHANGED: { GstState oldstate; GstState newstate; GstState pending; gst_message_parse_state_changed (message, &oldstate, &newstate, &pending); if (GST_MESSAGE_SRC (message) == GST_OBJECT (mp->priv->playbin)) { rb_debug ("playbin reached state %s", gst_element_state_get_name (newstate)); if (pending == GST_STATE_VOID_PENDING) { state_change_finished (mp, NULL); } } break; } case GST_MESSAGE_TAG: { GstTagList *tags; gst_message_parse_tag (message, &tags); if (mp->priv->stream_change_pending || mp->priv->playbin_stream_changing) { mp->priv->stream_tags = g_list_append (mp->priv->stream_tags, tags); } else { gst_tag_list_foreach (tags, (GstTagForeachFunc) process_tag, mp); gst_tag_list_free (tags); } break; } case GST_MESSAGE_BUFFERING: { gint progress; structure = gst_message_get_structure (message); if (!gst_structure_get_int (structure, "buffer-percent", &progress)) { g_warning ("Could not get value from BUFFERING message"); break; } if (progress >= 100) { mp->priv->buffering = FALSE; if (mp->priv->playing) { rb_debug ("buffering done, setting pipeline back to PLAYING"); gst_element_set_state (mp->priv->playbin, GST_STATE_PLAYING); } else { rb_debug ("buffering done, leaving pipeline PAUSED"); } } else if (mp->priv->buffering == FALSE && mp->priv->playing) { GstState cur_state; gst_element_get_state (mp->priv->playbin, &cur_state, NULL, 0); if (cur_state == GST_STATE_PLAYING) { rb_debug ("buffering - temporarily pausing playback"); gst_element_set_state (mp->priv->playbin, GST_STATE_PAUSED); } else { rb_debug ("buffering - during preroll; doing nothing"); } mp->priv->buffering = TRUE; } _rb_player_emit_buffering (RB_PLAYER (mp), mp->priv->stream_data, progress); break; } case GST_MESSAGE_APPLICATION: structure = gst_message_get_structure (message); _rb_player_emit_event (RB_PLAYER (mp), mp->priv->stream_data, gst_structure_get_name (structure), NULL); break; case GST_MESSAGE_ELEMENT: structure = gst_message_get_structure (message); if (gst_is_missing_plugin_message (message)) { handle_missing_plugin_message (mp, message); } else if (mp->priv->playbin_stream_changing && gst_structure_has_name (structure, "playbin2-stream-changed")) { rb_debug ("got playbin2-stream-changed message"); mp->priv->playbin_stream_changing = FALSE; emit_playing_stream_and_tags (mp, TRUE); } else if (gst_structure_has_name (structure, "redirect")) { const char *uri = gst_structure_get_string (structure, "new-location"); _rb_player_emit_redirect (RB_PLAYER (mp), mp->priv->stream_data, uri); } break; default: break; } /* emit message signals too, so plugins can process messages */ gst_bus_async_signal_func (bus, message, NULL); return TRUE; }