examples: webrtc: sendrecv: rust: Implement TWCC support in both directions
authorSebastian Dröge <sebastian@centricular.com>
Thu, 19 Jan 2023 18:56:44 +0000 (20:56 +0200)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 20 Jan 2023 11:36:57 +0000 (11:36 +0000)
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3758>

subprojects/gst-examples/webrtc/sendrecv/gst-rust/Cargo.lock
subprojects/gst-examples/webrtc/sendrecv/gst-rust/Cargo.toml
subprojects/gst-examples/webrtc/sendrecv/gst-rust/src/main.rs

index 58e2e95..7a67bba 100644 (file)
@@ -694,6 +694,46 @@ dependencies = [
 ]
 
 [[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]]
 name = "gstreamer-sdp"
 version = "0.19.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1590,6 +1630,7 @@ dependencies = [
  "cocoa",
  "futures",
  "gstreamer",
+ "gstreamer-rtp",
  "gstreamer-sdp",
  "gstreamer-webrtc",
  "rand",
index 16a4698..11f3ca9 100644 (file)
@@ -12,6 +12,7 @@ anyhow = "1"
 rand = "0.8"
 async-tungstenite = { version = "0.19", features = ["async-std-runtime", "async-native-tls"] }
 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-sdp = { package = "gstreamer-sdp", version = "0.19" }
 serde = "1"
index 7a53608..888f920 100644 (file)
@@ -18,6 +18,7 @@ use tungstenite::Message as WsMessage;
 
 use gst::glib;
 use gst::prelude::*;
+use gst_rtp::prelude::*;
 
 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 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
 #[macro_export]
 macro_rules! upgrade_weak {
@@ -149,6 +152,15 @@ impl App {
 
         // Connect to on-negotiation-needed to handle sending an Offer
         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();
             app.webrtcbin.connect_closure(
                 "on-negotiation-needed",
@@ -403,10 +415,25 @@ impl App {
                     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() {
-                    vp8_id = Some(pt);
+                    vp8_id = Some((pt, twcc_id));
                 } 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 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);
+
+                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 {
             gst::element_error!(