make jingle more generic over codecs
This adds a very simple Codec struct, which describes each codec supported by a RTP description. It will make it much easier to add newer codecs in the future, like AV1. This commit is best viewed with git log -p -w to ignore indent changes.
This commit is contained in:
parent
5db78b11bf
commit
7fa31bd796
|
@ -41,18 +41,82 @@ const RTP_HDREXT_TRANSPORT_CC: &str =
|
|||
const DEFAULT_STUN_PORT: u16 = 3478;
|
||||
const DEFAULT_TURNS_PORT: u16 = 5349;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
enum CodecName {
|
||||
Opus,
|
||||
H264,
|
||||
Vp8,
|
||||
Vp9,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Codec {
|
||||
name: CodecName,
|
||||
pt: u8,
|
||||
rtx_pt: Option<u8>,
|
||||
rtcp_fbs: Vec<RtcpFb>,
|
||||
}
|
||||
|
||||
impl Codec {
|
||||
fn is(&self, pt: u8) -> bool {
|
||||
self.pt == pt
|
||||
}
|
||||
|
||||
fn is_rtx(&self, rtx_pt: u8) -> bool {
|
||||
if let Some(pt) = self.rtx_pt {
|
||||
pt == rtx_pt
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn is_audio(&self) -> bool {
|
||||
self.name == CodecName::Opus
|
||||
}
|
||||
|
||||
fn is_video(&self) -> bool {
|
||||
self.name != CodecName::Opus
|
||||
}
|
||||
|
||||
fn is_codec(&self, name: &str) -> bool {
|
||||
match name {
|
||||
"h264" => self.name == CodecName::H264,
|
||||
"vp8" => self.name == CodecName::Vp8,
|
||||
"vp9" => self.name == CodecName::Vp9,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn encoding_name(&self) -> &'static str {
|
||||
match self.name {
|
||||
CodecName::Opus => "opus",
|
||||
CodecName::H264 => "H264",
|
||||
CodecName::Vp8 => "VP8",
|
||||
CodecName::Vp9 => "VP9",
|
||||
}
|
||||
}
|
||||
|
||||
fn make_depay_name(&self) -> &'static str {
|
||||
match self.name {
|
||||
CodecName::Opus => "rtpopusdepay",
|
||||
CodecName::H264 => "rtph264depay",
|
||||
CodecName::Vp8 => "rtpvp8depay",
|
||||
CodecName::Vp9 => "rtpvp9depay",
|
||||
}
|
||||
}
|
||||
|
||||
fn make_pay_name(&self) -> &'static str {
|
||||
match self.name {
|
||||
CodecName::Opus => "rtpopuspay",
|
||||
CodecName::H264 => "rtph264pay",
|
||||
CodecName::Vp8 => "rtpvp8pay",
|
||||
CodecName::Vp9 => "rtpvp9pay",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ParsedRtpDescription {
|
||||
opus_payload_type: Option<u8>,
|
||||
opus_rtcp_fbs: Option<Vec<RtcpFb>>,
|
||||
h264_payload_type: Option<u8>,
|
||||
h264_rtx_payload_type: Option<u8>,
|
||||
h264_rtcp_fbs: Option<Vec<RtcpFb>>,
|
||||
vp8_payload_type: Option<u8>,
|
||||
vp8_rtx_payload_type: Option<u8>,
|
||||
vp8_rtcp_fbs: Option<Vec<RtcpFb>>,
|
||||
vp9_payload_type: Option<u8>,
|
||||
vp9_rtx_payload_type: Option<u8>,
|
||||
vp9_rtcp_fbs: Option<Vec<RtcpFb>>,
|
||||
codecs: Vec<Codec>,
|
||||
audio_hdrext_ssrc_audio_level: Option<u8>,
|
||||
audio_hdrext_transport_cc: Option<u8>,
|
||||
video_hdrext_abs_send_time: Option<u8>,
|
||||
|
@ -111,17 +175,10 @@ impl JingleSession {
|
|||
}
|
||||
|
||||
fn parse_rtp_description(description: &RtpDescription, remote_ssrc_map: &mut HashMap<u32, Source>) -> Result<Option<ParsedRtpDescription>> {
|
||||
let mut opus_payload_type = None;
|
||||
let mut opus_rtcp_fbs = 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_rtx_payload_type = None;
|
||||
let mut vp8_rtcp_fbs = None;
|
||||
let mut vp9_payload_type = None;
|
||||
let mut vp9_rtx_payload_type = None;
|
||||
let mut vp9_rtcp_fbs = None;
|
||||
let mut opus = None;
|
||||
let mut h264 = None;
|
||||
let mut vp8 = None;
|
||||
let mut vp9 = None;
|
||||
let mut audio_hdrext_ssrc_audio_level = None;
|
||||
let mut audio_hdrext_transport_cc = None;
|
||||
let mut video_hdrext_abs_send_time = None;
|
||||
|
@ -133,8 +190,12 @@ impl JingleSession {
|
|||
if let Some(name) = &pt.name {
|
||||
match name.as_str() {
|
||||
"opus" => {
|
||||
opus_payload_type = Some(pt.id);
|
||||
opus_rtcp_fbs = Some(pt.rtcp_fbs.clone());
|
||||
opus = Some(Codec {
|
||||
name: CodecName::Opus,
|
||||
pt: pt.id,
|
||||
rtx_pt: None,
|
||||
rtcp_fbs: pt.rtcp_fbs.clone(),
|
||||
});
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -157,16 +218,28 @@ impl JingleSession {
|
|||
if let Some(name) = &pt.name {
|
||||
match name.as_str() {
|
||||
"H264" => {
|
||||
h264_payload_type = Some(pt.id);
|
||||
h264_rtcp_fbs = Some(pt.rtcp_fbs.clone());
|
||||
h264 = Some(Codec {
|
||||
name: CodecName::H264,
|
||||
pt: pt.id,
|
||||
rtx_pt: None,
|
||||
rtcp_fbs: pt.rtcp_fbs.clone(),
|
||||
});
|
||||
}
|
||||
"VP8" => {
|
||||
vp8_payload_type = Some(pt.id);
|
||||
vp8_rtcp_fbs = Some(pt.rtcp_fbs.clone());
|
||||
vp8 = Some(Codec {
|
||||
name: CodecName::Vp8,
|
||||
pt: pt.id,
|
||||
rtx_pt: None,
|
||||
rtcp_fbs: pt.rtcp_fbs.clone(),
|
||||
});
|
||||
}
|
||||
"VP9" => {
|
||||
vp9_payload_type = Some(pt.id);
|
||||
vp9_rtcp_fbs = Some(pt.rtcp_fbs.clone());
|
||||
vp9 = Some(Codec {
|
||||
name: CodecName::Vp9,
|
||||
pt: pt.id,
|
||||
rtx_pt: None,
|
||||
rtcp_fbs: pt.rtcp_fbs.clone(),
|
||||
});
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -177,18 +250,21 @@ impl JingleSession {
|
|||
if name == "rtx" {
|
||||
for param in pt.parameters.iter() {
|
||||
if param.name == "apt" {
|
||||
let pt: u8 = param.value.parse()?;
|
||||
if Some(pt) == h264_payload_type {
|
||||
h264_rtx_payload_type = Some(pt);
|
||||
let apt_pt: u8 = param.value.parse()?;
|
||||
if let Some(h264) = &mut h264 {
|
||||
if apt_pt == h264.pt {
|
||||
h264.rtx_pt = Some(pt.id);
|
||||
}
|
||||
}
|
||||
else if Some(pt) == h264_payload_type {
|
||||
h264_rtx_payload_type = Some(pt);
|
||||
if let Some(vp8) = &mut vp8 {
|
||||
if apt_pt == vp8.pt {
|
||||
vp8.rtx_pt = Some(pt.id);
|
||||
}
|
||||
}
|
||||
else if Some(pt) == h264_payload_type {
|
||||
h264_rtx_payload_type = Some(pt);
|
||||
}
|
||||
else {
|
||||
bail!("unknown rtx apt: {}", pt);
|
||||
if let Some(vp9) = &mut vp9 {
|
||||
if apt_pt == vp9.pt {
|
||||
vp9.rtx_pt = Some(pt.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -211,6 +287,8 @@ impl JingleSession {
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
let codecs = [opus, h264, vp8, vp9].iter().flatten().cloned().collect();
|
||||
|
||||
for ssrc in &description.ssrcs {
|
||||
let owner = ssrc
|
||||
.info
|
||||
|
@ -246,17 +324,7 @@ impl JingleSession {
|
|||
);
|
||||
}
|
||||
Ok(Some(ParsedRtpDescription {
|
||||
opus_payload_type,
|
||||
opus_rtcp_fbs,
|
||||
h264_payload_type,
|
||||
h264_rtx_payload_type,
|
||||
h264_rtcp_fbs,
|
||||
vp8_payload_type,
|
||||
vp8_rtx_payload_type,
|
||||
vp8_rtcp_fbs,
|
||||
vp9_payload_type,
|
||||
vp9_rtx_payload_type,
|
||||
vp9_rtcp_fbs,
|
||||
codecs,
|
||||
audio_hdrext_ssrc_audio_level,
|
||||
audio_hdrext_transport_cc,
|
||||
video_hdrext_abs_send_time,
|
||||
|
@ -396,17 +464,7 @@ impl JingleSession {
|
|||
debug!("Received Jingle session-initiate from {}", initiator);
|
||||
|
||||
let mut ice_transport = None;
|
||||
let mut opus_payload_type = None;
|
||||
let mut opus_rtcp_fbs = 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_rtx_payload_type = None;
|
||||
let mut vp8_rtcp_fbs = None;
|
||||
let mut vp9_payload_type = None;
|
||||
let mut vp9_rtx_payload_type = None;
|
||||
let mut vp9_rtcp_fbs = None;
|
||||
let mut codecs = vec![];
|
||||
let mut audio_hdrext_ssrc_audio_level = None;
|
||||
let mut audio_hdrext_transport_cc = None;
|
||||
let mut video_hdrext_abs_send_time = None;
|
||||
|
@ -417,17 +475,7 @@ impl JingleSession {
|
|||
for content in &jingle.contents {
|
||||
if let Some(Description::Rtp(description)) = &content.description {
|
||||
if let Some(description) = JingleSession::parse_rtp_description(description, &mut remote_ssrc_map)? {
|
||||
opus_payload_type = opus_payload_type.or(description.opus_payload_type);
|
||||
opus_rtcp_fbs = opus_rtcp_fbs.or(description.opus_rtcp_fbs);
|
||||
h264_payload_type = h264_payload_type.or(description.h264_payload_type);
|
||||
h264_rtx_payload_type = h264_rtx_payload_type.or(description.h264_rtx_payload_type);
|
||||
h264_rtcp_fbs = h264_rtcp_fbs.or(description.h264_rtcp_fbs);
|
||||
vp8_payload_type = vp8_payload_type.or(description.vp8_payload_type);
|
||||
vp8_rtx_payload_type = vp8_rtx_payload_type.or(description.vp8_rtx_payload_type);
|
||||
vp8_rtcp_fbs = vp8_rtcp_fbs.or(description.vp8_rtcp_fbs);
|
||||
vp9_payload_type = vp9_payload_type.or(description.vp9_payload_type);
|
||||
vp9_rtx_payload_type = vp9_rtx_payload_type.or(description.vp9_rtx_payload_type);
|
||||
vp9_rtcp_fbs = vp9_rtcp_fbs.or(description.vp9_rtcp_fbs);
|
||||
codecs.extend(description.codecs);
|
||||
audio_hdrext_ssrc_audio_level = audio_hdrext_ssrc_audio_level.or(description.audio_hdrext_ssrc_audio_level);
|
||||
audio_hdrext_transport_cc = audio_hdrext_transport_cc.or(description.audio_hdrext_transport_cc);
|
||||
video_hdrext_abs_send_time = video_hdrext_abs_send_time.or(description.video_hdrext_abs_send_time);
|
||||
|
@ -522,96 +570,68 @@ impl JingleSession {
|
|||
)?;
|
||||
pipeline.add(&dtlssrtpdec)?;
|
||||
|
||||
rtpbin.connect("request-pt-map", false, move |values| {
|
||||
let f = || {
|
||||
debug!("rtpbin request-pt-map {:?}", values);
|
||||
let pt = values[2].get::<u32>()? as u8;
|
||||
let mut caps = gstreamer::Caps::builder("application/x-rtp");
|
||||
if Some(pt) == opus_payload_type {
|
||||
caps = caps
|
||||
.field("media", "audio")
|
||||
.field("encoding-name", "OPUS")
|
||||
.field("clock-rate", 48000);
|
||||
if let Some(hdrext) = audio_hdrext_ssrc_audio_level {
|
||||
caps = caps.field(&format!("extmap-{}", hdrext), RTP_HDREXT_SSRC_AUDIO_LEVEL);
|
||||
}
|
||||
if let Some(hdrext) = audio_hdrext_transport_cc {
|
||||
caps = caps.field(&format!("extmap-{}", hdrext), &RTP_HDREXT_TRANSPORT_CC);
|
||||
}
|
||||
Ok::<_, anyhow::Error>(Some(caps.build()))
|
||||
}
|
||||
else if Some(pt) == h264_payload_type
|
||||
|| Some(pt) == vp8_payload_type
|
||||
|| Some(pt) == vp9_payload_type
|
||||
{
|
||||
caps = caps
|
||||
.field("media", "video")
|
||||
.field("clock-rate", 90000)
|
||||
.field(
|
||||
"encoding-name",
|
||||
if Some(pt) == h264_payload_type {
|
||||
"H264"
|
||||
}
|
||||
else if Some(pt) == vp8_payload_type {
|
||||
"VP8"
|
||||
}
|
||||
else if Some(pt) == vp9_payload_type {
|
||||
"VP9"
|
||||
{
|
||||
let codecs = codecs.clone();
|
||||
rtpbin.connect("request-pt-map", false, move |values| {
|
||||
let f = || {
|
||||
debug!("rtpbin request-pt-map {:?}", values);
|
||||
let pt = values[2].get::<u32>()? as u8;
|
||||
let mut caps = gstreamer::Caps::builder("application/x-rtp");
|
||||
for codec in codecs.iter() {
|
||||
if codec.is(pt) {
|
||||
if codec.is_audio() {
|
||||
caps = caps
|
||||
.field("media", "audio")
|
||||
.field("encoding-name", "OPUS")
|
||||
.field("clock-rate", 48000);
|
||||
if let Some(hdrext) = audio_hdrext_ssrc_audio_level {
|
||||
caps = caps.field(&format!("extmap-{}", hdrext), RTP_HDREXT_SSRC_AUDIO_LEVEL);
|
||||
}
|
||||
if let Some(hdrext) = audio_hdrext_transport_cc {
|
||||
caps = caps.field(&format!("extmap-{}", hdrext), &RTP_HDREXT_TRANSPORT_CC);
|
||||
}
|
||||
}
|
||||
else {
|
||||
unreachable!()
|
||||
},
|
||||
);
|
||||
// if let Some(hdrext) = video_hdrext_abs_send_time {
|
||||
// caps = caps.field(&format!("extmap-{}", hdrext), &RTP_HDREXT_ABS_SEND_TIME);
|
||||
// }
|
||||
if let Some(hdrext) = video_hdrext_transport_cc {
|
||||
caps = caps.field(&format!("extmap-{}", hdrext), &RTP_HDREXT_TRANSPORT_CC);
|
||||
// A video codec, as the only audio codec we support is Opus.
|
||||
caps = caps
|
||||
.field("media", "video")
|
||||
.field("clock-rate", 90000)
|
||||
.field("encoding-name", codec.encoding_name());
|
||||
// if let Some(hdrext) = video_hdrext_abs_send_time {
|
||||
// caps = caps.field(&format!("extmap-{}", hdrext), &RTP_HDREXT_ABS_SEND_TIME);
|
||||
// }
|
||||
if let Some(hdrext) = video_hdrext_transport_cc {
|
||||
caps = caps.field(&format!("extmap-{}", hdrext), &RTP_HDREXT_TRANSPORT_CC);
|
||||
}
|
||||
}
|
||||
return Ok::<_, anyhow::Error>(Some(caps.build()));
|
||||
}
|
||||
else if codec.is_rtx(pt) {
|
||||
caps = caps
|
||||
.field("media", "video")
|
||||
.field("clock-rate", 90000)
|
||||
.field("encoding-name", "RTX")
|
||||
.field("apt", codec.pt);
|
||||
return Ok(Some(caps.build()));
|
||||
}
|
||||
}
|
||||
Ok(Some(caps.build()))
|
||||
}
|
||||
else if Some(pt) == vp8_rtx_payload_type
|
||||
|| Some(pt) == vp9_rtx_payload_type
|
||||
|| Some(pt) == h264_rtx_payload_type
|
||||
{
|
||||
caps = caps
|
||||
.field("media", "video")
|
||||
.field("clock-rate", 90000)
|
||||
.field("encoding-name", "RTX")
|
||||
.field(
|
||||
"apt",
|
||||
if Some(pt) == vp8_rtx_payload_type {
|
||||
vp8_payload_type.context("missing VP8 payload type")?
|
||||
}
|
||||
else if Some(pt) == vp9_rtx_payload_type {
|
||||
vp9_payload_type.context("missing VP9 payload type")?
|
||||
}
|
||||
else if Some(pt) == h264_rtx_payload_type {
|
||||
h264_payload_type.context("missing H264 payload type")?
|
||||
}
|
||||
else {
|
||||
unreachable!()
|
||||
},
|
||||
);
|
||||
Ok(Some(caps.build()))
|
||||
}
|
||||
else {
|
||||
|
||||
warn!("unknown payload type: {}", pt);
|
||||
Ok(None)
|
||||
};
|
||||
match f() {
|
||||
Ok(Some(caps)) => {
|
||||
debug!("mapped pt to caps: {:?}", caps);
|
||||
Some(caps.to_value())
|
||||
},
|
||||
Ok(None) => None,
|
||||
Err(e) => {
|
||||
error!("handling request-pt-map: {:?}", e);
|
||||
None
|
||||
},
|
||||
}
|
||||
};
|
||||
match f() {
|
||||
Ok(Some(caps)) => {
|
||||
debug!("mapped pt to caps: {:?}", caps);
|
||||
Some(caps.to_value())
|
||||
},
|
||||
Ok(None) => None,
|
||||
Err(e) => {
|
||||
error!("handling request-pt-map: {:?}", e);
|
||||
None
|
||||
},
|
||||
}
|
||||
})?;
|
||||
})?;
|
||||
}
|
||||
|
||||
let handle = Handle::current();
|
||||
let jingle_session = conference.jingle_session.clone();
|
||||
|
@ -653,63 +673,64 @@ impl JingleSession {
|
|||
None
|
||||
})?;
|
||||
|
||||
rtpbin.connect("request-aux-sender", false, move |values| {
|
||||
let f = move || {
|
||||
let session: u32 = values[1].get()?;
|
||||
debug!("creating RTX sender for session {}", session);
|
||||
let mut pt_map = gstreamer::Structure::builder("application/x-rtp-pt-map");
|
||||
let mut ssrc_map = gstreamer::Structure::builder("application/x-rtp-ssrc-map");
|
||||
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), Some(rtx_pt)) = (vp9_payload_type, vp9_rtx_payload_type) {
|
||||
pt_map = pt_map.field(&pt.to_string(), &(rtx_pt as u32));
|
||||
}
|
||||
if let (Some(pt), Some(rtx_pt)) = (h264_payload_type, h264_rtx_payload_type) {
|
||||
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 rtx_sender = gstreamer::ElementFactory::make("rtprtxsend", None)?;
|
||||
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_pad(&gstreamer::GhostPad::with_target(
|
||||
Some(&format!("src_{}", session)),
|
||||
&rtx_sender
|
||||
.static_pad("src")
|
||||
.context("rtprtxsend has no src pad")?,
|
||||
)?)?;
|
||||
bin.add_pad(&gstreamer::GhostPad::with_target(
|
||||
Some(&format!("sink_{}", session)),
|
||||
&rtx_sender
|
||||
.static_pad("sink")
|
||||
.context("rtprtxsend has no sink pad")?,
|
||||
)?)?;
|
||||
Ok::<_, anyhow::Error>(Some(bin.to_value()))
|
||||
};
|
||||
match f() {
|
||||
Ok(o) => o,
|
||||
Err(e) => {
|
||||
warn!("request-aux-sender: {:?}", e);
|
||||
let pts: Vec<(String, u32)> = codecs.iter()
|
||||
.filter(|codec| codec.is_video())
|
||||
.flat_map(|codec| {
|
||||
if let Some(rtx_pt) = codec.rtx_pt {
|
||||
Some((codec.pt.to_string(), rtx_pt as u32))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}
|
||||
})?;
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
{
|
||||
let pts = pts.clone();
|
||||
rtpbin.connect("request-aux-sender", false, move |values| {
|
||||
let f = || {
|
||||
let session: u32 = values[1].get()?;
|
||||
debug!("creating RTX sender for session {}", session);
|
||||
let mut pt_map = gstreamer::Structure::builder("application/x-rtp-pt-map");
|
||||
let mut ssrc_map = gstreamer::Structure::builder("application/x-rtp-ssrc-map");
|
||||
for (pt, rtx_pt) in pts.iter() {
|
||||
pt_map = pt_map.field(pt, rtx_pt);
|
||||
}
|
||||
ssrc_map = ssrc_map.field(&video_ssrc.to_string(), &(video_rtx_ssrc as u32));
|
||||
let bin = gstreamer::Bin::new(None);
|
||||
let rtx_sender = gstreamer::ElementFactory::make("rtprtxsend", None)?;
|
||||
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_pad(&gstreamer::GhostPad::with_target(
|
||||
Some(&format!("src_{}", session)),
|
||||
&rtx_sender
|
||||
.static_pad("src")
|
||||
.context("rtprtxsend has no src pad")?,
|
||||
)?)?;
|
||||
bin.add_pad(&gstreamer::GhostPad::with_target(
|
||||
Some(&format!("sink_{}", session)),
|
||||
&rtx_sender
|
||||
.static_pad("sink")
|
||||
.context("rtprtxsend has no sink pad")?,
|
||||
)?)?;
|
||||
Ok::<_, anyhow::Error>(Some(bin.to_value()))
|
||||
};
|
||||
match f() {
|
||||
Ok(o) => o,
|
||||
Err(e) => {
|
||||
warn!("request-aux-sender: {:?}", e);
|
||||
None
|
||||
},
|
||||
}
|
||||
})?;
|
||||
}
|
||||
|
||||
rtpbin.connect("request-aux-receiver", false, move |values| {
|
||||
let f = move || {
|
||||
let f = || {
|
||||
let session: u32 = values[1].get()?;
|
||||
debug!("creating RTX receiver for session {}", session);
|
||||
let mut pt_map = gstreamer::Structure::builder("application/x-rtp-pt-map");
|
||||
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), Some(rtx_pt)) = (vp9_payload_type, vp9_rtx_payload_type) {
|
||||
pt_map = pt_map.field(&pt.to_string(), &(rtx_pt as u32));
|
||||
}
|
||||
if let (Some(pt), Some(rtx_pt)) = (h264_payload_type, h264_rtx_payload_type) {
|
||||
pt_map = pt_map.field(&pt.to_string(), &(rtx_pt as u32));
|
||||
for (pt, rtx_pt) in pts.iter() {
|
||||
pt_map = pt_map.field(pt, rtx_pt);
|
||||
}
|
||||
let bin = gstreamer::Bin::new(None);
|
||||
let rtx_receiver = gstreamer::ElementFactory::make("rtprtxreceive", None)?;
|
||||
|
@ -743,6 +764,7 @@ impl JingleSession {
|
|||
let conference = conference.clone();
|
||||
let pipeline = pipeline.clone();
|
||||
let rtpbin_ = rtpbin.clone();
|
||||
let codecs = codecs.clone();
|
||||
rtpbin.connect("pad-added", false, move |values| {
|
||||
let rtpbin = &rtpbin_;
|
||||
let f = || {
|
||||
|
@ -772,26 +794,22 @@ impl JingleSession {
|
|||
|
||||
let source_element = match source.media_type {
|
||||
MediaType::Audio => {
|
||||
if Some(pt) == opus_payload_type {
|
||||
gstreamer::ElementFactory::make("rtpopusdepay", None)?
|
||||
let codec = codecs.iter()
|
||||
.filter(|codec| codec.is_audio())
|
||||
.find(|codec| codec.is(pt));
|
||||
if let Some(codec) = codec {
|
||||
gstreamer::ElementFactory::make(codec.make_depay_name(), None)?
|
||||
}
|
||||
else {
|
||||
bail!("received audio with unsupported PT {}", pt);
|
||||
}
|
||||
},
|
||||
MediaType::Video => {
|
||||
if Some(pt) == h264_payload_type {
|
||||
let element = gstreamer::ElementFactory::make("rtph264depay", None)?;
|
||||
element.set_property("request-keyframe", true)?;
|
||||
element
|
||||
}
|
||||
else if Some(pt) == vp8_payload_type {
|
||||
let element = gstreamer::ElementFactory::make("rtpvp8depay", None)?;
|
||||
element.set_property("request-keyframe", true)?;
|
||||
element
|
||||
}
|
||||
else if Some(pt) == vp9_payload_type {
|
||||
let element = gstreamer::ElementFactory::make("rtpvp9depay", None)?;
|
||||
let codec = codecs.iter()
|
||||
.filter(|codec| codec.is_video())
|
||||
.find(|codec| codec.is(pt));
|
||||
if let Some(codec) = codec {
|
||||
let element = gstreamer::ElementFactory::make(codec.make_depay_name(), None)?;
|
||||
element.set_property("request-keyframe", true)?;
|
||||
element
|
||||
}
|
||||
|
@ -897,11 +915,14 @@ impl JingleSession {
|
|||
})?;
|
||||
}
|
||||
|
||||
let audio_sink_element = gstreamer::ElementFactory::make("rtpopuspay", None)?;
|
||||
audio_sink_element.set_property(
|
||||
"pt",
|
||||
opus_payload_type.context("no opus payload type in jingle session-initiate")? as u32,
|
||||
)?;
|
||||
let opus = codecs.iter().find(|codec| codec.name == CodecName::Opus);
|
||||
let audio_sink_element = if let Some(opus) = opus {
|
||||
let audio_sink_element = gstreamer::ElementFactory::make(opus.make_pay_name(), None)?;
|
||||
audio_sink_element.set_property("pt", opus.pt as u32)?;
|
||||
audio_sink_element
|
||||
} else {
|
||||
bail!("no opus payload type in jingle session-initiate");
|
||||
};
|
||||
audio_sink_element.set_property("min-ptime", 10i64 * 1000 * 1000)?;
|
||||
audio_sink_element.set_property("ssrc", audio_ssrc)?;
|
||||
if audio_sink_element.has_property("auto-header-extension", None) {
|
||||
|
@ -943,35 +964,21 @@ impl JingleSession {
|
|||
}
|
||||
pipeline.add(&audio_sink_element)?;
|
||||
|
||||
let video_sink_element = match conference.config.video_codec.as_str() {
|
||||
"h264" => {
|
||||
let element = gstreamer::ElementFactory::make("rtph264pay", None)?;
|
||||
element.set_property(
|
||||
"pt",
|
||||
h264_payload_type.context("no h264 payload type in jingle session-initiate")? as u32,
|
||||
)?;
|
||||
let codec_name = conference.config.video_codec.as_str();
|
||||
let codec = codecs.iter().find(|codec| codec.is_codec(codec_name));
|
||||
let video_sink_element = if let Some(codec) = codec {
|
||||
let element = gstreamer::ElementFactory::make(codec.make_pay_name(), None)?;
|
||||
element.set_property("pt", codec.pt as u32)?;
|
||||
if codec.name == CodecName::H264 {
|
||||
element.set_property_from_str("aggregate-mode", "zero-latency");
|
||||
element
|
||||
},
|
||||
"vp8" => {
|
||||
let element = gstreamer::ElementFactory::make("rtpvp8pay", None)?;
|
||||
element.set_property(
|
||||
"pt",
|
||||
vp8_payload_type.context("no vp8 payload type in jingle session-initiate")? as u32,
|
||||
)?;
|
||||
}
|
||||
else {
|
||||
element.set_property_from_str("picture-id-mode", "15-bit");
|
||||
element
|
||||
},
|
||||
"vp9" => {
|
||||
let element = gstreamer::ElementFactory::make("rtpvp9pay", None)?;
|
||||
element.set_property(
|
||||
"pt",
|
||||
vp9_payload_type.context("no vp9 payload type in jingle session-initiate")? as u32,
|
||||
)?;
|
||||
element.set_property_from_str("picture-id-mode", "15-bit");
|
||||
element
|
||||
},
|
||||
other => bail!("unsupported video codec: {}", other),
|
||||
}
|
||||
element
|
||||
}
|
||||
else {
|
||||
bail!("unsupported video codec: {}", codec_name);
|
||||
};
|
||||
video_sink_element.set_property("ssrc", video_ssrc)?;
|
||||
if video_sink_element.has_property("auto-header-extension", None) {
|
||||
|
@ -1114,73 +1121,40 @@ impl JingleSession {
|
|||
let mut description = RtpDescription::new(initiate_content.name.0.clone());
|
||||
|
||||
description.payload_types = if initiate_content.name.0 == "audio" {
|
||||
let mut pt = PayloadType::new(
|
||||
opus_payload_type.context("no opus payload type in jingle session-initiate")?,
|
||||
"opus".to_owned(),
|
||||
48000,
|
||||
2,
|
||||
);
|
||||
pt.rtcp_fbs = opus_rtcp_fbs.clone().unwrap_or_default();
|
||||
vec![pt]
|
||||
let codec = codecs.iter().find(|codec| codec.name == CodecName::Opus);
|
||||
if let Some(codec) = codec {
|
||||
let mut pt = PayloadType::new(
|
||||
codec.pt,
|
||||
"opus".to_owned(),
|
||||
48000,
|
||||
2,
|
||||
);
|
||||
pt.rtcp_fbs = codec.rtcp_fbs.clone();
|
||||
vec![pt]
|
||||
}
|
||||
else {
|
||||
bail!("no opus payload type in jingle session-initiate");
|
||||
}
|
||||
}
|
||||
else {
|
||||
let mut pts = vec![];
|
||||
match conference.config.video_codec.as_str() {
|
||||
"h264" => {
|
||||
if let Some(h264_pt) = h264_payload_type {
|
||||
let mut pt = PayloadType::new(h264_pt, "H264".to_owned(), 90000, 1);
|
||||
pt.rtcp_fbs = h264_rtcp_fbs.clone().unwrap_or_default();
|
||||
pts.push(pt);
|
||||
if let Some(rtx_pt) = h264_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: h264_pt.to_string(),
|
||||
}];
|
||||
pts.push(rtx_pt);
|
||||
}
|
||||
}
|
||||
else {
|
||||
bail!("no h264 payload type in jingle session-initiate");
|
||||
}
|
||||
},
|
||||
"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),
|
||||
let codec_name = conference.config.video_codec.as_str();
|
||||
let codec = codecs.iter().find(|codec| codec.is_codec(codec_name));
|
||||
if let Some(codec) = codec {
|
||||
let mut pt = PayloadType::new(codec.pt, codec.encoding_name().to_owned(), 90000, 1);
|
||||
pt.rtcp_fbs = codec.rtcp_fbs.clone();
|
||||
pts.push(pt);
|
||||
if let Some(rtx_pt) = codec.rtx_pt {
|
||||
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: codec.pt.to_string(),
|
||||
}];
|
||||
pts.push(rtx_pt);
|
||||
}
|
||||
}
|
||||
else {
|
||||
bail!("unsupported video codec: {}", codec_name);
|
||||
}
|
||||
pts
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue