mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 11:41:09 +00:00
webrtc: implement support for msid values
Local msid values are taken from sink pad property, or fallback to the previously used cname. The remote msid values are exposed on the relevant src pads. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3106>
This commit is contained in:
parent
3bb8700577
commit
993bc8fc01
6 changed files with 511 additions and 53 deletions
|
@ -236665,12 +236665,13 @@
|
|||
"caps": "application/x-rtp:\n",
|
||||
"direction": "sink",
|
||||
"presence": "request",
|
||||
"type": "GstWebRTCBinPad"
|
||||
"type": "GstWebRTCBinSinkPad"
|
||||
},
|
||||
"src_%%u": {
|
||||
"caps": "application/x-rtp:\n",
|
||||
"direction": "src",
|
||||
"presence": "sometimes"
|
||||
"presence": "sometimes",
|
||||
"type": "GstWebRTCBinSrcPad"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
@ -237128,6 +237129,60 @@
|
|||
"writable": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"GstWebRTCBinSinkPad": {
|
||||
"hierarchy": [
|
||||
"GstWebRTCBinSinkPad",
|
||||
"GstWebRTCBinPad",
|
||||
"GstGhostPad",
|
||||
"GstProxyPad",
|
||||
"GstPad",
|
||||
"GstObject",
|
||||
"GInitiallyUnowned",
|
||||
"GObject"
|
||||
],
|
||||
"kind": "object",
|
||||
"properties": {
|
||||
"msid": {
|
||||
"blurb": "Local MediaStream ID to use for this pad (NULL = unset)",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "NULL",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "gchararray",
|
||||
"writable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"GstWebRTCBinSrcPad": {
|
||||
"hierarchy": [
|
||||
"GstWebRTCBinSrcPad",
|
||||
"GstWebRTCBinPad",
|
||||
"GstGhostPad",
|
||||
"GstProxyPad",
|
||||
"GstPad",
|
||||
"GstObject",
|
||||
"GInitiallyUnowned",
|
||||
"GObject"
|
||||
],
|
||||
"kind": "object",
|
||||
"properties": {
|
||||
"msid": {
|
||||
"blurb": "Remote MediaStream ID in use for this pad (NULL = not advertised)",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "NULL",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "gchararray",
|
||||
"writable": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"package": "GStreamer Bad Plug-ins",
|
||||
|
|
|
@ -254,13 +254,9 @@ gst_webrtc_bin_pad_finalize (GObject * object)
|
|||
{
|
||||
GstWebRTCBinPad *pad = GST_WEBRTC_BIN_PAD (object);
|
||||
|
||||
if (pad->trans)
|
||||
gst_object_unref (pad->trans);
|
||||
pad->trans = NULL;
|
||||
|
||||
if (pad->received_caps)
|
||||
gst_caps_unref (pad->received_caps);
|
||||
pad->received_caps = NULL;
|
||||
gst_clear_object (&pad->trans);
|
||||
gst_clear_caps (&pad->received_caps);
|
||||
g_clear_pointer (&pad->msid, g_free);
|
||||
|
||||
G_OBJECT_CLASS (gst_webrtc_bin_pad_parent_class)->finalize (object);
|
||||
}
|
||||
|
@ -457,33 +453,177 @@ gst_webrtc_bin_pad_init (GstWebRTCBinPad * pad)
|
|||
}
|
||||
|
||||
static GstWebRTCBinPad *
|
||||
gst_webrtc_bin_pad_new (const gchar * name, GstPadDirection direction)
|
||||
gst_webrtc_bin_pad_new (const gchar * name, GstPadDirection direction,
|
||||
char *msid)
|
||||
{
|
||||
GstWebRTCBinPad *pad;
|
||||
GstPadTemplate *template;
|
||||
GType pad_type;
|
||||
|
||||
if (direction == GST_PAD_SINK)
|
||||
if (direction == GST_PAD_SINK) {
|
||||
template = gst_static_pad_template_get (&sink_template);
|
||||
else if (direction == GST_PAD_SRC)
|
||||
pad_type = GST_TYPE_WEBRTC_BIN_SINK_PAD;
|
||||
} else if (direction == GST_PAD_SRC) {
|
||||
template = gst_static_pad_template_get (&src_template);
|
||||
else
|
||||
pad_type = GST_TYPE_WEBRTC_BIN_SRC_PAD;
|
||||
} else {
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
pad =
|
||||
g_object_new (gst_webrtc_bin_pad_get_type (), "name", name, "direction",
|
||||
g_object_new (pad_type, "name", name, "direction",
|
||||
direction, "template", template, NULL);
|
||||
gst_object_unref (template);
|
||||
|
||||
if (direction == GST_PAD_SINK) {
|
||||
gst_pad_set_event_function (GST_PAD (pad), gst_webrtcbin_sink_event);
|
||||
gst_pad_set_query_function (GST_PAD (pad), gst_webrtcbin_sink_query);
|
||||
}
|
||||
pad->msid = msid;
|
||||
|
||||
GST_DEBUG_OBJECT (pad, "new visible pad with direction %s",
|
||||
direction == GST_PAD_SRC ? "src" : "sink");
|
||||
return pad;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_SINK_PAD_MSID = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* GstWebRTCBinSinkPad:
|
||||
*
|
||||
* Since: 1.22
|
||||
*/
|
||||
struct _GstWebRTCBinSinkPad
|
||||
{
|
||||
GstWebRTCBinPad pad;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GstWebRTCBinSinkPad, gst_webrtc_bin_sink_pad,
|
||||
GST_TYPE_WEBRTC_BIN_PAD);
|
||||
|
||||
static void
|
||||
gst_webrtc_bin_sink_pad_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstWebRTCBinPad *pad = GST_WEBRTC_BIN_PAD (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_SINK_PAD_MSID:
|
||||
g_value_set_string (value, pad->msid);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_webrtc_bin_sink_pad_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstWebRTCBinPad *pad = GST_WEBRTC_BIN_PAD (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_SINK_PAD_MSID:
|
||||
g_free (pad->msid);
|
||||
pad->msid = g_value_dup_string (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_webrtc_bin_sink_pad_class_init (GstWebRTCBinSinkPadClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||
|
||||
gobject_class->get_property = gst_webrtc_bin_sink_pad_get_property;
|
||||
gobject_class->set_property = gst_webrtc_bin_sink_pad_set_property;
|
||||
|
||||
/**
|
||||
* GstWebRTCBinSinkPad:msid:
|
||||
*
|
||||
* The MediaStream Identifier to use for this pad (MediaStreamTrack).
|
||||
* Fallback is the RTP SDES cname value if not provided.
|
||||
*
|
||||
* Since: 1.22
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_SINK_PAD_MSID,
|
||||
g_param_spec_string ("msid", "MSID",
|
||||
"Local MediaStream ID to use for this pad (NULL = unset)", NULL,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_webrtc_bin_sink_pad_init (GstWebRTCBinSinkPad * pad)
|
||||
{
|
||||
gst_pad_set_event_function (GST_PAD (pad), gst_webrtcbin_sink_event);
|
||||
gst_pad_set_query_function (GST_PAD (pad), gst_webrtcbin_sink_query);
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_SRC_PAD_MSID = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* GstWebRTCBinSrcPad:
|
||||
*
|
||||
* Since: 1.22
|
||||
*/
|
||||
struct _GstWebRTCBinSrcPad
|
||||
{
|
||||
GstWebRTCBinPad pad;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GstWebRTCBinSrcPad, gst_webrtc_bin_src_pad,
|
||||
GST_TYPE_WEBRTC_BIN_PAD);
|
||||
|
||||
static void
|
||||
gst_webrtc_bin_src_pad_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstWebRTCBinPad *pad = GST_WEBRTC_BIN_PAD (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_SRC_PAD_MSID:
|
||||
g_value_set_string (value, pad->msid);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_webrtc_bin_src_pad_class_init (GstWebRTCBinSrcPadClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||
|
||||
gobject_class->get_property = gst_webrtc_bin_src_pad_get_property;
|
||||
|
||||
/**
|
||||
* GstWebRTCBinSrcPad:msid:
|
||||
*
|
||||
* The MediaStream Identifier the remote peer used for this pad (MediaStreamTrack).
|
||||
* Will be NULL if not advertised in the remote SDP.
|
||||
*
|
||||
* Since: 1.22
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_SRC_PAD_MSID,
|
||||
g_param_spec_string ("msid", "MSID",
|
||||
"Remote MediaStream ID in use for this pad (NULL = not advertised)",
|
||||
NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_webrtc_bin_src_pad_init (GstWebRTCBinSrcPad * pad)
|
||||
{
|
||||
}
|
||||
|
||||
#define gst_webrtc_bin_parent_class parent_class
|
||||
G_DEFINE_TYPE_WITH_CODE (GstWebRTCBin, gst_webrtc_bin, GST_TYPE_BIN,
|
||||
G_ADD_PRIVATE (GstWebRTCBin)
|
||||
|
@ -2867,15 +3007,27 @@ _media_add_rtx_ssrc (GQuark field_id, const GValue * value, RtxSsrcData * data)
|
|||
gchar *str;
|
||||
GstStructure *sdes;
|
||||
const gchar *cname;
|
||||
GstWebRTCBinPad *sink_pad;
|
||||
const char *msid = NULL;
|
||||
|
||||
g_object_get (data->webrtc->rtpbin, "sdes", &sdes, NULL);
|
||||
/* http://www.freesoft.org/CIE/RFC/1889/24.htm */
|
||||
cname = gst_structure_get_string (sdes, "cname");
|
||||
|
||||
sink_pad =
|
||||
_find_pad_for_transceiver (data->webrtc, GST_PAD_SINK,
|
||||
GST_WEBRTC_RTP_TRANSCEIVER (data->trans));
|
||||
if (sink_pad)
|
||||
msid = sink_pad->msid;
|
||||
/* fallback to cname if no msid provided */
|
||||
if (!msid)
|
||||
msid = cname;
|
||||
|
||||
/* https://tools.ietf.org/html/draft-ietf-mmusic-msid-16 */
|
||||
/* FIXME: the ssrc is not present in RFC8830, do we still need that? */
|
||||
str =
|
||||
g_strdup_printf ("%u msid:%s %s", g_value_get_uint (value),
|
||||
cname, GST_OBJECT_NAME (data->trans));
|
||||
msid, GST_OBJECT_NAME (data->trans));
|
||||
gst_sdp_media_add_attribute (data->media, "ssrc", str);
|
||||
g_free (str);
|
||||
|
||||
|
@ -2883,6 +3035,7 @@ _media_add_rtx_ssrc (GQuark field_id, const GValue * value, RtxSsrcData * data)
|
|||
gst_sdp_media_add_attribute (data->media, "ssrc", str);
|
||||
g_free (str);
|
||||
|
||||
gst_clear_object (&sink_pad);
|
||||
gst_structure_free (sdes);
|
||||
|
||||
return TRUE;
|
||||
|
@ -2911,10 +3064,22 @@ _media_add_ssrcs (GstSDPMedia * media, GstCaps * caps, GstWebRTCBin * webrtc,
|
|||
|
||||
if (gst_structure_get_uint (s, "ssrc", &ssrc)) {
|
||||
gchar *str;
|
||||
GstWebRTCBinPad *sink_pad;
|
||||
const char *msid = NULL;
|
||||
|
||||
sink_pad =
|
||||
_find_pad_for_transceiver (webrtc, GST_PAD_SINK,
|
||||
GST_WEBRTC_RTP_TRANSCEIVER (trans));
|
||||
if (sink_pad)
|
||||
msid = sink_pad->msid;
|
||||
/* fallback to cname if no msid provided */
|
||||
if (!msid)
|
||||
msid = cname;
|
||||
|
||||
/* https://tools.ietf.org/html/draft-ietf-mmusic-msid-16 */
|
||||
/* FIXME: the ssrc is not present in RFC8830, do we still need that? */
|
||||
str =
|
||||
g_strdup_printf ("%u msid:%s %s", ssrc, cname,
|
||||
g_strdup_printf ("%u msid:%s %s", ssrc, msid,
|
||||
GST_OBJECT_NAME (trans));
|
||||
gst_sdp_media_add_attribute (media, "ssrc", str);
|
||||
g_free (str);
|
||||
|
@ -2922,6 +3087,8 @@ _media_add_ssrcs (GstSDPMedia * media, GstCaps * caps, GstWebRTCBin * webrtc,
|
|||
str = g_strdup_printf ("%u cname:%s", ssrc, cname);
|
||||
gst_sdp_media_add_attribute (media, "ssrc", str);
|
||||
g_free (str);
|
||||
|
||||
gst_clear_object (&sink_pad);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4697,7 +4864,7 @@ gst_webrtc_bin_create_answer (GstWebRTCBin * webrtc,
|
|||
|
||||
static GstWebRTCBinPad *
|
||||
_create_pad_for_sdp_media (GstWebRTCBin * webrtc, GstPadDirection direction,
|
||||
GstWebRTCRTPTransceiver * trans, guint serial)
|
||||
GstWebRTCRTPTransceiver * trans, guint serial, char *msid)
|
||||
{
|
||||
GstWebRTCBinPad *pad;
|
||||
gchar *pad_name;
|
||||
|
@ -4712,7 +4879,7 @@ _create_pad_for_sdp_media (GstWebRTCBin * webrtc, GstPadDirection direction,
|
|||
pad_name =
|
||||
g_strdup_printf ("%s_%u", direction == GST_PAD_SRC ? "src" : "sink",
|
||||
serial);
|
||||
pad = gst_webrtc_bin_pad_new (pad_name, direction);
|
||||
pad = gst_webrtc_bin_pad_new (pad_name, direction, msid);
|
||||
g_free (pad_name);
|
||||
|
||||
pad->trans = gst_object_ref (trans);
|
||||
|
@ -5420,12 +5587,21 @@ _update_transceiver_from_sdp_media (GstWebRTCBin * webrtc,
|
|||
WebRTCTransceiver *trans = WEBRTC_TRANSCEIVER (rtp_trans);
|
||||
GstWebRTCRTPTransceiverDirection prev_dir = rtp_trans->current_direction;
|
||||
GstWebRTCRTPTransceiverDirection new_dir;
|
||||
const GstSDPMedia *local_media, *remote_media;
|
||||
const GstSDPMedia *media = gst_sdp_message_get_media (sdp, media_idx);
|
||||
GstWebRTCDTLSSetup new_setup;
|
||||
char *local_msid = NULL;
|
||||
gboolean new_rtcp_rsize;
|
||||
ReceiveState receive_state = RECEIVE_STATE_UNSET;
|
||||
int i;
|
||||
|
||||
local_media =
|
||||
gst_sdp_message_get_media (webrtc->current_local_description->sdp,
|
||||
media_idx);
|
||||
remote_media =
|
||||
gst_sdp_message_get_media (webrtc->current_remote_description->sdp,
|
||||
media_idx);
|
||||
|
||||
rtp_trans->mline = media_idx;
|
||||
|
||||
if (!g_strcmp0 (gst_sdp_media_get_media (media), "audio")) {
|
||||
|
@ -5452,17 +5628,9 @@ _update_transceiver_from_sdp_media (GstWebRTCBin * webrtc,
|
|||
}
|
||||
|
||||
{
|
||||
const GstSDPMedia *local_media, *remote_media;
|
||||
GstWebRTCRTPTransceiverDirection local_dir, remote_dir;
|
||||
GstWebRTCDTLSSetup local_setup, remote_setup;
|
||||
|
||||
local_media =
|
||||
gst_sdp_message_get_media (webrtc->current_local_description->sdp,
|
||||
media_idx);
|
||||
remote_media =
|
||||
gst_sdp_message_get_media (webrtc->current_remote_description->sdp,
|
||||
media_idx);
|
||||
|
||||
local_setup = _get_dtls_setup_from_media (local_media);
|
||||
remote_setup = _get_dtls_setup_from_media (remote_media);
|
||||
new_setup = _get_final_setup (local_setup, remote_setup);
|
||||
|
@ -5555,16 +5723,30 @@ _update_transceiver_from_sdp_media (GstWebRTCBin * webrtc,
|
|||
new_dir == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV) {
|
||||
GstWebRTCBinPad *pad =
|
||||
_find_pad_for_transceiver (webrtc, GST_PAD_SINK, rtp_trans);
|
||||
local_msid = _get_msid_from_media (local_media);
|
||||
|
||||
if (pad) {
|
||||
GST_DEBUG_OBJECT (webrtc, "found existing send pad %" GST_PTR_FORMAT
|
||||
" for transceiver %" GST_PTR_FORMAT, pad, trans);
|
||||
" for transceiver %" GST_PTR_FORMAT " with msid \'%s\'", pad, trans,
|
||||
pad->msid);
|
||||
if (g_strcmp0 (pad->msid, local_msid) != 0) {
|
||||
GST_DEBUG_OBJECT (webrtc, "send pad %" GST_PTR_FORMAT
|
||||
" transceiver %" GST_PTR_FORMAT " changing msid from \'%s\'"
|
||||
" to \'%s\'", pad, trans, pad->msid, local_msid);
|
||||
g_clear_pointer (&pad->msid, g_free);
|
||||
pad->msid = local_msid;
|
||||
g_object_notify (G_OBJECT (pad), "msid");
|
||||
local_msid = NULL;
|
||||
} else {
|
||||
g_clear_pointer (&local_msid, g_free);
|
||||
}
|
||||
gst_object_unref (pad);
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (webrtc,
|
||||
"creating new send pad for transceiver %" GST_PTR_FORMAT, trans);
|
||||
pad = _create_pad_for_sdp_media (webrtc, GST_PAD_SINK, rtp_trans,
|
||||
G_MAXUINT);
|
||||
G_MAXUINT, local_msid);
|
||||
local_msid = NULL;
|
||||
_connect_input_stream (webrtc, pad);
|
||||
_add_pad (webrtc, pad);
|
||||
}
|
||||
|
@ -5573,15 +5755,30 @@ _update_transceiver_from_sdp_media (GstWebRTCBin * webrtc,
|
|||
new_dir == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV) {
|
||||
GstWebRTCBinPad *pad =
|
||||
_find_pad_for_transceiver (webrtc, GST_PAD_SRC, rtp_trans);
|
||||
char *remote_msid = _get_msid_from_media (remote_media);
|
||||
|
||||
if (pad) {
|
||||
GST_DEBUG_OBJECT (webrtc, "found existing receive pad %" GST_PTR_FORMAT
|
||||
" for transceiver %" GST_PTR_FORMAT, pad, trans);
|
||||
" for transceiver %" GST_PTR_FORMAT " with msid \'%s\'", pad, trans,
|
||||
pad->msid);
|
||||
if (g_strcmp0 (pad->msid, remote_msid) != 0) {
|
||||
GST_DEBUG_OBJECT (webrtc, "receive pad %" GST_PTR_FORMAT
|
||||
" transceiver %" GST_PTR_FORMAT " changing msid from \'%s\'"
|
||||
" to \'%s\'", pad, trans, pad->msid, remote_msid);
|
||||
g_clear_pointer (&pad->msid, g_free);
|
||||
pad->msid = remote_msid;
|
||||
remote_msid = NULL;
|
||||
g_object_notify (G_OBJECT (pad), "msid");
|
||||
} else {
|
||||
g_clear_pointer (&remote_msid, g_free);
|
||||
}
|
||||
gst_object_unref (pad);
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (webrtc,
|
||||
"creating new receive pad for transceiver %" GST_PTR_FORMAT, trans);
|
||||
pad = _create_pad_for_sdp_media (webrtc, GST_PAD_SRC, rtp_trans,
|
||||
G_MAXUINT);
|
||||
G_MAXUINT, remote_msid);
|
||||
remote_msid = NULL;
|
||||
|
||||
if (!trans->stream) {
|
||||
TransportStream *item;
|
||||
|
@ -5597,7 +5794,6 @@ _update_transceiver_from_sdp_media (GstWebRTCBin * webrtc,
|
|||
* as soon as the pad is added */
|
||||
_add_pad_to_list (webrtc, pad);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rtp_trans->mline = media_idx;
|
||||
|
@ -7058,7 +7254,8 @@ on_rtpbin_pad_added (GstElement * rtpbin, GstPad * new_pad,
|
|||
* or somesuch */
|
||||
gst_clear_object (&pad);
|
||||
pad =
|
||||
_create_pad_for_sdp_media (webrtc, GST_PAD_SRC, rtp_trans, G_MAXUINT);
|
||||
_create_pad_for_sdp_media (webrtc, GST_PAD_SRC, rtp_trans, G_MAXUINT,
|
||||
NULL);
|
||||
GST_TRACE_OBJECT (webrtc,
|
||||
"duplicate output ssrc? created new pad %" GST_PTR_FORMAT " for %"
|
||||
GST_PTR_FORMAT " for rtp pad %s", pad, rtp_trans, new_pad_name);
|
||||
|
@ -7940,7 +8137,7 @@ gst_webrtc_bin_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
|||
}
|
||||
}
|
||||
}
|
||||
pad = _create_pad_for_sdp_media (webrtc, GST_PAD_SINK, trans, serial);
|
||||
pad = _create_pad_for_sdp_media (webrtc, GST_PAD_SINK, trans, serial, NULL);
|
||||
|
||||
pad->block_id = gst_pad_add_probe (GST_PAD (pad), GST_PAD_PROBE_TYPE_BLOCK |
|
||||
GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST,
|
||||
|
@ -8265,8 +8462,9 @@ gst_webrtc_bin_class_init (GstWebRTCBinClass * klass)
|
|||
element_class->change_state = gst_webrtc_bin_change_state;
|
||||
|
||||
gst_element_class_add_static_pad_template_with_gtype (element_class,
|
||||
&sink_template, GST_TYPE_WEBRTC_BIN_PAD);
|
||||
gst_element_class_add_static_pad_template (element_class, &src_template);
|
||||
&sink_template, GST_TYPE_WEBRTC_BIN_SINK_PAD);
|
||||
gst_element_class_add_static_pad_template_with_gtype (element_class,
|
||||
&src_template, GST_TYPE_WEBRTC_BIN_SRC_PAD);
|
||||
|
||||
gst_element_class_set_metadata (element_class, "WebRTC Bin",
|
||||
"Filter/Network/WebRTC", "A bin for webrtc connections",
|
||||
|
@ -8764,6 +8962,8 @@ gst_webrtc_bin_class_init (GstWebRTCBinClass * klass)
|
|||
NULL, GST_TYPE_WEBRTC_DATA_CHANNEL, 2, G_TYPE_STRING, GST_TYPE_STRUCTURE);
|
||||
|
||||
gst_type_mark_as_plugin_api (GST_TYPE_WEBRTC_BIN_PAD, 0);
|
||||
gst_type_mark_as_plugin_api (GST_TYPE_WEBRTC_BIN_SINK_PAD, 0);
|
||||
gst_type_mark_as_plugin_api (GST_TYPE_WEBRTC_BIN_SRC_PAD, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -38,6 +38,8 @@ GType gst_webrtc_bin_pad_get_type(void);
|
|||
typedef struct _GstWebRTCBinPad GstWebRTCBinPad;
|
||||
typedef struct _GstWebRTCBinPadClass GstWebRTCBinPadClass;
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstWebRTCBinPad, gst_object_unref);
|
||||
|
||||
struct _GstWebRTCBinPad
|
||||
{
|
||||
GstGhostPad parent;
|
||||
|
@ -46,6 +48,7 @@ struct _GstWebRTCBinPad
|
|||
gulong block_id;
|
||||
|
||||
GstCaps *received_caps;
|
||||
char *msid;
|
||||
};
|
||||
|
||||
struct _GstWebRTCBinPadClass
|
||||
|
@ -53,6 +56,14 @@ struct _GstWebRTCBinPadClass
|
|||
GstGhostPadClass parent_class;
|
||||
};
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GstWebRTCBinSinkPad, gst_webrtc_bin_sink_pad, GST,
|
||||
WEBRTC_BIN_SINK_PAD, GstWebRTCBinPad);
|
||||
#define GST_TYPE_WEBRTC_BIN_SINK_PAD (gst_webrtc_bin_sink_pad_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GstWebRTCBinSrcPad, gst_webrtc_bin_src_pad, GST,
|
||||
WEBRTC_BIN_SRC_PAD, GstWebRTCBinPad);
|
||||
#define GST_TYPE_WEBRTC_BIN_SRC_PAD (gst_webrtc_bin_src_pad_get_type())
|
||||
|
||||
GType gst_webrtc_bin_get_type(void);
|
||||
#define GST_TYPE_WEBRTC_BIN (gst_webrtc_bin_get_type())
|
||||
#define GST_WEBRTC_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WEBRTC_BIN,GstWebRTCBin))
|
||||
|
|
|
@ -223,3 +223,28 @@ webrtc_kind_from_caps (const GstCaps * caps)
|
|||
|
||||
return GST_WEBRTC_KIND_UNKNOWN;
|
||||
}
|
||||
|
||||
char *
|
||||
_get_msid_from_media (const GstSDPMedia * media)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < gst_sdp_media_attributes_len (media); i++) {
|
||||
const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, i);
|
||||
const char *start, *end;
|
||||
|
||||
if (!attr->value)
|
||||
continue;
|
||||
|
||||
start = strstr (attr->value, "msid:");
|
||||
if (!start)
|
||||
continue;
|
||||
|
||||
start += strlen ("msid:");
|
||||
end = strstr (start, " ");
|
||||
if (end)
|
||||
return g_strndup (start, end - start);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -66,6 +66,8 @@ G_GNUC_INTERNAL
|
|||
GstCaps * _rtp_caps_from_media (const GstSDPMedia * media);
|
||||
G_GNUC_INTERNAL
|
||||
GstWebRTCKind webrtc_kind_from_caps (const GstCaps * caps);
|
||||
G_GNUC_INTERNAL
|
||||
char * _get_msid_from_media (const GstSDPMedia * media);
|
||||
|
||||
#define gst_webrtc_kind_to_string(kind) _enum_value_to_string(GST_TYPE_WEBRTC_KIND, kind)
|
||||
#define gst_webrtc_rtp_transceiver_direction_to_string(dir) _enum_value_to_string(GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION, dir)
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
|
||||
typedef enum
|
||||
{
|
||||
STATE_NEW,
|
||||
STATE_NEW = 1,
|
||||
STATE_NEGOTIATION_NEEDED,
|
||||
STATE_OFFER_CREATED,
|
||||
STATE_OFFER_SET,
|
||||
|
@ -776,27 +776,56 @@ test_webrtc_create_offer (struct test_webrtc *t)
|
|||
}
|
||||
|
||||
static TestState
|
||||
test_webrtc_wait_for_state_mask (struct test_webrtc *t, TestState state)
|
||||
test_webrtc_check_for_state_mask_unlocked (struct test_webrtc *t,
|
||||
TestState state)
|
||||
{
|
||||
guint i;
|
||||
|
||||
GST_LOG ("attempting to check for state mask 0x%x", state);
|
||||
for (i = 0; i < t->states->len; i++) {
|
||||
TestState val = g_array_index (t->states, TestState, i);
|
||||
|
||||
if (((1 << val) & state) != 0) {
|
||||
GST_DEBUG ("found state 0x%x in wait mask 0x%x at idx %u", val, state, i);
|
||||
g_array_remove_range (t->states, 0, i + 1);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TestState
|
||||
test_webrtc_check_for_state_mask (struct test_webrtc *t, TestState state)
|
||||
{
|
||||
TestState ret;
|
||||
|
||||
g_mutex_lock (&t->lock);
|
||||
ret = test_webrtc_check_for_state_mask_unlocked (t, state);
|
||||
g_mutex_unlock (&t->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static TestState
|
||||
test_webrtc_wait_for_state_mask (struct test_webrtc *t, TestState state)
|
||||
{
|
||||
TestState ret = 0;
|
||||
|
||||
g_mutex_lock (&t->lock);
|
||||
|
||||
GST_LOG ("attempting to wait for state mask 0x%x", state);
|
||||
while (TRUE) {
|
||||
for (i = 0; i < t->states->len; i++) {
|
||||
TestState val = g_array_index (t->states, TestState, i);
|
||||
ret = test_webrtc_check_for_state_mask_unlocked (t, state);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (((1 << val) & state) != 0) {
|
||||
GST_DEBUG ("found state 0x%x in wait mask 0x%x at idx %u", val, state,
|
||||
i);
|
||||
g_array_remove_range (t->states, 0, i + 1);
|
||||
g_mutex_unlock (&t->lock);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
g_cond_wait (&t->cond, &t->lock);
|
||||
}
|
||||
g_mutex_unlock (&t->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static TestState
|
||||
|
@ -3862,7 +3891,7 @@ GST_START_TEST (test_codec_preferences_incompatible_extmaps)
|
|||
t->on_ice_candidate = NULL;
|
||||
t->on_offer_created = offer_created_produced_error;
|
||||
|
||||
test_validate_sdp_full (t, NULL, NULL, STATE_OFFER_CREATED, TRUE);
|
||||
test_validate_sdp_full (t, NULL, NULL, 1 << STATE_ERROR, TRUE);
|
||||
|
||||
test_webrtc_free (t);
|
||||
}
|
||||
|
@ -3895,7 +3924,7 @@ GST_START_TEST (test_codec_preferences_invalid_extmap)
|
|||
t->on_ice_candidate = NULL;
|
||||
t->on_offer_created = offer_created_produced_error;
|
||||
|
||||
test_validate_sdp_full (t, NULL, NULL, STATE_OFFER_CREATED, TRUE);
|
||||
test_validate_sdp_full (t, NULL, NULL, 1 << STATE_ERROR, TRUE);
|
||||
|
||||
test_webrtc_free (t);
|
||||
}
|
||||
|
@ -5540,6 +5569,141 @@ GST_START_TEST (test_data_channel_recreate_offer)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
static void
|
||||
validate_msid (struct test_webrtc *t, GstElement * element,
|
||||
GstWebRTCSessionDescription * desc, gpointer user_data)
|
||||
{
|
||||
char **expected_msid = user_data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < gst_sdp_message_medias_len (desc->sdp); i++) {
|
||||
const GstSDPMedia *media = gst_sdp_message_get_media (desc->sdp, i);
|
||||
gboolean have_msid = FALSE;
|
||||
char *prev_msid = NULL;
|
||||
int j;
|
||||
|
||||
for (j = 0; j < gst_sdp_media_attributes_len (media); j++) {
|
||||
const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, j);
|
||||
const char *start;
|
||||
|
||||
if (!attr->value)
|
||||
continue;
|
||||
|
||||
start = strstr (attr->value, "msid:");
|
||||
if (start) {
|
||||
const char *end;
|
||||
char *msid;
|
||||
|
||||
start += strlen ("msid:");
|
||||
end = strstr (start, " ");
|
||||
msid = g_strndup (start, end - start);
|
||||
fail_unless (end, "Invalid msid attribute");
|
||||
fail_if (have_msid && g_strcmp0 (prev_msid, msid) != 0,
|
||||
"different values for multiple msid values at mline %u, "
|
||||
"prev msid %s, msid %s", i, prev_msid, msid);
|
||||
have_msid = TRUE;
|
||||
fail_unless_equals_string (msid, expected_msid[i]);
|
||||
g_clear_pointer (&prev_msid, g_free);
|
||||
prev_msid = msid;
|
||||
}
|
||||
}
|
||||
g_clear_pointer (&prev_msid, g_free);
|
||||
fail_unless (have_msid, "no msid attribute in media %u", i);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_pad_added_src_check_msid (struct test_webrtc *t, GstElement * element,
|
||||
GstPad * pad, gpointer user_data)
|
||||
{
|
||||
const char *expected_msid = user_data;
|
||||
char *msid;
|
||||
|
||||
if (GST_PAD_DIRECTION (pad) != GST_PAD_SRC)
|
||||
return;
|
||||
|
||||
g_object_get (pad, "msid", &msid, NULL);
|
||||
fail_unless_equals_string (msid, expected_msid);
|
||||
g_clear_pointer (&msid, g_free);
|
||||
|
||||
test_webrtc_signal_state_unlocked (t, STATE_CUSTOM);
|
||||
}
|
||||
|
||||
GST_START_TEST (test_msid)
|
||||
{
|
||||
struct test_webrtc *t = create_audio_test ();
|
||||
VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads,
|
||||
NULL, NULL);
|
||||
guint media_format_count[] = { 1, 5 };
|
||||
VAL_SDP_INIT (media_formats, on_sdp_media_count_formats,
|
||||
media_format_count, &no_duplicate_payloads);
|
||||
VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (2),
|
||||
&media_formats);
|
||||
const gchar *expected_offer_msid[] = { "a1", "a1", };
|
||||
VAL_SDP_INIT (offer_msid, validate_msid, expected_offer_msid, &count);
|
||||
const gchar *expected_offer_setup[] = { "actpass", "actpass", };
|
||||
VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup,
|
||||
&offer_msid);
|
||||
const gchar *expected_offer_direction[] = { "sendrecv", "sendrecv", };
|
||||
VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction,
|
||||
&offer_setup);
|
||||
const gchar *expected_answer_setup[] = { "active", "active", };
|
||||
VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup,
|
||||
&count);
|
||||
const gchar *expected_answer_direction[] = { "recvonly", "recvonly", };
|
||||
VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction,
|
||||
&answer_setup);
|
||||
GstPad *pad;
|
||||
GstHarness *src;
|
||||
GstElement *rtpbin2;
|
||||
|
||||
t->on_pad_added = _pad_added_src_check_msid;
|
||||
t->pad_added_data = (gpointer) "a1";
|
||||
|
||||
rtpbin2 = gst_bin_get_by_name (GST_BIN (t->webrtc2), "rtpbin");
|
||||
fail_unless (rtpbin2 != NULL);
|
||||
g_signal_connect (rtpbin2, "new-jitterbuffer",
|
||||
G_CALLBACK (new_jitterbuffer_set_fast_start), NULL);
|
||||
g_object_unref (rtpbin2);
|
||||
|
||||
g_signal_connect (t->webrtc1, "on-new-transceiver",
|
||||
G_CALLBACK (on_new_transceiver_set_rtx_fec), NULL);
|
||||
g_signal_connect (t->webrtc2, "on-new-transceiver",
|
||||
G_CALLBACK (on_new_transceiver_set_rtx_fec), NULL);
|
||||
|
||||
src = gst_harness_new_with_element (t->webrtc1, "sink_1", NULL);
|
||||
add_audio_test_src_harness (src, 0x12345678);
|
||||
t->harnesses = g_list_prepend (t->harnesses, src);
|
||||
|
||||
pad = gst_element_get_static_pad (t->webrtc1, "sink_0");
|
||||
g_object_set (pad, "msid", "a1", NULL);
|
||||
gst_clear_object (&pad);
|
||||
|
||||
pad = gst_element_get_static_pad (t->webrtc1, "sink_1");
|
||||
g_object_set (pad, "msid", "a1", NULL);
|
||||
gst_clear_object (&pad);
|
||||
|
||||
test_validate_sdp (t, &offer, &answer);
|
||||
|
||||
fail_if (gst_element_set_state (t->webrtc1,
|
||||
GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
|
||||
fail_if (gst_element_set_state (t->webrtc2,
|
||||
GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE);
|
||||
|
||||
while (TRUE) {
|
||||
gst_harness_push_from_src (src);
|
||||
|
||||
if (test_webrtc_check_for_state_mask (t, 1 << STATE_CUSTOM))
|
||||
break;
|
||||
|
||||
g_usleep (10 * 1000);
|
||||
}
|
||||
|
||||
test_webrtc_free (t);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
webrtcbin_suite (void)
|
||||
{
|
||||
|
@ -5604,6 +5768,7 @@ webrtcbin_suite (void)
|
|||
tcase_add_test (tc, test_bundle_multiple_media_rtx_payload_mapping);
|
||||
tcase_add_test (tc, test_invalid_add_media_in_answer);
|
||||
tcase_add_test (tc, test_add_turn_server);
|
||||
tcase_add_test (tc, test_msid);
|
||||
if (sctpenc && sctpdec) {
|
||||
tcase_add_test (tc, test_data_channel_create);
|
||||
tcase_add_test (tc, test_data_channel_remote_notify);
|
||||
|
|
Loading…
Reference in a new issue