spectrusty_audio/host/
sdl2.rs1use core::convert::TryFrom;
14use core::time::Duration;
15
16#[allow(unused_imports)]
17use log::{error, warn, info, debug, trace};
18
19use sdl2::{
20 Sdl,
21 audio::{AudioDevice, AudioCallback, AudioSpecDesired, AudioFormatNum}
22};
23
24pub use sdl2::audio::AudioStatus;
25
26use spectrusty_core::audio::AudioSample;
27use crate::carousel::*;
28pub use super::{AudioHandleError, AudioHandleErrorKind};
29
30struct AudioCb<T>(AudioFrameConsumer<T>);
31
32impl<T: AudioFormatNum + AudioSample> AudioCallback for AudioCb<T> {
33 type Channel = T;
34
35 fn callback(&mut self, out: &mut [T]) {
36 match self.0.fill_buffer(out, false) {
37 Ok(unfilled) => {
38 if !unfilled.is_empty() {
39 for t in unfilled {
40 *t = T::SILENCE
41 }
42 debug!("missing buffer");
43 }
44 }
45 Err(_) => {
46 error!("fatal: producer terminated");
47 }
48 }
49 }
50}
51
52pub struct AudioHandle<T: AudioFormatNum + AudioSample> {
61 pub sample_rate: u32,
63 pub channels: u8,
65 pub samples: u16,
67 pub producer: AudioFrameProducer<T>,
69 device: AudioDevice<AudioCb<T>>,
70}
71
72const DEFAULT_SAMPLE_RATE: i32 = 44100;
73const DEFAULT_CHANNELS: u8 = 2;
74
75impl<T: AudioFormatNum + AudioSample> AudioHandle<T> {
76 pub fn status(&self) -> AudioStatus {
78 self.device.status()
79 }
80 pub fn play(&self) {
82 self.device.resume()
83 }
84 pub fn pause(&self) {
86 self.device.pause()
87 }
88 pub fn close(self) -> AudioFrameConsumer<T> {
91 self.device.close_and_get_callback().0
92 }
93 pub fn create(
102 sdl_context: &Sdl,
103 frame_duration_nanos: u32,
104 latency: usize
105 ) -> Result<Self, AudioHandleError>
106 {
107 Self::create_with_specs(
108 sdl_context,
109 AudioSpecDesired { freq: None, channels: None, samples: None },
110 frame_duration_nanos,
111 latency
112 )
113 }
114 pub fn create_with_specs(
125 sdl_context: &Sdl,
126 mut desired_spec: AudioSpecDesired,
127 frame_duration_nanos: u32,
128 latency: usize
129 ) -> Result<Self, AudioHandleError>
130 {
131 let audio_subsystem = sdl_context.audio().map_err(|e| (e, AudioHandleErrorKind::AudioSubsystem))?;
132 let frame_duration_secs = Duration::from_nanos(frame_duration_nanos.into()).as_secs_f64();
133
134 if desired_spec.freq.is_none() {
135 desired_spec.freq = Some(DEFAULT_SAMPLE_RATE);
136 }
137 if desired_spec.channels.is_none() {
138 desired_spec.channels = Some(DEFAULT_CHANNELS);
139 }
140 if desired_spec.samples.is_none() {
141 let audio_frame_samples = (desired_spec.freq.unwrap() as f64 * frame_duration_secs).ceil() as usize;
142 let samples: u16 = (audio_frame_samples * latency.max(1)).checked_next_power_of_two()
143 .and_then(|samples| u16::try_from(samples).ok())
144 .unwrap_or(0x8000);
145 desired_spec.samples = Some(samples);
146 }
147
148 let mut producer: Option<AudioFrameProducer<T>> = None;
149
150 let device = audio_subsystem.open_playback(None, &desired_spec, |spec| {
151 let audio_frame_samples = (spec.freq as f64 * frame_duration_secs).ceil() as usize;
152 let min_latency = (spec.samples as usize / audio_frame_samples).max(1);
153 let latency = latency.max(min_latency);
154 debug!("audio specs: {:?}", spec);
155 debug!("audio frame samples: {} latency: {}", audio_frame_samples, latency);
156 let (prd, consumer) = create_carousel::<T>(latency, audio_frame_samples, spec.channels);
157 producer = Some(prd);
158 AudioCb(consumer)
159 }).map_err(|e| (e, AudioHandleErrorKind::AudioStream))?;
160
161 let spec = device.spec();
162
163 Ok(AudioHandle {
164 sample_rate: spec.freq as u32,
165 channels: spec.channels,
166 samples: spec.samples,
167 producer: producer.unwrap(),
168 device
169 })
170 }
171}