mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
webrtc: Set the DSCP markings based on the priority
This matches how the WebRTC javascript API works and the Chrome implementation. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1425>
This commit is contained in:
parent
39723dbe93
commit
8ba08598bb
9 changed files with 308 additions and 1 deletions
|
@ -31,6 +31,8 @@
|
|||
#include "webrtcdatachannel.h"
|
||||
#include "sctptransport.h"
|
||||
|
||||
#include <gst/rtp/rtp.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -247,6 +249,21 @@ gst_webrtc_bin_pad_class_init (GstWebRTCBinPadClass * klass)
|
|||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_webrtc_bin_pad_update_ssrc_event (GstWebRTCBinPad * wpad)
|
||||
{
|
||||
if (wpad->received_caps) {
|
||||
WebRTCTransceiver *trans = (WebRTCTransceiver *) wpad->trans;
|
||||
GstPad *pad = GST_PAD (wpad);
|
||||
|
||||
trans->ssrc_event =
|
||||
gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_STICKY,
|
||||
gst_structure_new ("GstWebRtcBinUpdateTos", "ssrc", G_TYPE_UINT,
|
||||
trans->current_ssrc, NULL));
|
||||
gst_pad_send_event (pad, gst_event_ref (trans->ssrc_event));
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_webrtcbin_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||
{
|
||||
|
@ -272,6 +289,7 @@ gst_webrtcbin_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
|||
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
gst_structure_get_uint (s, "ssrc", &trans->current_ssrc);
|
||||
gst_webrtc_bin_pad_update_ssrc_event (wpad);
|
||||
}
|
||||
} else if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
|
||||
check_negotiation = TRUE;
|
||||
|
@ -1635,6 +1653,242 @@ _on_dtls_transport_notify_state (GstWebRTCDTLSTransport * transport,
|
|||
_update_peer_connection_state (webrtc);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
match_ssrc (GstWebRTCRTPTransceiver * rtp_trans, gconstpointer data)
|
||||
{
|
||||
WebRTCTransceiver *trans = (WebRTCTransceiver *) rtp_trans;
|
||||
|
||||
return (trans->current_ssrc == GPOINTER_TO_UINT (data));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_on_sending_rtcp (GObject * internal_session, GstBuffer * buffer,
|
||||
gboolean early, gpointer user_data)
|
||||
{
|
||||
GstWebRTCBin *webrtc = user_data;
|
||||
GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
|
||||
GstRTCPPacket packet;
|
||||
|
||||
if (!gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp))
|
||||
goto done;
|
||||
|
||||
if (gst_rtcp_buffer_get_first_packet (&rtcp, &packet)) {
|
||||
if (gst_rtcp_packet_get_type (&packet) == GST_RTCP_TYPE_SR) {
|
||||
guint32 ssrc;
|
||||
GstWebRTCRTPTransceiver *rtp_trans;
|
||||
WebRTCTransceiver *trans;
|
||||
|
||||
gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, NULL, NULL, NULL,
|
||||
NULL);
|
||||
|
||||
rtp_trans = _find_transceiver (webrtc, GUINT_TO_POINTER (ssrc),
|
||||
match_ssrc);
|
||||
trans = (WebRTCTransceiver *) rtp_trans;
|
||||
|
||||
if (rtp_trans && rtp_trans->sender && trans->ssrc_event) {
|
||||
GstPad *pad;
|
||||
gchar *pad_name = NULL;
|
||||
|
||||
pad_name =
|
||||
g_strdup_printf ("send_rtcp_src_%u",
|
||||
rtp_trans->sender->rtcp_transport->session_id);
|
||||
pad = gst_element_get_static_pad (webrtc->rtpbin, pad_name);
|
||||
g_free (pad_name);
|
||||
if (pad) {
|
||||
gst_pad_push_event (pad, gst_event_ref (trans->ssrc_event));
|
||||
gst_object_unref (pad);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gst_rtcp_buffer_unmap (&rtcp);
|
||||
|
||||
done:
|
||||
/* False means we don't care about suppression */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_webrtc_bin_attach_tos_to_session (GstWebRTCBin * webrtc, guint session_id)
|
||||
{
|
||||
GObject *internal_session = NULL;
|
||||
|
||||
g_signal_emit_by_name (webrtc->rtpbin, "get-internal-session",
|
||||
session_id, &internal_session);
|
||||
|
||||
if (internal_session) {
|
||||
g_signal_connect (internal_session, "on-sending-rtcp",
|
||||
G_CALLBACK (_on_sending_rtcp), webrtc);
|
||||
g_object_unref (internal_session);
|
||||
}
|
||||
}
|
||||
|
||||
static GstPadProbeReturn
|
||||
_nicesink_pad_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
|
||||
{
|
||||
GstWebRTCBin *webrtc = user_data;
|
||||
|
||||
if (GST_EVENT_TYPE (GST_PAD_PROBE_INFO_EVENT (info))
|
||||
== GST_EVENT_CUSTOM_DOWNSTREAM_STICKY) {
|
||||
const GstStructure *s =
|
||||
gst_event_get_structure (GST_PAD_PROBE_INFO_EVENT (info));
|
||||
|
||||
if (gst_structure_has_name (s, "GstWebRtcBinUpdateTos")) {
|
||||
guint ssrc;
|
||||
gint priority;
|
||||
|
||||
if (gst_structure_get_uint (s, "ssrc", &ssrc)) {
|
||||
GstWebRTCRTPTransceiver *rtp_trans;
|
||||
|
||||
rtp_trans = _find_transceiver (webrtc, GUINT_TO_POINTER (ssrc),
|
||||
match_ssrc);
|
||||
if (rtp_trans) {
|
||||
WebRTCTransceiver *trans = WEBRTC_TRANSCEIVER (rtp_trans);
|
||||
GstWebRTCICEStream *stream = _find_ice_stream_for_session (webrtc,
|
||||
trans->stream->session_id);
|
||||
guint8 dscp = 0;
|
||||
|
||||
/* Set DSCP field based on
|
||||
* https://tools.ietf.org/html/draft-ietf-tsvwg-rtcweb-qos-18#section-5
|
||||
*/
|
||||
switch (rtp_trans->sender->priority) {
|
||||
case GST_WEBRTC_PRIORITY_TYPE_VERY_LOW:
|
||||
dscp = 8; /* CS1 */
|
||||
break;
|
||||
case GST_WEBRTC_PRIORITY_TYPE_LOW:
|
||||
dscp = 0; /* DF */
|
||||
break;
|
||||
case GST_WEBRTC_PRIORITY_TYPE_MEDIUM:
|
||||
switch (rtp_trans->kind) {
|
||||
case GST_WEBRTC_KIND_AUDIO:
|
||||
dscp = 46; /* EF */
|
||||
break;
|
||||
case GST_WEBRTC_KIND_VIDEO:
|
||||
dscp = 38; /* AF43 *//* TODO: differentiate non-interactive */
|
||||
break;
|
||||
case GST_WEBRTC_KIND_UNKNOWN:
|
||||
dscp = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GST_WEBRTC_PRIORITY_TYPE_HIGH:
|
||||
switch (rtp_trans->kind) {
|
||||
case GST_WEBRTC_KIND_AUDIO:
|
||||
dscp = 46; /* EF */
|
||||
break;
|
||||
case GST_WEBRTC_KIND_VIDEO:
|
||||
dscp = 36; /* AF42 *//* TODO: differentiate non-interactive */
|
||||
break;
|
||||
case GST_WEBRTC_KIND_UNKNOWN:
|
||||
dscp = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
gst_webrtc_ice_set_tos (webrtc->priv->ice, stream, dscp << 2);
|
||||
}
|
||||
} else if (gst_structure_get_enum (s, "sctp-priority",
|
||||
GST_TYPE_WEBRTC_PRIORITY_TYPE, &priority)) {
|
||||
guint8 dscp = 0;
|
||||
|
||||
/* Set DSCP field based on
|
||||
* https://tools.ietf.org/html/draft-ietf-tsvwg-rtcweb-qos-18#section-5
|
||||
*/
|
||||
switch (priority) {
|
||||
case GST_WEBRTC_PRIORITY_TYPE_VERY_LOW:
|
||||
dscp = 8; /* CS1 */
|
||||
break;
|
||||
case GST_WEBRTC_PRIORITY_TYPE_LOW:
|
||||
dscp = 0; /* DF */
|
||||
break;
|
||||
case GST_WEBRTC_PRIORITY_TYPE_MEDIUM:
|
||||
dscp = 10; /* AF11 */
|
||||
break;
|
||||
case GST_WEBRTC_PRIORITY_TYPE_HIGH:
|
||||
dscp = 18; /* AF21 */
|
||||
break;
|
||||
}
|
||||
if (webrtc->priv->data_channel_transport)
|
||||
gst_webrtc_ice_set_tos (webrtc->priv->ice,
|
||||
webrtc->priv->data_channel_transport->stream, dscp << 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return GST_PAD_PROBE_OK;
|
||||
}
|
||||
|
||||
static void gst_webrtc_bin_attach_tos (GstWebRTCBin * webrtc);
|
||||
|
||||
static void
|
||||
gst_webrtc_bin_update_sctp_priority (GstWebRTCBin * webrtc)
|
||||
{
|
||||
GstWebRTCPriorityType sctp_priority = 0;
|
||||
guint i;
|
||||
|
||||
if (!webrtc->priv->sctp_transport)
|
||||
return;
|
||||
|
||||
for (i = 0; i < webrtc->priv->data_channels->len; i++) {
|
||||
GstWebRTCDataChannel *channel
|
||||
= g_ptr_array_index (webrtc->priv->data_channels, i);
|
||||
|
||||
sctp_priority = MAX (sctp_priority, channel->priority);
|
||||
}
|
||||
|
||||
/* Default priority is low means DSCP field is left as 0 */
|
||||
if (sctp_priority == 0)
|
||||
sctp_priority = GST_WEBRTC_PRIORITY_TYPE_LOW;
|
||||
|
||||
/* Nobody asks for DSCP, leave it as-is */
|
||||
if (sctp_priority == GST_WEBRTC_PRIORITY_TYPE_LOW &&
|
||||
!webrtc->priv->tos_attached)
|
||||
return;
|
||||
|
||||
/* If one stream has a non-default priority, then everyone else does too */
|
||||
gst_webrtc_bin_attach_tos (webrtc);
|
||||
|
||||
gst_webrtc_sctp_transport_set_priority (webrtc->priv->sctp_transport,
|
||||
sctp_priority);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_webrtc_bin_attach_probe_to_ice_sink (GstWebRTCBin * webrtc,
|
||||
GstWebRTCICETransport * transport)
|
||||
{
|
||||
GstPad *pad;
|
||||
|
||||
pad = gst_element_get_static_pad (transport->sink, "sink");
|
||||
gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
|
||||
_nicesink_pad_probe, g_object_ref (webrtc),
|
||||
(GDestroyNotify) gst_object_unref);
|
||||
gst_object_unref (pad);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_webrtc_bin_attach_tos (GstWebRTCBin * webrtc)
|
||||
{
|
||||
guint i;
|
||||
|
||||
if (webrtc->priv->tos_attached)
|
||||
return;
|
||||
webrtc->priv->tos_attached = TRUE;
|
||||
|
||||
for (i = 0; i < webrtc->priv->transports->len; i++) {
|
||||
TransportStream *stream = g_ptr_array_index (webrtc->priv->transports, i);
|
||||
|
||||
gst_webrtc_bin_attach_tos_to_session (webrtc, stream->session_id);
|
||||
|
||||
gst_webrtc_bin_attach_probe_to_ice_sink (webrtc,
|
||||
stream->transport->transport);
|
||||
gst_webrtc_bin_attach_probe_to_ice_sink (webrtc,
|
||||
stream->rtcp_transport->transport);
|
||||
}
|
||||
|
||||
gst_webrtc_bin_update_sctp_priority (webrtc);
|
||||
}
|
||||
|
||||
static WebRTCTransceiver *
|
||||
_create_webrtc_transceiver (GstWebRTCBin * webrtc,
|
||||
GstWebRTCRTPTransceiverDirection direction, guint mline)
|
||||
|
@ -1653,6 +1907,9 @@ _create_webrtc_transceiver (GstWebRTCBin * webrtc,
|
|||
/* FIXME: We don't support stopping transceiver yet so they're always not stopped */
|
||||
rtp_trans->stopped = FALSE;
|
||||
|
||||
g_signal_connect_object (sender, "notify::priority",
|
||||
G_CALLBACK (gst_webrtc_bin_attach_tos), webrtc, G_CONNECT_SWAPPED);
|
||||
|
||||
g_ptr_array_add (webrtc->priv->transceivers, trans);
|
||||
|
||||
gst_object_unref (sender);
|
||||
|
@ -1681,6 +1938,8 @@ _create_transport_channel (GstWebRTCBin * webrtc, guint session_id)
|
|||
G_CALLBACK (_on_ice_transport_notify_gathering_state), webrtc);
|
||||
g_signal_connect (G_OBJECT (transport), "notify::state",
|
||||
G_CALLBACK (_on_dtls_transport_notify_state), webrtc);
|
||||
if (webrtc->priv->tos_attached)
|
||||
gst_webrtc_bin_attach_probe_to_ice_sink (webrtc, transport->transport);
|
||||
|
||||
if ((transport = ret->rtcp_transport)) {
|
||||
g_signal_connect (G_OBJECT (transport->transport),
|
||||
|
@ -1690,6 +1949,8 @@ _create_transport_channel (GstWebRTCBin * webrtc, guint session_id)
|
|||
G_CALLBACK (_on_ice_transport_notify_gathering_state), webrtc);
|
||||
g_signal_connect (G_OBJECT (transport), "notify::state",
|
||||
G_CALLBACK (_on_dtls_transport_notify_state), webrtc);
|
||||
if (webrtc->priv->tos_attached)
|
||||
gst_webrtc_bin_attach_probe_to_ice_sink (webrtc, transport->transport);
|
||||
}
|
||||
|
||||
GST_TRACE_OBJECT (webrtc,
|
||||
|
@ -1722,6 +1983,8 @@ _get_or_create_rtp_transport_channel (GstWebRTCBin * webrtc, guint session_id)
|
|||
if (!gst_element_link_pads (GST_ELEMENT (webrtc->rtpbin), pad_name,
|
||||
GST_ELEMENT (ret->send_bin), "rtcp_sink"))
|
||||
g_warn_if_reached ();
|
||||
if (webrtc->priv->tos_attached)
|
||||
gst_webrtc_bin_attach_tos_to_session (webrtc, ret->session_id);
|
||||
g_free (pad_name);
|
||||
}
|
||||
|
||||
|
@ -1761,6 +2024,8 @@ _on_data_channel_ready_state (WebRTCDataChannel * channel,
|
|||
|
||||
g_ptr_array_add (webrtc->priv->data_channels, channel);
|
||||
|
||||
gst_webrtc_bin_update_sctp_priority (webrtc);
|
||||
|
||||
g_signal_emit (webrtc, gst_webrtc_bin_signals[ON_DATA_CHANNEL_SIGNAL], 0,
|
||||
gst_object_ref (channel));
|
||||
}
|
||||
|
@ -2011,6 +2276,7 @@ _get_or_create_data_channel_transports (GstWebRTCBin * webrtc, guint session_id)
|
|||
}
|
||||
|
||||
webrtc->priv->sctp_transport = sctp_transport;
|
||||
gst_webrtc_bin_update_sctp_priority (webrtc);
|
||||
}
|
||||
|
||||
return webrtc->priv->data_channel_transport;
|
||||
|
@ -5299,6 +5565,7 @@ gst_webrtc_bin_create_data_channel (GstWebRTCBin * webrtc, const gchar * label,
|
|||
ret = gst_object_ref (ret);
|
||||
ret->webrtcbin = webrtc;
|
||||
g_ptr_array_add (webrtc->priv->data_channels, ret);
|
||||
gst_webrtc_bin_update_sctp_priority (webrtc);
|
||||
webrtc_data_channel_link_to_sctp (ret, webrtc->priv->sctp_transport);
|
||||
if (webrtc->priv->sctp_transport &&
|
||||
webrtc->priv->sctp_transport->association_established
|
||||
|
|
|
@ -141,6 +141,8 @@ struct _GstWebRTCBinPrivate
|
|||
GstWebRTCSessionDescription *last_generated_answer;
|
||||
|
||||
GstStructure *stats;
|
||||
|
||||
gboolean tos_attached;
|
||||
};
|
||||
|
||||
typedef void (*GstWebRTCBinFunc) (GstWebRTCBin * webrtc, gpointer data);
|
||||
|
|
|
@ -867,6 +867,18 @@ gst_webrtc_ice_set_on_ice_candidate (GstWebRTCICE * ice,
|
|||
ice->priv->on_candidate_notify = notify;
|
||||
}
|
||||
|
||||
void
|
||||
gst_webrtc_ice_set_tos (GstWebRTCICE * ice, GstWebRTCICEStream * stream,
|
||||
guint tos)
|
||||
{
|
||||
struct NiceStreamItem *item;
|
||||
|
||||
item = _find_item (ice, -1, -1, stream);
|
||||
g_return_if_fail (item != NULL);
|
||||
|
||||
nice_agent_set_stream_tos (ice->priv->nice_agent, item->nice_stream_id, tos);
|
||||
}
|
||||
|
||||
static void
|
||||
_clear_ice_stream (struct NiceStreamItem *item)
|
||||
{
|
||||
|
|
|
@ -101,6 +101,9 @@ void gst_webrtc_ice_set_on_ice_candidate (GstWebRTCIC
|
|||
gpointer user_data,
|
||||
GDestroyNotify notify);
|
||||
|
||||
void gst_webrtc_ice_set_tos (GstWebRTCICE * ice,
|
||||
GstWebRTCICEStream * stream,
|
||||
guint tos);
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_WEBRTC_ICE_H__ */
|
||||
|
|
|
@ -25,7 +25,7 @@ if libnice_dep.found()
|
|||
c_args : gst_plugins_bad_args + ['-DGST_USE_UNSTABLE_API'],
|
||||
include_directories : [configinc],
|
||||
dependencies : [gio_dep, libnice_dep, gstbase_dep, gstsdp_dep,
|
||||
gstapp_dep, gstwebrtc_dep, gstsctp_dep],
|
||||
gstapp_dep, gstwebrtc_dep, gstsctp_dep, gstrtp_dep],
|
||||
install : true,
|
||||
install_dir : plugins_install_dir,
|
||||
)
|
||||
|
|
|
@ -145,6 +145,20 @@ gst_webrtc_sctp_transport_set_property (GObject * object, guint prop_id,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
gst_webrtc_sctp_transport_set_priority (GstWebRTCSCTPTransport * sctp,
|
||||
GstWebRTCPriorityType priority)
|
||||
{
|
||||
GstPad *pad;
|
||||
|
||||
pad = gst_element_get_static_pad (sctp->sctpenc, "src");
|
||||
gst_pad_push_event (pad,
|
||||
gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_STICKY,
|
||||
gst_structure_new ("GstWebRtcBinUpdateTos", "sctp-priority",
|
||||
GST_TYPE_WEBRTC_PRIORITY_TYPE, priority, NULL)));
|
||||
gst_object_unref (pad);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_webrtc_sctp_transport_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
|
|
|
@ -61,6 +61,10 @@ struct _GstWebRTCSCTPTransportClass
|
|||
|
||||
GstWebRTCSCTPTransport * gst_webrtc_sctp_transport_new (void);
|
||||
|
||||
void
|
||||
gst_webrtc_sctp_transport_set_priority (GstWebRTCSCTPTransport *sctp,
|
||||
GstWebRTCPriorityType priority);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_WEBRTC_SCTP_TRANSPORT_H__ */
|
||||
|
|
|
@ -173,6 +173,10 @@ webrtc_transceiver_finalize (GObject * object)
|
|||
|
||||
gst_caps_replace (&trans->last_configured_caps, NULL);
|
||||
|
||||
if (trans->ssrc_event)
|
||||
gst_event_unref (trans->ssrc_event);
|
||||
trans->ssrc_event = NULL;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ struct _WebRTCTransceiver
|
|||
TransportStream *stream;
|
||||
GstStructure *local_rtx_ssrc_map;
|
||||
guint current_ssrc;
|
||||
GstEvent *ssrc_event;
|
||||
|
||||
/* Properties */
|
||||
GstWebRTCFECType fec_type;
|
||||
|
|
Loading…
Reference in a new issue