Merge pull request #79 from tomaka/alsa-robust
Make the ALSA implementation more robust by recovering from underruns
This commit is contained in:
commit
6c72a7c08b
|
@ -233,11 +233,11 @@ impl Voice {
|
||||||
check_errors(alsa::snd_pcm_prepare(playback_handle)).unwrap();
|
check_errors(alsa::snd_pcm_prepare(playback_handle)).unwrap();
|
||||||
|
|
||||||
let buffer_len = {
|
let buffer_len = {
|
||||||
let obtained_params = HwParams::alloc();
|
let mut dummy = mem::uninitialized();
|
||||||
check_errors(alsa::snd_pcm_hw_params_current(playback_handle, hw_params.0)).unwrap();
|
|
||||||
let mut val = mem::uninitialized();
|
let mut val = mem::uninitialized();
|
||||||
check_errors(alsa::snd_pcm_hw_params_get_buffer_size(obtained_params.0, &mut val)).unwrap();
|
check_errors(alsa::snd_pcm_get_params(playback_handle, &mut val, &mut dummy)).unwrap();
|
||||||
val as usize / format.data_type.get_sample_size()
|
assert!(val != 0);
|
||||||
|
val as usize * format.channels.len()
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Voice {
|
Ok(Voice {
|
||||||
|
@ -252,10 +252,19 @@ impl Voice {
|
||||||
let available = {
|
let available = {
|
||||||
let channel = self.channel.lock().unwrap();
|
let channel = self.channel.lock().unwrap();
|
||||||
let available = unsafe { alsa::snd_pcm_avail(*channel) };
|
let available = unsafe { alsa::snd_pcm_avail(*channel) };
|
||||||
available * self.num_channels as alsa::snd_pcm_sframes_t
|
|
||||||
|
if available == -32 {
|
||||||
|
// buffer underrun
|
||||||
|
self.buffer_len
|
||||||
|
} else if available < 0 {
|
||||||
|
check_errors(available as libc::c_int).unwrap();
|
||||||
|
unreachable!()
|
||||||
|
} else {
|
||||||
|
(available * self.num_channels as alsa::snd_pcm_sframes_t) as usize
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let elements = ::std::cmp::min(available as usize, max_elements);
|
let elements = cmp::min(available, max_elements);
|
||||||
|
|
||||||
Buffer {
|
Buffer {
|
||||||
channel: self,
|
channel: self,
|
||||||
|
@ -278,14 +287,25 @@ impl Voice {
|
||||||
let available = {
|
let available = {
|
||||||
let channel = self.channel.lock().unwrap();
|
let channel = self.channel.lock().unwrap();
|
||||||
let available = unsafe { alsa::snd_pcm_avail(*channel) };
|
let available = unsafe { alsa::snd_pcm_avail(*channel) };
|
||||||
available * self.num_channels as alsa::snd_pcm_sframes_t
|
|
||||||
|
if available == -32 {
|
||||||
|
0 // buffer underrun
|
||||||
|
} else if available < 0 {
|
||||||
|
check_errors(available as libc::c_int).unwrap();
|
||||||
|
unreachable!()
|
||||||
|
} else {
|
||||||
|
available * self.num_channels as alsa::snd_pcm_sframes_t
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.buffer_len - available as usize
|
self.buffer_len - available as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn underflowed(&self) -> bool {
|
pub fn underflowed(&self) -> bool {
|
||||||
false // TODO:
|
let channel = self.channel.lock().unwrap();
|
||||||
|
|
||||||
|
let state = unsafe { alsa::snd_pcm_state(*channel) };
|
||||||
|
state == alsa::SND_PCM_STATE_XRUN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,17 +333,25 @@ impl<'a, T> Buffer<'a, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(self) {
|
pub fn finish(self) {
|
||||||
let written = (self.buffer.len() / self.channel.num_channels as usize)
|
let to_write = (self.buffer.len() / self.channel.num_channels as usize)
|
||||||
as alsa::snd_pcm_uframes_t;
|
as alsa::snd_pcm_uframes_t;
|
||||||
let channel = self.channel.channel.lock().unwrap();
|
let channel = self.channel.channel.lock().unwrap();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let result = alsa::snd_pcm_writei(*channel,
|
loop {
|
||||||
self.buffer.as_ptr() as *const libc::c_void,
|
let result = alsa::snd_pcm_writei(*channel,
|
||||||
written);
|
self.buffer.as_ptr() as *const libc::c_void,
|
||||||
|
to_write);
|
||||||
|
|
||||||
if result < 0 {
|
if result == -32 {
|
||||||
check_errors(result as libc::c_int).unwrap();
|
// buffer underrun
|
||||||
|
alsa::snd_pcm_prepare(*channel);
|
||||||
|
} else if result < 0 {
|
||||||
|
check_errors(result as libc::c_int).unwrap();
|
||||||
|
} else {
|
||||||
|
assert_eq!(result as alsa::snd_pcm_uframes_t, to_write);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue