use bytes::{Bytes, BytesMut};
use std::any::Any;
use super::traits::PayloadFormat;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OpusBandwidth {
Narrowband,
Mediumband,
Wideband,
SuperWideband,
Fullband,
}
impl OpusBandwidth {
pub fn sampling_rate(&self) -> u32 {
match self {
Self::Narrowband => 8000,
Self::Mediumband => 12000,
Self::Wideband => 16000,
Self::SuperWideband => 24000,
Self::Fullband => 48000,
}
}
pub fn name(&self) -> &'static str {
match self {
Self::Narrowband => "Narrowband (4kHz)",
Self::Mediumband => "Mediumband (6kHz)",
Self::Wideband => "Wideband (8kHz)",
Self::SuperWideband => "Super Wideband (12kHz)",
Self::Fullband => "Fullband (20kHz)",
}
}
}
pub struct OpusPayloadFormat {
clock_rate: u32,
channels: u8,
preferred_duration: u32,
payload_type: u8,
max_bitrate: u32,
bandwidth: OpusBandwidth,
}
impl OpusPayloadFormat {
pub fn new(payload_type: u8, channels: u8) -> Self {
Self {
clock_rate: 48000, channels,
preferred_duration: 20, payload_type,
max_bitrate: 64000, bandwidth: OpusBandwidth::Fullband,
}
}
pub fn with_max_bitrate(mut self, max_bitrate: u32) -> Self {
self.max_bitrate = max_bitrate;
self
}
pub fn with_bandwidth(mut self, bandwidth: OpusBandwidth) -> Self {
self.bandwidth = bandwidth;
self
}
pub fn with_duration(mut self, duration_ms: u32) -> Self {
self.preferred_duration = match duration_ms {
3 => 2, 5 | 10 | 20 | 40 | 60 | 80 | 100 | 120 => duration_ms,
_ => 20,
};
self
}
pub fn max_bitrate(&self) -> u32 {
self.max_bitrate
}
pub fn bandwidth(&self) -> OpusBandwidth {
self.bandwidth
}
}
impl PayloadFormat for OpusPayloadFormat {
fn payload_type(&self) -> u8 {
self.payload_type
}
fn clock_rate(&self) -> u32 {
self.clock_rate
}
fn channels(&self) -> u8 {
self.channels
}
fn preferred_packet_duration(&self) -> u32 {
self.preferred_duration
}
fn packet_size_from_duration(&self, duration_ms: u32) -> usize {
let max_bytes = (self.max_bitrate * duration_ms) / (8 * 1000);
max_bytes as usize
}
fn duration_from_packet_size(&self, packet_size: usize) -> u32 {
let bits = packet_size as u32 * 8;
(bits * 1000) / self.max_bitrate
}
fn pack(&self, media_data: &[u8], _timestamp: u32) -> Bytes {
Bytes::copy_from_slice(media_data)
}
fn unpack(&self, payload: &[u8], _timestamp: u32) -> Bytes {
Bytes::copy_from_slice(payload)
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_opus_payload_format() {
let format = OpusPayloadFormat::new(101, 1)
.with_max_bitrate(32000) .with_bandwidth(OpusBandwidth::Wideband)
.with_duration(20);
assert_eq!(format.payload_type(), 101);
assert_eq!(format.clock_rate(), 48000);
assert_eq!(format.channels(), 1);
assert_eq!(format.preferred_packet_duration(), 20);
assert_eq!(format.max_bitrate(), 32000);
assert_eq!(format.bandwidth(), OpusBandwidth::Wideband);
assert_eq!(format.samples_from_duration(20), 960);
assert_eq!(format.packet_size_from_duration(20), 80);
let stereo_format = OpusPayloadFormat::new(102, 2)
.with_max_bitrate(64000);
assert_eq!(stereo_format.channels(), 2);
assert_eq!(stereo_format.max_bitrate(), 64000);
assert_eq!(stereo_format.packet_size_from_duration(20), 160);
}
#[test]
fn test_opus_bandwidth_modes() {
assert_eq!(OpusBandwidth::Narrowband.sampling_rate(), 8000);
assert_eq!(OpusBandwidth::Mediumband.sampling_rate(), 12000);
assert_eq!(OpusBandwidth::Wideband.sampling_rate(), 16000);
assert_eq!(OpusBandwidth::SuperWideband.sampling_rate(), 24000);
assert_eq!(OpusBandwidth::Fullband.sampling_rate(), 48000);
}
}