[farsight2/master] Add first version of the code to gather the codec config data

Olivier Crête olivier.crete at collabora.co.uk
Tue Dec 23 15:22:54 PST 2008


---
 gst/fsrtpconference/fs-rtp-session.c |  475 +++++++++++++++++++++++++++++++++-
 1 files changed, 474 insertions(+), 1 deletions(-)

diff --git a/gst/fsrtpconference/fs-rtp-session.c b/gst/fsrtpconference/fs-rtp-session.c
index a6b89f0..508ac13 100644
--- a/gst/fsrtpconference/fs-rtp-session.c
+++ b/gst/fsrtpconference/fs-rtp-session.c
@@ -46,6 +46,7 @@
 #include "fs-rtp-codec-negotiation.h"
 #include "fs-rtp-substream.h"
 #include "fs-rtp-special-source.h"
+#include "fs-rtp-specific-nego.h"
 
 #define GST_CAT_DEFAULT fsrtpconference_debug
 
@@ -108,6 +109,18 @@ struct _FsRtpSessionPrivate
    */
   GstPad *media_sink_pad;
 
+
+  /* The discovery elements are only created when codec parameter discovery is
+   * under progress.
+   * They are normally destroyed when the caps are found but may be destroyed
+   * by the dispose function too, we hold refs to them
+   */
+  GstElement *discovery_fakesink;
+  GstElement *discovery_capsfilter;
+  GstElement *discovery_codecbin;
+  FsCodec *discovery_codec;
+  gulong discovery_blocking_id;
+
   /* Request pad to release on dispose */
   GstPad *rtpbin_send_rtp_sink;
   GstPad *rtpbin_send_rtcp_src;
@@ -224,6 +237,12 @@ fs_rtp_session_update_codecs (FsRtpSession *session,
     GList *remote_codecs,
     GError **error);
 
+static void
+fs_rtp_session_start_codec_param_gathering (FsRtpSession *session);
+static void
+fs_rtp_session_stop_codec_param_gathering (FsRtpSession *session);
+
+
 static GObjectClass *parent_class = NULL;
 
 //static guint signals[LAST_SIGNAL] = { 0 };
@@ -390,6 +409,8 @@ fs_rtp_session_dispose (GObject *object)
   if (self->priv->rtpbin_send_rtp_sink)
     gst_pad_set_active (self->priv->rtpbin_send_rtp_sink, FALSE);
 
+  fs_rtp_session_stop_codec_param_gathering (self);
+
   stop_and_remove (conferencebin, &self->priv->rtpmuxer, TRUE);
   stop_and_remove (conferencebin, &self->priv->send_capsfilter, TRUE);
   stop_and_remove (conferencebin, &self->priv->send_codecbin, FALSE);
@@ -589,7 +610,7 @@ fs_rtp_session_get_property (GObject *object,
              item = g_list_next (item))
         {
           CodecAssociation *ca = item->data;
-          if (ca->need_config)
+          if (!ca->disable && ca->need_config)
             break;
         }
         FS_RTP_SESSION_UNLOCK (self);
@@ -1123,6 +1144,8 @@ fs_rtp_session_constructed (GObject *object)
 
   gst_element_set_state (capsfilter, GST_STATE_PLAYING);
 
+  fs_rtp_session_start_codec_param_gathering (self);
+
   GST_CALL_PARENT (G_OBJECT_CLASS, constructed, (object));
 }
 
@@ -1791,6 +1814,8 @@ fs_rtp_session_update_codecs (FsRtpSession *session,
   if (old_negotiated_codec_associations)
     codec_association_list_destroy (old_negotiated_codec_associations);
 
+  fs_rtp_session_start_codec_param_gathering (session);
+
   if (!fs_rtp_session_verify_send_codec_bin_locked (session, error))
   {
     FS_RTP_SESSION_UNLOCK (session);
@@ -2833,3 +2858,451 @@ fs_rtp_session_bye_ssrc (FsRtpSession *session,
    * come from the right ip/port/etc ??
    */
 }
+
+static void
+_discovery_caps_changed (GstPad *pad, GParamSpec *pspec, FsRtpSession *session)
+{
+  GstCaps *caps = NULL;
+  GstStructure *s = NULL;
+  int i;
+  FsCodec *codec = NULL;
+  CodecAssociation *ca = NULL;
+
+  g_object_get (pad, "caps", &caps, NULL);
+
+  g_return_if_fail (GST_CAPS_IS_SIMPLE(caps));
+
+  s = gst_caps_get_structure (caps, 0);
+
+  FS_RTP_SESSION_LOCK (session);
+
+  if (!session->priv->discovery_codec)
+  {
+    fs_session_emit_error (FS_SESSION (session), FS_ERROR_INTERNAL,
+        "Internal error while discovering codecs configurations",
+        "Got notify::caps signal on the discovery codecs whith no codecs"
+        " being discovered");
+    goto out;
+  }
+
+  codec = session->priv->discovery_codec;
+
+  session->priv->discovery_codec = NULL;
+
+  ca = lookup_codec_association_by_codec (session->priv->codec_associations,
+      codec);
+
+  if (!ca)
+  {
+    fs_codec_destroy (codec);
+    goto out;
+  }
+
+  for (i = 0; i < gst_structure_n_fields (s); i++)
+  {
+    const gchar *name = gst_structure_nth_field_name (s, i);
+    if (name)
+    {
+      const gchar *value = gst_structure_get_string (s, name);
+      if (value)
+      {
+        if (codec_has_config_data_named (codec, name))
+        {
+          GList *item = NULL;
+
+          for (item = codec->config_params; item; item = g_list_next (item))
+          {
+            FsCodecParameter *param = item->data;
+            if (!g_ascii_strcasecmp (param->name, name))
+            {
+              if (!g_ascii_strcasecmp (param->value, value))
+                break;
+
+              /* replace the value if its different */
+              codec->config_params = g_list_delete_link (codec->config_params,
+                  item);
+              fs_codec_add_config_parameter (codec, name, value);
+              break;
+            }
+          }
+
+          /* Add it if it wasn't there */
+          if (item == NULL)
+            fs_codec_add_config_parameter (codec, name, value);
+        }
+      }
+    }
+  }
+
+  fs_codec_destroy (ca->codec);
+  ca->codec = codec;
+  ca->need_config = FALSE;
+
+ out:
+
+  FS_RTP_SESSION_UNLOCK (session);
+
+  if (caps)
+    gst_caps_unref (caps);
+}
+
+/**
+ * fs_rtp_session_get_codec_params:
+ * @session: a #FsRtpSession
+ * @ca: the #CodecAssociaton to get params for
+ *
+ * Gets the parameters for the specified #CodecAssociation
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ */
+
+static gboolean
+fs_rtp_session_get_codec_params (FsRtpSession *session, CodecAssociation *ca,
+    GError **error)
+{
+  GstPad *pad = NULL;
+  gchar *tmp;
+
+  FS_RTP_SESSION_LOCK (session);
+
+  if (session->priv->discovery_codecbin)
+  {
+    gst_element_set_locked_state (session->priv->discovery_codecbin, TRUE);
+    gst_element_set_state (session->priv->discovery_codecbin, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN (session->priv->conference),
+        session->priv->discovery_codecbin);
+    session->priv->discovery_codecbin = NULL;
+  }
+
+  if ((session->priv->discovery_fakesink == NULL ||
+          session->priv->discovery_capsfilter == NULL) &&
+      session->priv->discovery_fakesink != session->priv->discovery_capsfilter)
+  {
+    g_set_error (error, FS_ERROR, FS_ERROR_INTERNAL,
+        "Capsfilter and fakesink not synchronized, fakesink:%p capsfilter:%p",
+        session->priv->discovery_fakesink, session->priv->discovery_capsfilter);
+    goto error;
+  }
+
+  if (session->priv->discovery_fakesink == NULL &&
+      session->priv->discovery_capsfilter == NULL)
+  {
+    GstCaps *caps;
+
+    session->priv->discovery_fakesink =
+      gst_element_factory_make ("fakesink", NULL);
+    if (!session->priv->discovery_fakesink)
+    {
+      g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+          "Could not make fakesink element");
+      goto error;
+    }
+    g_object_set (session->priv->discovery_fakesink,
+        "sync", FALSE,
+        "async", FALSE,
+        NULL);
+
+    if (!gst_bin_add (GST_BIN (session->priv->conference),
+            session->priv->discovery_fakesink))
+    {
+      g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+          "Could not add the discovery fakesink to the bin");
+      goto error;
+    }
+
+    if (!gst_element_sync_state_with_parent (session->priv->discovery_fakesink))
+    {
+      g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+          "Could not sync the discovery fakesink's state with its parent");
+      goto error;
+    }
+
+    session->priv->discovery_capsfilter =
+      gst_element_factory_make ("capsfilter", NULL);
+    if (!session->priv->discovery_capsfilter)
+    {
+      g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+          "Could not make capsfilter element");
+      goto error;
+    }
+
+    caps = fs_codec_to_gst_caps (ca->codec);
+    g_object_set (session->priv->discovery_capsfilter,
+        "caps", caps,
+        NULL);
+    gst_caps_unref (caps);
+
+    if (!gst_bin_add (GST_BIN (session->priv->conference),
+            session->priv->discovery_capsfilter))
+    {
+      g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+          "Could not add the discovery capsfilter to the bin");
+      goto error;
+    }
+
+    if (!gst_element_sync_state_with_parent (session->priv->discovery_fakesink))
+    {
+      g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+          "Could not sync the discovery capsfilter's state with its parent");
+      goto error;
+    }
+
+    if (!gst_element_link_pads (session->priv->discovery_capsfilter, "src",
+            session->priv->discovery_fakesink, "sink"))
+    {
+      g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+          "Could not link discovery capsfilter and fakesink");
+      goto error;
+    }
+
+    pad = gst_element_get_static_pad (session->priv->discovery_capsfilter,
+        "src");
+    g_signal_connect (pad, "notify::caps", G_CALLBACK (_discovery_caps_changed),
+        session);
+    gst_object_unref (pad);
+  }
+
+  tmp = g_strdup_printf ("discover_%d_%d", session->id, ca->codec->id);
+  session->priv->discovery_codecbin = _create_codec_bin (ca->blueprint,
+      ca->codec, tmp, TRUE, error);
+  g_free (tmp);
+
+  if (!session->priv->discovery_codecbin)
+    goto error;
+
+  if (!gst_bin_add (GST_BIN (session->priv->conference),
+            session->priv->discovery_codecbin))
+  {
+    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+        "Could not add the discovery codecbin to the bin");
+    goto error;
+  }
+
+  if (!gst_element_sync_state_with_parent (session->priv->discovery_codecbin))
+  {
+    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+        "Could not sync the discovery codecbin's state with its parent");
+    goto error;
+  }
+
+  if (!gst_element_link_pads (session->priv->discovery_codecbin, "src",
+            session->priv->discovery_capsfilter, "sink"))
+  {
+    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+        "Could not link discovery codecbin and capsfilter");
+    goto error;
+  }
+
+  pad = gst_element_get_static_pad (session->priv->discovery_codecbin, "sink");
+
+  if (GST_PAD_LINK_FAILED (gst_pad_link (session->priv->send_tee_discovery_pad,
+              pad)))
+  {
+    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
+        "Could not link the tee and the discovery codecbin");
+    gst_object_unref (pad);
+    goto error;
+  }
+
+  gst_object_unref (pad);
+
+  session->priv->discovery_codec = fs_codec_copy (ca->codec);
+
+  g_object_set (session->priv->media_sink_valve, "drop", FALSE, NULL);
+
+  FS_RTP_SESSION_UNLOCK (session);
+
+  return TRUE;
+
+ error:
+
+  if (session->priv->discovery_fakesink)
+  {
+    gst_element_set_locked_state (session->priv->discovery_fakesink, TRUE);
+    gst_element_set_state (session->priv->discovery_fakesink, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN (session->priv->conference),
+        session->priv->discovery_fakesink);
+    session->priv->discovery_fakesink = NULL;
+  }
+
+  if (session->priv->discovery_capsfilter)
+  {
+    gst_element_set_locked_state (session->priv->discovery_capsfilter, TRUE);
+    gst_element_set_state (session->priv->discovery_capsfilter, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN (session->priv->conference),
+        session->priv->discovery_capsfilter);
+    session->priv->discovery_capsfilter = NULL;
+  }
+
+  if (session->priv->discovery_codecbin)
+  {
+    gst_element_set_locked_state (session->priv->discovery_codecbin, TRUE);
+    gst_element_set_state (session->priv->discovery_codecbin, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN (session->priv->conference),
+        session->priv->discovery_codecbin);
+    session->priv->discovery_codecbin = NULL;
+  }
+
+  FS_RTP_SESSION_UNLOCK (session);
+
+  return FALSE;
+}
+
+/**
+ * _send_sink_pad_have_data_callback:
+ *
+ * This is a callback function for the "have-data" signal, it returns always
+ * %TRUE, because we never drop buffers at this stage
+ */
+
+static gboolean
+_send_sink_pad_have_data_callback (GstPad *pad, GstMiniObject *obj,
+    FsRtpSession *session)
+{
+  GError *error = NULL;
+  GList *item = NULL;
+  CodecAssociation *ca = NULL;
+
+  FS_RTP_SESSION_LOCK (session);
+
+  if (session->priv->discovery_codec)
+    goto out;
+
+
+  /* Find out if there is a codec that needs the config to be fetched */
+  for (item = g_list_first (session->priv->codec_associations);
+       item;
+       item = g_list_next (item))
+  {
+    ca = item->data;
+    if (ca->need_config)
+      break;
+  }
+  if (!item)
+  {
+    fs_rtp_session_stop_codec_param_gathering (session);
+    g_object_notify (G_OBJECT (session), "codecs-ready");
+    gst_element_post_message (GST_ELEMENT (session->priv->conference),
+        gst_message_new_element (GST_OBJECT (session->priv->conference),
+            gst_structure_new ("farsight-codecs-ready",
+                "session", FS_TYPE_SESSION, session,
+                NULL)));
+
+    goto out;
+  }
+
+  if (!fs_rtp_session_get_codec_params (session, ca, &error))
+  {
+    fs_rtp_session_stop_codec_param_gathering (session);
+    fs_session_emit_error (FS_SESSION (session), error->code,
+        "Error while discovering codec data, discovery cancelled",
+        error->message);
+  }
+
+ out:
+
+  g_clear_error (&error);
+
+  FS_RTP_SESSION_UNLOCK (session);
+  return TRUE;
+}
+
+/**
+ * fs_rtp_session_start_codec_param_gathering
+ * @session: a #FsRtpSession
+ *
+ * Check if there is any codec associations that requires codec discovery and
+ * if there is, starts the gathering process by adding a pad probe to the
+ * send valve
+ */
+
+static void
+fs_rtp_session_start_codec_param_gathering (FsRtpSession *session)
+{
+  GList *item = NULL;
+
+  FS_RTP_SESSION_LOCK (session);
+
+  /* Find out if there is a codec that needs the config to be fetched */
+  for (item = g_list_first (session->priv->codec_associations);
+       item;
+       item = g_list_next (item))
+  {
+    CodecAssociation *ca = item->data;
+    if (ca->need_config)
+      break;
+  }
+  if (!item)
+    goto out;
+
+  if (!session->priv->discovery_blocking_id)
+    session->priv->discovery_blocking_id = gst_pad_add_data_probe (
+        session->priv->media_sink_pad,
+        G_CALLBACK (_send_sink_pad_have_data_callback), session);
+
+ out:
+
+  FS_RTP_SESSION_UNLOCK (session);
+}
+
+
+/**
+ * fs_rtp_session_stop_codec_param_gathering
+ * @session: a #FsRtpSession
+ *
+ * Check if there is any codec associations that requires codec discovery and
+ * if there is, starts the gathering process by adding a pad probe to the
+ * send valve
+ */
+
+static void
+fs_rtp_session_stop_codec_param_gathering (FsRtpSession *session)
+{
+
+  FS_RTP_SESSION_LOCK (session);
+
+  if (session->priv->discovery_codec)
+  {
+    fs_codec_destroy (session->priv->discovery_codec);
+    session->priv->discovery_codec = NULL;
+  }
+
+  if (session->priv->discovery_blocking_id)
+  {
+    gst_pad_remove_data_probe (session->priv->media_sink_pad,
+        session->priv->discovery_blocking_id);
+    session->priv->discovery_blocking_id = 0;
+  }
+
+  if (!session->priv->send_codecbin)
+    g_object_set (session->priv->media_sink_valve, "drop", TRUE, NULL);
+
+  if (session->priv->discovery_fakesink)
+  {
+    gst_element_set_locked_state (session->priv->discovery_fakesink, TRUE);
+    gst_element_set_state (session->priv->discovery_fakesink, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN (session->priv->conference),
+        session->priv->discovery_fakesink);
+    session->priv->discovery_fakesink = NULL;
+  }
+
+  if (session->priv->discovery_capsfilter)
+  {
+    gst_element_set_locked_state (session->priv->discovery_capsfilter, TRUE);
+    gst_element_set_state (session->priv->discovery_capsfilter, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN (session->priv->conference),
+        session->priv->discovery_capsfilter);
+    session->priv->discovery_capsfilter = NULL;
+  }
+
+  if (session->priv->discovery_codecbin)
+  {
+    gst_element_set_locked_state (session->priv->discovery_codecbin, TRUE);
+    gst_element_set_state (session->priv->discovery_codecbin, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN (session->priv->conference),
+        session->priv->discovery_codecbin);
+    session->priv->discovery_codecbin = NULL;
+  }
+
+  FS_RTP_SESSION_UNLOCK (session);
+}
-- 
1.5.6.5




More information about the farsight-commits mailing list