use mediaway_common::Rational;
use crate::opus::error::OpusError;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OpusApplication {
Voip,
Audio,
RestrictedLowDelay,
}
impl OpusApplication {
pub(crate) const fn to_raw(self) -> i32 {
match self {
Self::Voip => unsafe_libopus::OPUS_APPLICATION_VOIP,
Self::Audio => unsafe_libopus::OPUS_APPLICATION_AUDIO,
Self::RestrictedLowDelay => unsafe_libopus::OPUS_APPLICATION_RESTRICTED_LOWDELAY,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OpusEncoderConfig {
pub sample_rate: u32,
pub channels: u16,
pub application: OpusApplication,
pub time_base: Rational,
pub bitrate_bps: Option<u32>,
pub inband_fec: bool,
pub packet_loss_percent: u8,
}
impl OpusEncoderConfig {
#[must_use]
pub const fn new(
sample_rate: u32,
channels: u16,
application: OpusApplication,
time_base: Rational,
) -> Self {
Self {
sample_rate,
channels,
application,
time_base,
bitrate_bps: None,
inband_fec: false,
packet_loss_percent: 0,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OpusDecoderConfig {
pub sample_rate: u32,
pub channels: u16,
pub time_base: Rational,
}
impl OpusDecoderConfig {
#[must_use]
pub const fn new(sample_rate: u32, channels: u16, time_base: Rational) -> Self {
Self {
sample_rate,
channels,
time_base,
}
}
}
pub(crate) fn frame_size_samples(
sample_rate: u32,
time_base: Rational,
) -> Result<usize, OpusError> {
let invalid = || OpusError::InvalidFrameDuration {
num: time_base.num,
den: time_base.den,
sample_rate,
};
if time_base.den == 0 {
return Err(invalid());
}
let numerator = u64::from(sample_rate) * time_base.num;
let denominator = u64::from(time_base.den);
if numerator % denominator != 0 {
return Err(invalid());
}
let samples = numerator / denominator;
if samples == 0 || samples > u64::from(u32::MAX / 2) {
return Err(invalid());
}
usize::try_from(samples).map_err(|_| invalid())
}
#[cfg(test)]
#[path = "config_tests.rs"]
mod tests;