From 019b27350f7bca8085d8f859046cacfac9c3850b Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Thu, 2 Nov 2017 19:30:15 +1000 Subject: [PATCH] Implement `pause` and `play` for ALSA backend (#176) * Implement `pause` and `play` for ALSA backend This commit also ensures that the Voice is initially paused when returned to remain consistent with the rest of the CPAL backends. Related to #175. * Remove ineffective pause from end of build_voice method * ALSA - Change `is_paused` flag from `AtomicBool` to `bool` * Add pause and play ALSA addition to CHANGELOG --- CHANGELOG.md | 1 + src/alsa/mod.rs | 60 +++++++++++++++++++++++++++++++++---------------- 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c0d8b3..7ab3b84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Changed the emscripten backend to consume less CPU. - Added improvements to the crate documentation. +- Implement `pause` and `play` for ALSA backend. # Version 0.5.1 (2017-10-21) diff --git a/src/alsa/mod.rs b/src/alsa/mod.rs index 393f313..5251d55 100644 --- a/src/alsa/mod.rs +++ b/src/alsa/mod.rs @@ -13,8 +13,8 @@ use SupportedFormat; use UnknownTypeBuffer; use std::{cmp, ffi, iter, mem, ptr}; -use std::sync::{Arc, Mutex}; -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use std::sync::Mutex; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::vec::IntoIter as VecIntoIter; pub type SupportedFormatsIterator = VecIntoIter; @@ -276,6 +276,8 @@ unsafe impl Sync for EventLoop { enum Command { NewVoice(VoiceInner), + PlayVoice(VoiceId), + PauseVoice(VoiceId), DestroyVoice(VoiceId), } @@ -309,8 +311,11 @@ struct VoiceInner { // Minimum number of samples to put in the buffer. period_len: usize, - // Wherease the sample stream is paused - is_paused: AtomicBool, + // Whether or not the hardware supports pausing the stream. + can_pause: bool, + + // Whether or not the sample stream is currently paused. + is_paused: bool, // A file descriptor opened with `eventfd`. // It is used to wait for resume signal. @@ -367,6 +372,22 @@ impl EventLoop { Command::DestroyVoice(voice_id) => { run_context.voices.retain(|v| v.id != voice_id); }, + Command::PlayVoice(voice_id) => { + if let Some(voice) = run_context.voices.iter_mut() + .find(|voice| voice.can_pause && voice.id == voice_id) + { + alsa::snd_pcm_pause(voice.channel, 0); + voice.is_paused = false; + } + }, + Command::PauseVoice(voice_id) => { + if let Some(voice) = run_context.voices.iter_mut() + .find(|voice| voice.can_pause && voice.id == voice_id) + { + alsa::snd_pcm_pause(voice.channel, 1); + voice.is_paused = true; + } + }, Command::NewVoice(voice_inner) => { run_context.voices.push(voice_inner); }, @@ -561,6 +582,8 @@ impl EventLoop { check_errors(alsa::snd_pcm_hw_params(playback_handle, hw_params.0)) .expect("hardware params could not be set"); + let can_pause = alsa::snd_pcm_hw_params_can_pause(hw_params.0) == 1; + let mut sw_params = mem::uninitialized(); // TODO: RAII check_errors(alsa::snd_pcm_sw_params_malloc(&mut sw_params)).unwrap(); check_errors(alsa::snd_pcm_sw_params_current(playback_handle, sw_params)).unwrap(); @@ -605,36 +628,35 @@ impl EventLoop { num_channels: format.channels.len() as u16, buffer_len: buffer_len, period_len: period_len, - is_paused: AtomicBool::new(true), + can_pause: can_pause, + is_paused: false, resume_trigger: Trigger::new(), }; - self.commands - .lock() - .unwrap() - .push(Command::NewVoice(voice_inner)); - self.pending_trigger.wakeup(); + self.push_command(Command::NewVoice(voice_inner)); Ok(new_voice_id) } } #[inline] - pub fn destroy_voice(&self, voice_id: VoiceId) { - self.commands - .lock() - .unwrap() - .push(Command::DestroyVoice(voice_id)); + fn push_command(&self, command: Command) { + self.commands.lock().unwrap().push(command); self.pending_trigger.wakeup(); } #[inline] - pub fn play(&self, _: VoiceId) { - //unimplemented!() + pub fn destroy_voice(&self, voice_id: VoiceId) { + self.push_command(Command::DestroyVoice(voice_id)); } #[inline] - pub fn pause(&self, _: VoiceId) { - unimplemented!() + pub fn play(&self, voice_id: VoiceId) { + self.push_command(Command::PlayVoice(voice_id)); + } + + #[inline] + pub fn pause(&self, voice_id: VoiceId) { + self.push_command(Command::PauseVoice(voice_id)); } }