examples: webrtc: sendrecv: rust: Implement TWCC support in both directions

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3758>
This commit is contained in:
Sebastian Dröge 2023-01-19 20:56:44 +02:00 committed by GStreamer Marge Bot
parent 6541dccaea
commit 541c637910
3 changed files with 78 additions and 3 deletions

View file

@ -693,6 +693,46 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "gstreamer-base-sys"
version = "0.19.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbc3c4476e1503ae245c89fbe20060c30ec6ade5f44620bcc402cbc70a3911a1"
dependencies = [
"glib-sys",
"gobject-sys",
"gstreamer-sys",
"libc",
"system-deps",
]
[[package]]
name = "gstreamer-rtp"
version = "0.19.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2e464957d09a9abb8c3cbf818635f38113b327d9ba23b89ef11b10afb25cdfe"
dependencies = [
"bitflags",
"glib",
"gstreamer",
"gstreamer-rtp-sys",
"libc",
"once_cell",
]
[[package]]
name = "gstreamer-rtp-sys"
version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e65dbc4429a8cb494907c654caa74c1630111116f9ac2d1d9bf585c144e4821d"
dependencies = [
"glib-sys",
"gstreamer-base-sys",
"gstreamer-sys",
"libc",
"system-deps",
]
[[package]] [[package]]
name = "gstreamer-sdp" name = "gstreamer-sdp"
version = "0.19.4" version = "0.19.4"
@ -1590,6 +1630,7 @@ dependencies = [
"cocoa", "cocoa",
"futures", "futures",
"gstreamer", "gstreamer",
"gstreamer-rtp",
"gstreamer-sdp", "gstreamer-sdp",
"gstreamer-webrtc", "gstreamer-webrtc",
"rand", "rand",

View file

@ -12,6 +12,7 @@ anyhow = "1"
rand = "0.8" rand = "0.8"
async-tungstenite = { version = "0.19", features = ["async-std-runtime", "async-native-tls"] } async-tungstenite = { version = "0.19", features = ["async-std-runtime", "async-native-tls"] }
gst = { package = "gstreamer", version = "0.19" } gst = { package = "gstreamer", version = "0.19" }
gst-rtp = { package = "gstreamer-rtp", version = "0.19", features = ["v1_20"] }
gst-webrtc = { package = "gstreamer-webrtc", version = "0.19" } gst-webrtc = { package = "gstreamer-webrtc", version = "0.19" }
gst-sdp = { package = "gstreamer-sdp", version = "0.19" } gst-sdp = { package = "gstreamer-sdp", version = "0.19" }
serde = "1" serde = "1"

View file

@ -18,6 +18,7 @@ use tungstenite::Message as WsMessage;
use gst::glib; use gst::glib;
use gst::prelude::*; use gst::prelude::*;
use gst_rtp::prelude::*;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
@ -26,6 +27,8 @@ use anyhow::{anyhow, bail, Context};
const STUN_SERVER: &str = "stun://stun.l.google.com:19302"; const STUN_SERVER: &str = "stun://stun.l.google.com:19302";
const TURN_SERVER: &str = "turn://foo:bar@webrtc.nirbheek.in:3478"; const TURN_SERVER: &str = "turn://foo:bar@webrtc.nirbheek.in:3478";
const TWCC_URI: &str = "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01";
// upgrade weak reference or return // upgrade weak reference or return
#[macro_export] #[macro_export]
macro_rules! upgrade_weak { macro_rules! upgrade_weak {
@ -149,6 +152,15 @@ impl App {
// Connect to on-negotiation-needed to handle sending an Offer // Connect to on-negotiation-needed to handle sending an Offer
if app.args.peer_id.is_some() { if app.args.peer_id.is_some() {
let vpay = app.pipeline.by_name("vpay").unwrap();
let apay = app.pipeline.by_name("apay").unwrap();
for pay in [vpay, apay] {
let twcc = gst_rtp::RTPHeaderExtension::create_from_uri(TWCC_URI).unwrap();
twcc.set_id(1);
pay.emit_by_name::<()>("add-extension", &[&twcc]);
}
let app_clone = app.downgrade(); let app_clone = app.downgrade();
app.webrtcbin.connect_closure( app.webrtcbin.connect_closure(
"on-negotiation-needed", "on-negotiation-needed",
@ -403,10 +415,25 @@ impl App {
Err(_) => continue, Err(_) => continue,
}; };
let twcc_id = media.attributes().find_map(|attr| {
let key = attr.key();
let value = attr.value();
if key != "extmap" || !value.map_or(false, |value| value.ends_with(TWCC_URI)) {
return None;
}
let value = value.unwrap();
let id = value
.strip_suffix(TWCC_URI)
.and_then(|id| id.trim().parse::<u8>().ok());
id
});
if encoding_name == "VP8" && vp8_id.is_none() { if encoding_name == "VP8" && vp8_id.is_none() {
vp8_id = Some(pt); vp8_id = Some((pt, twcc_id));
} else if encoding_name == "OPUS" && opus_id.is_none() { } else if encoding_name == "OPUS" && opus_id.is_none() {
opus_id = Some(pt); opus_id = Some((pt, twcc_id));
} }
} }
} }
@ -415,8 +442,14 @@ impl App {
let apay = self.pipeline.by_name("apay").unwrap(); let apay = self.pipeline.by_name("apay").unwrap();
let vpay = self.pipeline.by_name("vpay").unwrap(); let vpay = self.pipeline.by_name("vpay").unwrap();
for (pay, pt) in [(apay, opus_id), (vpay, vp8_id)] { for (pay, (pt, twcc_id)) in [(apay, opus_id), (vpay, vp8_id)] {
pay.set_property("pt", pt as u32); pay.set_property("pt", pt as u32);
if let Some(twcc_id) = twcc_id {
let twcc = gst_rtp::RTPHeaderExtension::create_from_uri(TWCC_URI).unwrap();
twcc.set_id(twcc_id as u32);
pay.emit_by_name::<()>("add-extension", &[&twcc]);
}
} }
} else { } else {
gst::element_error!( gst::element_error!(