pub mod celt;
pub mod encoder;
pub mod hybrid;
pub mod mdct;
pub mod packet;
pub mod range_decoder;
pub mod range_encoder;
pub mod silk;
pub mod silk_decoder;
pub mod silk_range;
pub mod silk_tables;
pub mod vad;
use crate::{AudioFrame, CodecError, CodecResult, SampleFormat};
use celt::CeltDecoder;
use hybrid::HybridDecoder;
use packet::{OpusBandwidth, OpusMode, OpusPacket};
use silk::SilkDecoder;
pub use encoder::{OpusEncoder, OpusEncoderConfig};
#[derive(Debug, Clone)]
pub struct OpusConfig {
pub sample_rate: u32,
pub channels: usize,
pub sample_format: SampleFormat,
}
impl Default for OpusConfig {
fn default() -> Self {
Self {
sample_rate: 48000,
channels: 2,
sample_format: SampleFormat::F32,
}
}
}
pub struct OpusDecoder {
config: OpusConfig,
silk: Option<SilkDecoder>,
celt: Option<CeltDecoder>,
hybrid: Option<HybridDecoder>,
current_mode: Option<OpusMode>,
frame_count: u64,
}
impl OpusDecoder {
pub fn new(sample_rate: u32, channels: usize) -> CodecResult<Self> {
Self::with_config(OpusConfig {
sample_rate,
channels,
sample_format: SampleFormat::F32,
})
}
pub fn with_config(config: OpusConfig) -> CodecResult<Self> {
if !matches!(config.sample_rate, 8000 | 12000 | 16000 | 24000 | 48000) {
return Err(CodecError::InvalidData(format!(
"Invalid sample rate: {}",
config.sample_rate
)));
}
if config.channels == 0 || config.channels > 2 {
return Err(CodecError::InvalidData(format!(
"Invalid channel count: {}",
config.channels
)));
}
Ok(Self {
config,
silk: None,
celt: None,
hybrid: None,
current_mode: None,
frame_count: 0,
})
}
pub fn decode_packet(&mut self, data: &[u8]) -> CodecResult<AudioFrame> {
let packet = OpusPacket::parse(data)?;
let frame_size = packet.toc.frame_size as usize;
self.initialize_decoder(&packet.toc.mode, packet.toc.bandwidth, frame_size)?;
let sample_count = frame_size * packet.frame_count();
let mut samples = vec![0.0f32; sample_count * self.config.channels];
let mut offset = 0;
for frame_data in &packet.frames {
let frame_samples = frame_size * self.config.channels;
let output_slice = &mut samples[offset..offset + frame_samples];
self.decode_frame(&packet.toc.mode, frame_data, output_slice, frame_size)?;
offset += frame_samples;
self.frame_count += 1;
}
let output_samples = self.convert_samples(&samples)?;
Ok(AudioFrame::new(
output_samples,
sample_count,
self.config.sample_rate,
self.config.channels,
self.config.sample_format,
))
}
fn initialize_decoder(
&mut self,
mode: &OpusMode,
bandwidth: OpusBandwidth,
frame_size: usize,
) -> CodecResult<()> {
if self.current_mode.as_ref() != Some(mode) {
match mode {
OpusMode::Silk => {
if self.silk.is_none() {
self.silk = Some(SilkDecoder::new(
self.config.sample_rate,
self.config.channels,
bandwidth,
));
}
}
OpusMode::Celt => {
if self.celt.is_none() {
self.celt = Some(CeltDecoder::new(
self.config.sample_rate,
self.config.channels,
bandwidth,
frame_size,
));
}
}
OpusMode::Hybrid => {
if self.hybrid.is_none() {
self.hybrid = Some(HybridDecoder::new(
self.config.sample_rate,
self.config.channels,
bandwidth,
frame_size,
));
}
}
}
self.current_mode = Some(*mode);
}
Ok(())
}
fn decode_frame(
&mut self,
mode: &OpusMode,
data: &[u8],
output: &mut [f32],
frame_size: usize,
) -> CodecResult<()> {
match mode {
OpusMode::Silk => {
if let Some(silk) = &mut self.silk {
silk.decode(data, output, frame_size)?;
} else {
return Err(CodecError::InvalidData(
"SILK decoder not initialized".to_string(),
));
}
}
OpusMode::Celt => {
if let Some(celt) = &mut self.celt {
celt.decode(data, output, frame_size)?;
} else {
return Err(CodecError::InvalidData(
"CELT decoder not initialized".to_string(),
));
}
}
OpusMode::Hybrid => {
if let Some(hybrid) = &mut self.hybrid {
hybrid.decode(data, output, frame_size)?;
} else {
return Err(CodecError::InvalidData(
"Hybrid decoder not initialized".to_string(),
));
}
}
}
Ok(())
}
fn convert_samples(&self, samples: &[f32]) -> CodecResult<Vec<u8>> {
match self.config.sample_format {
SampleFormat::F32 => {
let mut output = Vec::with_capacity(samples.len() * 4);
for &sample in samples {
output.extend_from_slice(&sample.to_le_bytes());
}
Ok(output)
}
SampleFormat::I16 => {
let mut output = Vec::with_capacity(samples.len() * 2);
for &sample in samples {
let i16_sample = (sample.clamp(-1.0, 1.0) * 32767.0) as i16;
output.extend_from_slice(&i16_sample.to_le_bytes());
}
Ok(output)
}
SampleFormat::I32 => {
let mut output = Vec::with_capacity(samples.len() * 4);
for &sample in samples {
let i32_sample = (sample.clamp(-1.0, 1.0) * 2_147_483_647.0) as i32;
output.extend_from_slice(&i32_sample.to_le_bytes());
}
Ok(output)
}
SampleFormat::U8 => {
let mut output = Vec::with_capacity(samples.len());
for &sample in samples {
let u8_sample = ((sample.clamp(-1.0, 1.0) + 1.0) * 127.5) as u8;
output.push(u8_sample);
}
Ok(output)
}
}
}
pub fn reset(&mut self) {
if let Some(silk) = &mut self.silk {
silk.reset();
}
if let Some(celt) = &mut self.celt {
celt.reset();
}
if let Some(hybrid) = &mut self.hybrid {
hybrid.reset();
}
self.current_mode = None;
self.frame_count = 0;
}
#[must_use]
pub const fn config(&self) -> &OpusConfig {
&self.config
}
#[must_use]
pub const fn frame_count(&self) -> u64 {
self.frame_count
}
#[must_use]
pub const fn current_mode(&self) -> Option<OpusMode> {
self.current_mode
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_opus_decoder_creation() {
let decoder = OpusDecoder::new(48000, 2);
assert!(decoder.is_ok());
}
#[test]
fn test_opus_decoder_invalid_sample_rate() {
let decoder = OpusDecoder::new(44100, 2);
assert!(decoder.is_err());
}
#[test]
fn test_opus_decoder_invalid_channels() {
let decoder = OpusDecoder::new(48000, 0);
assert!(decoder.is_err());
}
#[test]
fn test_opus_config_default() {
let config = OpusConfig::default();
assert_eq!(config.sample_rate, 48000);
assert_eq!(config.channels, 2);
assert_eq!(config.sample_format, SampleFormat::F32);
}
#[test]
fn test_opus_decoder_reset() {
let mut decoder = OpusDecoder::new(48000, 2).expect("should succeed");
decoder.reset();
assert_eq!(decoder.frame_count(), 0);
}
}