use tokio::sync::Mutex;
use audiopus::{Bitrate, SampleRate};
use std::{
sync::Arc,
time::Duration,
};
use async_trait::async_trait;
pub const HEADER_LEN: usize = 12;
pub const SAMPLE_RATE: SampleRate = SampleRate::Hz48000;
pub const DEFAULT_BITRATE: Bitrate = Bitrate::BitsPerSecond(128_000);
#[async_trait]
pub trait AudioSource: Send + Sync {
async fn is_stereo(&mut self) -> bool;
async fn get_type(&self) -> AudioType;
async fn read_pcm_frame(&mut self, buffer: &mut [i16]) -> Option<usize>;
async fn read_opus_frame(&mut self) -> Option<Vec<u8>>;
async fn decode_and_add_opus_frame(&mut self, float_buffer: &mut [f32; 1920], volume: f32) -> Option<usize>;
}
#[async_trait]
pub trait AudioReceiver: Send + Sync {
async fn speaking_update(&self, _ssrc: u32, _user_id: u64, _speaking: bool) { }
#[allow(clippy::too_many_arguments)]
async fn voice_packet(&self,
_ssrc: u32,
_sequence: u16,
_timestamp: u32,
_stereo: bool,
_data: &[i16],
_compressed_size: usize) { }
async fn client_connect(&self, _ssrc: u32, _user_id: u64) { }
async fn client_disconnect(&self, _user_id: u64) { }
}
#[derive(Clone, Copy)]
#[non_exhaustive]
pub enum AudioType {
Opus,
Pcm,
}
pub struct Audio {
pub playing: bool,
pub volume: f32,
pub finished: bool,
pub source: Box<dyn AudioSource>,
pub position: Duration,
pub position_modified: bool,
}
impl Audio {
pub fn new(source: Box<dyn AudioSource>) -> Self {
Self {
playing: true,
volume: 1.0,
finished: false,
source,
position: Duration::new(0, 0),
position_modified: false,
}
}
pub fn play(&mut self) -> &mut Self {
self.playing = true;
self
}
pub fn pause(&mut self) -> &mut Self {
self.playing = false;
self
}
pub fn volume(&mut self, volume: f32) -> &mut Self {
self.volume = volume;
self
}
pub fn position(&mut self, position: Duration) -> &mut Self {
self.position = position;
self.position_modified = true;
self
}
pub(crate) fn step_frame(&mut self) {
self.position += Duration::from_millis(20);
self.position_modified = false;
}
}
pub type LockedAudio = Arc<Mutex<Audio>>;