1use core::convert::TryInto;
14use core::time::Duration;
15
16#[allow(unused_imports)]
17use log::{error, warn, info, debug, trace};
18
19use cpal::{
20 Stream,
21 PlayStreamError, PauseStreamError, DefaultStreamConfigError, BuildStreamError,
22 traits::{DeviceTrait, HostTrait, StreamTrait}
23};
24
25pub use cpal::SampleFormat;
26
27use spectrusty_core::audio::AudioSample;
28use crate::carousel::*;
29pub use super::{AudioHandleError, AudioHandleErrorKind};
30
31pub struct AudioHandle<T: cpal::Sample + AudioSample> {
40 pub sample_rate: u32,
42 pub channels: u8,
44 pub producer: AudioFrameProducer<T>,
46 stream: Stream
47}
48
49pub enum AudioHandleAnyFormat {
51 I16(AudioHandle<i16>),
52 U16(AudioHandle<u16>),
53 F32(AudioHandle<f32>),
54}
55
56impl AudioHandleAnyFormat {
57 pub fn sample_format(&self) -> SampleFormat {
59 use AudioHandleAnyFormat::*;
60 match self {
61 I16(..) => SampleFormat::I16,
62 U16(..) => SampleFormat::U16,
63 F32(..) => SampleFormat::F32,
64 }
65 }
66 pub fn sample_rate(&self) -> u32 {
68 use AudioHandleAnyFormat::*;
69 match self {
70 I16(audio) => audio.sample_rate,
71 U16(audio) => audio.sample_rate,
72 F32(audio) => audio.sample_rate,
73 }
74 }
75 pub fn channels(&self) -> u8 {
77 use AudioHandleAnyFormat::*;
78 match self {
79 I16(audio) => audio.channels,
80 U16(audio) => audio.channels,
81 F32(audio) => audio.channels,
82 }
83 }
84 pub fn play(&self) -> Result<(), AudioHandleError> {
86 use AudioHandleAnyFormat::*;
87 match self {
88 I16(audio) => audio.play(),
89 U16(audio) => audio.play(),
90 F32(audio) => audio.play(),
91 }
92 }
93 pub fn pause(&self) -> Result<(), AudioHandleError> {
95 use AudioHandleAnyFormat::*;
96 match self {
97 I16(audio) => audio.pause(),
98 U16(audio) => audio.pause(),
99 F32(audio) => audio.pause(),
100 }
101 }
102 pub fn close(self) {}
104 pub fn send_frame(&mut self) -> AudioFrameResult<()> {
106 use AudioHandleAnyFormat::*;
107 match self {
108 I16(audio) => audio.producer.send_frame(),
109 U16(audio) => audio.producer.send_frame(),
110 F32(audio) => audio.producer.send_frame(),
111 }
112 }
113 pub fn create(
119 host: &cpal::Host,
120 frame_duration_nanos: u32,
121 latency: usize
122 ) -> Result<Self, AudioHandleError>
123 {
124 let device = host.default_output_device()
125 .ok_or_else(|| ("no default output device".to_string(),
126 AudioHandleErrorKind::AudioSubsystem))?;
127 Self::create_with_device(&device, frame_duration_nanos, latency)
128 }
129 pub fn create_with_device(
135 device: &cpal::Device,
136 frame_duration_nanos: u32,
137 latency: usize
138 ) -> Result<Self, AudioHandleError>
139 {
140 let config = device.default_output_config()?.config();
141 Self::create_with_device_and_config(
142 device,
143 &config,
144 frame_duration_nanos,
145 latency,
146 )
147 }
148 pub fn create_with_device_and_config(
155 device: &cpal::Device,
156 config: &cpal::StreamConfig,
157 frame_duration_nanos: u32,
158 latency: usize,
159 ) -> Result<Self, AudioHandleError>
160 {
161 Ok(match device.default_output_config()?.sample_format() {
162 SampleFormat::I16 => AudioHandleAnyFormat::I16(
163 AudioHandle::<i16>::create_with_device_and_config(device, config, frame_duration_nanos, latency)?
164 ),
165 SampleFormat::U16 => AudioHandleAnyFormat::U16(
166 AudioHandle::<u16>::create_with_device_and_config(device, config, frame_duration_nanos, latency)?
167 ),
168 SampleFormat::F32 => AudioHandleAnyFormat::F32(
169 AudioHandle::<f32>::create_with_device_and_config(device, config, frame_duration_nanos, latency)?
170 )
171 })
172 }
173}
174
175impl<T: cpal::Sample + AudioSample> AudioHandle<T> {
176 pub fn play(&self) -> Result<(), AudioHandleError> {
178 self.stream.play().map_err(From::from)
179 }
180 pub fn pause(&self) -> Result<(), AudioHandleError> {
182 self.stream.pause().map_err(From::from)
183 }
184 pub fn close(self) {}
186 pub fn create_with_device_and_config(
193 device: &cpal::Device,
194 config: &cpal::StreamConfig,
195 frame_duration_nanos: u32,
196 latency: usize,
197 ) -> Result<Self, AudioHandleError>
198 {
199 let channels: u8 = config.channels.try_into()
200 .map_err(|_| (format!("number of channels: {} exceed the maximum value of 255", config.channels),
201 AudioHandleErrorKind::InvalidArguments))?;
202 let sample_rate = config.sample_rate.0;
203
204 let frame_duration_secs = Duration::from_nanos(frame_duration_nanos.into()).as_secs_f64();
205 let audio_frame_samples = (sample_rate as f64 * frame_duration_secs).ceil() as usize;
206 debug!("audio specs: {:?}", config);
207 debug!("audio frame samples: {} latency: {}", audio_frame_samples, latency);
208 let (producer, mut consumer) = create_carousel::<T>(latency, audio_frame_samples, channels);
209
210 let data_fn = move |out: &mut [T], _: &_| match consumer.fill_buffer(out, false) {
211 Ok(unfilled) => {
212 if !unfilled.is_empty() {
213 for t in unfilled {
214 *t = T::silence()
215 }
216 debug!("missing buffer");
217 }
218 }
219 Err(_) => {
220 error!("fatal: producer terminated");
221 }
222 };
223
224 let err_fn = |err| error!("an error occurred on stream: {}", err);
225
226 let stream = device.build_output_stream(config, data_fn, err_fn)?;
227
228 Ok(AudioHandle {
229 sample_rate,
230 channels,
231 producer,
232 stream
233 })
234 }
235}
236
237impl From<PlayStreamError> for AudioHandleError {
238 fn from(e: PlayStreamError) -> Self {
239 let kind = match e {
240 PlayStreamError::DeviceNotAvailable => AudioHandleErrorKind::AudioSubsystem,
241 _ => AudioHandleErrorKind::AudioStream
242 };
243 (e.to_string(), kind).into()
244 }
245}
246
247impl From<PauseStreamError> for AudioHandleError {
248 fn from(e: PauseStreamError) -> Self {
249 let kind = match e {
250 PauseStreamError::DeviceNotAvailable => AudioHandleErrorKind::AudioSubsystem,
251 _ => AudioHandleErrorKind::AudioStream
252 };
253 (e.to_string(), kind).into()
254 }
255}
256
257impl From<DefaultStreamConfigError> for AudioHandleError {
258 fn from(e: DefaultStreamConfigError) -> Self {
259 let kind = match e {
260 DefaultStreamConfigError::StreamTypeNotSupported => AudioHandleErrorKind::InvalidArguments,
261 _ => AudioHandleErrorKind::AudioSubsystem
262 };
263 (e.to_string(), kind).into()
264 }
265}
266
267impl From<BuildStreamError> for AudioHandleError {
268 fn from(e: BuildStreamError) -> Self {
269 let kind = match e {
270 BuildStreamError::DeviceNotAvailable => AudioHandleErrorKind::AudioSubsystem,
271 BuildStreamError::StreamConfigNotSupported|
272 BuildStreamError::InvalidArgument => AudioHandleErrorKind::InvalidArguments,
273 _ => AudioHandleErrorKind::AudioStream
274 };
275 (e.to_string(), kind).into()
276 }
277}