limnus_audio_stream/
lib.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/limnus
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use cpal::traits::{DeviceTrait, StreamTrait};
6use cpal::{Device, StreamConfig};
7use limnus_app::prelude::{App, Plugin};
8use limnus_audio_device::low_level::Audio;
9use limnus_audio_mixer::AudioMixer;
10use limnus_local_resource::prelude::LocalResource;
11use std::fmt::Debug;
12use std::sync::{Arc, Mutex};
13use tracing::error;
14
15fn start_stream(
16    device: &Device,
17    config: &StreamConfig,
18    sample_rate: u32,
19    low_level_mixer: Arc<Mutex<oddio::Mixer<[f32; 2]>>>,
20) -> cpal::Stream {
21    let stream = device
22        .build_output_stream(
23            config,
24            move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
25                let out_frames = oddio::frame_stereo(data);
26                oddio::run(
27                    &mut *low_level_mixer.lock().unwrap(),
28                    sample_rate,
29                    out_frames,
30                );
31            },
32            move |err| {
33                error!("Stream error: {}", err);
34            },
35            None,
36        )
37        .expect("Failed to build output stream");
38
39    stream.play().expect("Failed to start stream");
40    stream
41}
42
43#[derive(LocalResource)]
44pub struct AudioStream {
45    #[allow(dead_code)]
46    stream: cpal::Stream,
47}
48
49impl Debug for AudioStream {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        write!(f, "AudioStream")
52    }
53}
54
55pub struct AudioStreamPlugin;
56
57impl Plugin for AudioStreamPlugin {
58    fn build(&self, app: &mut App) {
59        let resources = app.local_resources();
60        let audio = resources.fetch::<Audio>();
61        let mixer = resources.fetch::<AudioMixer>();
62
63        let device = audio.device();
64        let config = audio.config();
65        let stream = start_stream(device, config, audio.sample_rate(), mixer.mixer.clone());
66        let audio_stream = AudioStream { stream };
67        app.insert_local_resource(audio_stream);
68    }
69}