voice_engine/media/codecs/
mod.rs1use crate::media::{PcmBuf, Sample};
2pub mod g722;
3pub mod g729;
4#[cfg(feature = "opus")]
5pub mod opus;
6pub mod pcma;
7pub mod pcmu;
8pub mod resample;
9pub mod telephone_event;
10#[cfg(test)]
11mod tests;
12#[derive(Debug, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
13pub enum CodecType {
14 PCMU,
15 PCMA,
16 G722,
17 G729,
18 #[cfg(feature = "opus")]
19 Opus,
20 TelephoneEvent,
21}
22
23pub trait Decoder: Send + Sync {
24 fn decode(&mut self, data: &[u8]) -> PcmBuf;
26
27 fn sample_rate(&self) -> u32;
29
30 fn channels(&self) -> u16;
32}
33
34pub trait Encoder: Send + Sync {
35 fn encode(&mut self, samples: &[Sample]) -> Vec<u8>;
37
38 fn sample_rate(&self) -> u32;
40
41 fn channels(&self) -> u16;
43}
44
45pub fn create_decoder(codec: CodecType) -> Box<dyn Decoder> {
46 match codec {
47 CodecType::PCMU => Box::new(pcmu::PcmuDecoder::new()),
48 CodecType::PCMA => Box::new(pcma::PcmaDecoder::new()),
49 CodecType::G722 => Box::new(g722::G722Decoder::new()),
50 CodecType::G729 => Box::new(g729::G729Decoder::new()),
51 #[cfg(feature = "opus")]
52 CodecType::Opus => Box::new(opus::OpusDecoder::new_default()),
53 CodecType::TelephoneEvent => Box::new(telephone_event::TelephoneEventDecoder::new()),
54 }
55}
56
57pub fn create_encoder(codec: CodecType) -> Box<dyn Encoder> {
58 match codec {
59 CodecType::PCMU => Box::new(pcmu::PcmuEncoder::new()),
60 CodecType::PCMA => Box::new(pcma::PcmaEncoder::new()),
61 CodecType::G722 => Box::new(g722::G722Encoder::new()),
62 CodecType::G729 => Box::new(g729::G729Encoder::new()),
63 #[cfg(feature = "opus")]
64 CodecType::Opus => Box::new(opus::OpusEncoder::new_default()),
65 CodecType::TelephoneEvent => Box::new(telephone_event::TelephoneEventEncoder::new()),
66 }
67}
68
69impl CodecType {
70 pub fn mime_type(&self) -> &str {
71 match self {
72 CodecType::PCMU => "audio/PCMU",
73 CodecType::PCMA => "audio/PCMA",
74 CodecType::G722 => "audio/G722",
75 CodecType::G729 => "audio/G729",
76 #[cfg(feature = "opus")]
77 CodecType::Opus => "audio/opus",
78 CodecType::TelephoneEvent => "audio/telephone-event",
79 }
80 }
81 pub fn rtpmap(&self) -> &str {
82 match self {
83 CodecType::PCMU => "PCMU/8000",
84 CodecType::PCMA => "PCMA/8000",
85 CodecType::G722 => "G722/8000",
86 CodecType::G729 => "G729/8000",
87 #[cfg(feature = "opus")]
88 CodecType::Opus => "opus/48000/2",
89 CodecType::TelephoneEvent => "telephone-event/8000",
90 }
91 }
92 pub fn fmtp(&self) -> Option<&str> {
93 match self {
94 CodecType::PCMU => None,
95 CodecType::PCMA => None,
96 CodecType::G722 => None,
97 CodecType::G729 => None,
98 #[cfg(feature = "opus")]
99 CodecType::Opus => Some("minptime=10;useinbandfec=1"),
100 CodecType::TelephoneEvent => Some("0-16"),
101 }
102 }
103
104 pub fn clock_rate(&self) -> u32 {
105 match self {
106 CodecType::PCMU => 8000,
107 CodecType::PCMA => 8000,
108 CodecType::G722 => 8000,
109 CodecType::G729 => 8000,
110 #[cfg(feature = "opus")]
111 CodecType::Opus => 48000,
112 CodecType::TelephoneEvent => 8000,
113 }
114 }
115
116 pub fn channels(&self) -> u16 {
117 match self {
118 #[cfg(feature = "opus")]
119 CodecType::Opus => 2,
120 _ => 1,
121 }
122 }
123
124 pub fn payload_type(&self) -> u8 {
125 match self {
126 CodecType::PCMU => 0,
127 CodecType::PCMA => 8,
128 CodecType::G722 => 9,
129 CodecType::G729 => 18,
130 #[cfg(feature = "opus")]
131 CodecType::Opus => 111,
132 CodecType::TelephoneEvent => 101,
133 }
134 }
135 pub fn samplerate(&self) -> u32 {
136 match self {
137 CodecType::PCMU => 8000,
138 CodecType::PCMA => 8000,
139 CodecType::G722 => 16000,
140 CodecType::G729 => 8000,
141 #[cfg(feature = "opus")]
142 CodecType::Opus => 48000,
143 CodecType::TelephoneEvent => 8000,
144 }
145 }
146 pub fn is_audio(&self) -> bool {
147 match self {
148 CodecType::PCMU | CodecType::PCMA | CodecType::G722 => true,
149 CodecType::G729 => true,
150 #[cfg(feature = "opus")]
151 CodecType::Opus => true,
152 _ => false,
153 }
154 }
155
156 pub fn is_dynamic(&self) -> bool {
157 match self {
158 #[cfg(feature = "opus")]
159 CodecType::Opus => true,
160 CodecType::TelephoneEvent => true,
161 _ => false,
162 }
163 }
164}
165
166impl TryFrom<u8> for CodecType {
167 type Error = anyhow::Error;
168
169 fn try_from(value: u8) -> Result<Self, Self::Error> {
170 match value {
171 0 => Ok(CodecType::PCMU),
172 8 => Ok(CodecType::PCMA),
173 9 => Ok(CodecType::G722),
174 18 => Ok(CodecType::G729), 101 => Ok(CodecType::TelephoneEvent),
177 #[cfg(feature = "opus")]
178 111 => Ok(CodecType::Opus), _ => Err(anyhow::anyhow!("Invalid codec type: {}", value)),
180 }
181 }
182}
183
184pub fn parse_rtpmap(rtpmap: &str) -> Result<(u8, CodecType, u32, u16), anyhow::Error> {
202 if let [payload_type_str, codec_spec] = rtpmap.split(' ').collect::<Vec<&str>>().as_slice() {
203 let payload_type = payload_type_str
205 .parse::<u8>()
206 .map_err(|e| anyhow::anyhow!("Failed to parse payload type: {}", e))?;
207 let codec_parts: Vec<&str> = codec_spec.split('/').collect();
208
209 if let [codec_name, clock_rate_str, channel_count @ ..] = codec_parts.as_slice() {
210 let codec_type = match codec_name.to_lowercase().as_str() {
211 "pcmu" => CodecType::PCMU,
212 "pcma" => CodecType::PCMA,
213 "g722" => CodecType::G722,
214 "g729" => CodecType::G729,
215 #[cfg(feature = "opus")]
216 "opus" => CodecType::Opus,
217 "telephone-event" => CodecType::TelephoneEvent,
218 _ => return Err(anyhow::anyhow!("Unsupported codec name: {}", codec_name)),
219 };
220
221 let clock_rate = clock_rate_str
222 .parse::<u32>()
223 .map_err(|e| anyhow::anyhow!("Failed to parse clock rate: {}", e))?;
224
225 let channel_count = match channel_count {
226 ["2"] => 2,
227 _ => 1,
228 };
229 Ok((payload_type, codec_type, clock_rate, channel_count))
230 } else {
231 return Err(anyhow::anyhow!("Invalid codec specification in rtpmap"));
232 }
233 } else {
234 Err(anyhow::anyhow!(
235 "Invalid rtpmap format: missing space between payload type and encoding name"
236 ))
237 }
238}
239
240#[cfg(target_endian = "little")]
241pub fn samples_to_bytes(samples: &[Sample]) -> Vec<u8> {
242 unsafe {
243 std::slice::from_raw_parts(
244 samples.as_ptr() as *const u8,
245 samples.len() * std::mem::size_of::<Sample>(),
246 )
247 .to_vec()
248 }
249}
250
251#[cfg(target_endian = "big")]
252pub fn samples_to_bytes(samples: &[Sample]) -> Vec<u8> {
253 samples.iter().flat_map(|s| s.to_le_bytes()).collect()
254}
255
256#[cfg(target_endian = "little")]
257pub fn bytes_to_samples(u8_data: &[u8]) -> PcmBuf {
258 unsafe {
259 std::slice::from_raw_parts(
260 u8_data.as_ptr() as *const Sample,
261 u8_data.len() / std::mem::size_of::<Sample>(),
262 )
263 .to_vec()
264 }
265}
266#[cfg(target_endian = "big")]
267pub fn bytes_to_samples(u8_data: &[u8]) -> PcmBuf {
268 u8_data
269 .chunks(2)
270 .map(|chunk| (chunk[0] as i16) | ((chunk[1] as i16) << 8))
271 .collect()
272}