1use std::{collections::VecDeque, os::raw::c_int, sync::Arc};
2
3use bytemuck;
4use ctor::ctor;
5use media_codec::{
6 encoder::{register_encoder, AudioEncoder, AudioEncoderParameters, Encoder, EncoderBuilder, EncoderParameters},
7 packet::Packet,
8 AudioParameters, Codec, CodecBuilder, CodecID, CodecInformation, CodecParameters,
9};
10use media_core::{
11 audio::{AudioFrame, SampleFormat},
12 buffer::BufferPool,
13 error::Error,
14 frame::SharedFrame,
15 invalid_param_error,
16 rational::Rational64,
17 unsupported_error,
18 variant::Variant,
19 Result,
20};
21
22use crate::{opus_error_string, opus_sys};
23
24struct OpusOptions {
25 application: i32,
26 frame_duration: f32,
27 frame_size: u32,
28 packet_loss: i32,
29 fec: bool,
30 vbr: u32,
31 max_bandwidth: u32,
32 complexity: u32,
33}
34
35impl Default for OpusOptions {
36 fn default() -> Self {
37 OpusOptions {
38 application: opus_sys::OPUS_APPLICATION_AUDIO,
39 frame_duration: 20.0,
40 frame_size: 960,
41 packet_loss: 0,
42 fec: false,
43 vbr: 1,
44 max_bandwidth: 0,
45 complexity: 10,
46 }
47 }
48}
49
50impl OpusOptions {
51 fn from_variant(variant: Option<&Variant>) -> Self {
52 if let Some(variant) = variant {
53 let application = variant["application"].get_int32().unwrap_or(opus_sys::OPUS_APPLICATION_AUDIO);
54 let frame_duration = variant["frame_duration"].get_float().unwrap_or(20.0);
55 let packet_loss = variant["packet_loss"].get_int32().unwrap_or(0);
56 let fec = variant["fec"].get_bool().unwrap_or(false);
57 let vbr = variant["vbr"].get_uint32().unwrap_or(1);
58 let max_bandwidth = variant["max_bandwidth"].get_uint32().unwrap_or(0);
59 let complexity = variant["complexity"].get_uint32().unwrap_or(10);
60
61 OpusOptions {
62 application,
63 frame_duration,
64 frame_size: (frame_duration * 48000f32 / 1000f32) as u32,
65 packet_loss,
66 fec,
67 vbr,
68 max_bandwidth,
69 complexity,
70 }
71 } else {
72 Self::default()
73 }
74 }
75}
76
77struct OpusEncoder {
78 encoder: *mut opus_sys::OpusEncoder,
79 pending: VecDeque<Packet<'static>>,
80 options: OpusOptions,
81 buffer: Vec<u8>,
82}
83
84unsafe impl Send for OpusEncoder {}
85unsafe impl Sync for OpusEncoder {}
86
87impl CodecInformation for OpusEncoder {
88 fn id(&self) -> CodecID {
89 CodecID::OPUS
90 }
91
92 fn name(&self) -> &'static str {
93 CODEC_NAME
94 }
95}
96
97impl Codec<AudioEncoder> for OpusEncoder {
98 fn configure(&mut self, params: Option<&CodecParameters>, options: Option<&Variant>) -> Result<()> {
99 if let Some(params) = params {
100 let params: &AudioEncoderParameters = ¶ms.try_into()?;
101 self.set_audio_parameters(¶ms.audio)?;
102 self.set_encoder_parameters(¶ms.encoder)?;
103 }
104
105 if let Some(options) = options {
106 self.options = OpusOptions::from_variant(Some(options));
107 self.update_options()?;
108 }
109
110 Ok(())
111 }
112
113 fn set_option(&mut self, key: &str, value: &Variant) -> Result<()> {
114 let value = match value {
115 Variant::Bool(value) => *value as i32,
116 _ => value.get_int32().ok_or_else(|| invalid_param_error!(value))?,
117 };
118
119 match key {
120 "bit_rate" => self.encoder_ctl(opus_sys::OPUS_SET_BITRATE_REQUEST, value),
121 "packet_loss_percent" => {
122 self.options.packet_loss = value;
123 self.encoder_ctl(opus_sys::OPUS_SET_PACKET_LOSS_PERC_REQUEST, value)
124 }
125 "fec" => {
126 self.options.fec = value != 0;
127 self.encoder_ctl(opus_sys::OPUS_SET_INBAND_FEC_REQUEST, value)
128 }
129 "vbr" => {
130 self.options.vbr = value as u32;
131 self.encoder_ctl(opus_sys::OPUS_SET_VBR_REQUEST, value)
132 }
133 "max_bandwidth" => {
134 self.options.max_bandwidth = value as u32;
135 self.encoder_ctl(opus_sys::OPUS_SET_MAX_BANDWIDTH_REQUEST, value)
136 }
137 "complexity" => {
138 self.options.complexity = value as u32;
139 self.encoder_ctl(opus_sys::OPUS_SET_COMPLEXITY_REQUEST, value)
140 }
141 _ => Err(unsupported_error!(key)),
142 }
143 }
144}
145
146const DEFAULT_PACKET_PENDING_CAPACITY: usize = 8;
147
148const MAX_FRAME_SIZE: usize = 1275;
150const MAX_FRAMES: usize = 6;
152const PACKET_HEADER_SIZE: usize = 7;
154
155impl Encoder<AudioEncoder> for OpusEncoder {
156 fn send_frame(&mut self, _config: &AudioEncoder, pool: Option<&Arc<BufferPool>>, frame: SharedFrame<AudioFrame<'static>>) -> Result<()> {
157 self.encode(frame, pool)?;
158 Ok(())
159 }
160
161 fn receive_packet(&mut self, _parameters: &AudioEncoder, _pool: Option<&Arc<BufferPool>>) -> Result<Packet<'static>> {
162 self.pending.pop_front().ok_or_else(|| Error::Again("no packet available".into()))
163 }
164
165 fn flush(&mut self, _config: &AudioEncoder) -> Result<()> {
166 self.buffer.fill(0);
167
168 Ok(())
169 }
170}
171
172impl Drop for OpusEncoder {
173 fn drop(&mut self) {
174 unsafe { opus_sys::opus_encoder_destroy(self.encoder) }
175 }
176}
177
178impl OpusEncoder {
179 pub fn new(codec_id: CodecID, parameters: &AudioEncoderParameters, options: Option<&Variant>) -> Result<Self> {
180 if codec_id != CodecID::OPUS {
181 return Err(unsupported_error!(codec_id));
182 }
183
184 let mut opts = OpusOptions::from_variant(options);
185
186 let audio_params = ¶meters.audio;
187 let sample_format = audio_params.format.ok_or_else(|| invalid_param_error!(parameters))?;
188
189 if sample_format != SampleFormat::S16 && sample_format != SampleFormat::F32 {
190 return Err(unsupported_error!(sample_format));
191 }
192
193 let sample_rate = audio_params.sample_rate.ok_or_else(|| invalid_param_error!(parameters))?.get() as opus_sys::opus_int32;
194 let channels = audio_params.channel_layout.as_ref().ok_or_else(|| invalid_param_error!(parameters))?.channels.get() as c_int;
195
196 let frame_size = (opts.frame_duration * 48000f32 / 1000f32) as u32;
198 match frame_size {
199 120 | 240 => {
201 if opts.application != opus_sys::OPUS_APPLICATION_RESTRICTED_LOWDELAY {
202 opts.application = opus_sys::OPUS_APPLICATION_RESTRICTED_LOWDELAY;
203 }
204 }
205 480 | 960 | 1920 | 2880 | 3840 | 4800 | 5760 => {}
207 _ => return Err(Error::Invalid("frame duration".into())),
208 }
209
210 opts.frame_size = frame_size * sample_rate as u32 / 48000;
211
212 let mut error = 0;
213 let opus_encoder = unsafe { opus_sys::opus_encoder_create(sample_rate, channels, opts.application, &mut error) };
214 if opus_encoder.is_null() || error != opus_sys::OPUS_OK {
215 return Err(Error::CreationFailed(opus_error_string(error)));
216 }
217
218 let mut encoder: OpusEncoder = OpusEncoder {
219 encoder: opus_encoder,
220 pending: VecDeque::with_capacity(DEFAULT_PACKET_PENDING_CAPACITY),
221 options: opts,
222 buffer: vec![0u8; frame_size as usize * channels as usize * sample_format.bytes() as usize],
223 };
224
225 encoder.set_audio_parameters(audio_params)?;
226 encoder.set_encoder_parameters(¶meters.encoder)?;
227 encoder.update_options()?;
228
229 Ok(encoder)
230 }
231
232 fn encoder_ctl(&mut self, key: i32, value: i32) -> Result<()> {
233 let ret = unsafe { opus_sys::opus_encoder_ctl(self.encoder, key, value) };
234
235 if ret != opus_sys::OPUS_OK {
236 return Err(Error::SetFailed(opus_error_string(ret)));
237 }
238
239 Ok(())
240 }
241
242 fn set_audio_parameters(&mut self, _audio_params: &AudioParameters) -> Result<()> {
243 Ok(())
244 }
245
246 fn set_encoder_parameters(&mut self, encoder_params: &EncoderParameters) -> Result<()> {
247 if let Some(bit_rate) = encoder_params.bit_rate {
248 self.encoder_ctl(opus_sys::OPUS_SET_BITRATE_REQUEST, bit_rate as i32)?;
249 }
250
251 if let Some(level) = encoder_params.level {
252 self.options.complexity = if !(0..=10).contains(&level) {
253 10
254 } else {
255 level as u32
256 };
257 }
258
259 Ok(())
260 }
261
262 fn update_options(&mut self) -> Result<()> {
263 self.encoder_ctl(opus_sys::OPUS_SET_VBR_REQUEST, (self.options.vbr > 0) as i32)?;
264 self.encoder_ctl(opus_sys::OPUS_SET_VBR_CONSTRAINT_REQUEST, (self.options.vbr == 2) as i32)?;
265 self.encoder_ctl(opus_sys::OPUS_SET_PACKET_LOSS_PERC_REQUEST, self.options.packet_loss)?;
266 self.encoder_ctl(opus_sys::OPUS_SET_INBAND_FEC_REQUEST, self.options.fec as i32)?;
267
268 if self.options.complexity > 0 {
269 self.encoder_ctl(opus_sys::OPUS_SET_COMPLEXITY_REQUEST, self.options.complexity as i32)?;
270 }
271
272 if self.options.max_bandwidth > 0 {
273 self.encoder_ctl(opus_sys::OPUS_SET_MAX_BANDWIDTH_REQUEST, self.options.max_bandwidth as i32)?;
274 }
275
276 Ok(())
277 }
278
279 fn encode(&mut self, frame: SharedFrame<AudioFrame<'static>>, pool: Option<&Arc<BufferPool>>) -> Result<()> {
280 let frame = frame.read();
281 let desc = frame.descriptor();
282 let sample_format = desc.format;
283
284 if sample_format != SampleFormat::S16 && sample_format != SampleFormat::F32 {
285 return Err(unsupported_error!(sample_format));
286 }
287
288 let guard = frame.map().map_err(|_| Error::Invalid("not readable".into()))?;
289 let planes = guard.planes().unwrap();
290 let packet_size = PACKET_HEADER_SIZE + MAX_FRAME_SIZE * MAX_FRAMES;
291 let channels = desc.channels().get() as usize;
292 let sample_size = channels * sample_format.bytes() as usize;
293 let frame_data = planes.plane_data(0).unwrap();
294 let frame_data_size = desc.samples.get() as usize * sample_size;
295 let chunk_size = self.options.frame_size as usize * sample_size;
296 let mut pts = frame.pts.unwrap_or(0);
297
298 self.buffer.fill(0);
299
300 for chunk in frame_data[..frame_data_size].chunks(chunk_size) {
301 let mut packet = if let Some(pool) = pool {
302 Packet::from_buffer(pool.get_buffer_with_length(packet_size))
303 } else {
304 Packet::new(packet_size)
305 };
306
307 let packet_data = packet.data_mut().ok_or_else(|| Error::Invalid("packet not writable".into()))?;
308 let data = if chunk.len() < chunk_size {
309 self.buffer[..chunk.len()].copy_from_slice(chunk);
310 self.buffer.as_slice()
311 } else {
312 chunk
313 };
314
315 let ret = match desc.format {
316 SampleFormat::S16 => {
317 let data = bytemuck::cast_slice::<u8, i16>(data);
318 unsafe {
319 opus_sys::opus_encode(
320 self.encoder,
321 data.as_ptr(),
322 (data.len() / channels) as i32,
323 packet_data.as_mut_ptr(),
324 packet_data.len() as i32,
325 )
326 }
327 }
328 SampleFormat::F32 => {
329 let data = bytemuck::cast_slice::<u8, f32>(data);
330 unsafe {
331 opus_sys::opus_encode_float(
332 self.encoder,
333 data.as_ptr(),
334 (data.len() / channels) as i32,
335 packet_data.as_mut_ptr(),
336 packet_data.len() as i32,
337 )
338 }
339 }
340 _ => return Err(unsupported_error!(sample_format)),
341 };
342
343 if ret < 0 {
344 return Err(Error::Failed(opus_error_string(ret)));
345 }
346
347 let samples = self.options.frame_size as i64;
348 let (duration, time_base) = if let Some(time_base) = frame.time_base {
349 let duration = (Rational64::new(samples, desc.sample_rate.get() as i64) / time_base).to_integer();
350 (duration, time_base)
351 } else {
352 let time_base = Rational64::new(1, desc.sample_rate.get() as i64);
353 let duration = samples;
354 (duration, time_base)
355 };
356
357 packet.pts = Some(pts);
358 packet.duration = Some(duration);
359 packet.time_base = Some(time_base);
360 pts += duration;
361
362 packet.truncate(ret as usize)?;
363
364 self.pending.push_back(packet);
365 }
366
367 Ok(())
368 }
369}
370
371const CODEC_NAME: &str = "opus-enc";
372
373pub struct OpusEncoderBuilder;
374
375impl EncoderBuilder<AudioEncoder> for OpusEncoderBuilder {
376 fn new_encoder(&self, codec_id: CodecID, params: &CodecParameters, options: Option<&Variant>) -> Result<Box<dyn Encoder<AudioEncoder>>> {
377 Ok(Box::new(OpusEncoder::new(codec_id, ¶ms.try_into()?, options)?))
378 }
379}
380
381impl CodecBuilder<AudioEncoder> for OpusEncoderBuilder {
382 fn ids(&self) -> &[CodecID] {
383 &[CodecID::OPUS]
384 }
385
386 fn name(&self) -> &'static str {
387 CODEC_NAME
388 }
389}
390
391#[ctor]
392pub fn initialize() {
393 register_encoder(Arc::new(OpusEncoderBuilder), false);
394}