use std::fmt;
use super::*;
use crate::api::media_engine::*;
use crate::error::{Error, Result};
use crate::rtp_transceiver::fmtp;
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub enum RTPCodecType {
#[default]
Unspecified = 0,
Audio = 1,
Video = 2,
}
impl From<&str> for RTPCodecType {
fn from(raw: &str) -> Self {
match raw {
"audio" => RTPCodecType::Audio,
"video" => RTPCodecType::Video,
_ => RTPCodecType::Unspecified,
}
}
}
impl From<u8> for RTPCodecType {
fn from(v: u8) -> Self {
match v {
1 => RTPCodecType::Audio,
2 => RTPCodecType::Video,
_ => RTPCodecType::Unspecified,
}
}
}
impl fmt::Display for RTPCodecType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match *self {
RTPCodecType::Audio => "audio",
RTPCodecType::Video => "video",
RTPCodecType::Unspecified => crate::UNSPECIFIED_STR,
};
write!(f, "{s}")
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct RTCRtpCodecCapability {
pub mime_type: String,
pub clock_rate: u32,
pub channels: u16,
pub sdp_fmtp_line: String,
pub rtcp_feedback: Vec<RTCPFeedback>,
}
impl RTCRtpCodecCapability {
pub fn payloader_for_codec(&self) -> Result<Box<dyn rtp::packetizer::Payloader + Send + Sync>> {
let mime_type = self.mime_type.to_lowercase();
if mime_type == MIME_TYPE_H264.to_lowercase() {
Ok(Box::<rtp::codecs::h264::H264Payloader>::default())
} else if mime_type == MIME_TYPE_VP8.to_lowercase() {
let mut vp8_payloader = rtp::codecs::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::codecs::vp9::Vp9Payloader>::default())
} else if mime_type == MIME_TYPE_OPUS.to_lowercase() {
Ok(Box::<rtp::codecs::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::codecs::g7xx::G7xxPayloader>::default())
} else if mime_type == MIME_TYPE_AV1.to_lowercase() {
Ok(Box::<rtp::codecs::av1::Av1Payloader>::default())
} else {
Err(Error::ErrNoPayloaderForCodec)
}
}
}
#[derive(Default, Debug, Clone)]
pub struct RTCRtpHeaderExtensionCapability {
pub uri: String,
}
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct RTCRtpHeaderExtensionParameters {
pub uri: String,
pub id: isize,
}
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct RTCRtpCodecParameters {
pub capability: RTCRtpCodecCapability,
pub payload_type: PayloadType,
pub stats_id: String,
}
#[derive(Default, Debug, Clone)]
pub struct RTCRtpParameters {
pub header_extensions: Vec<RTCRtpHeaderExtensionParameters>,
pub codecs: Vec<RTCRtpCodecParameters>,
}
#[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: &RTCRtpCodecParameters,
haystack: &[RTCRtpCodecParameters],
) -> (RTCRtpCodecParameters, CodecMatch) {
let needle_fmtp = fmtp::parse(
&needle.capability.mime_type,
&needle.capability.sdp_fmtp_line,
);
for c in haystack {
let cfmpt = fmtp::parse(&c.capability.mime_type, &c.capability.sdp_fmtp_line);
if needle_fmtp.match_fmtp(&*cfmpt) {
return (c.clone(), CodecMatch::Exact);
}
}
for c in haystack {
if c.capability.mime_type.to_uppercase() == needle.capability.mime_type.to_uppercase() {
return (c.clone(), CodecMatch::Partial);
}
}
(RTCRtpCodecParameters::default(), CodecMatch::None)
}