RTX and TWCC working correctly

This commit is contained in:
Jasper Hugo 2021-08-24 15:40:08 +07:00
parent d5842ee79f
commit f414c9db66
3 changed files with 284 additions and 108 deletions

74
Cargo.lock generated
View File

@ -387,9 +387,9 @@ dependencies = [
[[package]] [[package]]
name = "gio" name = "gio"
version = "0.14.0" version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86c6823b39d46d22cac2466de261f28d7f049ebc18f7b35296a42c7ed8a88325" checksum = "402a7057cd21d64bfa7ac027b344a7f50f677fb3308693df0e8c70fb55d29f0d"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"futures-channel", "futures-channel",
@ -417,9 +417,9 @@ dependencies = [
[[package]] [[package]]
name = "glib" name = "glib"
version = "0.14.2" version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbecad7a3a898ee749d491ce2ae0decb0bce9e736f9747bc49159b1cea5d37f4" checksum = "a8fb802e3798d75b415bea8f016eed88d50106ce82f1274e80f31d80cfd4b056"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"futures-channel", "futures-channel",
@ -489,9 +489,9 @@ dependencies = [
[[package]] [[package]]
name = "gstreamer" name = "gstreamer"
version = "0.17.2" version = "0.17.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4aa71d1b3f562645e2d3b96c8d5cf1f26174696e37781ef34193311da733f98c" checksum = "810e68483c27518ec8491d71ee163f9fc03dcc4ebacee98caa348e8a064898ef"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cfg-if", "cfg-if",
@ -512,9 +512,9 @@ dependencies = [
[[package]] [[package]]
name = "gstreamer-sys" name = "gstreamer-sys"
version = "0.17.0" version = "0.17.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8188ba998999a4a16005c3984812807ff882a87f5f3457c3d5bbbfcbdf631ebd" checksum = "a81704feeb3e8599913bdd1e738455c2991a01ff4a1780cb62200993e454cc3e"
dependencies = [ dependencies = [
"glib-sys", "glib-sys",
"gobject-sys", "gobject-sys",
@ -559,9 +559,9 @@ dependencies = [
[[package]] [[package]]
name = "httparse" name = "httparse"
version = "1.5.0" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ba8d84e9efea6aedae6fed9b6d9cfcaac6c53992b437d79a87a549d5537fea9" checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503"
[[package]] [[package]]
name = "idna" name = "idna"
@ -603,9 +603,9 @@ dependencies = [
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "0.4.7" version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]] [[package]]
name = "jid" name = "jid"
@ -618,9 +618,9 @@ dependencies = [
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.52" version = "0.3.53"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce791b7ca6638aae45be056e068fc756d871eb3b3b10b8efa62d1c9cec616752" checksum = "e4bf49d50e2961077d9c99f4b7997d770a1114f087c3c2e0069b36c13fc2979d"
dependencies = [ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
@ -683,9 +683,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.99" version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
@ -744,8 +744,6 @@ dependencies = [
[[package]] [[package]]
name = "minidom" name = "minidom"
version = "0.13.0" version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "332592c2149fc7dd40a64fc9ef6f0d65607284b474cef9817d1fc8c7e7b3608e"
dependencies = [ dependencies = [
"quick-xml", "quick-xml",
] ]
@ -1085,9 +1083,9 @@ dependencies = [
[[package]] [[package]]
name = "rcgen" name = "rcgen"
version = "0.8.11" version = "0.8.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48b4fc1b81d685fcd442a86da2e2c829d9e353142633a8159f42bf28e7e94428" checksum = "2351cbef4bf91837f5ff7face6091cb277ba960d1638d2c5ae2327859912fbba"
dependencies = [ dependencies = [
"chrono", "chrono",
"ring", "ring",
@ -1179,18 +1177,18 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.127" version = "1.0.129"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" checksum = "d1f72836d2aa753853178eda473a3b9d8e4eefdaf20523b919677e6de489f8f1"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.127" version = "1.0.129"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" checksum = "e57ae87ad533d9a56427558b516d0adac283614e347abf85b0dc0cbbf0a249f3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1338,9 +1336,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.74" version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1683,9 +1681,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.75" version = "0.2.76"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b608ecc8f4198fe8680e2ed18eccab5f0cd4caaf3d83516fa5fb2e927fda2586" checksum = "8ce9b1b516211d33767048e5d47fa2a381ed8b76fc48d2ce4aa39877f9f183e0"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"wasm-bindgen-macro", "wasm-bindgen-macro",
@ -1693,9 +1691,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-backend" name = "wasm-bindgen-backend"
version = "0.2.75" version = "0.2.76"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "580aa3a91a63d23aac5b6b267e2d13cb4f363e31dce6c352fca4752ae12e479f" checksum = "cfe8dc78e2326ba5f845f4b5bf548401604fa20b1dd1d365fb73b6c1d6364041"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"lazy_static", "lazy_static",
@ -1708,9 +1706,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.75" version = "0.2.76"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "171ebf0ed9e1458810dfcb31f2e766ad6b3a89dbda42d8901f2b268277e5f09c" checksum = "44468aa53335841d9d6b6c023eaab07c0cd4bddbcfdee3e2bb1e8d2cb8069fef"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@ -1718,9 +1716,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.75" version = "0.2.76"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c2657dd393f03aa2a659c25c6ae18a13a4048cebd220e147933ea837efc589f" checksum = "0195807922713af1e67dc66132c7328206ed9766af3858164fb583eedc25fbad"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1731,15 +1729,15 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.75" version = "0.2.76"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e0c4a743a309662d45f4ede961d7afa4ba4131a59a639f29b0069c3798bbcc2" checksum = "acdb075a845574a1fa5f09fd77e43f7747599301ea3417a9fbffdeedfc1f4a29"
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.52" version = "0.3.53"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01c70a82d842c9979078c772d4a1344685045f1a5628f677c2b2eab4dd7d2696" checksum = "224b2f6b67919060055ef1a67807367c2066ed520c3862cc013d26cf893a783c"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",

View File

@ -6,3 +6,6 @@ members = [
"nice-gst-meet", "nice-gst-meet",
"nice-gst-meet-sys", "nice-gst-meet-sys",
] ]
[patch.crates-io]
minidom = { path = "../xmpp-rs/minidom" }

View File

@ -22,7 +22,7 @@ use xmpp_parsers::{
jingle::{Action, Content, Creator, Description, Jingle, Senders, Transport}, jingle::{Action, Content, Creator, Description, Jingle, Senders, Transport},
jingle_dtls_srtp::{Fingerprint, Setup}, jingle_dtls_srtp::{Fingerprint, Setup},
jingle_ice_udp::{self, Transport as IceUdpTransport}, jingle_ice_udp::{self, Transport as IceUdpTransport},
jingle_rtp::{Description as RtpDescription, PayloadType, RtcpMux}, jingle_rtp::{self, Description as RtpDescription, PayloadType, RtcpMux},
jingle_rtp_hdrext::RtpHdrext, jingle_rtp_hdrext::RtpHdrext,
jingle_ssma::{self, Parameter}, jingle_ssma::{self, Parameter},
Jid, Jid,
@ -39,10 +39,6 @@ const RTP_HDREXT_SSRC_AUDIO_LEVEL: &str = "urn:ietf:params:rtp-hdrext:ssrc-audio
const RTP_HDREXT_ABS_SEND_TIME: &str = "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"; const RTP_HDREXT_ABS_SEND_TIME: &str = "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
const RTP_HDREXT_TRANSPORT_CC: &str = "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"; const RTP_HDREXT_TRANSPORT_CC: &str = "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01";
const RTX_PAYLOAD_TYPE_VP8: u8 = 96;
const RTX_PAYLOAD_TYPE_VP9: u8 = 97;
const RTX_PAYLOAD_TYPE_H264: u8 = 99;
const DEFAULT_STUN_PORT: u16 = 3478; const DEFAULT_STUN_PORT: u16 = 3478;
const DEFAULT_TURNS_PORT: u16 = 5349; const DEFAULT_TURNS_PORT: u16 = 5349;
@ -111,9 +107,16 @@ impl JingleSession {
let mut ice_remote_pwd = None; let mut ice_remote_pwd = None;
let mut dtls_fingerprint = None; let mut dtls_fingerprint = None;
let mut opus_payload_type = None; let mut opus_payload_type = None;
let mut opus_rtcp_fbs = None;
let mut h264_payload_type = None; let mut h264_payload_type = None;
let mut h264_rtx_payload_type = None;
let mut h264_rtcp_fbs = None;
let mut vp8_payload_type = None; let mut vp8_payload_type = None;
let mut vp8_rtx_payload_type = None;
let mut vp8_rtcp_fbs = None;
let mut vp9_payload_type = None; let mut vp9_payload_type = None;
let mut vp9_rtx_payload_type = None;
let mut vp9_rtcp_fbs = None;
let mut audio_hdrext_ssrc_audio_level = None; let mut audio_hdrext_ssrc_audio_level = None;
let mut audio_hdrext_transport_cc = None; let mut audio_hdrext_transport_cc = None;
let mut video_hdrext_abs_send_time = None; let mut video_hdrext_abs_send_time = None;
@ -130,6 +133,11 @@ impl JingleSession {
.iter() .iter()
.find(|pt| pt.name.as_deref() == Some("opus")) .find(|pt| pt.name.as_deref() == Some("opus"))
.map(|pt| pt.id); .map(|pt| pt.id);
opus_rtcp_fbs = description
.payload_types
.iter()
.find(|pt| pt.name.as_deref() == Some("opus"))
.map(|pt| pt.rtcp_fbs.clone());
audio_hdrext_ssrc_audio_level = description audio_hdrext_ssrc_audio_level = description
.hdrexts .hdrexts
.iter() .iter()
@ -149,16 +157,79 @@ impl JingleSession {
.iter() .iter()
.find(|pt| pt.name.as_deref() == Some("H264")) .find(|pt| pt.name.as_deref() == Some("H264"))
.map(|pt| pt.id); .map(|pt| pt.id);
h264_rtx_payload_type = description
.payload_types
.iter()
.find(|pt| {
pt.name.as_deref() == Some("rtx")
&&
pt
.parameters
.iter()
.any(|param| {
param.name == "apt"
&&
param.value == h264_payload_type.map(|pt| pt.to_string()).unwrap_or_default()
})
})
.map(|pt| pt.id);
h264_rtcp_fbs = description
.payload_types
.iter()
.find(|pt| pt.name.as_deref() == Some("H264"))
.map(|pt| pt.rtcp_fbs.clone());
vp8_payload_type = description vp8_payload_type = description
.payload_types .payload_types
.iter() .iter()
.find(|pt| pt.name.as_deref() == Some("VP8")) .find(|pt| pt.name.as_deref() == Some("VP8"))
.map(|pt| pt.id); .map(|pt| pt.id);
vp8_rtx_payload_type = description
.payload_types
.iter()
.find(|pt| {
pt.name.as_deref() == Some("rtx")
&&
pt
.parameters
.iter()
.any(|param| {
param.name == "apt"
&&
param.value == vp8_payload_type.map(|pt| pt.to_string()).unwrap_or_default()
})
})
.map(|pt| pt.id);
vp8_rtcp_fbs = description
.payload_types
.iter()
.find(|pt| pt.name.as_deref() == Some("VP8"))
.map(|pt| pt.rtcp_fbs.clone());
vp9_payload_type = description vp9_payload_type = description
.payload_types .payload_types
.iter() .iter()
.find(|pt| pt.name.as_deref() == Some("VP9")) .find(|pt| pt.name.as_deref() == Some("VP9"))
.map(|pt| pt.id); .map(|pt| pt.id);
vp9_rtx_payload_type = description
.payload_types
.iter()
.find(|pt| {
pt.name.as_deref() == Some("rtx")
&&
pt
.parameters
.iter()
.any(|param| {
param.name == "apt"
&&
param.value == vp9_payload_type.map(|pt| pt.to_string()).unwrap_or_default()
})
})
.map(|pt| pt.id);
vp9_rtcp_fbs = description
.payload_types
.iter()
.find(|pt| pt.name.as_deref() == Some("VP9"))
.map(|pt| pt.rtcp_fbs.clone());
video_hdrext_abs_send_time = description video_hdrext_abs_send_time = description
.hdrexts .hdrexts
.iter() .iter()
@ -257,9 +328,11 @@ impl JingleSession {
let audio_ssrc: u32 = random(); let audio_ssrc: u32 = random();
let video_ssrc: u32 = random(); let video_ssrc: u32 = random();
let video_rtx_ssrc: u32 = random();
debug!("audio SSRC: {}", audio_ssrc); debug!("audio SSRC: {}", audio_ssrc);
debug!("video SSRC: {}", video_ssrc); debug!("video SSRC: {}", video_ssrc);
debug!("video RTX SSRC: {}", video_rtx_ssrc);
let ice_agent = nice::Agent::new(&conference.glib_main_context, nice::Compatibility::Rfc5245); let ice_agent = nice::Agent::new(&conference.glib_main_context, nice::Compatibility::Rfc5245);
ice_agent.set_ice_tcp(false); ice_agent.set_ice_tcp(false);
@ -389,7 +462,6 @@ impl JingleSession {
let rtpbin = gstreamer::ElementFactory::make("rtpbin", Some("rtpbin"))?; let rtpbin = gstreamer::ElementFactory::make("rtpbin", Some("rtpbin"))?;
rtpbin.set_property_from_str("rtp-profile", "savpf"); rtpbin.set_property_from_str("rtp-profile", "savpf");
rtpbin.set_property("do-retransmission", true)?;
rtpbin.set_property("autoremove", true)?; rtpbin.set_property("autoremove", true)?;
pipeline.add(&rtpbin)?; pipeline.add(&rtpbin)?;
@ -407,6 +479,11 @@ impl JingleSession {
let dtls_srtp_connection_id = "gst-meet"; let dtls_srtp_connection_id = "gst-meet";
let dtlssrtpenc = gstreamer::ElementFactory::make("dtlssrtpenc", None)?;
dtlssrtpenc.set_property("connection-id", dtls_srtp_connection_id)?;
dtlssrtpenc.set_property("is-client", true)?;
pipeline.add(&dtlssrtpenc)?;
let dtlssrtpdec = gstreamer::ElementFactory::make("dtlssrtpdec", None)?; let dtlssrtpdec = gstreamer::ElementFactory::make("dtlssrtpdec", None)?;
dtlssrtpdec.set_property("connection-id", dtls_srtp_connection_id)?; dtlssrtpdec.set_property("connection-id", dtls_srtp_connection_id)?;
dtlssrtpdec.set_property( dtlssrtpdec.set_property(
@ -415,11 +492,6 @@ impl JingleSession {
)?; )?;
pipeline.add(&dtlssrtpdec)?; pipeline.add(&dtlssrtpdec)?;
let dtlssrtpenc = gstreamer::ElementFactory::make("dtlssrtpenc", None)?;
dtlssrtpenc.set_property("connection-id", dtls_srtp_connection_id)?;
dtlssrtpenc.set_property("is-client", true)?;
pipeline.add(&dtlssrtpenc)?;
rtpbin.connect("request-pt-map", false, move |values| { rtpbin.connect("request-pt-map", false, move |values| {
let f = || { let f = || {
debug!("rtpbin request-pt-map {:?}", values); debug!("rtpbin request-pt-map {:?}", values);
@ -462,20 +534,20 @@ impl JingleSession {
} }
Ok(Some(caps.build())) Ok(Some(caps.build()))
} }
else if pt == RTX_PAYLOAD_TYPE_VP8 || pt == RTX_PAYLOAD_TYPE_VP9 || pt == RTX_PAYLOAD_TYPE_H264 { else if Some(pt) == vp8_rtx_payload_type || Some(pt) == vp9_rtx_payload_type || Some(pt) == h264_rtx_payload_type {
caps = caps caps = caps
.field("media", "video") .field("media", "video")
.field("clock-rate", 90000) .field("clock-rate", 90000)
.field("encoding-name", "RTX") .field("encoding-name", "RTX")
.field("apt", if pt == RTX_PAYLOAD_TYPE_VP8 { .field("apt", if Some(pt) == vp8_rtx_payload_type {
vp8_payload_type vp8_payload_type
.context("missing VP8 payload type")? .context("missing VP8 payload type")?
} }
else if pt == RTX_PAYLOAD_TYPE_VP9 { else if Some(pt) == vp9_rtx_payload_type {
vp9_payload_type vp9_payload_type
.context("missing VP9 payload type")? .context("missing VP9 payload type")?
} }
else if pt == RTX_PAYLOAD_TYPE_H264 { else if Some(pt) == h264_rtx_payload_type {
h264_payload_type h264_payload_type
.context("missing H264 payload type")? .context("missing H264 payload type")?
} }
@ -502,23 +574,64 @@ impl JingleSession {
} }
})?; })?;
let handle = Handle::current();
let inner_ = conference.inner.clone();
rtpbin.connect("new-jitterbuffer", false, move |values| {
let handle = handle.clone();
let inner_ = inner_.clone();
let f = move || {
let rtpjitterbuffer: gstreamer::Element = values[1].get()?;
let session: u32 = values[2].get()?;
let ssrc: u32 = values[3].get()?;
debug!("new jitterbuffer created for session {} ssrc {}", session, ssrc);
let source = handle.block_on(async move {
let locked_inner = inner_.lock().await;
let jingle_session = locked_inner
.jingle_session
.as_ref()
.context("not connected (no jingle session)")?;
Ok::<_, anyhow::Error>(
jingle_session
.remote_ssrc_map
.get(&ssrc)
.context(format!("unknown ssrc: {}", ssrc))?
.clone(),
)
})?;
debug!("jitterbuffer is for remote source: {:?}", source);
if source.media_type == MediaType::Video {
debug!("enabling RTX for ssrc {}", ssrc);
rtpjitterbuffer.set_property("do-retransmission", true)?;
}
Ok::<_, anyhow::Error>(())
};
if let Err(e) = f() {
warn!("new-jitterbuffer: {:?}", e);
}
None
})?;
rtpbin.connect("request-aux-sender", false, move |values| { rtpbin.connect("request-aux-sender", false, move |values| {
let f = move || { let f = move || {
let session: u32 = values[1].get()?; let session: u32 = values[1].get()?;
debug!("creating RTX sender for session {}", session); debug!("creating RTX sender for session {}", session);
let mut pt_map = gstreamer::Structure::builder("application/x-rtp-pt-map"); let mut pt_map = gstreamer::Structure::builder("application/x-rtp-pt-map");
if let Some(pt) = vp8_payload_type { let mut ssrc_map = gstreamer::Structure::builder("application/x-rtp-ssrc-map");
pt_map = pt_map.field(&pt.to_string(), &(RTX_PAYLOAD_TYPE_VP8 as u32)); if let (Some(pt), Some(rtx_pt)) = (vp8_payload_type, vp8_rtx_payload_type) {
pt_map = pt_map.field(&pt.to_string(), &(rtx_pt as u32));
} }
if let Some(pt) = vp9_payload_type { if let (Some(pt), Some(rtx_pt)) = (vp9_payload_type, vp9_rtx_payload_type) {
pt_map = pt_map.field(&pt.to_string(), &(RTX_PAYLOAD_TYPE_VP9 as u32)); pt_map = pt_map.field(&pt.to_string(), &(rtx_pt as u32));
} }
if let Some(pt) = h264_payload_type { if let (Some(pt), Some(rtx_pt)) = (h264_payload_type, h264_rtx_payload_type) {
pt_map = pt_map.field(&pt.to_string(), &(RTX_PAYLOAD_TYPE_H264 as u32)); pt_map = pt_map.field(&pt.to_string(), &(rtx_pt as u32));
} }
ssrc_map = ssrc_map.field(&video_ssrc.to_string(), &(video_rtx_ssrc as u32));
let bin = gstreamer::Bin::new(None); let bin = gstreamer::Bin::new(None);
let rtx_sender = gstreamer::ElementFactory::make("rtprtxsend", None)?; let rtx_sender = gstreamer::ElementFactory::make("rtprtxsend", None)?;
rtx_sender.set_property("payload-type-map", pt_map.build())?; rtx_sender.set_property("payload-type-map", pt_map.build())?;
rtx_sender.set_property("ssrc-map", ssrc_map.build())?;
bin.add(&rtx_sender)?; bin.add(&rtx_sender)?;
bin.add_pad( bin.add_pad(
&gstreamer::GhostPad::with_target( &gstreamer::GhostPad::with_target(
@ -552,14 +665,14 @@ impl JingleSession {
let session: u32 = values[1].get()?; let session: u32 = values[1].get()?;
debug!("creating RTX receiver for session {}", session); debug!("creating RTX receiver for session {}", session);
let mut pt_map = gstreamer::Structure::builder("application/x-rtp-pt-map"); let mut pt_map = gstreamer::Structure::builder("application/x-rtp-pt-map");
if let Some(pt) = vp8_payload_type { if let (Some(pt), Some(rtx_pt)) = (vp8_payload_type, vp8_rtx_payload_type) {
pt_map = pt_map.field(&pt.to_string(), RTX_PAYLOAD_TYPE_VP8 as u32); pt_map = pt_map.field(&pt.to_string(), &(rtx_pt as u32));
} }
if let Some(pt) = vp9_payload_type { if let (Some(pt), Some(rtx_pt)) = (vp9_payload_type, vp9_rtx_payload_type) {
pt_map = pt_map.field(&pt.to_string(), RTX_PAYLOAD_TYPE_VP9 as u32); pt_map = pt_map.field(&pt.to_string(), &(rtx_pt as u32));
} }
if let Some(pt) = h264_payload_type { if let (Some(pt), Some(rtx_pt)) = (h264_payload_type, h264_rtx_payload_type) {
pt_map = pt_map.field(&pt.to_string(), RTX_PAYLOAD_TYPE_H264 as u32); pt_map = pt_map.field(&pt.to_string(), &(rtx_pt as u32));
} }
let bin = gstreamer::Bin::new(None); let bin = gstreamer::Bin::new(None);
let rtx_receiver = gstreamer::ElementFactory::make("rtprtxreceive", None)?; let rtx_receiver = gstreamer::ElementFactory::make("rtprtxreceive", None)?;
@ -800,28 +913,34 @@ impl JingleSession {
video_capsfilter.set_property("caps", video_caps.build())?; video_capsfilter.set_property("caps", video_caps.build())?;
pipeline.add(&video_capsfilter)?; pipeline.add(&video_capsfilter)?;
debug!("linking audio payloader -> rtpbin"); let rtpfunnel = gstreamer::ElementFactory::make("funnel", None)?;
pipeline.add(&rtpfunnel)?;
debug!("linking audio payloader -> rtp funnel");
audio_sink_element.link(&audio_capsfilter)?; audio_sink_element.link(&audio_capsfilter)?;
audio_capsfilter.link_pads(None, &rtpbin, Some("send_rtp_sink_0"))?; audio_capsfilter.link_pads(None, &rtpfunnel, Some("sink_0"))?;
debug!("linking video payloader -> rtpbin"); debug!("linking video payloader -> rtp funnel");
video_sink_element.link(&video_capsfilter)?; video_sink_element.link(&video_capsfilter)?;
video_capsfilter.link_pads(None, &rtpbin, Some("send_rtp_sink_1"))?; video_capsfilter.link_pads(None, &rtpfunnel, Some("sink_1"))?;
debug!("linking ICE <-> DTLS-SRTP"); debug!("linking rtp funnel -> rtpbin");
nicesrc.link(&dtlssrtpdec)?; rtpfunnel.link_pads(None, &rtpbin, Some("send_rtp_sink_0"))?;
dtlssrtpenc.link(&nicesink)?;
debug!("linking rtpbin -> DTLS-SRTP encoder"); debug!("link dtlssrtpdec -> rtpbin");
rtpbin.link_pads(Some("send_rtp_src_0"), &dtlssrtpenc, Some("rtp_sink_0"))?;
rtpbin.link_pads(Some("send_rtcp_src_0"), &dtlssrtpenc, Some("rtcp_sink_0"))?;
rtpbin.link_pads(Some("send_rtp_src_1"), &dtlssrtpenc, Some("rtp_sink_1"))?;
rtpbin.link_pads(Some("send_rtcp_src_1"), &dtlssrtpenc, Some("rtcp_sink_1"))?;
debug!("linking DTLS-SRTP decoder -> rtpbin");
dtlssrtpdec.link_pads(Some("rtp_src"), &rtpbin, Some("recv_rtp_sink_0"))?; dtlssrtpdec.link_pads(Some("rtp_src"), &rtpbin, Some("recv_rtp_sink_0"))?;
dtlssrtpdec.link_pads(Some("rtcp_src"), &rtpbin, Some("recv_rtcp_sink_0"))?; dtlssrtpdec.link_pads(Some("rtcp_src"), &rtpbin, Some("recv_rtcp_sink_0"))?;
debug!("linking rtpbin -> dtlssrtpenc");
rtpbin.link_pads(Some("send_rtp_src_0"), &dtlssrtpenc, Some("rtp_sink_0"))?;
rtpbin.link_pads(Some("send_rtcp_src_0"), &dtlssrtpenc, Some("rtcp_sink_0"))?;
debug!("linking ice src -> dtlssrtpdec");
nicesrc.link(&dtlssrtpdec)?;
debug!("linking dtlssrtpenc -> ice sink");
dtlssrtpenc.link_pads(Some("src"), &nicesink, Some("sink"))?;
let bus = pipeline.bus().context("failed to get pipeline bus")?; let bus = pipeline.bus().context("failed to get pipeline bus")?;
let (pipeline_state_null_tx, pipeline_state_null_rx) = oneshot::channel(); let (pipeline_state_null_tx, pipeline_state_null_rx) = oneshot::channel();
@ -875,35 +994,76 @@ impl JingleSession {
let mut description = RtpDescription::new(initiate_content.name.0.clone()); let mut description = RtpDescription::new(initiate_content.name.0.clone());
description.payload_types = if initiate_content.name.0 == "audio" { description.payload_types = if initiate_content.name.0 == "audio" {
vec![PayloadType::new( let mut pt = PayloadType::new(
opus_payload_type.context("no opus payload type in jingle session-initiate")?, opus_payload_type.context("no opus payload type in jingle session-initiate")?,
"opus".to_owned(), "opus".to_owned(),
48000, 48000,
2, 2,
)] );
pt.rtcp_fbs = opus_rtcp_fbs.clone().unwrap_or_default();
vec![pt]
} }
else { else {
let mut pts = vec![];
match conference.config.video_codec.as_str() { match conference.config.video_codec.as_str() {
"h264" => vec![PayloadType::new( "h264" => {
h264_payload_type.context("no h264 payload type in jingle session-initiate")?, if let Some(h264_pt) = h264_payload_type {
"H264".to_owned(), let mut pt = PayloadType::new(h264_pt, "H264".to_owned(), 90000, 1);
90000, pt.rtcp_fbs = h264_rtcp_fbs.clone().unwrap_or_default();
1, pts.push(pt);
)], if let Some(rtx_pt) = h264_rtx_payload_type {
"vp8" => vec![PayloadType::new( let mut rtx_pt = PayloadType::new(rtx_pt, "rtx".to_owned(), 90000, 1);
vp8_payload_type.context("no vp8 payload type in jingle session-initiate")?, rtx_pt.parameters = vec![jingle_rtp::Parameter {
"VP8".to_owned(), name: "apt".to_owned(),
90000, value: h264_pt.to_string(),
1, }];
)], pts.push(rtx_pt);
"vp9" => vec![PayloadType::new( }
vp9_payload_type.context("no vp9 payload type in jingle session-initiate")?, }
"VP9".to_owned(), else {
90000, bail!("no h264 payload type in jingle session-initiate");
1, }
)], },
"vp8" => {
if let Some(vp8_pt) = vp8_payload_type {
let mut pt = PayloadType::new(vp8_pt, "VP8".to_owned(), 90000, 1);
pt.rtcp_fbs = vp8_rtcp_fbs.clone().unwrap_or_default();
pts.push(pt);
if let Some(rtx_pt) = vp8_rtx_payload_type {
let mut rtx_pt = PayloadType::new(rtx_pt, "rtx".to_owned(), 90000, 1);
rtx_pt.parameters = vec![jingle_rtp::Parameter {
name: "apt".to_owned(),
value: vp8_pt.to_string(),
}];
pts.push(rtx_pt);
}
}
else {
bail!("no vp8 payload type in jingle session-initiate");
}
},
"vp9" => {
if let Some(vp9_pt) = vp9_payload_type {
let mut pt = PayloadType::new(vp9_pt, "VP9".to_owned(), 90000, 1);
pt.rtcp_fbs = vp9_rtcp_fbs.clone().unwrap_or_default();
pts.push(pt);
if let Some(rtx_pt) = vp9_rtx_payload_type {
let mut rtx_pt = PayloadType::new(rtx_pt, "rtx".to_owned(), 90000, 1);
rtx_pt.parameters = vec![jingle_rtp::Parameter {
name: "apt".to_owned(),
value: vp9_pt.to_string(),
}];
pts.push(rtx_pt);
}
}
else {
bail!("no vp9 payload type in jingle session-initiate");
}
},
other => bail!("unsupported video codec: {}", other), other => bail!("unsupported video codec: {}", other),
} }
pts
}; };
description.rtcp_mux = Some(RtcpMux); description.rtcp_mux = Some(RtcpMux);
@ -912,11 +1072,21 @@ impl JingleSession {
let label = Uuid::new_v4().to_string(); let label = Uuid::new_v4().to_string();
let cname = Uuid::new_v4().to_string(); let cname = Uuid::new_v4().to_string();
description.ssrc = Some(if initiate_content.name.0 == "audio" {
audio_ssrc.to_string()
}
else {
video_ssrc.to_string()
});
description.ssrcs = if initiate_content.name.0 == "audio" { description.ssrcs = if initiate_content.name.0 == "audio" {
vec![jingle_ssma::Source::new(audio_ssrc.to_string())] vec![jingle_ssma::Source::new(audio_ssrc.to_string())]
} }
else { else {
vec![jingle_ssma::Source::new(video_ssrc.to_string())] vec![
jingle_ssma::Source::new(video_ssrc.to_string()),
jingle_ssma::Source::new(video_rtx_ssrc.to_string()),
]
}; };
for ssrc in description.ssrcs.iter_mut() { for ssrc in description.ssrcs.iter_mut() {
@ -928,16 +1098,21 @@ impl JingleSession {
name: "msid".to_owned(), name: "msid".to_owned(),
value: Some(format!("{} {}", mslabel, label)), value: Some(format!("{} {}", mslabel, label)),
}); });
ssrc.parameters.push(Parameter {
name: "mslabel".to_owned(),
value: Some(mslabel.clone()),
});
ssrc.parameters.push(Parameter {
name: "label".to_owned(),
value: Some(label.clone()),
});
} }
description.ssrc_groups = if initiate_content.name.0 == "audio" {
vec![]
}
else {
vec![jingle_ssma::Group {
semantics: "FID".to_owned(),
sources: vec![
jingle_ssma::Source::new(video_ssrc.to_string()),
jingle_ssma::Source::new(video_rtx_ssrc.to_string()),
],
}]
};
if initiate_content.name.0 == "audio" { if initiate_content.name.0 == "audio" {
// TODO: fails to negotiate // TODO: fails to negotiate
// if let Some(hdrext) = audio_hdrext_ssrc_audio_level { // if let Some(hdrext) = audio_hdrext_ssrc_audio_level {