TeaWeb/web/audio-lib/src/audio.rs
2020-09-07 12:42:00 +02:00

184 lines
5.5 KiB
Rust

use std::ops::{Add, Sub};
pub mod packet_queue;
pub mod codec;
pub mod decoder;
pub mod converter;
/// A wrapper around an u16 to represent an audio packet it
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct PacketId {
pub packet_id: u16
}
impl PacketId {
pub fn new(packet_id: u16) -> PacketId {
PacketId{ packet_id }
}
pub fn is_less(&self, other: &Self, clipping_window: Option<u16>) -> bool {
if let Some(window) = clipping_window {
if self.packet_id < window {
self.packet_id < other.packet_id && other.packet_id < 0xFFFF - window
} else if self.packet_id > 0xFFFF - window {
self.packet_id < other.packet_id || self.packet_id.wrapping_add(window) >= other.packet_id
} else {
self.packet_id < other.packet_id
}
} else {
self.packet_id < other.packet_id
}
}
pub fn difference(&self, other: &Self, clipping_window: Option<u16>) -> u16 {
if let Some(window) = clipping_window {
if self.packet_id < window {
return if other.packet_id > 0xFFFF - window {
(0xFFFF - other.packet_id) + self.packet_id + 1
} else if other.packet_id > self.packet_id {
other.packet_id - self.packet_id
} else {
self.packet_id - other.packet_id
}
} else if other.packet_id < window {
return if self.packet_id > 0xFFFF - window {
(0xFFFF - self.packet_id) + other.packet_id + 1
} else if self.packet_id > other.packet_id {
self.packet_id - other.packet_id
} else {
other.packet_id - self.packet_id
}
}
}
if self.packet_id > other.packet_id {
self.packet_id - other.packet_id
} else {
other.packet_id - self.packet_id
}
}
}
impl Add<u16> for PacketId {
type Output = PacketId;
fn add(self, rhs: u16) -> Self::Output {
PacketId::new(self.packet_id.wrapping_add(rhs))
}
}
impl Sub<u16> for PacketId {
type Output = PacketId;
fn sub(self, rhs: u16) -> Self::Output {
PacketId::new(self.packet_id.wrapping_sub(rhs))
}
}
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum Codec {
/// Speex narrow band, not supported any more
SpeexNarrow = 0x00,
/// Speex wide band, not supported any more
SpeexWide = 0x01,
/// Speex ultra wide band, not supported any more
SpeexUltraWide = 0x02,
/// Celt, not supported any more
Celt = 0x03,
/// Opus using the VoIP quality
Opus = 0x04,
/// Opus using the stereo music quality
OpusMusic = 0x05,
/// A lossless compression codec, currently not yet supported, but planned to
Flac = 0x10,
/// The codec is unknown
Unknown = 0xFF
}
impl Codec {
pub fn from_u8(value: u8) -> Codec {
match value {
x if x == Codec::SpeexNarrow as u8 => Codec::SpeexNarrow,
x if x == Codec::SpeexWide as u8 => Codec::SpeexWide,
x if x == Codec::SpeexUltraWide as u8 => Codec::SpeexUltraWide,
x if x == Codec::Celt as u8 => Codec::Celt,
x if x == Codec::Opus as u8 => Codec::Opus,
x if x == Codec::OpusMusic as u8 => Codec::OpusMusic,
x if x == Codec::Flac as u8 => Codec::Flac,
_ => Codec::Unknown
}
}
}
#[derive(PartialEq, Debug)]
pub struct AudioPacket {
pub client_id: u16,
pub packet_id: PacketId,
pub codec: Codec,
pub payload: Vec<u8>,
}
impl AudioPacket {
pub fn is_stop(&self) -> bool {
self.payload.is_empty()
}
}
#[cfg(test)]
mod tests {
use crate::audio::PacketId;
fn test_packet_id(a: u16, b: u16, result: bool, clipping_window: Option<u16>) {
let a = PacketId{ packet_id: a };
let b = PacketId{ packet_id: b };
assert_eq!(a.is_less(&b, clipping_window), result);
}
fn test_packet_difference(a: u16, b: u16, expected: u16, clipping_window: Option<u16>) {
let a = PacketId{ packet_id: a };
let b = PacketId{ packet_id: b };
assert_eq!(a.difference(&b, clipping_window), expected);
assert_eq!(b.difference(&a, clipping_window), expected);
}
#[test]
fn packet_id_is_less_basic() {
test_packet_id(2, 3, true, None);
test_packet_id(4, 3, false, None);
}
#[test]
fn packet_id_is_less_clipping() {
test_packet_id(0xFFFF, 0, false, None);
test_packet_id(0xFFFF, 1, false, None);
test_packet_id(0xFFFF, 2, false, None);
test_packet_id(0xFFFF, 2, true, Some(4));
test_packet_id(0xFFFF, 2, false, Some(2));
test_packet_id(2, 0xFFFF, false, Some(4));
for i in 1..0x2Fu16 {
test_packet_id(i.wrapping_add(0xFFF0), i.wrapping_add(0xFFF1), true, Some(2));
test_packet_id(i.wrapping_add(0xFFF0), i.wrapping_add(0xFFF5), true, Some(6));
test_packet_id(i.wrapping_add(0xFFF6), i.wrapping_add(0xFFF0), false, Some(6));
test_packet_id(i.wrapping_add(0xFFF0), i.wrapping_add(0xFFF6), true, Some(6));
}
}
#[test]
fn packet_id_difference() {
test_packet_difference(0, 0, 0, None);
test_packet_difference(0xFFFF, 0, 0xFFFF, None);
test_packet_difference(0xFFFF, 0, 1, Some(1));
for i in 0..0xFFu16 {
test_packet_difference(0xFF8F_u16.wrapping_add(i), 0xFF9F_u16.wrapping_add(i), 16, Some(16));
}
}
}