static gboolean _rtpbin_pad_have_data_callback (GstPad *pad, GstMiniObject *miniobj, gpointer user_data) { FsRtpSubStream *self = FS_RTP_SUB_STREAM (user_data); gboolean ret = TRUE; gboolean remove = FALSE; FsRtpSession *session; if (fs_rtp_session_has_disposed_enter (self->priv->session, NULL)) return FALSE; if (fs_rtp_sub_stream_has_stopped_enter (self)) { fs_rtp_session_has_disposed_exit (self->priv->session); return FALSE; } g_object_ref (self); session = g_object_ref (self->priv->session); FS_RTP_SESSION_LOCK (self->priv->session); if (!self->priv->codecbin || !self->codec || !self->priv->caps) { ret = FALSE; } else if (GST_IS_BUFFER (miniobj)) { if (!gst_caps_is_equal_fixed (GST_BUFFER_CAPS (miniobj), self->priv->caps)) { if (!gst_caps_can_intersect (GST_BUFFER_CAPS (miniobj), self->priv->caps)) ret = FALSE; } else { remove = TRUE; } } if (remove && self->priv->blocking_id) { gst_pad_remove_data_probe (pad, self->priv->blocking_id); self->priv->blocking_id = 0; } FS_RTP_SESSION_UNLOCK (self->priv->session); fs_rtp_sub_stream_has_stopped_exit (self); fs_rtp_session_has_disposed_exit (self->priv->session); g_object_unref (self); g_object_unref (session); return ret; }
static void fs_rtp_sub_stream_dispose (GObject *object) { FsRtpSubStream *self = FS_RTP_SUB_STREAM (object); fs_rtp_sub_stream_stop (self); fs_rtp_sub_stream_stop_no_rtcp_timeout_thread (self); if (self->priv->output_ghostpad) { gst_element_remove_pad (GST_ELEMENT (self->priv->conference), self->priv->output_ghostpad); self->priv->output_ghostpad = NULL; } if (self->priv->output_valve) { gst_element_set_locked_state (self->priv->output_valve, TRUE); gst_element_set_state (self->priv->output_valve, GST_STATE_NULL); gst_bin_remove (GST_BIN (self->priv->conference), self->priv->output_valve); self->priv->output_valve = NULL; } if (self->priv->codecbin) { gst_element_set_locked_state (self->priv->codecbin, TRUE); gst_element_set_state (self->priv->codecbin, GST_STATE_NULL); gst_bin_remove (GST_BIN (self->priv->conference), self->priv->codecbin); self->priv->codecbin = NULL; } if (self->priv->capsfilter) { gst_element_set_locked_state (self->priv->capsfilter, TRUE); gst_element_set_state (self->priv->capsfilter, GST_STATE_NULL); gst_bin_remove (GST_BIN (self->priv->conference), self->priv->capsfilter); self->priv->capsfilter = NULL; } if (self->priv->input_valve) { gst_element_set_locked_state (self->priv->input_valve, TRUE); gst_element_set_state (self->priv->input_valve, GST_STATE_NULL); gst_bin_remove (GST_BIN (self->priv->conference), self->priv->input_valve); self->priv->input_valve = NULL; } if (self->priv->blocking_id) { gst_pad_remove_data_probe (self->priv->rtpbin_pad, self->priv->blocking_id); self->priv->blocking_id = 0; } if (self->priv->rtpbin_pad) { gst_object_unref (self->priv->rtpbin_pad); self->priv->rtpbin_pad = NULL; } self->priv->disposed = TRUE; G_OBJECT_CLASS (fs_rtp_sub_stream_parent_class)->dispose (object); }
static void fs_rtp_sub_stream_finalize (GObject *object) { FsRtpSubStream *self = FS_RTP_SUB_STREAM (object); if (self->codec) fs_codec_destroy (self->codec); if (self->priv->caps) gst_caps_unref (self->priv->caps); if (self->priv->mutex) g_mutex_free (self->priv->mutex); G_OBJECT_CLASS (fs_rtp_sub_stream_parent_class)->finalize (object); }
static void fs_rtp_sub_stream_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { FsRtpSubStream *self = FS_RTP_SUB_STREAM (object); switch (prop_id) { case PROP_CONFERENCE: self->priv->conference = g_value_get_object (value); break; case PROP_SESSION: self->priv->session = g_value_get_object (value); break; case PROP_STREAM: if (self->priv->stream) GST_WARNING ("Stream already set, not re-setting"); else self->priv->stream = g_value_get_object (value); break; case PROP_RTPBIN_PAD: self->priv->rtpbin_pad = GST_PAD (g_value_dup_object (value)); break; case PROP_SSRC: self->ssrc = g_value_get_uint (value); break; case PROP_PT: self->pt = g_value_get_uint (value); break; case PROP_RECEIVING: self->priv->receiving = g_value_get_boolean (value); if (self->priv->input_valve) g_object_set (G_OBJECT (self->priv->input_valve), "drop", !self->priv->receiving, NULL); break; case PROP_NO_RTCP_TIMEOUT: self->no_rtcp_timeout = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void fs_rtp_sub_stream_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { FsRtpSubStream *self = FS_RTP_SUB_STREAM (object); switch (prop_id) { case PROP_CONFERENCE: g_value_set_object (value, self->priv->conference); break; case PROP_SESSION: g_value_set_object (value, self->priv->session); break; case PROP_STREAM: g_value_set_object (value, self->priv->stream); break; case PROP_RTPBIN_PAD: g_value_set_object (value, self->priv->rtpbin_pad); break; case PROP_SSRC: g_value_set_uint (value, self->ssrc); break; case PROP_PT: g_value_set_uint (value, self->pt); break; case PROP_CODEC: g_value_set_boxed (value, self->codec); break; case PROP_RECEIVING: g_value_set_boolean (value, self->priv->receiving); break; case PROP_OUTPUT_GHOSTPAD: g_value_set_object (value, self->priv->output_ghostpad); break; case PROP_NO_RTCP_TIMEOUT: g_value_set_int (value, self->no_rtcp_timeout); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gpointer no_rtcp_timeout_func (gpointer user_data) { FsRtpSubStream *self = FS_RTP_SUB_STREAM (user_data); GstClock *sysclock = NULL; GstClockID id; gboolean emit = TRUE; sysclock = gst_system_clock_obtain (); if (sysclock == NULL) goto no_sysclock; FS_RTP_SUB_STREAM_LOCK(self); id = self->priv->no_rtcp_timeout_id = gst_clock_new_single_shot_id (sysclock, self->priv->next_no_rtcp_timeout); FS_RTP_SUB_STREAM_UNLOCK(self); gst_clock_id_wait (id, NULL); FS_RTP_SUB_STREAM_LOCK(self); gst_clock_id_unref (id); self->priv->no_rtcp_timeout_id = NULL; if (self->priv->next_no_rtcp_timeout == 0) emit = FALSE; FS_RTP_SUB_STREAM_UNLOCK(self); gst_object_unref (sysclock); if (emit) g_signal_emit (self, signals[NO_RTCP_TIMEDOUT], 0); return NULL; no_sysclock: { fs_rtp_sub_stream_emit_error (self, FS_ERROR_INTERNAL, "Could not get system clock", "Could not get system clock"); return NULL; } }
static gboolean _rtpbin_pad_have_data_callback (GstPad *pad, GstMiniObject *miniobj, gpointer user_data) { FsRtpSubStream *self = FS_RTP_SUB_STREAM (user_data); gboolean ret = TRUE; gboolean remove = FALSE; FS_RTP_SESSION_LOCK (self->priv->session); if (!self->priv->codecbin || !self->codec || !self->priv->caps) { ret = FALSE; } else if (GST_IS_BUFFER (miniobj)) { if (!gst_caps_is_equal_fixed (GST_BUFFER_CAPS (miniobj), self->priv->caps)) { GstCaps *intersect = gst_caps_intersect (GST_BUFFER_CAPS (miniobj), self->priv->caps); if (gst_caps_is_empty (intersect)) ret = FALSE; else gst_buffer_set_caps (GST_BUFFER (miniobj), self->priv->caps); gst_caps_unref (intersect); } else { remove = TRUE; } } if (remove && self->priv->blocking_id) { gst_pad_remove_data_probe (pad, self->priv->blocking_id); self->priv->blocking_id = 0; } FS_RTP_SESSION_UNLOCK (self->priv->session); return ret; }
static void fs_rtp_sub_stream_constructed (GObject *object) { FsRtpSubStream *self = FS_RTP_SUB_STREAM (object); GstPad *valve_sink_pad = NULL; GstPadLinkReturn linkret; gchar *tmp; GST_DEBUG ("New substream in session %u for ssrc %x and pt %u", self->priv->session->id, self->ssrc, self->pt); if (!self->priv->conference) { self->priv->construction_error = g_error_new (FS_ERROR, FS_ERROR_INVALID_ARGUMENTS, "A Substream needs a conference object"); return; } self->priv->rtpbin_unlinked_sig = g_signal_connect_object ( self->priv->rtpbin_pad, "unlinked", G_CALLBACK (rtpbin_pad_unlinked), self, 0); tmp = g_strdup_printf ("output_recv_valve_%d_%d_%d", self->priv->session->id, self->ssrc, self->pt); self->priv->output_valve = gst_element_factory_make ("valve", tmp); g_free (tmp); if (!self->priv->output_valve) { self->priv->construction_error = g_error_new (FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not create a valve element for" " session substream with ssrc: %u and pt:%d", self->ssrc, self->pt); return; } if (!gst_bin_add (GST_BIN (self->priv->conference), self->priv->output_valve)) { self->priv->construction_error = g_error_new (FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not add the valve element for session" " substream with ssrc: %u and pt:%d to the conference bin", self->ssrc, self->pt); return; } /* We set the valve to dropping, the stream will unblock it when its linked */ g_object_set (self->priv->output_valve, "drop", TRUE, NULL); if (gst_element_set_state (self->priv->output_valve, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { self->priv->construction_error = g_error_new (FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not set the valve element for session" " substream with ssrc: %u and pt:%d to the playing state", self->ssrc, self->pt); return; } tmp = g_strdup_printf ("recv_capsfilter_%d_%d_%d", self->priv->session->id, self->ssrc, self->pt); self->priv->capsfilter = gst_element_factory_make ("capsfilter", tmp); g_free (tmp); if (!self->priv->capsfilter) { self->priv->construction_error = g_error_new (FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not create a capsfilter element for" " session substream with ssrc: %u and pt:%d", self->ssrc, self->pt); return; } if (!gst_bin_add (GST_BIN (self->priv->conference), self->priv->capsfilter)) { self->priv->construction_error = g_error_new (FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not add the capsfilter element for session" " substream with ssrc: %u and pt:%d to the conference bin", self->ssrc, self->pt); return; } if (gst_element_set_state (self->priv->capsfilter, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { self->priv->construction_error = g_error_new (FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not set the capsfilter element for session" " substream with ssrc: %u and pt:%d to the playing state", self->ssrc, self->pt); return; } tmp = g_strdup_printf ("input_recv_valve_%d_%d_%d", self->priv->session->id, self->ssrc, self->pt); self->priv->input_valve = gst_element_factory_make ("valve", tmp); g_free (tmp); if (!self->priv->input_valve) { self->priv->construction_error = g_error_new (FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not create a valve element for" " session substream with ssrc: %u and pt:%d", self->ssrc, self->pt); return; } if (!gst_bin_add (GST_BIN (self->priv->conference), self->priv->input_valve)) { self->priv->construction_error = g_error_new (FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not add the valve element for session" " substream with ssrc: %u and pt:%d to the conference bin", self->ssrc, self->pt); return; } if (gst_element_set_state (self->priv->input_valve, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { self->priv->construction_error = g_error_new (FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not set the valve element for session" " substream with ssrc: %u and pt:%d to the playing state", self->ssrc, self->pt); return; } if (!gst_element_link (self->priv->input_valve, self->priv->capsfilter)) { self->priv->construction_error = g_error_new (FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not link the input valve" " and the capsfilter"); return; } valve_sink_pad = gst_element_get_static_pad (self->priv->input_valve, "sink"); if (!valve_sink_pad) { self->priv->construction_error = g_error_new (FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not get the valve's sink pad"); return; } linkret = gst_pad_link (self->priv->rtpbin_pad, valve_sink_pad); gst_object_unref (valve_sink_pad); if (GST_PAD_LINK_FAILED (linkret)) { self->priv->construction_error = g_error_new (FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not link the rtpbin to the codec bin (%d)", linkret); return; } if (self->no_rtcp_timeout > 0) if (!fs_rtp_sub_stream_start_no_rtcp_timeout_thread (self, &self->priv->construction_error)) return; GST_CALL_PARENT (G_OBJECT_CLASS, constructed, (object)); }