1 use super::*;
2 use crate::api::media_engine::*;
3 use crate::error::{Error, Result};
4 use crate::rtp_transceiver::fmtp;
5 
6 use std::fmt;
7 
8 /// RTPCodecType determines the type of a codec
9 #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
10 pub enum RTPCodecType {
11     #[default]
12     Unspecified = 0,
13 
14     /// RTPCodecTypeAudio indicates this is an audio codec
15     Audio = 1,
16 
17     /// RTPCodecTypeVideo indicates this is a video codec
18     Video = 2,
19 }
20 
21 impl From<&str> for RTPCodecType {
from(raw: &str) -> Self22     fn from(raw: &str) -> Self {
23         match raw {
24             "audio" => RTPCodecType::Audio,
25             "video" => RTPCodecType::Video,
26             _ => RTPCodecType::Unspecified,
27         }
28     }
29 }
30 
31 impl From<u8> for RTPCodecType {
from(v: u8) -> Self32     fn from(v: u8) -> Self {
33         match v {
34             1 => RTPCodecType::Audio,
35             2 => RTPCodecType::Video,
36             _ => RTPCodecType::Unspecified,
37         }
38     }
39 }
40 
41 impl fmt::Display for RTPCodecType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result42     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43         let s = match *self {
44             RTPCodecType::Audio => "audio",
45             RTPCodecType::Video => "video",
46             RTPCodecType::Unspecified => crate::UNSPECIFIED_STR,
47         };
48         write!(f, "{s}")
49     }
50 }
51 
52 /// RTPCodecCapability provides information about codec capabilities.
53 /// <https://w3c.github.io/webrtc-pc/#dictionary-rtcrtpcodeccapability-members>
54 #[derive(Default, Debug, Clone, PartialEq, Eq)]
55 pub struct RTCRtpCodecCapability {
56     pub mime_type: String,
57     pub clock_rate: u32,
58     pub channels: u16,
59     pub sdp_fmtp_line: String,
60     pub rtcp_feedback: Vec<RTCPFeedback>,
61 }
62 
63 impl RTCRtpCodecCapability {
64     /// Turn codec capability into a `packetizer::Payloader`
payloader_for_codec(&self) -> Result<Box<dyn rtp::packetizer::Payloader + Send + Sync>>65     pub fn payloader_for_codec(&self) -> Result<Box<dyn rtp::packetizer::Payloader + Send + Sync>> {
66         let mime_type = self.mime_type.to_lowercase();
67         if mime_type == MIME_TYPE_H264.to_lowercase() {
68             Ok(Box::<rtp::codecs::h264::H264Payloader>::default())
69         } else if mime_type == MIME_TYPE_VP8.to_lowercase() {
70             let mut vp8_payloader = rtp::codecs::vp8::Vp8Payloader::default();
71             vp8_payloader.enable_picture_id = true;
72             Ok(Box::new(vp8_payloader))
73         } else if mime_type == MIME_TYPE_VP9.to_lowercase() {
74             Ok(Box::<rtp::codecs::vp9::Vp9Payloader>::default())
75         } else if mime_type == MIME_TYPE_OPUS.to_lowercase() {
76             Ok(Box::<rtp::codecs::opus::OpusPayloader>::default())
77         } else if mime_type == MIME_TYPE_G722.to_lowercase()
78             || mime_type == MIME_TYPE_PCMU.to_lowercase()
79             || mime_type == MIME_TYPE_PCMA.to_lowercase()
80             || mime_type == MIME_TYPE_TELEPHONE_EVENT.to_lowercase()
81         {
82             Ok(Box::<rtp::codecs::g7xx::G7xxPayloader>::default())
83         } else {
84             Err(Error::ErrNoPayloaderForCodec)
85         }
86     }
87 }
88 
89 /// RTPHeaderExtensionCapability is used to define a RFC5285 RTP header extension supported by the codec.
90 /// <https://w3c.github.io/webrtc-pc/#dom-rtcrtpcapabilities-headerextensions>
91 #[derive(Default, Debug, Clone)]
92 pub struct RTCRtpHeaderExtensionCapability {
93     pub uri: String,
94 }
95 
96 /// RTPHeaderExtensionParameter represents a negotiated RFC5285 RTP header extension.
97 /// <https://w3c.github.io/webrtc-pc/#dictionary-rtcrtpheaderextensionparameters-members>
98 #[derive(Default, Debug, Clone, PartialEq, Eq)]
99 pub struct RTCRtpHeaderExtensionParameters {
100     pub uri: String,
101     pub id: isize,
102 }
103 
104 /// RTPCodecParameters is a sequence containing the media codecs that an RtpSender
105 /// will choose from, as well as entries for RTX, RED and FEC mechanisms. This also
106 /// includes the PayloadType that has been negotiated
107 /// <https://w3c.github.io/webrtc-pc/#rtcrtpcodecparameters>
108 #[derive(Default, Debug, Clone, PartialEq, Eq)]
109 pub struct RTCRtpCodecParameters {
110     pub capability: RTCRtpCodecCapability,
111     pub payload_type: PayloadType,
112     pub stats_id: String,
113 }
114 
115 /// RTPParameters is a list of negotiated codecs and header extensions
116 /// <https://w3c.github.io/webrtc-pc/#dictionary-rtcrtpparameters-members>
117 #[derive(Default, Debug, Clone)]
118 pub struct RTCRtpParameters {
119     pub header_extensions: Vec<RTCRtpHeaderExtensionParameters>,
120     pub codecs: Vec<RTCRtpCodecParameters>,
121 }
122 
123 #[derive(Default, Debug, Copy, Clone, PartialEq)]
124 pub(crate) enum CodecMatch {
125     #[default]
126     None = 0,
127     Partial = 1,
128     Exact = 2,
129 }
130 
131 /// Do a fuzzy find for a codec in the list of codecs
132 /// Used for lookup up a codec in an existing list to find a match
133 /// Returns codecMatchExact, codecMatchPartial, or codecMatchNone
codec_parameters_fuzzy_search( needle: &RTCRtpCodecParameters, haystack: &[RTCRtpCodecParameters], ) -> (RTCRtpCodecParameters, CodecMatch)134 pub(crate) fn codec_parameters_fuzzy_search(
135     needle: &RTCRtpCodecParameters,
136     haystack: &[RTCRtpCodecParameters],
137 ) -> (RTCRtpCodecParameters, CodecMatch) {
138     let needle_fmtp = fmtp::parse(
139         &needle.capability.mime_type,
140         &needle.capability.sdp_fmtp_line,
141     );
142 
143     //TODO: add unicode case-folding equal support
144 
145     // First attempt to match on mime_type + sdpfmtp_line
146     for c in haystack {
147         let cfmpt = fmtp::parse(&c.capability.mime_type, &c.capability.sdp_fmtp_line);
148         if needle_fmtp.match_fmtp(&*cfmpt) {
149             return (c.clone(), CodecMatch::Exact);
150         }
151     }
152 
153     // Fallback to just mime_type
154     for c in haystack {
155         if c.capability.mime_type.to_uppercase() == needle.capability.mime_type.to_uppercase() {
156             return (c.clone(), CodecMatch::Partial);
157         }
158     }
159 
160     (RTCRtpCodecParameters::default(), CodecMatch::None)
161 }
162