split RTP description parsing into its own function

This keeps the ugly Options used after in the code, in the future these
could be replaced with the ParsedRtpDescription struct instead.
This commit is contained in:
Emmanuel Gil Peyrot 2021-10-23 16:33:10 +02:00 committed by Jasper
parent 0040d20151
commit c920fdf0a5
1 changed files with 220 additions and 148 deletions

View File

@ -19,6 +19,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_rtcp_fb::RtcpFb,
jingle_rtp::{self, 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},
@ -40,6 +41,24 @@ const RTP_HDREXT_TRANSPORT_CC: &str =
const DEFAULT_STUN_PORT: u16 = 3478; const DEFAULT_STUN_PORT: u16 = 3478;
const DEFAULT_TURNS_PORT: u16 = 5349; const DEFAULT_TURNS_PORT: u16 = 5349;
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>>,
audio_hdrext_ssrc_audio_level: Option<u8>,
audio_hdrext_transport_cc: Option<u8>,
video_hdrext_abs_send_time: Option<u8>,
video_hdrext_transport_cc: Option<u8>,
}
pub(crate) struct JingleSession { pub(crate) struct JingleSession {
pipeline: gstreamer::Pipeline, pipeline: gstreamer::Pipeline,
audio_sink_element: gstreamer::Element, audio_sink_element: gstreamer::Element,
@ -91,6 +110,191 @@ impl JingleSession {
Ok(self.pipeline_state_null_rx.await?) Ok(self.pipeline_state_null_rx.await?)
} }
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 audio_hdrext_ssrc_audio_level = None;
let mut audio_hdrext_transport_cc = None;
let mut video_hdrext_abs_send_time = None;
let mut video_hdrext_transport_cc = None;
if description.media == "audio" {
opus_payload_type = description
.payload_types
.iter()
.find(|pt| pt.name.as_deref() == Some("opus"))
.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
.hdrexts
.iter()
.find(|hdrext| hdrext.uri == RTP_HDREXT_SSRC_AUDIO_LEVEL)
.map(|hdrext| hdrext.id.parse::<u8>())
.transpose()?;
audio_hdrext_transport_cc = description
.hdrexts
.iter()
.find(|hdrext| hdrext.uri == RTP_HDREXT_TRANSPORT_CC)
.map(|hdrext| hdrext.id.parse::<u8>())
.transpose()?;
}
else if description.media == "video" {
h264_payload_type = description
.payload_types
.iter()
.find(|pt| pt.name.as_deref() == Some("H264"))
.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
.payload_types
.iter()
.find(|pt| pt.name.as_deref() == Some("VP8"))
.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
.payload_types
.iter()
.find(|pt| pt.name.as_deref() == Some("VP9"))
.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
.hdrexts
.iter()
.find(|hdrext| hdrext.uri == RTP_HDREXT_ABS_SEND_TIME)
.map(|hdrext| hdrext.id.parse::<u8>())
.transpose()?;
video_hdrext_transport_cc = description
.hdrexts
.iter()
.find(|hdrext| hdrext.uri == RTP_HDREXT_TRANSPORT_CC)
.map(|hdrext| hdrext.id.parse::<u8>())
.transpose()?;
}
else {
debug!("skipping media: {}", description.media);
return Ok(None);
}
for ssrc in &description.ssrcs {
let owner = ssrc
.info
.as_ref()
.context("missing ssrc-info")?
.owner
.clone();
debug!("adding ssrc to remote_ssrc_map: {:?}", ssrc);
remote_ssrc_map.insert(
ssrc.id.parse()?,
Source {
ssrc: ssrc.id.parse()?,
participant_id: if owner == "jvb" {
None
}
else {
Some(
owner
.split('/')
.nth(1)
.context("invalid ssrc-info owner")?
.to_owned(),
)
},
media_type: if description.media == "audio" {
MediaType::Audio
}
else {
MediaType::Video
},
},
);
}
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,
audio_hdrext_ssrc_audio_level,
audio_hdrext_transport_cc,
video_hdrext_abs_send_time,
video_hdrext_transport_cc,
}))
}
pub(crate) async fn initiate(conference: &JitsiConference, jingle: Jingle) -> Result<Self> { pub(crate) async fn initiate(conference: &JitsiConference, jingle: Jingle) -> Result<Self> {
let initiator = jingle let initiator = jingle
.initiator .initiator
@ -125,154 +329,22 @@ impl JingleSession {
for content in &jingle.contents { for content in &jingle.contents {
if let Some(Description::Rtp(description)) = &content.description { if let Some(Description::Rtp(description)) = &content.description {
if description.media == "audio" { if let Some(description) = JingleSession::parse_rtp_description(description, &mut remote_ssrc_map)? {
opus_payload_type = description opus_payload_type = opus_payload_type.or(description.opus_payload_type);
.payload_types opus_rtcp_fbs = opus_rtcp_fbs.or(description.opus_rtcp_fbs);
.iter() h264_payload_type = h264_payload_type.or(description.h264_payload_type);
.find(|pt| pt.name.as_deref() == Some("opus")) h264_rtx_payload_type = h264_rtx_payload_type.or(description.h264_rtx_payload_type);
.map(|pt| pt.id); h264_rtcp_fbs = h264_rtcp_fbs.or(description.h264_rtcp_fbs);
opus_rtcp_fbs = description vp8_payload_type = vp8_payload_type.or(description.vp8_payload_type);
.payload_types vp8_rtx_payload_type = vp8_rtx_payload_type.or(description.vp8_rtx_payload_type);
.iter() vp8_rtcp_fbs = vp8_rtcp_fbs.or(description.vp8_rtcp_fbs);
.find(|pt| pt.name.as_deref() == Some("opus")) vp9_payload_type = vp9_payload_type.or(description.vp9_payload_type);
.map(|pt| pt.rtcp_fbs.clone()); vp9_rtx_payload_type = vp9_rtx_payload_type.or(description.vp9_rtx_payload_type);
audio_hdrext_ssrc_audio_level = description vp9_rtcp_fbs = vp9_rtcp_fbs.or(description.vp9_rtcp_fbs);
.hdrexts audio_hdrext_ssrc_audio_level = audio_hdrext_ssrc_audio_level.or(description.audio_hdrext_ssrc_audio_level);
.iter() audio_hdrext_transport_cc = audio_hdrext_transport_cc.or(description.audio_hdrext_transport_cc);
.find(|hdrext| hdrext.uri == RTP_HDREXT_SSRC_AUDIO_LEVEL) video_hdrext_abs_send_time = video_hdrext_abs_send_time.or(description.video_hdrext_abs_send_time);
.map(|hdrext| hdrext.id.parse::<u8>()) video_hdrext_transport_cc = video_hdrext_transport_cc.or(description.video_hdrext_transport_cc);
.transpose()?;
audio_hdrext_transport_cc = description
.hdrexts
.iter()
.find(|hdrext| hdrext.uri == RTP_HDREXT_TRANSPORT_CC)
.map(|hdrext| hdrext.id.parse::<u8>())
.transpose()?;
}
else if description.media == "video" {
h264_payload_type = description
.payload_types
.iter()
.find(|pt| pt.name.as_deref() == Some("H264"))
.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
.payload_types
.iter()
.find(|pt| pt.name.as_deref() == Some("VP8"))
.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
.payload_types
.iter()
.find(|pt| pt.name.as_deref() == Some("VP9"))
.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
.hdrexts
.iter()
.find(|hdrext| hdrext.uri == RTP_HDREXT_ABS_SEND_TIME)
.map(|hdrext| hdrext.id.parse::<u8>())
.transpose()?;
video_hdrext_transport_cc = description
.hdrexts
.iter()
.find(|hdrext| hdrext.uri == RTP_HDREXT_TRANSPORT_CC)
.map(|hdrext| hdrext.id.parse::<u8>())
.transpose()?;
}
else {
debug!("skipping media: {}", description.media);
continue;
}
for ssrc in &description.ssrcs {
let owner = ssrc
.info
.as_ref()
.context("missing ssrc-info")?
.owner
.clone();
debug!("adding ssrc to remote_ssrc_map: {:?}", ssrc);
remote_ssrc_map.insert(
ssrc.id.parse()?,
Source {
ssrc: ssrc.id.parse()?,
participant_id: if owner == "jvb" {
None
}
else {
Some(
owner
.split('/')
.nth(1)
.context("invalid ssrc-info owner")?
.to_owned(),
)
},
media_type: if description.media == "audio" {
MediaType::Audio
}
else {
MediaType::Video
},
},
);
} }
} }