khora_infra/audio/backends/cpal/
device.rs1use anyhow::{anyhow, Result};
18use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
19use khora_core::audio::device::{AudioDevice, StreamInfo};
20
21#[derive(Default)]
23pub struct CpalAudioDevice;
24
25impl CpalAudioDevice {
26 pub fn new() -> Self {
28 Self
29 }
30}
31
32impl AudioDevice for CpalAudioDevice {
33 fn start(
34 self: Box<Self>,
35 mut on_mix_needed: Box<dyn FnMut(&mut [f32], &StreamInfo) + Send>,
36 ) -> Result<()> {
37 let host = cpal::default_host();
39 let device = host
40 .default_output_device()
41 .ok_or_else(|| anyhow!("No default output device available"))?;
42 let config = device.default_output_config()?;
43
44 let stream_info = StreamInfo {
45 channels: config.channels(),
46 sample_rate: config.sample_rate(),
47 };
48
49 let audio_callback = move |output_buffer: &mut [f32], _: &cpal::OutputCallbackInfo| {
50 on_mix_needed(output_buffer, &stream_info);
51 };
52
53 let error_callback = |err| {
54 eprintln!("An error occurred on the audio stream: {}", err);
55 };
56
57 let stream = match config.sample_format() {
58 cpal::SampleFormat::F32 => {
59 device.build_output_stream(&config.into(), audio_callback, error_callback, None)?
60 }
61 format => return Err(anyhow!("Unsupported sample format: {}", format)),
62 };
63
64 stream.play()?;
65
66 std::mem::forget(stream);
68
69 Ok(())
70 }
71}