Commit f52e16ce authored by Mathieu Duponchelle's avatar Mathieu Duponchelle 🐸 Committed by Mathieu Duponchelle

Revert "rtpbin: receive bundle support"

This reverts commit dcd3ce97.

This functionality was implemented for gstopenwebrtc, but it
turned out this was not actually needed for webrtc bundling
support, as shown in webrtcbin. It also doesn't correspond
to any standards.

This is an API break, but nothing should actually depend on
this, at least not for its initial purpose.

Changes in rtpbin.c were reverted manually, to preserve some
refactoring that had occurred in the original commit.

Fixes #537
parent 05059ce1
......@@ -374,14 +374,6 @@ GstRtpBin *gstrtpbin
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::on-bundled-ssrc</NAME>
<RETURNS>guint</RETURNS>
<FLAGS>l</FLAGS>
GstRtpBin *gstrtpbin
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::get-internal-storage</NAME>
<RETURNS>GObject*</RETURNS>
......
......@@ -53,13 +53,6 @@
* SSRC in the RTP packets to its own SSRC and wil forward the packets on the
* send_rtp_src_\%u pad after updating its internal state.
*
* #GstRtpBin can also demultiplex incoming bundled streams. The first
* #GstRtpSession will have a #GstRtpSsrcDemux element splitting the streams
* based on their SSRC and potentially dispatched to a different #GstRtpSession.
* Because retransmission SSRCs need to be merged with the corresponding media
* stream the #GstRtpBin::on-bundled-ssrc signal is emitted so that the
* application can find out to which session the SSRC belongs.
*
* The session manager needs the clock-rate of the payload types it is handling
* and will signal the #GstRtpSession::request-pt-map signal when it needs such a
* mapping. One can clear the cached values with the #GstRtpSession::clear-pt-map
......@@ -384,12 +377,12 @@ static void free_client (GstRtpBinClient * client, GstRtpBin * bin);
static void free_stream (GstRtpBinStream * stream, GstRtpBin * bin);
static GstRtpBinSession *create_session (GstRtpBin * rtpbin, gint id);
static GstPad *complete_session_sink (GstRtpBin * rtpbin,
GstRtpBinSession * session, gboolean bundle_demuxer_needed);
GstRtpBinSession * session);
static void
complete_session_receiver (GstRtpBin * rtpbin, GstRtpBinSession * session,
guint sessid);
static GstPad *complete_session_rtcp (GstRtpBin * rtpbin,
GstRtpBinSession * session, guint sessid, gboolean bundle_demuxer_needed);
GstRtpBinSession * session, guint sessid);
/* Manages the RTP stream for one SSRC.
*
......@@ -462,12 +455,6 @@ struct _GstRtpBinSession
/* Fec support */
GstElement *storage;
/* Bundling support */
GstElement *rtp_funnel;
GstElement *rtcp_funnel;
GstElement *bundle_demux;
gulong bundle_demux_newpad_sig;
GMutex lock;
/* list of GstRtpBinStream */
......@@ -668,102 +655,6 @@ ssrc_demux_pad_removed (GstElement * element, guint ssrc, GstPad * pad,
GST_RTP_BIN_UNLOCK (rtpbin);
}
static void
new_bundled_ssrc_pad_found (GstElement * element, guint ssrc, GstPad * pad,
GstRtpBinSession * session)
{
GValue result = G_VALUE_INIT;
GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
guint session_id = 0;
GstRtpBinSession *target_session = NULL;
GstRtpBin *rtpbin = session->bin;
gchar *name;
GstPad *src_pad;
GstPad *recv_rtp_sink = NULL;
GstPad *recv_rtcp_sink = NULL;
GstPadLinkReturn ret;
GST_RTP_BIN_DYN_LOCK (rtpbin);
GST_DEBUG_OBJECT (rtpbin, "new bundled SSRC pad %08x, %s:%s", ssrc,
GST_DEBUG_PAD_NAME (pad));
g_value_init (&result, G_TYPE_UINT);
g_value_init (&params[0], GST_TYPE_ELEMENT);
g_value_set_object (&params[0], rtpbin);
g_value_init (&params[1], G_TYPE_UINT);
g_value_set_uint (&params[1], ssrc);
g_signal_emitv (params,
gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC], 0, &result);
g_value_unset (&params[0]);
session_id = g_value_get_uint (&result);
if (session_id == 0) {
target_session = session;
} else {
target_session = find_session_by_id (rtpbin, (gint) session_id);
if (!target_session) {
target_session = create_session (rtpbin, session_id);
}
if (!target_session) {
/* create_session() warned already */
GST_RTP_BIN_DYN_UNLOCK (rtpbin);
return;
}
if (!target_session->recv_rtp_sink) {
recv_rtp_sink = complete_session_sink (rtpbin, target_session, FALSE);
}
if (!target_session->recv_rtp_src)
complete_session_receiver (rtpbin, target_session, session_id);
if (!target_session->recv_rtcp_sink) {
recv_rtcp_sink =
complete_session_rtcp (rtpbin, target_session, session_id, FALSE);
}
}
GST_DEBUG_OBJECT (rtpbin, "Assigning bundled ssrc %u to session %u", ssrc,
session_id);
if (!recv_rtp_sink) {
recv_rtp_sink =
gst_element_get_request_pad (target_session->rtp_funnel, "sink_%u");
}
if (!recv_rtcp_sink) {
recv_rtcp_sink =
gst_element_get_request_pad (target_session->rtcp_funnel, "sink_%u");
}
name = g_strdup_printf ("src_%u", ssrc);
src_pad = gst_element_get_static_pad (element, name);
ret = gst_pad_link (src_pad, recv_rtp_sink);
g_free (name);
gst_object_unref (src_pad);
gst_object_unref (recv_rtp_sink);
if (ret != GST_PAD_LINK_OK) {
g_warning
("rtpbin: failed to link bundle demuxer to receive rtp funnel for session %u",
session_id);
}
name = g_strdup_printf ("rtcp_src_%u", ssrc);
src_pad = gst_element_get_static_pad (element, name);
gst_pad_link (src_pad, recv_rtcp_sink);
g_free (name);
gst_object_unref (src_pad);
gst_object_unref (recv_rtcp_sink);
if (ret != GST_PAD_LINK_OK) {
g_warning
("rtpbin: failed to link bundle demuxer to receive rtcp sink pad for session %u",
session_id);
}
GST_RTP_BIN_DYN_UNLOCK (rtpbin);
}
/* create a session with the given id. Must be called with RTP_BIN_LOCK */
static GstRtpBinSession *
create_session (GstRtpBin * rtpbin, gint id)
......@@ -796,9 +687,6 @@ create_session (GstRtpBin * rtpbin, gint id)
sess->demux = demux;
sess->storage = storage;
sess->rtp_funnel = gst_element_factory_make ("funnel", NULL);
sess->rtcp_funnel = gst_element_factory_make ("funnel", NULL);
sess->ptmap = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) gst_caps_unref);
rtpbin->sessions = g_slist_prepend (rtpbin->sessions, sess);
......@@ -846,8 +734,6 @@ create_session (GstRtpBin * rtpbin, gint id)
gst_bin_add (GST_BIN_CAST (rtpbin), session);
gst_bin_add (GST_BIN_CAST (rtpbin), demux);
gst_bin_add (GST_BIN_CAST (rtpbin), sess->rtp_funnel);
gst_bin_add (GST_BIN_CAST (rtpbin), sess->rtcp_funnel);
gst_bin_add (GST_BIN_CAST (rtpbin), storage);
/* unref the storage again, the bin has a reference now and
......@@ -861,8 +747,6 @@ create_session (GstRtpBin * rtpbin, gint id)
/* change state only to what's needed */
gst_element_set_state (demux, target);
gst_element_set_state (session, target);
gst_element_set_state (sess->rtp_funnel, target);
gst_element_set_state (sess->rtcp_funnel, target);
gst_element_set_state (storage, target);
return sess;
......@@ -2511,29 +2395,6 @@ gst_rtp_bin_class_init (GstRtpBinClass * klass)
on_sender_ssrc_active), NULL, NULL, g_cclosure_marshal_generic,
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
/**
* GstRtpBin::on-bundled-ssrc:
* @rtpbin: the object which received the signal
* @ssrc: the bundled SSRC
*
* Notify of a new incoming bundled SSRC. If no handler is connected to the
* signal then the #GstRtpSession created for the recv_rtp_sink_\%u
* request pad will be managing this new SSRC. However if there is a handler
* connected then the application can decided to dispatch this new stream to
* another session by providing its ID as return value of the handler. This
* can be particularly useful to keep retransmission SSRCs grouped with the
* session for which they handle retransmission.
*
* Since: 1.12
*/
gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC] =
g_signal_new ("on-bundled-ssrc", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass,
on_bundled_ssrc), NULL, NULL,
g_cclosure_marshal_generic, G_TYPE_UINT, 1, G_TYPE_UINT);
g_object_class_install_property (gobject_class, PROP_SDES,
g_param_spec_boxed ("sdes", "SDES",
"The SDES items of this session",
......@@ -3733,39 +3594,11 @@ no_stream:
}
}
static void
session_maybe_create_bundle_demuxer (GstRtpBinSession * session)
{
GstRtpBin *rtpbin;
if (session->bundle_demux)
return;
rtpbin = session->bin;
if (g_signal_has_handler_pending (rtpbin,
gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC], 0, TRUE)) {
GST_DEBUG_OBJECT (rtpbin, "Adding a bundle SSRC demuxer to session %u",
session->id);
session->bundle_demux = gst_element_factory_make ("rtpssrcdemux", NULL);
session->bundle_demux_newpad_sig = g_signal_connect (session->bundle_demux,
"new-ssrc-pad", (GCallback) new_bundled_ssrc_pad_found, session);
gst_bin_add (GST_BIN_CAST (rtpbin), session->bundle_demux);
gst_element_sync_state_with_parent (session->bundle_demux);
} else {
GST_DEBUG_OBJECT (rtpbin,
"No handler for the on-bundled-ssrc signal so no need for a bundle SSRC demuxer in session %u",
session->id);
}
}
static GstPad *
complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session,
gboolean bundle_demuxer_needed)
complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
{
guint sessid = session->id;
GstPad *recv_rtp_sink;
GstPad *funnel_src;
GstElement *decoder;
g_assert (!session->recv_rtp_sink);
......@@ -3779,9 +3612,6 @@ complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session,
g_signal_connect (session->recv_rtp_sink, "notify::caps",
(GCallback) caps_changed, session);
if (bundle_demuxer_needed)
session_maybe_create_bundle_demuxer (session);
GST_DEBUG_OBJECT (rtpbin, "requesting RTP decoder");
decoder = session_request_element (session, SIGNAL_REQUEST_RTP_DECODER);
if (decoder) {
......@@ -3799,14 +3629,8 @@ complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session,
if (decsrc == NULL)
goto dec_src_failed;
if (session->bundle_demux) {
GstPad *demux_sink;
demux_sink = gst_element_get_static_pad (session->bundle_demux, "sink");
ret = gst_pad_link (decsrc, demux_sink);
gst_object_unref (demux_sink);
} else {
ret = gst_pad_link (decsrc, session->recv_rtp_sink);
}
ret = gst_pad_link (decsrc, session->recv_rtp_sink);
gst_object_unref (decsrc);
if (ret != GST_PAD_LINK_OK)
......@@ -3814,19 +3638,9 @@ complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session,
} else {
GST_DEBUG_OBJECT (rtpbin, "no RTP decoder given");
if (session->bundle_demux) {
recv_rtp_sink =
gst_element_get_static_pad (session->bundle_demux, "sink");
} else {
recv_rtp_sink =
gst_element_get_request_pad (session->rtp_funnel, "sink_%u");
}
recv_rtp_sink = gst_object_ref (session->recv_rtp_sink);
}
funnel_src = gst_element_get_static_pad (session->rtp_funnel, "src");
gst_pad_link (funnel_src, session->recv_rtp_sink);
gst_object_unref (funnel_src);
return recv_rtp_sink;
/* ERRORS */
......@@ -3984,11 +3798,10 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
return session->recv_rtp_sink_ghost;
/* setup the session sink pad */
recv_rtp_sink = complete_session_sink (rtpbin, session, TRUE);
recv_rtp_sink = complete_session_sink (rtpbin, session);
if (!recv_rtp_sink)
goto session_sink_failed;
GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad");
session->recv_rtp_sink_ghost =
gst_ghost_pad_new_from_template (name, recv_rtp_sink, templ);
......@@ -4029,11 +3842,6 @@ remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
g_signal_handler_disconnect (session->demux, session->demux_padremoved_sig);
session->demux_padremoved_sig = 0;
}
if (session->bundle_demux_newpad_sig) {
g_signal_handler_disconnect (session->bundle_demux,
session->bundle_demux_newpad_sig);
session->bundle_demux_newpad_sig = 0;
}
if (session->recv_rtp_src) {
gst_object_unref (session->recv_rtp_src);
session->recv_rtp_src = NULL;
......@@ -4053,12 +3861,11 @@ remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
static GstPad *
complete_session_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session,
guint sessid, gboolean bundle_demuxer_needed)
guint sessid)
{
GstElement *decoder;
GstPad *sinkdpad;
GstPad *decsink = NULL;
GstPad *funnel_src;
/* get recv_rtp pad and store */
GST_DEBUG_OBJECT (rtpbin, "getting RTCP sink pad");
......@@ -4067,9 +3874,6 @@ complete_session_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session,
if (session->recv_rtcp_sink == NULL)
goto pad_failed;
if (bundle_demuxer_needed)
session_maybe_create_bundle_demuxer (session);
GST_DEBUG_OBJECT (rtpbin, "getting RTCP decoder");
decoder = session_request_element (session, SIGNAL_REQUEST_RTCP_DECODER);
if (decoder) {
......@@ -4086,26 +3890,15 @@ complete_session_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session,
if (decsrc == NULL)
goto dec_src_failed;
if (session->bundle_demux) {
GstPad *demux_sink;
demux_sink =
gst_element_get_static_pad (session->bundle_demux, "rtcp_sink");
ret = gst_pad_link (decsrc, demux_sink);
gst_object_unref (demux_sink);
} else {
ret = gst_pad_link (decsrc, session->recv_rtcp_sink);
}
ret = gst_pad_link (decsrc, session->recv_rtcp_sink);
gst_object_unref (decsrc);
if (ret != GST_PAD_LINK_OK)
goto dec_link_failed;
} else {
GST_DEBUG_OBJECT (rtpbin, "no RTCP decoder given");
if (session->bundle_demux) {
decsink = gst_element_get_static_pad (session->bundle_demux, "rtcp_sink");
} else {
decsink = gst_element_get_request_pad (session->rtcp_funnel, "sink_%u");
}
decsink = gst_object_ref (session->recv_rtcp_sink);
}
/* get srcpad, link to SSRCDemux */
......@@ -4119,10 +3912,6 @@ complete_session_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session,
gst_pad_link_full (session->sync_src, sinkdpad, GST_PAD_LINK_CHECK_NOTHING);
gst_object_unref (sinkdpad);
funnel_src = gst_element_get_static_pad (session->rtcp_funnel, "src");
gst_pad_link (funnel_src, session->recv_rtcp_sink);
gst_object_unref (funnel_src);
return decsink;
pad_failed:
......@@ -4186,7 +3975,7 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
if (session->recv_rtcp_sink_ghost != NULL)
return session->recv_rtcp_sink_ghost;
decsink = complete_session_rtcp (rtpbin, session, sessid, TRUE);
decsink = complete_session_rtcp (rtpbin, session, sessid);
if (!decsink)
goto create_error;
......
......@@ -137,8 +137,6 @@ struct _GstRtpBinClass {
void (*on_new_sender_ssrc) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
void (*on_sender_ssrc_active) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
guint (*on_bundled_ssrc) (GstRtpBin *rtpbin, guint ssrc);
};
GType gst_rtp_bin_get_type (void);
......
......@@ -246,7 +246,6 @@ if USE_PLUGIN_RTPMANAGER
check_rtpmanager = \
elements/rtpbin \
elements/rtpbin_buffer_list \
elements/rtpbundle \
elements/rtpcollision \
elements/rtpjitterbuffer \
elements/rtpmux \
......@@ -619,9 +618,6 @@ elements_rtpfunnel_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstrtp-$(GST_API_VERSION)
elements_rtpcollision_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
elements_rtpcollision_LDADD = $(GST_PLUGINS_BASE_LIBS) $(GST_NET_LIBS) -lgstrtp-$(GST_API_VERSION) $(GIO_LIBS) $(LDADD)
elements_rtpbundle_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
elements_rtpbundle_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstrtp-$(GST_API_VERSION) $(LDADD)
elements_rtpstorage_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
elements_rtpstorage_LDADD = $(GST_PLUGINS_BASE_LIBS) $(GST_NET_LIBS) -lgstrtp-$(GST_API_VERSION) $(GIO_LIBS) $(LDADD)
......
......@@ -54,7 +54,6 @@ rgvolume
rtp-payloading
rtpbin
rtpbin_buffer_list
rtpbundle
rtpcollision
rtph261
rtph263
......
/* GStreamer
*
* Copyright (C) 2016 Igalia S.L.
* @author Philippe Normand <philn@igalia.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <gst/check/gstcheck.h>
#include <gst/check/gstconsistencychecker.h>
#include <gst/check/gsttestclock.h>
#include <gst/rtp/gstrtpbuffer.h>
static GMainLoop *main_loop;
static void
message_received (GstBus * bus, GstMessage * message, GstPipeline * bin)
{
GST_INFO ("bus message from \"%" GST_PTR_FORMAT "\": %" GST_PTR_FORMAT,
GST_MESSAGE_SRC (message), message);
switch (message->type) {
case GST_MESSAGE_EOS:
g_main_loop_quit (main_loop);
break;
case GST_MESSAGE_WARNING:{
GError *gerror;
gchar *debug;
gst_message_parse_warning (message, &gerror, &debug);
gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
g_error_free (gerror);
g_free (debug);
break;
}
case GST_MESSAGE_ERROR:{
GError *gerror;
gchar *debug;
gst_message_parse_error (message, &gerror, &debug);
gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
g_error_free (gerror);
g_free (debug);
fail ("Error!");
break;
}
default:
break;
}
}
static void
on_rtpbinreceive_pad_added (GstElement * element, GstPad * new_pad,
gpointer data)
{
GstElement *pipeline = GST_ELEMENT (data);
gchar *pad_name = gst_pad_get_name (new_pad);
if (g_str_has_prefix (pad_name, "recv_rtp_src_")) {
GstCaps *caps = gst_pad_get_current_caps (new_pad);
GstStructure *s = gst_caps_get_structure (caps, 0);
const gchar *media_type = gst_structure_get_string (s, "media");
gchar *depayloader_name = g_strdup_printf ("%s_rtpdepayloader", media_type);
GstElement *rtpdepayloader =
gst_bin_get_by_name (GST_BIN (pipeline), depayloader_name);
GstPad *sinkpad;
g_free (depayloader_name);
fail_unless (rtpdepayloader != NULL, NULL);
sinkpad = gst_element_get_static_pad (rtpdepayloader, "sink");
gst_pad_link (new_pad, sinkpad);
gst_object_unref (sinkpad);
gst_object_unref (rtpdepayloader);
gst_caps_unref (caps);
}
g_free (pad_name);
}
static guint
on_bundled_ssrc (GstElement * rtpbin, guint ssrc, gpointer user_data)
{
static gboolean create_session = FALSE;
guint session_id = 0;
if (create_session) {
session_id = 1;
} else {
create_session = TRUE;
/* use existing session 0, a new session will be created for the next discovered bundled SSRC */
}
return session_id;
}
static GstCaps *
on_request_pt_map (GstElement * rtpbin, guint session_id, guint pt,
gpointer user_data)
{
GstCaps *caps = NULL;
if (pt == 96) {
caps =
gst_caps_from_string
("application/x-rtp,media=(string)audio,encoding-name=(string)PCMA,clock-rate=(int)8000");
} else if (pt == 100) {
caps =
gst_caps_from_string
("application/x-rtp,media=(string)video,encoding-name=(string)RAW,clock-rate=(int)90000,sampling=(string)\"YCbCr-4:2:0\",depth=(string)8,width=(string)320,height=(string)240");
}
return caps;
}
static GstElement *
create_pipeline (gboolean send)
{
GstElement *pipeline, *rtpbin, *audiosrc, *audio_encoder,
*audio_rtppayloader, *sendrtp_udpsink, *recv_rtp_udpsrc,
*send_rtcp_udpsink, *recv_rtcp_udpsrc, *sendrtcp_funnel, *sendrtp_funnel;
GstElement *audio_rtpdepayloader, *audio_decoder, *audio_sink;
GstElement *videosrc, *video_rtppayloader, *video_rtpdepayloader, *video_sink;
gboolean res;
GstPad *funnel_pad, *rtp_src_pad;
GstCaps *rtpcaps;
gint rtp_udp_port = 5001;
gint rtcp_udp_port = 5002;
pipeline = gst_pipeline_new (send ? "pipeline_send" : "pipeline_receive");
rtpbin =
gst_element_factory_make ("rtpbin",
send ? "rtpbin_send" : "rtpbin_receive");
g_object_set (rtpbin, "latency", 200, NULL);
if (!send) {
g_signal_connect (rtpbin, "on-bundled-ssrc",
G_CALLBACK (on_bundled_ssrc), NULL);
g_signal_connect (rtpbin, "request-pt-map",
G_CALLBACK (on_request_pt_map), NULL);
}
g_signal_connect (rtpbin, "pad-added",
G_CALLBACK (on_rtpbinreceive_pad_added), pipeline);
gst_bin_add (GST_BIN (pipeline), rtpbin);
if (send) {
audiosrc = gst_element_factory_make ("audiotestsrc", NULL);
audio_encoder = gst_element_factory_make ("alawenc", NULL);
audio_rtppayloader = gst_element_factory_make ("rtppcmapay", NULL);
g_object_set (audio_rtppayloader, "pt", 96, NULL);
g_object_set (audio_rtppayloader, "seqnum-offset", 1, NULL);
videosrc = gst_element_factory_make ("videotestsrc", NULL);
video_rtppayloader = gst_element_factory_make ("rtpvrawpay", NULL);
g_object_set (video_rtppayloader, "pt", 100, "seqnum-offset", 1, NULL);
g_object_set (audiosrc, "num-buffers", 5, NULL);
g_object_set (videosrc, "num-buffers", 5, NULL);
/* muxed rtcp */
sendrtcp_funnel = gst_element_factory_make ("funnel", "send_rtcp_funnel");
send_rtcp_udpsink = gst_element_factory_make ("udpsink", NULL);
g_object_set (send_rtcp_udpsink, "host", "127.0.0.1", NULL);
g_object_set (send_rtcp_udpsink, "port", rtcp_udp_port, NULL);
g_object_set (send_rtcp_udpsink, "sync", FALSE, NULL);
g_object_set (send_rtcp_udpsink, "async", FALSE, NULL);
/* outgoing bundled stream */
sendrtp_funnel = gst_element_factory_make ("funnel", "send_rtp_funnel");
sendrtp_udpsink = gst_element_factory_make ("udpsink", NULL);
g_object_set (sendrtp_udpsink, "host", "127.0.0.1", NULL);
g_object_set (sendrtp_udpsink, "port", rtp_udp_port, NULL);
gst_bin_add_many (GST_BIN (pipeline), audiosrc, audio_encoder,
audio_rtppayloader, sendrtp_udpsink, send_rtcp_udpsink,
sendrtp_funnel, sendrtcp_funnel, videosrc, video_rtppayloader, NULL);
res = gst_element_link (audiosrc, audio_encoder);
fail_unless (res == TRUE, NULL);
res = gst_element_link (audio_encoder, audio_rtppayloader);
fail_unless (res == TRUE, NULL);
res =
gst_element_link_pads_full (audio_rtppayloader, "src", rtpbin,
"send_rtp_sink_0", GST_PAD_LINK_CHECK_NOTHING);
fail_unless (res == TRUE, NULL);
res = gst_element_link (videosrc, video_rtppayloader);
fail_unless (res == TRUE, NULL);
res =
gst_element_link_pads_full (video_rtppayloader, "src", rtpbin,