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