[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