gst/rtpmanager/: Some more ghostpad magic.
authorWim Taymans <wim.taymans@gmail.com>
Tue, 3 Apr 2007 11:35:39 +0000 (11:35 +0000)
committerTim-Philipp Müller <tim.muller@collabora.co.uk>
Tue, 11 Aug 2009 01:30:23 +0000 (02:30 +0100)
Original commit message from CVS:
* gst/rtpmanager/gstrtpbin.c: (find_session_by_id),
(create_session), (gst_rtp_bin_base_init), (create_recv_rtp),
(create_recv_rtcp), (create_send_rtp), (create_rtcp),
(gst_rtp_bin_request_new_pad):
* gst/rtpmanager/gstrtpbin.h:
* gst/rtpmanager/gstrtpclient.c:
Some more ghostpad magic.

gst/rtpmanager/gstrtpbin.c
gst/rtpmanager/gstrtpbin.h
gst/rtpmanager/gstrtpclient.c

index 629f098..c1ec713 100644 (file)
@@ -79,8 +79,8 @@ GST_STATIC_PAD_TEMPLATE ("recv_rtp_src_%d_%d_%d",
     GST_STATIC_CAPS ("application/x-rtp")
     );
 
-static GstStaticPadTemplate rtpbin_send_rtcp_src_template =
-GST_STATIC_PAD_TEMPLATE ("send_rtcp_src_%d",
+static GstStaticPadTemplate rtpbin_rtcp_src_template =
+GST_STATIC_PAD_TEMPLATE ("rtcp_src_%d",
     GST_PAD_SRC,
     GST_PAD_REQUEST,
     GST_STATIC_CAPS ("application/x-rtcp")
@@ -112,6 +112,63 @@ enum
   PROP_0
 };
 
+/* helper objects */
+typedef struct
+{
+  /* session id */
+  gint id;
+  /* the session element */
+  GstElement *session;
+  /* the SSRC demuxer */
+  GstElement *ssrcdemux;
+
+  /* the pads of the session */
+  GstPad *recv_rtp_sink;
+  GstPad *recv_rtcp_sink;
+  GstPad *send_rtp_sink;
+  GstPad *rtcp_src;
+
+} GstRTPBinSession;
+
+/* find a session with the given id */
+static GstRTPBinSession *
+find_session_by_id (GstRTPBin * rtpbin, gint id)
+{
+  GList *walk;
+
+  for (walk = rtpbin->sessions; walk; walk = g_list_next (walk)) {
+    GstRTPBinSession *sess = (GstRTPBinSession *) walk->data;
+
+    if (sess->id == id)
+      return sess;
+  }
+  return NULL;
+}
+
+/* create a session with the given id */
+static GstRTPBinSession *
+create_session (GstRTPBin * rtpbin, gint id)
+{
+  GstRTPBinSession *sess;
+  GstElement *elem;
+
+  if (!(elem = gst_element_factory_make ("rtpsession", NULL)))
+    goto no_session;
+
+  sess = g_new0 (GstRTPBinSession, 1);
+  sess->id = id;
+  sess->session = elem;
+
+  return sess;
+
+  /* ERRORS */
+no_session:
+  {
+    g_warning ("rtpbin: could not create rtpsession element");
+    return NULL;
+  }
+}
+
 /* GObject vmethods */
 static void gst_rtp_bin_finalize (GObject * object);
 static void gst_rtp_bin_set_property (GObject * object, guint prop_id,
@@ -147,7 +204,7 @@ gst_rtp_bin_base_init (gpointer klass)
   gst_element_class_add_pad_template (element_class,
       gst_static_pad_template_get (&rtpbin_recv_rtp_src_template));
   gst_element_class_add_pad_template (element_class,
-      gst_static_pad_template_get (&rtpbin_send_rtcp_src_template));
+      gst_static_pad_template_get (&rtpbin_rtcp_src_template));
   gst_element_class_add_pad_template (element_class,
       gst_static_pad_template_get (&rtpbin_send_rtp_src_template));
 
@@ -255,6 +312,267 @@ gst_rtp_bin_change_state (GstElement * element, GstStateChange transition)
   return res;
 }
 
+/* Create a pad for receiving RTP for the session in @name
+ */
+static GstPad *
+create_recv_rtp (GstRTPBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+{
+  GstPad *result;
+  guint sessid;
+  GstRTPBinSession *session;
+
+  /* first get the session number */
+  if (name == NULL || sscanf (name, "recv_rtp_sink_%d", &sessid) != 1)
+    goto no_name;
+
+  /* get or create session */
+  session = find_session_by_id (rtpbin, sessid);
+  if (!session) {
+    /* create session now */
+    session = create_session (rtpbin, sessid);
+    if (session == NULL)
+      goto create_error;
+  }
+  /* check if pad was requested */
+  if (session->recv_rtp_sink != NULL)
+    goto existed;
+
+  /* get recv_rtp pad and store */
+  session->recv_rtp_sink =
+      gst_element_get_request_pad (session->session, "recv_rtp_sink");
+  if (session->recv_rtp_sink == NULL)
+    goto pad_failed;
+
+  result =
+      gst_ghost_pad_new_from_template (name, session->recv_rtp_sink, templ);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
+
+  /* FIXME, get srcpad, link to SSRCDemux */
+
+  return result;
+
+  /* ERRORS */
+no_name:
+  {
+    g_warning ("rtpbin: invalid name given");
+    return NULL;
+  }
+create_error:
+  {
+    /* create_session already warned */
+    return NULL;
+  }
+existed:
+  {
+    g_warning ("rtpbin: recv_rtp pad already requested for session %d", sessid);
+    return NULL;
+  }
+pad_failed:
+  {
+    g_warning ("rtpbin: failed to get session pad");
+    return NULL;
+  }
+}
+
+/* Create a pad for receiving RTCP for the session in @name
+ */
+static GstPad *
+create_recv_rtcp (GstRTPBin * rtpbin, GstPadTemplate * templ,
+    const gchar * name)
+{
+  GstPad *result;
+  guint sessid;
+  GstRTPBinSession *session;
+
+  /* first get the session number */
+  if (name == NULL || sscanf (name, "recv_rtcp_sink_%d", &sessid) != 1)
+    goto no_name;
+
+  /* get the session, it must exist or we error */
+  session = find_session_by_id (rtpbin, sessid);
+  if (!session)
+    goto no_session;
+
+  /* check if pad was requested */
+  if (session->recv_rtcp_sink != NULL)
+    goto existed;
+
+  /* get recv_rtp pad and store */
+  session->recv_rtcp_sink =
+      gst_element_get_request_pad (session->session, "recv_rtcp_sink");
+  if (session->recv_rtcp_sink == NULL)
+    goto pad_failed;
+
+  result =
+      gst_ghost_pad_new_from_template (name, session->recv_rtcp_sink, templ);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
+
+  /* FIXME, get srcpad, link to SSRCDemux */
+
+  return result;
+
+  /* ERRORS */
+no_name:
+  {
+    g_warning ("rtpbin: invalid name given");
+    return NULL;
+  }
+no_session:
+  {
+    g_warning ("rtpbin: no session with id %d", sessid);
+    return NULL;
+  }
+existed:
+  {
+    g_warning ("rtpbin: recv_rtcp pad already requested for session %d",
+        sessid);
+    return NULL;
+  }
+pad_failed:
+  {
+    g_warning ("rtpbin: failed to get session pad");
+    return NULL;
+  }
+}
+
+/* Create a pad for sending RTP for the session in @name
+ */
+static GstPad *
+create_send_rtp (GstRTPBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+{
+  GstPad *result, *srcpad, *srcghost;
+  gchar *gname;
+  guint sessid;
+  GstRTPBinSession *session;
+  GstElementClass *klass;
+
+  /* first get the session number */
+  if (name == NULL || sscanf (name, "send_rtp_sink_%d", &sessid) != 1)
+    goto no_name;
+
+  /* get or create session */
+  session = find_session_by_id (rtpbin, sessid);
+  if (!session) {
+    /* create session now */
+    session = create_session (rtpbin, sessid);
+    if (session == NULL)
+      goto create_error;
+  }
+
+  /* check if pad was requested */
+  if (session->send_rtp_sink != NULL)
+    goto existed;
+
+  /* get recv_rtp pad and store */
+  session->send_rtp_sink =
+      gst_element_get_request_pad (session->session, "send_rtp_sink");
+  if (session->send_rtp_sink == NULL)
+    goto pad_failed;
+
+  result =
+      gst_ghost_pad_new_from_template (name, session->send_rtp_sink, templ);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
+
+  /* get srcpad */
+  srcpad = gst_element_get_pad (session->session, "send_rtp_src");
+  if (srcpad == NULL)
+    goto no_srcpad;
+
+  /* ghost the new source pad */
+  klass = GST_ELEMENT_GET_CLASS (rtpbin);
+  gname = g_strdup_printf ("send_rtp_src_%d", sessid);
+  templ = gst_element_class_get_pad_template (klass, "send_rtp_src_%d");
+  srcghost =
+      gst_ghost_pad_new_from_template (gname, session->send_rtp_sink, templ);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), srcghost);
+  g_free (gname);
+
+  return result;
+
+  /* ERRORS */
+no_name:
+  {
+    g_warning ("rtpbin: invalid name given");
+    return NULL;
+  }
+create_error:
+  {
+    /* create_session already warned */
+    return NULL;
+  }
+existed:
+  {
+    g_warning ("rtpbin: send_rtp pad already requested for session %d", sessid);
+    return NULL;
+  }
+pad_failed:
+  {
+    g_warning ("rtpbin: failed to get session pad for session %d", sessid);
+    return NULL;
+  }
+no_srcpad:
+  {
+    g_warning ("rtpbin: failed to get rtp source pad for session %d", sessid);
+    return NULL;
+  }
+}
+
+/* Create a pad for sending RTCP for the session in @name
+ */
+static GstPad *
+create_rtcp (GstRTPBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+{
+  GstPad *result;
+  guint sessid;
+  GstRTPBinSession *session;
+
+  /* first get the session number */
+  if (name == NULL || sscanf (name, "send_rtp_sink_%d", &sessid) != 1)
+    goto no_name;
+
+  /* get or create session */
+  session = find_session_by_id (rtpbin, sessid);
+  if (!session)
+    goto no_session;
+
+  /* check if pad was requested */
+  if (session->rtcp_src != NULL)
+    goto existed;
+
+  /* get rtcp_src pad and store */
+  session->rtcp_src =
+      gst_element_get_request_pad (session->session, "rtcp_src");
+  if (session->rtcp_src == NULL)
+    goto pad_failed;
+
+  result = gst_ghost_pad_new_from_template (name, session->rtcp_src, templ);
+  gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
+
+  return result;
+
+  /* ERRORS */
+no_name:
+  {
+    g_warning ("rtpbin: invalid name given");
+    return NULL;
+  }
+no_session:
+  {
+    g_warning ("rtpbin: session with id %d does not exist", sessid);
+    return NULL;
+  }
+existed:
+  {
+    g_warning ("rtpbin: rtcp_src pad already requested for session %d", sessid);
+    return NULL;
+  }
+pad_failed:
+  {
+    g_warning ("rtpbin: failed to get rtcp pad for session %d", sessid);
+    return NULL;
+  }
+}
+
 /* 
  */
 static GstPad *
@@ -263,6 +581,7 @@ gst_rtp_bin_request_new_pad (GstElement * element,
 {
   GstRTPBin *rtpbin;
   GstElementClass *klass;
+  GstPad *result;
 
   g_return_val_if_fail (templ != NULL, NULL);
   g_return_val_if_fail (GST_IS_RTP_BIN (element), NULL);
@@ -270,7 +589,28 @@ gst_rtp_bin_request_new_pad (GstElement * element,
   rtpbin = GST_RTP_BIN (element);
   klass = GST_ELEMENT_GET_CLASS (element);
 
-  return NULL;
+  /* figure out the template */
+  if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%d")) {
+    result = create_recv_rtp (rtpbin, templ, name);
+  } else if (templ == gst_element_class_get_pad_template (klass,
+          "recv_rtcp_sink_%d")) {
+    result = create_recv_rtcp (rtpbin, templ, name);
+  } else if (templ == gst_element_class_get_pad_template (klass,
+          "send_rtp_sink_%d")) {
+    result = create_send_rtp (rtpbin, templ, name);
+  } else if (templ == gst_element_class_get_pad_template (klass, "rtcp_src_%d")) {
+    result = create_rtcp (rtpbin, templ, name);
+  } else
+    goto wrong_template;
+
+  return result;
+
+  /* ERRORS */
+wrong_template:
+  {
+    g_warning ("rtpbin: this is not our template");
+    return NULL;
+  }
 }
 
 static void
index 5b3d795..517c117 100644 (file)
@@ -40,8 +40,8 @@ typedef struct _GstRTPBinPrivate GstRTPBinPrivate;
 struct _GstRTPBin {
   GstBin         element;
 
-  /* a list of streams from a client */
-  GList         *streams;
+  /* a list of session */
+  GList         *sessions;
 
   /*< private >*/
   GstRTPBinPrivate *priv;
index 2984d3f..422d57c 100644 (file)
  * This element handles RTP data from one client. It accepts multiple RTP streams that
  * should be synchronized together.
  * </para>
+ * <para>
+ * Normally the SSRCs that map to the same CNAME (as given in the RTCP SDES messages)
+ * should be synchronized.
+ * </para>
  * <title>Example pipelines</title>
  * <para>
  * <programlisting>
- * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! alsasink
  * </programlisting>
  * </para>
  * </refsect2>