use anyhow::Context;
use log::error;
use wasapi::{AudioClient, Direction, SampleType, StreamMode, WaveFormat};
use crate::common::builder::ChunkBuilder;
use crate::common::result::Result;
use crate::common::source::AudioSource;
pub const SAMPLE_RATE: usize = 48000; pub const STORE_BITS: usize = 32; pub const VALID_BITS: usize = 32; pub const CHANNELS: usize = 2; pub const SAMPLE_TYPE: SampleType = SampleType::Float; pub const BLOCKALIGN: usize = CHANNELS * size_of::<f32>(); pub const PACKET_SAMPLES: usize = 480; pub const PACKET_FRAMES: usize = PACKET_SAMPLES * 2; pub const PACKET_BYTES: usize = BLOCKALIGN * PACKET_SAMPLES; pub const TIMEOUT_MS: u32 = 1000;
pub struct LinkState {
pub audio_client: AudioClient,
pub capture_client: wasapi::AudioCaptureClient,
pub event_handle: wasapi::Handle,
pub buffer: ChunkBuilder<u8, PACKET_BYTES>,
}
impl LinkState {
pub fn link(source: &AudioSource) -> Result<Self> {
let format = &WaveFormat::new(STORE_BITS, VALID_BITS, &SAMPLE_TYPE, SAMPLE_RATE, CHANNELS, None);
let mut audio_client = AudioClient::new_application_loopback_client(source.id[0], true)?;
let mode = StreamMode::EventsShared {
autoconvert: true,
buffer_duration_hns: 0,
};
audio_client.initialize_client(format, &Direction::Capture, &mode)?;
let capture_client = audio_client.get_audiocaptureclient()
.context("Failed to get audio capture client")?;
let event_handle = audio_client.set_get_eventhandle()
.context("Failed to get audio event handle")?;
audio_client.start_stream()
.context("Failed to start stream")?;
Ok(Self { audio_client, capture_client, event_handle, buffer: ChunkBuilder::default() })
}
}
impl Drop for LinkState {
fn drop(&mut self) {
if let Err(e) = self.audio_client.stop_stream() {
error!("cleanup failed: {e}");
}
}
}