use crate::media_stream::MediaStreamId;
use crate::media_stream::track::MediaStreamTrack;
use crate::peer_connection::RTCPeerConnection;
use crate::peer_connection::configuration::media_engine::{MIME_TYPE_RTX, MediaEngine};
use crate::peer_connection::sdp::codecs_from_media_description;
use crate::rtp_transceiver::rtp_receiver::internal::RTCRtpReceiverInternal;
use crate::rtp_transceiver::rtp_sender::internal::RTCRtpSenderInternal;
use crate::rtp_transceiver::rtp_sender::rtp_codec::*;
use crate::rtp_transceiver::rtp_sender::rtp_codec_parameters::RTCRtpCodecParameters;
use crate::rtp_transceiver::rtp_sender::rtp_encoding_parameters::RTCRtpEncodingParameters;
pub use direction::RTCRtpTransceiverDirection;
use interceptor::Interceptor;
use log::trace;
use sdp::MediaDescription;
use shared::error::{Error, Result};
use std::collections::HashMap;
use std::fmt;
use unicase::UniCase;
pub(crate) mod direction;
pub(crate) mod fmtp;
pub mod rtp_receiver;
pub mod rtp_sender;
#[allow(clippy::upper_case_acronyms)]
pub type SSRC = u32;
pub type PayloadType = u8;
pub type RtpStreamId = String;
pub type RepairedStreamId = String;
pub type RTCRtpTransceiverId = usize;
#[derive(Default, Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RTCRtpSenderId(pub(crate) RTCRtpTransceiverId);
#[derive(Default, Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RTCRtpReceiverId(pub(crate) RTCRtpTransceiverId);
#[derive(Default, Clone)]
pub struct RTCRtpTransceiverInit {
pub direction: RTCRtpTransceiverDirection,
pub streams: Vec<MediaStreamId>,
pub send_encodings: Vec<RTCRtpEncodingParameters>,
}
#[derive(Default, Clone)]
pub(crate) struct RTCRtpTransceiver<I>
where
I: Interceptor,
{
mid: Option<String>,
kind: RtpCodecKind,
sender: Option<RTCRtpSenderInternal<I>>,
receiver: Option<RTCRtpReceiverInternal<I>>,
direction: RTCRtpTransceiverDirection,
current_direction: RTCRtpTransceiverDirection,
preferred_codecs: Vec<RTCRtpCodecParameters>,
stopped: bool,
}
impl<I> fmt::Debug for RTCRtpTransceiver<I>
where
I: Interceptor,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RTCRtpTransceiver")
.field("mid", &self.mid)
.field("kind", &self.kind)
.field("direction", &self.direction)
.field("current_direction", &self.current_direction)
.field("preferred_codecs", &self.preferred_codecs)
.field("stopped", &self.stopped)
.finish()
}
}
impl<I> RTCRtpTransceiver<I>
where
I: Interceptor,
{
pub(crate) fn new(
kind: RtpCodecKind,
track: Option<MediaStreamTrack>,
init: RTCRtpTransceiverInit,
) -> Self {
Self {
mid: None,
kind,
sender: if let Some(track) = track {
Some(RTCRtpSenderInternal::new(
kind,
track,
init.streams,
init.send_encodings,
))
} else {
None
},
receiver: if init.direction.has_recv() {
Some(RTCRtpReceiverInternal::new(kind, vec![]))
} else {
None
},
direction: init.direction,
current_direction: RTCRtpTransceiverDirection::Unspecified,
preferred_codecs: vec![],
stopped: false,
}
}
pub(crate) fn mid(&self) -> &Option<String> {
&self.mid
}
pub(crate) fn kind(&self) -> RtpCodecKind {
self.kind
}
pub(crate) fn sender(&self) -> &Option<RTCRtpSenderInternal<I>> {
&self.sender
}
pub(crate) fn sender_mut(&mut self) -> &mut Option<RTCRtpSenderInternal<I>> {
&mut self.sender
}
pub(crate) fn receiver(&self) -> &Option<RTCRtpReceiverInternal<I>> {
&self.receiver
}
pub(crate) fn receiver_mut(&mut self) -> &mut Option<RTCRtpReceiverInternal<I>> {
&mut self.receiver
}
pub fn direction(&self) -> RTCRtpTransceiverDirection {
self.direction
}
pub(crate) fn set_direction(&mut self, direction: RTCRtpTransceiverDirection) {
let previous_direction: RTCRtpTransceiverDirection = self.direction;
self.direction = direction;
if direction != previous_direction {
trace!("Changing direction of transceiver from {previous_direction} to {direction}");
}
}
pub(crate) fn current_direction(&self) -> RTCRtpTransceiverDirection {
self.current_direction
}
pub(crate) fn stop(&mut self, media_engine: &MediaEngine, interceptor: &mut I) -> Result<()> {
if self.stopped {
return Ok(());
}
self.stopped = true;
if let Some(sender) = self.sender_mut() {
sender.stop(media_engine, interceptor)?;
}
if let Some(receiver) = self.receiver_mut() {
receiver.stop(media_engine, interceptor)?;
}
self.direction = RTCRtpTransceiverDirection::Inactive;
self.current_direction = RTCRtpTransceiverDirection::Inactive;
Ok(())
}
pub(crate) fn set_codec_preferences(
&mut self,
codecs: Vec<RTCRtpCodecParameters>,
media_engine: &MediaEngine,
) -> Result<()> {
for codec in &codecs {
let media_engine_codecs = media_engine.get_codecs_by_kind(self.kind());
let (_, match_type) =
codec_parameters_fuzzy_search(&codec.rtp_codec, &media_engine_codecs);
if match_type == CodecMatch::None {
return Err(Error::ErrRTPTransceiverCodecUnsupported);
}
}
if let Some(sender) = self.sender_mut() {
sender.set_codec_preferences(codecs.clone());
}
if let Some(receiver) = self.receiver_mut() {
receiver.set_codec_preferences(codecs.clone());
}
self.preferred_codecs = codecs;
Ok(())
}
pub(crate) fn get_codec_preferences(&self) -> &[RTCRtpCodecParameters] {
&self.preferred_codecs
}
pub(crate) fn get_codecs(&self, media_engine: &MediaEngine) -> Vec<RTCRtpCodecParameters> {
RTCRtpReceiverInternal::<I>::get_codecs(&self.preferred_codecs, self.kind(), media_engine)
}
pub(crate) fn set_mid(&mut self, mid: String) -> Result<()> {
if self.mid.is_some() {
return Err(Error::ErrRTPTransceiverCannotChangeMid);
}
self.mid = Some(mid);
Ok(())
}
pub(crate) fn stopped(&self) -> bool {
self.stopped
}
pub(crate) fn set_current_direction(&mut self, d: RTCRtpTransceiverDirection) {
let previous: RTCRtpTransceiverDirection = self.current_direction;
self.current_direction = d;
if d != previous {
trace!("Changing current direction of transceiver from {previous} to {d}",);
}
}
pub(crate) fn set_codec_preferences_from_remote_description(
&mut self,
media: &MediaDescription,
media_engine: &MediaEngine,
) -> Result<()> {
let mut remote_codecs = codecs_from_media_description(media)?;
let mut left_codecs = media_engine.get_codecs_by_kind(self.kind);
let mut payload_mapping = HashMap::new(); let mut filter_by_match = |match_filter: CodecMatch| -> Vec<RTCRtpCodecParameters> {
let mut filtered_codecs = vec![];
for remote_codec_idx in (0..remote_codecs.len()).rev() {
let remote_codec = &mut remote_codecs[remote_codec_idx];
if UniCase::new(remote_codec.rtp_codec.mime_type.as_str())
== UniCase::new(MIME_TYPE_RTX)
{
continue;
}
let (match_codec, match_type) =
codec_parameters_fuzzy_search(&remote_codec.rtp_codec, &left_codecs);
if match_type == match_filter {
payload_mapping.insert(remote_codec.payload_type, match_codec.payload_type);
remote_codec.payload_type = match_codec.payload_type;
filtered_codecs.push(remote_codec.clone());
remote_codecs.remove(remote_codec_idx);
let needle_fmtp = fmtp::parse(
match_codec.rtp_codec.mime_type.as_str(),
match_codec.rtp_codec.sdp_fmtp_line.as_str(),
);
for left_codec_idx in (0..left_codecs.len()).rev() {
let left_codec = &left_codecs[left_codec_idx];
let left_codec_fmtp = fmtp::parse(
left_codec.rtp_codec.mime_type.as_str(),
left_codec.rtp_codec.sdp_fmtp_line.as_str(),
);
if needle_fmtp.match_fmtp(&*left_codec_fmtp) {
left_codecs.remove(left_codec_idx);
break;
}
}
}
}
filtered_codecs
};
let mut filtered_codecs = filter_by_match(CodecMatch::Exact);
filtered_codecs.append(&mut filter_by_match(CodecMatch::Partial));
for (remote_payload_type, media_engine_payload_type) in payload_mapping {
let remote_rtx = find_rtx_payload_type(remote_payload_type, &remote_codecs);
if remote_rtx.is_none() {
continue;
}
if let Some(media_engine_rtx) =
find_rtx_payload_type(media_engine_payload_type, &left_codecs)
{
for rtx_codec in &left_codecs {
if rtx_codec.payload_type == media_engine_rtx {
filtered_codecs.push(rtx_codec.clone());
break;
}
}
}
}
self.set_codec_preferences(filtered_codecs, media_engine)
}
}
impl<I> RTCPeerConnection<I>
where
I: Interceptor,
{
pub(crate) fn find_by_mid(
mid: &String,
local_transceivers: &[RTCRtpTransceiver<I>],
) -> Option<usize> {
local_transceivers
.iter()
.enumerate()
.find(|(_i, t)| t.mid.as_ref() == Some(mid))
.map(|(i, _v)| i)
}
pub(crate) fn satisfy_type_and_direction(
remote_kind: RtpCodecKind,
remote_direction: RTCRtpTransceiverDirection,
local_transceivers: &mut [RTCRtpTransceiver<I>],
) -> Option<&mut RTCRtpTransceiver<I>> {
let get_preferred_directions = || -> Vec<RTCRtpTransceiverDirection> {
match remote_direction {
RTCRtpTransceiverDirection::Sendrecv => vec![
RTCRtpTransceiverDirection::Recvonly,
RTCRtpTransceiverDirection::Sendrecv,
],
RTCRtpTransceiverDirection::Sendonly => vec![RTCRtpTransceiverDirection::Recvonly],
RTCRtpTransceiverDirection::Recvonly => vec![
RTCRtpTransceiverDirection::Sendonly,
RTCRtpTransceiverDirection::Sendrecv,
],
_ => vec![],
}
};
for possible_direction in get_preferred_directions() {
if let Some(index) = local_transceivers.iter().position(|t| {
t.mid.is_none() && t.kind() == remote_kind && possible_direction == t.direction
}) {
return Some(&mut local_transceivers[index]);
}
}
None
}
}