use super::Client;
use crate::events::Event;
use crate::types::{AudioPreprocessor, SoundDevice, UserId};
use std::io::Write;
use std::net::UdpSocket;
use std::sync::{Arc, Mutex};
use teamtalk_sys as ffi;
#[derive(Debug, Clone, Copy)]
pub struct AudioDeviceProfile {
pub input_id: i32,
pub output_id: i32,
pub duplex: bool,
}
impl AudioDeviceProfile {
pub fn split(input_id: i32, output_id: i32) -> Self {
Self {
input_id,
output_id,
duplex: false,
}
}
pub fn duplex(input_id: i32, output_id: i32) -> Self {
Self {
input_id,
output_id,
duplex: true,
}
}
}
mod blocks;
mod devices;
pub struct AudioBlockView<'a> {
pub sample_rate: i32,
pub channels: i32,
pub stream_types: u32,
pub samples: i32,
pub sample_index: u32,
pub data: &'a [i16],
}
impl<'a> AudioBlockView<'a> {
pub fn from_block(block: &'a ffi::AudioBlock) -> Option<Self> {
if block.lpRawAudio.is_null() || block.nSamples <= 0 || block.nChannels <= 0 {
return None;
}
let count = block.nSamples.saturating_mul(block.nChannels) as usize;
let ptr = block.lpRawAudio as *const i16;
let data = unsafe { std::slice::from_raw_parts(ptr, count) };
Some(Self {
sample_rate: block.nSampleRate,
channels: block.nChannels,
stream_types: block.uStreamTypes,
samples: block.nSamples,
sample_index: block.uSampleIndex,
data,
})
}
}
pub trait AudioBlockSink {
fn handle(&mut self, block: &AudioBlockView<'_>);
}
pub struct CallbackSink<F>(pub F);
impl<F> AudioBlockSink for CallbackSink<F>
where
F: FnMut(&AudioBlockView<'_>),
{
fn handle(&mut self, block: &AudioBlockView<'_>) {
(self.0)(block);
}
}
pub struct WriterSink<W> {
writer: W,
}
impl<W> WriterSink<W>
where
W: Write,
{
pub fn new(writer: W) -> Self {
Self { writer }
}
}
impl<W> AudioBlockSink for WriterSink<W>
where
W: Write,
{
fn handle(&mut self, block: &AudioBlockView<'_>) {
let bytes = unsafe {
std::slice::from_raw_parts(
block.data.as_ptr() as *const u8,
std::mem::size_of_val(block.data),
)
};
let _ = self.writer.write_all(bytes);
}
}
pub struct UdpSink {
socket: UdpSocket,
}
impl UdpSink {
pub fn connect(addr: &str) -> std::io::Result<Self> {
let socket = UdpSocket::bind("0.0.0.0:0")?;
socket.connect(addr)?;
Ok(Self { socket })
}
}
impl AudioBlockSink for UdpSink {
fn handle(&mut self, block: &AudioBlockView<'_>) {
let bytes = unsafe {
std::slice::from_raw_parts(
block.data.as_ptr() as *const u8,
std::mem::size_of_val(block.data),
)
};
let _ = self.socket.send(bytes);
}
}
pub struct AudioBlockSubscription<'a> {
client: &'a Client,
subscription_id: crate::client::EventSubscriptionId,
user_id: UserId,
stream_types: u32,
}
impl Drop for AudioBlockSubscription<'_> {
fn drop(&mut self) {
let _ = self
.client
.enable_audio_block_event(self.user_id, self.stream_types, false);
let _ = self.client.unsubscribe_event(self.subscription_id);
}
}