[farsight2/master] Implement changing the recv codec bin and simplify its creation a bit
Olivier Crête
olivier.crete at collabora.co.uk
Tue Dec 23 15:20:05 PST 2008
---
gst/fsrtpconference/fs-rtp-session.c | 75 ++++++----------
gst/fsrtpconference/fs-rtp-session.h | 10 ++-
gst/fsrtpconference/fs-rtp-substream.c | 158 ++++++++++++++++++++++++++-----
gst/fsrtpconference/fs-rtp-substream.h | 2 -
4 files changed, 169 insertions(+), 76 deletions(-)
diff --git a/gst/fsrtpconference/fs-rtp-session.c b/gst/fsrtpconference/fs-rtp-session.c
index 32b06fd..c348780 100644
--- a/gst/fsrtpconference/fs-rtp-session.c
+++ b/gst/fsrtpconference/fs-rtp-session.c
@@ -181,14 +181,6 @@ static FsStreamTransmitter *fs_rtp_session_get_new_stream_transmitter (
GParameter *parameters,
GError **error);
-static GstElement *
-fs_rtp_session_new_recv_codec_bin (FsRtpSession *session,
- const gchar *name,
- guint pt,
- FsCodec **out_codec,
- GError **error);
-
-
static GObjectClass *parent_class = NULL;
@@ -1517,10 +1509,7 @@ fs_rtp_session_new_recv_pad (FsRtpSession *session, GstPad *new_pad,
{
FsRtpSubStream *substream = NULL;
FsRtpStream *stream = NULL;
- GstElement *codecbin = NULL;
- gchar *codec_bin_name = NULL;
GError *error = NULL;
- FsCodec *codec = NULL;
substream = fs_rtp_substream_new (session->priv->conference, session, new_pad,
ssrc, pt, &error);
@@ -1538,45 +1527,20 @@ fs_rtp_session_new_recv_pad (FsRtpSession *session, GstPad *new_pad,
return;
}
- codec_bin_name = g_strdup_printf ("recv%d_%d", ssrc, pt);
- codecbin = fs_rtp_session_new_recv_codec_bin (session, codec_bin_name, pt,
- &codec, &error);
- g_free (codec_bin_name);
-
- if (codecbin) {
- if (!fs_rtp_sub_stream_add_codecbin (substream, codecbin, codec, &error)) {
- if (error)
- fs_session_emit_error (FS_SESSION (session), error->code,
+ if (!fs_rtp_sub_stream_add_codecbin (substream, &error)) {
+ if (error)
+ fs_session_emit_error (FS_SESSION (session), error->code,
"Could not add the codec bin to the new substream", error->message);
- else
- fs_session_emit_error (FS_SESSION (session), FS_ERROR_CONSTRUCTION,
+ else
+ fs_session_emit_error (FS_SESSION (session), FS_ERROR_CONSTRUCTION,
"Could not add the codec bin to the new substream",
"No error details returned");
- fs_rtp_sub_stream_block (substream, NULL, NULL);
- }
- } else {
- if (error) {
- /* Ignore errors the case where we receive buffers before the negotiatoon
- happens */
- if (error->code != FS_ERROR_INTERNAL)
- fs_session_emit_error (FS_SESSION (session), error->code,
- "Could not create a codec bin for the new pad", error->message);
- } else {
- fs_session_emit_error (FS_SESSION (session), FS_ERROR_CONSTRUCTION,
- "Could not create a codec bin for the new pad",
- "No error details returned");
- }
-
fs_rtp_sub_stream_block (substream, NULL, NULL);
}
g_clear_error (&error);
- fs_codec_destroy (codec);
- codec = NULL;
-
-
/* Lets find the FsRtpStream for this substream, if no Stream claims it
* then we just store it
*/
@@ -1795,7 +1759,7 @@ _create_codec_bin (CodecBlueprint *blueprint, const FsCodec *codec,
/**
* fs_rtp_session_new_recv_codec_bin:
* @session: a #FsRtpSession
- * @name: The name of the codec bin to create
+ * @ssrc: The SSRC that this codec bin will receive from
* @pt: The payload type to create a codec bin for
* @out_codec: The address where a newly-allocated copy of the #FsCodec
* this codec bin is for
@@ -1808,17 +1772,18 @@ _create_codec_bin (CodecBlueprint *blueprint, const FsCodec *codec,
* Returns: a newly-allocated codec bin
*/
-static GstElement *
+GstElement *
fs_rtp_session_new_recv_codec_bin (FsRtpSession *session,
- const gchar *name,
- guint pt,
- FsCodec **out_codec,
- GError **error)
+ guint32 ssrc,
+ guint pt,
+ FsCodec **out_codec,
+ GError **error)
{
GstElement *codec_bin = NULL;
CodecAssociation *ca = NULL;
CodecBlueprint *blueprint = NULL;
FsCodec *codec = NULL;
+ gchar *name;
FS_RTP_SESSION_LOCK (session);
@@ -1847,7 +1812,9 @@ fs_rtp_session_new_recv_codec_bin (FsRtpSession *session,
return NULL;
}
+ name = g_strdup_printf ("recv%d_%d", ssrc, pt);
codec_bin = _create_codec_bin (blueprint, codec, name, FALSE, error);
+ g_free (name);
if (out_codec)
*out_codec = codec;
@@ -2175,3 +2142,17 @@ fs_rtp_session_verify_send_codec_bin_locked (FsRtpSession *self, GError **error)
return ret;
}
+
+
+
+FsCodec *
+fs_rtp_session_get_recv_codec_for_pt_locked (FsRtpSession *session,
+ gint pt,
+ GError **error)
+{
+ CodecAssociation *codec_association = g_hash_table_lookup (
+ session->priv->negotiated_codec_associations, GINT_TO_POINTER (pt));
+ g_assert (codec_association);
+
+ return fs_codec_copy (codec_association->codec);
+}
diff --git a/gst/fsrtpconference/fs-rtp-session.h b/gst/fsrtpconference/fs-rtp-session.h
index 2f81c60..b44a6de 100644
--- a/gst/fsrtpconference/fs-rtp-session.h
+++ b/gst/fsrtpconference/fs-rtp-session.h
@@ -97,7 +97,15 @@ void fs_rtp_session_new_recv_pad (FsRtpSession *session, GstPad *new_pad,
gboolean fs_rtp_session_negotiate_codecs (FsRtpSession *session,
GList *remote_codecs, GError **error);
-
+GstElement *fs_rtp_session_new_recv_codec_bin (FsRtpSession *session,
+ guint32 ssrc,
+ guint pt,
+ FsCodec **out_codec,
+ GError **error);
+
+FsCodec *fs_rtp_session_get_recv_codec_for_pt_locked (FsRtpSession *session,
+ gint pt,
+ GError **error);
G_END_DECLS
diff --git a/gst/fsrtpconference/fs-rtp-substream.c b/gst/fsrtpconference/fs-rtp-substream.c
index 7292b53..7957db1 100644
--- a/gst/fsrtpconference/fs-rtp-substream.c
+++ b/gst/fsrtpconference/fs-rtp-substream.c
@@ -377,66 +377,66 @@ fs_rtp_sub_stream_block (FsRtpSubStream *substream,
}
/**
- * fs_rtp_session_add_codecbin:
+ * fs_rtp_session_add_codecbin_locked:
* @substream: a #FsRtpSubStream
- * @codecbin: The codec bin
- * @codec: The #FsCodec currently received by this substream
*
* Add and links the rtpbin for a given substream.
- * Eats a reference to the codec bin on success.
*
- * MT safe.
+ * The caller MUST hold the session lock
*
* Returns: TRUE on success
*/
-gboolean
-fs_rtp_sub_stream_add_codecbin (FsRtpSubStream *substream,
- GstElement *codecbin,
- FsCodec *codec,
+static gboolean
+fs_rtp_sub_stream_add_codecbin_locked (FsRtpSubStream *substream,
GError **error)
{
GstPad *codec_bin_sink_pad;
GstPadLinkReturn linkret;
- gboolean has_codecbin = FALSE;
+ FsCodec *codec = NULL;
+ GstElement *codecbin;
- FS_RTP_SESSION_LOCK (substream->priv->session);
- if (substream->priv->codecbin == NULL) {
- substream->priv->codecbin = codecbin;
- substream->priv->codec = fs_codec_copy (codec);
- has_codecbin = TRUE;
- }
- FS_RTP_SESSION_LOCK (substream->priv->session);
- if (has_codecbin) {
+ if (substream->priv->codecbin)
+ {
g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
"There already is a codec bin for this substream");
return FALSE;
}
+ codecbin = fs_rtp_session_new_recv_codec_bin (substream->priv->session,
+ substream->priv->ssrc, substream->priv->pt, &codec, error);
+
+ if (!codecbin)
+ return FALSE;
- if (!gst_bin_add (GST_BIN (substream->priv->conference), codecbin)) {
+
+ if (!gst_bin_add (GST_BIN (substream->priv->conference), codecbin))
+ {
g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
"Could not add the codec bin to the conference");
goto error_no_remove;
}
if (gst_element_set_state (codecbin, GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
+ GST_STATE_CHANGE_FAILURE)
+ {
g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
"Could not set the codec bin to the playing state");
goto error;
}
if (!gst_element_link_pads (codecbin, "src",
- substream->priv->valve, "sink")) {
+ substream->priv->valve, "sink"))
+ {
g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
"Could not link the codec bin to the valve");
goto error;
}
codec_bin_sink_pad = gst_element_get_static_pad (codecbin, "sink");
- if (!codec_bin_sink_pad) {
+ if (!codec_bin_sink_pad)
+ {
g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
"Could not get the codecbin's sink pad");
goto error;
@@ -446,7 +446,8 @@ fs_rtp_sub_stream_add_codecbin (FsRtpSubStream *substream,
gst_object_unref (codec_bin_sink_pad);
- if (GST_PAD_LINK_FAILED (linkret)) {
+ if (GST_PAD_LINK_FAILED (linkret))
+ {
g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
"Could not link the rtpbin to the codec bin (%d)", linkret);
goto error;
@@ -459,19 +460,42 @@ fs_rtp_sub_stream_add_codecbin (FsRtpSubStream *substream,
error:
gst_element_set_state (codecbin, GST_STATE_NULL);
+ gst_object_ref (codecbin);
gst_bin_remove (GST_BIN (substream->priv->conference), codecbin);
error_no_remove:
- FS_RTP_SESSION_LOCK (substream->priv->session);
substream->priv->codecbin = NULL;
fs_codec_destroy (substream->priv->codec);
substream->priv->codec = NULL;
- FS_RTP_SESSION_UNLOCK (substream->priv->session);
return FALSE;
}
+/**
+ * fs_rtp_session_add_codecbin:
+ * @substream: a #FsRtpSubStream
+ *
+ * Add and links the rtpbin for a given substream.
+ *
+ * MT safe.
+ *
+ * Returns: TRUE on success
+ */
+
+gboolean
+fs_rtp_sub_stream_add_codecbin (FsRtpSubStream *substream,
+ GError **error)
+{
+ gboolean ret;
+
+ FS_RTP_SESSION_LOCK (substream->priv->session);
+ ret = fs_rtp_sub_stream_add_codecbin_locked (substream, error);
+ FS_RTP_SESSION_UNLOCK (substream->priv->session);
+
+ return ret;
+}
+
FsRtpSubStream *
fs_rtp_sub_stream_new (FsRtpConference *conference,
FsRtpSession *session,
@@ -581,12 +605,94 @@ fs_rtp_sub_stream_get_output_ghostpad (FsRtpSubStream *substream,
return gst_object_ref (ghostpad);
}
+/**
+ *_rtpbin_pad_have_data_callback:
+ *
+ * This is the pad probe callback on the sink pad of the rtpbin.
+ * It is used to replace the codec bin when the recv codec has been changed.
+ *
+ * Its a callback, it returns TRUE to let the data through and FALSE to drop it
+ * (See the "have-data" signal documentation of #GstPad).
+ */
static gboolean
_rtpbin_pad_have_data_callback (GstPad *pad, GstMiniObject *miniobj,
gpointer user_data)
{
- return TRUE;
+ FsRtpSubStream *self = FS_RTP_SUB_STREAM (user_data);
+ FsCodec *codec = NULL;
+ gboolean ret = TRUE;
+ GError *error = NULL;
+ gboolean success = FALSE;
+
+ FS_RTP_SESSION_LOCK (self->priv->session);
+
+ codec = fs_rtp_session_get_recv_codec_for_pt_locked (self->priv->session,
+ self->priv->pt, &error);
+
+ if (!codec)
+ {
+ fs_session_emit_error (FS_SESSION (self), error->code,
+ "Could not get the new recv codec for pt %d", error->message);
+ goto done;
+ }
+
+ g_clear_error (&error);
+
+ if (fs_codec_are_equal (codec, self->priv->codec))
+ {
+ success = TRUE;
+ goto done;
+ }
+
+
+ if (gst_element_set_state (self->priv->codecbin, GST_STATE_NULL) !=
+ GST_STATE_CHANGE_SUCCESS)
+ {
+ /* TODO: WE NEED AN ERROR SIGNAL OF SOME KIND HERE */
+ g_error ("could not set the codecbin to NULL");
+ goto done;
+ }
+
+ gst_bin_remove (GST_BIN (self->priv->conference), self->priv->codecbin);
+ self->priv->codecbin = NULL;
+
+ fs_codec_destroy (self->priv->codec);
+ self->priv->codec = NULL;
+
+
+ if (!fs_rtp_sub_stream_add_codecbin_locked (self, &error))
+ {
+ g_error ("Could not add the new recv codec bin");
+ goto done;
+ }
+
+ g_clear_error (&error);
+
+ success = TRUE;
+
+ done:
+ if (success && GST_IS_BUFFER (miniobj))
+ {
+ GstCaps *caps = fs_codec_to_gst_caps (codec);
+ GstCaps *intersection = gst_caps_intersect (GST_BUFFER_CAPS (miniobj),
+ caps);
+
+ if (gst_caps_is_empty (intersection))
+ ret = FALSE;
+ gst_caps_unref (intersection);
+ gst_caps_unref (caps);
+ }
+
+ if (ret && 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;
}
/**
diff --git a/gst/fsrtpconference/fs-rtp-substream.h b/gst/fsrtpconference/fs-rtp-substream.h
index 1a4a800..41be0bd 100644
--- a/gst/fsrtpconference/fs-rtp-substream.h
+++ b/gst/fsrtpconference/fs-rtp-substream.h
@@ -80,8 +80,6 @@ FsRtpSubStream *fs_rtp_substream_new (FsRtpConference *conference,
gboolean fs_rtp_sub_stream_add_codecbin (FsRtpSubStream *substream,
- GstElement *codecbin,
- FsCodec *codec,
GError **error);
void fs_rtp_sub_stream_stop (FsRtpSubStream *substream);
--
1.5.6.5
More information about the farsight-commits
mailing list