#![forbid(unsafe_code)]
pub mod bitpack;
pub mod codebook;
pub mod encoder;
pub mod floor;
pub mod header;
pub mod mdct;
pub mod psycho;
pub mod residue;
use crate::{AudioDecoder, AudioDecoderConfig, AudioError, AudioFrame, AudioResult, ChannelLayout};
use oximedia_core::{CodecId, SampleFormat};
pub use codebook::{Codebook, CodebookEntry, HuffmanTree};
pub use encoder::{QualityMode, VorbisEncoder};
pub use floor::{Floor, FloorType0, FloorType1};
pub use header::{CommentHeader, IdentificationHeader, SetupHeader, VorbisHeader};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[allow(dead_code)]
enum DecoderState {
#[default]
WaitingForIdentification,
WaitingForComment,
WaitingForSetup,
Ready,
Flushed,
}
pub struct VorbisDecoder {
#[allow(dead_code)]
config: AudioDecoderConfig,
sample_rate: u32,
channels: u8,
flushing: bool,
#[allow(dead_code)]
state: DecoderState,
#[allow(dead_code)]
id_header: Option<IdentificationHeader>,
#[allow(dead_code)]
comment_header: Option<CommentHeader>,
#[allow(dead_code)]
setup_header: Option<SetupHeader>,
}
impl VorbisDecoder {
pub fn new(config: &AudioDecoderConfig) -> AudioResult<Self> {
if config.codec != CodecId::Vorbis {
return Err(AudioError::InvalidParameter("Expected Vorbis codec".into()));
}
Ok(Self {
config: config.clone(),
sample_rate: config.sample_rate,
channels: config.channels,
flushing: false,
state: DecoderState::WaitingForIdentification,
id_header: None,
comment_header: None,
setup_header: None,
})
}
pub fn parse_identification_header(data: &[u8]) -> AudioResult<IdentificationHeader> {
IdentificationHeader::parse(data)
}
pub fn parse_comment_header(data: &[u8]) -> AudioResult<CommentHeader> {
CommentHeader::parse(data)
}
#[must_use]
pub fn is_ready(&self) -> bool {
self.state == DecoderState::Ready
}
}
impl AudioDecoder for VorbisDecoder {
fn codec(&self) -> CodecId {
CodecId::Vorbis
}
fn send_packet(&mut self, _data: &[u8], _pts: i64) -> AudioResult<()> {
Ok(())
}
fn receive_frame(&mut self) -> AudioResult<Option<AudioFrame>> {
Ok(None)
}
fn flush(&mut self) -> AudioResult<()> {
self.flushing = true;
Ok(())
}
fn reset(&mut self) {
self.flushing = false;
self.state = DecoderState::WaitingForIdentification;
self.id_header = None;
self.comment_header = None;
self.setup_header = None;
}
fn output_format(&self) -> Option<SampleFormat> {
Some(SampleFormat::F32)
}
fn sample_rate(&self) -> Option<u32> {
Some(self.sample_rate)
}
fn channel_layout(&self) -> Option<ChannelLayout> {
Some(ChannelLayout::from_count(usize::from(self.channels)))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vorbis_decoder() {
let config = AudioDecoderConfig {
codec: CodecId::Vorbis,
..Default::default()
};
let decoder = VorbisDecoder::new(&config).unwrap();
assert_eq!(decoder.codec(), CodecId::Vorbis);
}
#[test]
fn test_vorbis_decoder_wrong_codec() {
let config = AudioDecoderConfig {
codec: CodecId::Opus,
..Default::default()
};
assert!(VorbisDecoder::new(&config).is_err());
}
#[test]
fn test_vorbis_decoder_reset() {
let config = AudioDecoderConfig {
codec: CodecId::Vorbis,
..Default::default()
};
let mut decoder = VorbisDecoder::new(&config).unwrap();
decoder.reset();
assert!(!decoder.flushing);
assert_eq!(decoder.state, DecoderState::WaitingForIdentification);
}
#[test]
fn test_vorbis_decoder_not_ready() {
let config = AudioDecoderConfig {
codec: CodecId::Vorbis,
..Default::default()
};
let decoder = VorbisDecoder::new(&config).unwrap();
assert!(!decoder.is_ready());
}
}