symphonia_adapter_libopus/
lib.rs

1#![warn(missing_docs, missing_debug_implementations)]
2#![forbid(clippy::unwrap_used)]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4#![doc = include_str!("../README.md")]
5
6use std::fmt;
7
8use symphonia_core::audio::{
9    AsAudioBufferRef, AudioBuffer, AudioBufferRef, Channels, Layout, Signal, SignalSpec,
10};
11use symphonia_core::codecs::{
12    self, CODEC_TYPE_OPUS, CodecDescriptor, CodecParameters, DecoderOptions, FinalizeResult,
13};
14use symphonia_core::errors::{Result, unsupported_error};
15use symphonia_core::formats::Packet;
16use symphonia_core::io::{BufReader, ReadBytes};
17use symphonia_core::support_codec;
18
19use crate::decoder::Decoder;
20
21mod decoder;
22
23/// Maximum sampling rate is 48 kHz for normal opus, and 96 kHz for Opus HD in the 1.6 spec.
24const MAX_SAMPLE_RATE: usize = 48000;
25const DEFAULT_SAMPLE_RATE: usize = 48000;
26/// Assuming 48 kHz sample rate with the default 20 ms frames.
27const DEFAULT_SAMPLES_PER_CHANNEL: usize = DEFAULT_SAMPLE_RATE * 20 / 1000;
28/// Opus maximum frame size is 60 ms, with worst case being 120 ms when combining frames per packet.
29const MAX_SAMPLES_PER_CHANNEL: usize = MAX_SAMPLE_RATE * 120 / 1000;
30
31/// Symphonia-compatible wrapper for the libopus decoder.
32pub struct OpusDecoder {
33    params: CodecParameters,
34    decoder: Decoder,
35    buf: AudioBuffer<f32>,
36    pcm: [f32; MAX_SAMPLES_PER_CHANNEL * 2],
37    samples_per_channel: usize,
38    sample_rate: u32,
39    num_channels: usize,
40    pre_skip: usize,
41}
42
43impl fmt::Debug for OpusDecoder {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        f.debug_struct("OpusDecoder")
46            .field("params", &self.params)
47            .field("decoder", &self.decoder)
48            .field("buf", &"<buf>")
49            .field("pcm", &self.pcm)
50            .field("samples_per_channel", &self.samples_per_channel)
51            .field("sample_rate", &self.sample_rate)
52            .field("num_channels", &self.num_channels)
53            .field("pre_skip", &self.pre_skip)
54            .finish()
55    }
56}
57
58// This should probably be handled in the Ogg demuxer, but we'll include it here for now.
59fn parse_pre_skip(buf: &[u8]) -> Result<usize> {
60    // See https://wiki.xiph.org/OggOpus
61
62    let mut reader = BufReader::new(buf);
63
64    // Header - "OpusHead"
65    let mut header = [0; 8];
66    reader.read_buf_exact(&mut header)?;
67
68    // Version - 1 is the only valid version currently
69    reader.read_byte()?;
70
71    // Number of channels (same as what we get from the CodecParameters)
72    reader.read_byte()?;
73
74    // Pre-skip - number of samples (at 48 kHz) to discard from the start of the stream
75    let pre_skip = reader.read_u16()?;
76
77    Ok(pre_skip as usize)
78}
79
80impl codecs::Decoder for OpusDecoder {
81    fn try_new(params: &CodecParameters, _opts: &DecoderOptions) -> Result<Self>
82    where
83        Self: Sized,
84    {
85        let num_channels = if let Some(channels) = &params.channels {
86            channels.count()
87        } else {
88            return unsupported_error("opus: channels or channel layout is required");
89        };
90        let sample_rate = if let Some(sample_rate) = params.sample_rate {
91            sample_rate
92        } else {
93            return unsupported_error("opus: sample rate required");
94        };
95
96        if !(1..=2).contains(&num_channels) {
97            return unsupported_error("opus: unsupported number of channels");
98        }
99
100        let pre_skip = if let Some(extra_data) = &params.extra_data {
101            parse_pre_skip(extra_data).unwrap_or_default()
102        } else {
103            0
104        };
105
106        Ok(Self {
107            params: params.to_owned(),
108            decoder: Decoder::new(sample_rate, num_channels as u32)?,
109            buf: audio_buffer(
110                sample_rate,
111                DEFAULT_SAMPLES_PER_CHANNEL as u64,
112                num_channels,
113            ),
114            pcm: [0.0; _],
115            samples_per_channel: DEFAULT_SAMPLES_PER_CHANNEL,
116            sample_rate,
117            num_channels,
118            pre_skip,
119        })
120    }
121
122    fn supported_codecs() -> &'static [CodecDescriptor]
123    where
124        Self: Sized,
125    {
126        &[support_codec!(CODEC_TYPE_OPUS, "opus", "Opus")]
127    }
128
129    fn reset(&mut self) {
130        self.decoder.reset()
131    }
132
133    fn codec_params(&self) -> &CodecParameters {
134        &self.params
135    }
136
137    fn decode(&mut self, packet: &Packet) -> Result<AudioBufferRef<'_>> {
138        let samples_per_channel = self.decoder.decode(&packet.data, &mut self.pcm)?;
139
140        if samples_per_channel != self.samples_per_channel {
141            self.buf = audio_buffer(
142                self.sample_rate,
143                samples_per_channel as u64,
144                self.num_channels,
145            );
146            self.samples_per_channel = samples_per_channel;
147        }
148
149        let samples = samples_per_channel * self.num_channels;
150        let pcm = &self.pcm[..samples];
151
152        self.buf.clear();
153        self.buf.render_reserved(None);
154        match self.num_channels {
155            1 => {
156                self.buf.chan_mut(0).copy_from_slice(pcm);
157            }
158            2 => {
159                let (l, r) = self.buf.chan_pair_mut(0, 1);
160                for (i, j) in (0..samples).step_by(2).enumerate() {
161                    l[i] = pcm[j];
162                    r[i] = pcm[j + 1];
163                }
164            }
165            _ => {}
166        }
167
168        self.buf.trim(
169            packet.trim_start() as usize
170                + (self.pre_skip * self.sample_rate as usize) / DEFAULT_SAMPLE_RATE,
171            packet.trim_end() as usize,
172        );
173        // Pre-skip should only be used for the first packet, after that it should always be 0.
174        self.pre_skip = 0;
175        Ok(self.buf.as_audio_buffer_ref())
176    }
177
178    fn finalize(&mut self) -> FinalizeResult {
179        FinalizeResult::default()
180    }
181
182    fn last_decoded(&self) -> AudioBufferRef<'_> {
183        self.buf.as_audio_buffer_ref()
184    }
185}
186
187fn map_to_channels(num_channels: usize) -> Option<Channels> {
188    let channels = match num_channels {
189        1 => Layout::Mono.into_channels(),
190        2 => Layout::Stereo.into_channels(),
191        _ => return None,
192    };
193
194    Some(channels)
195}
196
197fn audio_buffer(
198    sample_rate: u32,
199    samples_per_channel: u64,
200    num_channels: usize,
201) -> AudioBuffer<f32> {
202    let channels = map_to_channels(num_channels).expect("invalid channels");
203    let spec = SignalSpec::new(sample_rate, channels);
204    AudioBuffer::new(samples_per_channel, spec)
205}