static gboolean impl_open (RBPlayer *player, const char *uri, gpointer stream_data, GDestroyNotify stream_data_destroy, GError **error) { RBPlayerGst *mp = RB_PLAYER_GST (player); if (mp->priv->playbin == NULL) { if (!construct_pipeline (mp, error)) return FALSE; } g_assert (mp->priv->playbin != NULL); if (uri == NULL) { return impl_close (player, NULL, error); } rb_debug ("setting new uri to %s", uri); _destroy_next_stream_data (mp); g_free (mp->priv->prev_uri); mp->priv->prev_uri = mp->priv->uri; mp->priv->uri = g_strdup (uri); mp->priv->next_stream_data = stream_data; mp->priv->next_stream_data_destroy = stream_data_destroy; mp->priv->emitted_error = FALSE; mp->priv->stream_change_pending = TRUE; return TRUE; }
static float impl_get_volume (RBPlayer *player) { RBPlayerGst *mp = RB_PLAYER_GST (player); return mp->priv->cur_volume; }
static gboolean impl_playing (RBPlayer *player) { RBPlayerGst *mp = RB_PLAYER_GST (player); return mp->priv->playing; }
static gboolean impl_opened (RBPlayer *player) { RBPlayerGst *mp = RB_PLAYER_GST (player); return mp->priv->uri != NULL; }
static void impl_dispose (GObject *object) { RBPlayerGst *mp; mp = RB_PLAYER_GST (object); if (mp->priv->tick_timeout_id != 0) { g_source_remove (mp->priv->tick_timeout_id); mp->priv->tick_timeout_id = 0; } if (mp->priv->playbin != NULL) { gst_element_set_state (mp->priv->playbin, GST_STATE_NULL); g_object_unref (mp->priv->playbin); mp->priv->playbin = NULL; mp->priv->audio_sink = NULL; } if (mp->priv->waiting_tees != NULL) { g_list_foreach (mp->priv->waiting_tees, (GFunc)gst_object_sink, NULL); g_list_free (mp->priv->waiting_tees); mp->priv->waiting_tees = NULL; } if (mp->priv->waiting_filters != NULL) { g_list_foreach (mp->priv->waiting_filters, (GFunc)gst_object_sink, NULL); g_list_free (mp->priv->waiting_filters); mp->priv->waiting_filters = NULL; } G_OBJECT_CLASS (rb_player_gst_parent_class)->dispose (object); }
static gboolean impl_close (RBPlayer *player, const char *uri, GError **error) { RBPlayerGst *mp = RB_PLAYER_GST (player); if ((uri != NULL) && (mp->priv->uri != NULL) && strcmp (mp->priv->uri, uri) == 0) { rb_debug ("URI doesn't match current playing URI; ignoring"); return TRUE; } mp->priv->playing = FALSE; mp->priv->buffering = FALSE; mp->priv->current_track_finishing = FALSE; _destroy_stream_data (mp); if (uri == NULL) { _destroy_next_stream_data (mp); } g_free (mp->priv->uri); g_free (mp->priv->prev_uri); mp->priv->uri = NULL; mp->priv->prev_uri = NULL; if (mp->priv->tick_timeout_id != 0) { g_source_remove (mp->priv->tick_timeout_id); mp->priv->tick_timeout_id = 0; } if (mp->priv->playbin != NULL) { start_state_change (mp, GST_STATE_NULL, PLAYER_SHUTDOWN); } return TRUE; }
static void impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { RBPlayerGst *mp = RB_PLAYER_GST (object); switch (prop_id) { case PROP_PLAYBIN: g_value_set_object (value, mp->priv->playbin); break; case PROP_BUS: if (mp->priv->playbin) { GstBus *bus; bus = gst_element_get_bus (mp->priv->playbin); g_value_set_object (value, bus); gst_object_unref (bus); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean impl_play (RBPlayer *player, RBPlayerPlayType play_type, gint64 crossfade, GError **error) { RBPlayerGst *mp = RB_PLAYER_GST (player); g_return_val_if_fail (mp->priv->playbin != NULL, FALSE); mp->priv->track_change = TRUE; if (mp->priv->stream_change_pending == FALSE) { rb_debug ("no stream change pending, just restarting playback"); mp->priv->track_change = FALSE; start_state_change (mp, GST_STATE_PLAYING, FINISH_TRACK_CHANGE); } else if (mp->priv->current_track_finishing) { switch (play_type) { case RB_PLAYER_PLAY_AFTER_EOS: rb_debug ("current track finishing -> just setting URI on playbin"); g_object_set (mp->priv->playbin, "uri", mp->priv->uri, NULL); mp->priv->playbin_stream_changing = TRUE; track_change_done (mp, NULL); break; case RB_PLAYER_PLAY_REPLACE: case RB_PLAYER_PLAY_CROSSFADE: rb_debug ("current track finishing, waiting for EOS to start next"); break; default: g_assert_not_reached (); } } else { gboolean reused = FALSE; /* try to reuse the stream */ if (mp->priv->prev_uri != NULL) { g_signal_emit (mp, signals[CAN_REUSE_STREAM], 0, mp->priv->uri, mp->priv->prev_uri, mp->priv->playbin, &reused); if (reused) { rb_debug ("reusing stream to switch from %s to %s", mp->priv->prev_uri, mp->priv->uri); g_signal_emit (player, signals[REUSE_STREAM], 0, mp->priv->uri, mp->priv->prev_uri, mp->priv->playbin); track_change_done (mp, *error); } } /* no stream reuse, so stop, set the new URI, then start */ if (reused == FALSE) { rb_debug ("not in transition, stopping current track to start the new one"); start_state_change (mp, GST_STATE_READY, SET_NEXT_URI); } } return TRUE; }
static gboolean impl_add_filter (RBPlayerGstFilter *player, GstElement *element) { RBPlayerGst *mp = RB_PLAYER_GST (player); if (mp->priv->filterbin == NULL) { mp->priv->waiting_filters = g_list_prepend (mp->priv->waiting_filters, element); return TRUE; } return rb_gst_add_filter (RB_PLAYER (mp), mp->priv->filterbin, element, need_pad_blocking (mp)); }
static gboolean impl_add_tee (RBPlayerGstTee *player, GstElement *element) { RBPlayerGst *mp = RB_PLAYER_GST (player); if (mp->priv->tee == NULL) { mp->priv->waiting_tees = g_list_prepend (mp->priv->waiting_tees, element); return TRUE; } return rb_gst_add_tee (RB_PLAYER (player), mp->priv->tee, element, need_pad_blocking (mp)); }
static gboolean impl_remove_filter (RBPlayerGstFilter *player, GstElement *element) { RBPlayerGst *mp = RB_PLAYER_GST (player); if (mp->priv->filterbin == NULL) { gst_object_sink (element); mp->priv->waiting_filters = g_list_remove (mp->priv->waiting_filters, element); return TRUE; } return rb_gst_remove_filter (RB_PLAYER (mp), mp->priv->filterbin, element, need_pad_blocking (mp)); }
static void impl_set_time (RBPlayer *player, gint64 time) { RBPlayerGst *mp = RB_PLAYER_GST (player); rb_debug ("seeking to %" G_GINT64_FORMAT, time); gst_element_seek (mp->priv->playbin, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1); gst_element_get_state (mp->priv->playbin, NULL, NULL, 100 * GST_MSECOND); }
static gboolean impl_remove_tee (RBPlayerGstTee *player, GstElement *element) { RBPlayerGst *mp = RB_PLAYER_GST (player); if (mp->priv->tee == NULL) { gst_object_sink (element); mp->priv->waiting_tees = g_list_remove (mp->priv->waiting_tees, element); return TRUE; } return rb_gst_remove_tee (RB_PLAYER (mp), mp->priv->tee, element, need_pad_blocking (mp)); }
static void impl_pause (RBPlayer *player) { RBPlayerGst *mp = RB_PLAYER_GST (player); if (!mp->priv->playing) return; mp->priv->playing = FALSE; g_return_if_fail (mp->priv->playbin != NULL); start_state_change (mp, GST_STATE_PAUSED, STOP_TICK_TIMER); }
static gint64 impl_get_time (RBPlayer *player) { RBPlayerGst *mp = RB_PLAYER_GST (player); if (mp->priv->playbin != NULL) { gint64 position = -1; GstFormat fmt = GST_FORMAT_TIME; gst_element_query_position (mp->priv->playbin, &fmt, &position); return position; } else { return -1; } }
static void impl_set_volume (RBPlayer *player, float volume) { RBPlayerGst *mp = RB_PLAYER_GST (player); g_return_if_fail (volume >= 0.0 && volume <= 1.0); mp->priv->volume_changed++; if (mp->priv->volume_applied > 0) { set_playbin_volume (mp, volume); mp->priv->volume_applied = mp->priv->volume_changed; } else { /* volume will be applied in the first call to impl_play */ } mp->priv->cur_volume = volume; }
static void impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { RBPlayerGst *mp = RB_PLAYER_GST (object); switch (prop_id) { case PROP_BUFFER_SIZE: mp->priv->buffer_size = g_value_get_uint (value); if (mp->priv->playbin != NULL) { rb_debug ("setting buffer size on playbin: %d", mp->priv->buffer_size * 1024); g_object_set (mp->priv->playbin, "buffer-size", mp->priv->buffer_size * 1024, NULL); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean impl_seekable (RBPlayer *player) { RBPlayerGst *mp = RB_PLAYER_GST (player); gboolean can_seek = TRUE; GstQuery *query; if (mp->priv->playbin == NULL) return FALSE; query = gst_query_new_seeking (GST_FORMAT_TIME); if (gst_element_query (mp->priv->playbin, query)) { gst_query_parse_seeking (query, NULL, &can_seek, NULL, NULL); } else { gst_query_unref (query); query = gst_query_new_duration (GST_FORMAT_TIME); can_seek = gst_element_query (mp->priv->playbin, query); } gst_query_unref (query); return can_seek; }