use crate::peer_connection::configuration::UNSPECIFIED_STR;
use crate::peer_connection::configuration::media_engine::*;
use crate::rtp_transceiver::rtp_sender::rtcp_parameters::RTCPFeedback;
use crate::rtp_transceiver::rtp_sender::rtp_codec_parameters::RTCRtpCodecParameters;
use crate::rtp_transceiver::rtp_sender::rtp_encoding_parameters::RTCRtpEncodingParameters;
use crate::rtp_transceiver::{PayloadType, fmtp};
use serde::{Deserialize, Serialize};
use shared::error::{Error, Result};
use std::fmt;
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum RtpCodecKind {
#[default]
Unspecified = 0,
#[serde(rename = "audio")]
Audio = 1,
#[serde(rename = "video")]
Video = 2,
}
impl From<&str> for RtpCodecKind {
fn from(raw: &str) -> Self {
match raw {
"audio" => RtpCodecKind::Audio,
"video" => RtpCodecKind::Video,
_ => RtpCodecKind::Unspecified,
}
}
}
impl From<u8> for RtpCodecKind {
fn from(v: u8) -> Self {
match v {
1 => RtpCodecKind::Audio,
2 => RtpCodecKind::Video,
_ => RtpCodecKind::Unspecified,
}
}
}
impl fmt::Display for RtpCodecKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match *self {
RtpCodecKind::Audio => "audio",
RtpCodecKind::Video => "video",
RtpCodecKind::Unspecified => UNSPECIFIED_STR,
};
write!(f, "{s}")
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct RTCRtpCodec {
pub mime_type: String,
pub clock_rate: u32,
pub channels: u16,
pub sdp_fmtp_line: String,
pub rtcp_feedback: Vec<RTCPFeedback>, }
impl RTCRtpCodec {
pub fn payloader(&self) -> Result<Box<dyn rtp::packetizer::Payloader>> {
let mime_type = self.mime_type.to_lowercase();
if mime_type == MIME_TYPE_H264.to_lowercase() {
Ok(Box::<rtp::codec::h264::H264Payloader>::default())
} else if mime_type == MIME_TYPE_HEVC.to_lowercase() {
Ok(Box::<rtp::codec::h265::HevcPayloader>::default())
} else if mime_type == MIME_TYPE_VP8.to_lowercase() {
let mut vp8_payloader = rtp::codec::vp8::Vp8Payloader::default();
vp8_payloader.enable_picture_id = true;
Ok(Box::new(vp8_payloader))
} else if mime_type == MIME_TYPE_VP9.to_lowercase() {
Ok(Box::<rtp::codec::vp9::Vp9Payloader>::default())
} else if mime_type == MIME_TYPE_OPUS.to_lowercase() {
Ok(Box::<rtp::codec::opus::OpusPayloader>::default())
} else if mime_type == MIME_TYPE_G722.to_lowercase()
|| mime_type == MIME_TYPE_PCMU.to_lowercase()
|| mime_type == MIME_TYPE_PCMA.to_lowercase()
|| mime_type == MIME_TYPE_TELEPHONE_EVENT.to_lowercase()
{
Ok(Box::<rtp::codec::g7xx::G7xxPayloader>::default())
} else if mime_type == MIME_TYPE_AV1.to_lowercase() {
Ok(Box::<rtp::codec::av1::Av1Payloader>::default())
} else {
Err(Error::ErrNoPayloaderForCodec)
}
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq)]
pub(crate) enum CodecMatch {
#[default]
None = 0,
Partial = 1,
Exact = 2,
}
pub(crate) fn codec_parameters_fuzzy_search(
needle_rtp_codec: &RTCRtpCodec,
haystack: &[RTCRtpCodecParameters],
) -> (RTCRtpCodecParameters, CodecMatch) {
let needle_fmtp = fmtp::parse(&needle_rtp_codec.mime_type, &needle_rtp_codec.sdp_fmtp_line);
for c in haystack {
let cfmpt = fmtp::parse(&c.rtp_codec.mime_type, &c.rtp_codec.sdp_fmtp_line);
if needle_fmtp.match_fmtp(&*cfmpt) {
return (c.clone(), CodecMatch::Exact);
}
}
for c in haystack {
if c.rtp_codec.mime_type.to_uppercase() == needle_rtp_codec.mime_type.to_uppercase() {
return (c.clone(), CodecMatch::Partial);
}
}
(RTCRtpCodecParameters::default(), CodecMatch::None)
}
pub(crate) fn encoding_parameters_fuzzy_search(
encodings: &[RTCRtpEncodingParameters],
haystack: &[RTCRtpCodecParameters],
) -> (RTCRtpEncodingParameters, CodecMatch) {
let mut result = None;
for encoding in encodings {
let (_, codec_match_type) = codec_parameters_fuzzy_search(&encoding.codec, haystack);
if codec_match_type == CodecMatch::Exact {
return (encoding.clone(), codec_match_type);
} else if result.is_none() {
result = Some((encoding.clone(), CodecMatch::Partial));
}
}
if let Some((encoding, code_match_type)) = result {
(encoding, code_match_type)
} else {
(RTCRtpEncodingParameters::default(), CodecMatch::None)
}
}
pub(crate) fn find_rtx_payload_type(
needle: PayloadType,
haystack: &[RTCRtpCodecParameters],
) -> Option<PayloadType> {
let apt_str = format!("apt={}", needle);
for c in haystack {
if apt_str == c.rtp_codec.sdp_fmtp_line {
return Some(c.payload_type);
}
}
None
}
pub(crate) fn find_fec_payload_type(haystack: &[RTCRtpCodecParameters]) -> Option<PayloadType> {
for c in haystack {
if c.rtp_codec
.mime_type
.to_lowercase()
.contains(MIME_TYPE_FLEX_FEC)
{
return Some(c.payload_type);
}
}
None
}
pub(crate) fn rtcp_feedback_intersection(
a: &[RTCPFeedback],
b: &[RTCPFeedback],
) -> Vec<RTCPFeedback> {
let mut out = vec![];
for a_feedback in a {
for b_feeback in b {
if a_feedback.typ == b_feeback.typ && a_feedback.parameter == b_feeback.parameter {
out.push(a_feedback.clone());
break;
}
}
}
out
}