diff options
Diffstat (limited to 'gst')
-rw-r--r-- | gst/rtpmanager/gstrtpbin.c | 348 | ||||
-rw-r--r-- | gst/rtpmanager/gstrtpbin.h | 4 | ||||
-rw-r--r-- | gst/rtpmanager/gstrtpclient.c | 5 |
3 files changed, 350 insertions, 7 deletions
diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index 629f098d..c1ec7130 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -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 diff --git a/gst/rtpmanager/gstrtpbin.h b/gst/rtpmanager/gstrtpbin.h index 5b3d7954..517c1178 100644 --- a/gst/rtpmanager/gstrtpbin.h +++ b/gst/rtpmanager/gstrtpbin.h @@ -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; diff --git a/gst/rtpmanager/gstrtpclient.c b/gst/rtpmanager/gstrtpclient.c index 2984d3f9..422d57c6 100644 --- a/gst/rtpmanager/gstrtpclient.c +++ b/gst/rtpmanager/gstrtpclient.c @@ -27,10 +27,13 @@ * 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> |