use crate::error::CodecError;
mod reference;
#[cfg(test)]
pub mod tests;
pub use reference::{alaw_compress, alaw_expand, ulaw_compress, ulaw_expand};
pub struct G711Codec {
variant: G711Variant,
frame_size: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum G711Variant {
ALaw,
MuLaw,
}
impl G711Codec {
pub fn new(variant: G711Variant) -> Self {
Self {
variant,
frame_size: 160, }
}
pub fn new_with_config(
variant: G711Variant,
config: crate::types::CodecConfig,
) -> Result<Self, CodecError> {
if config.sample_rate.hz() != 8000 {
return Err(CodecError::InvalidSampleRate {
rate: config.sample_rate.hz(),
supported: vec![8000],
});
}
if config.channels != 1 {
return Err(CodecError::InvalidChannelCount {
channels: config.channels,
supported: vec![1],
});
}
let frame_size = if let Some(frame_ms) = config.frame_size_ms {
let samples_per_ms = 8000.0 / 1000.0; (samples_per_ms * frame_ms) as usize
} else {
160 };
let valid_sizes = [80, 160, 240, 320];
if !valid_sizes.contains(&frame_size) {
return Err(CodecError::InvalidFrameSize {
expected: 160,
actual: frame_size,
});
}
Ok(Self {
variant,
frame_size,
})
}
pub fn new_pcmu(config: crate::types::CodecConfig) -> Result<Self, CodecError> {
Self::new_with_config(G711Variant::MuLaw, config)
}
pub fn new_pcma(config: crate::types::CodecConfig) -> Result<Self, CodecError> {
Self::new_with_config(G711Variant::ALaw, config)
}
pub fn variant(&self) -> G711Variant {
self.variant
}
pub fn compress(&self, samples: &[i16]) -> Result<Vec<u8>, CodecError> {
match self.variant {
G711Variant::ALaw => Ok(samples
.iter()
.map(|&sample| alaw_compress(sample))
.collect()),
G711Variant::MuLaw => Ok(samples
.iter()
.map(|&sample| ulaw_compress(sample))
.collect()),
}
}
pub fn expand(&self, compressed: &[u8]) -> Result<Vec<i16>, CodecError> {
match self.variant {
G711Variant::ALaw => Ok(compressed
.iter()
.map(|&sample| alaw_expand(sample))
.collect()),
G711Variant::MuLaw => Ok(compressed
.iter()
.map(|&sample| ulaw_expand(sample))
.collect()),
}
}
pub fn compress_alaw(&self, samples: &[i16]) -> Result<Vec<u8>, CodecError> {
Ok(samples
.iter()
.map(|&sample| alaw_compress(sample))
.collect())
}
pub fn expand_alaw(&self, compressed: &[u8]) -> Result<Vec<i16>, CodecError> {
Ok(compressed
.iter()
.map(|&sample| alaw_expand(sample))
.collect())
}
pub fn compress_ulaw(&self, samples: &[i16]) -> Result<Vec<u8>, CodecError> {
Ok(samples
.iter()
.map(|&sample| ulaw_compress(sample))
.collect())
}
pub fn expand_ulaw(&self, compressed: &[u8]) -> Result<Vec<i16>, CodecError> {
Ok(compressed
.iter()
.map(|&sample| ulaw_expand(sample))
.collect())
}
}
impl crate::types::AudioCodec for G711Codec {
fn encode(&mut self, samples: &[i16]) -> Result<Vec<u8>, CodecError> {
self.compress(samples)
}
fn decode(&mut self, data: &[u8]) -> Result<Vec<i16>, CodecError> {
self.expand(data)
}
fn info(&self) -> crate::types::CodecInfo {
let (name, payload_type) = match self.variant {
G711Variant::ALaw => ("PCMA", Some(8)),
G711Variant::MuLaw => ("PCMU", Some(0)),
};
crate::types::CodecInfo {
name,
sample_rate: 8000,
channels: 1,
bitrate: 64000,
frame_size: self.frame_size,
payload_type,
}
}
fn reset(&mut self) -> Result<(), CodecError> {
Ok(())
}
fn frame_size(&self) -> usize {
self.frame_size
}
fn supports_variable_frame_size(&self) -> bool {
true
}
}
impl crate::types::AudioCodecExt for G711Codec {
fn encode_to_buffer(
&mut self,
samples: &[i16],
output: &mut [u8],
) -> Result<usize, CodecError> {
if output.len() < samples.len() {
return Err(CodecError::BufferTooSmall {
needed: samples.len(),
actual: output.len(),
});
}
match self.variant {
G711Variant::ALaw => {
for (i, &sample) in samples.iter().enumerate() {
output[i] = alaw_compress(sample);
}
}
G711Variant::MuLaw => {
for (i, &sample) in samples.iter().enumerate() {
output[i] = ulaw_compress(sample);
}
}
}
Ok(samples.len())
}
fn decode_to_buffer(&mut self, data: &[u8], output: &mut [i16]) -> Result<usize, CodecError> {
if output.len() < data.len() {
return Err(CodecError::BufferTooSmall {
needed: data.len(),
actual: output.len(),
});
}
match self.variant {
G711Variant::ALaw => {
for (i, &encoded) in data.iter().enumerate() {
output[i] = alaw_expand(encoded);
}
}
G711Variant::MuLaw => {
for (i, &encoded) in data.iter().enumerate() {
output[i] = ulaw_expand(encoded);
}
}
}
Ok(data.len())
}
fn max_encoded_size(&self, input_samples: usize) -> usize {
input_samples }
fn max_decoded_size(&self, input_bytes: usize) -> usize {
input_bytes }
}
pub fn init_tables() {
}