2015-03-26 09:03:13 +00:00
|
|
|
extern crate alsa_sys as alsa;
|
2014-12-16 15:45:45 +00:00
|
|
|
extern crate libc;
|
|
|
|
|
2015-01-08 19:34:27 +00:00
|
|
|
use std::{ffi, iter, mem};
|
2014-12-16 15:45:45 +00:00
|
|
|
|
2014-12-17 08:16:26 +00:00
|
|
|
pub struct Voice {
|
2014-12-16 15:45:45 +00:00
|
|
|
channel: *mut alsa::snd_pcm_t,
|
|
|
|
num_channels: u16,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Buffer<'a, T> {
|
2014-12-17 08:16:26 +00:00
|
|
|
channel: &'a mut Voice,
|
2014-12-16 15:45:45 +00:00
|
|
|
buffer: Vec<T>,
|
|
|
|
}
|
|
|
|
|
2014-12-17 08:16:26 +00:00
|
|
|
impl Voice {
|
|
|
|
pub fn new() -> Voice {
|
2014-12-16 15:45:45 +00:00
|
|
|
unsafe {
|
2015-04-04 07:06:46 +00:00
|
|
|
let name = ffi::CString::new(b"default".to_vec()).unwrap();
|
2014-12-16 15:45:45 +00:00
|
|
|
|
|
|
|
let mut playback_handle = mem::uninitialized();
|
2015-02-22 09:31:25 +00:00
|
|
|
check_errors(alsa::snd_pcm_open(&mut playback_handle, name.as_ptr(), alsa::SND_PCM_STREAM_PLAYBACK, alsa::SND_PCM_NONBLOCK)).unwrap();
|
2014-12-16 15:45:45 +00:00
|
|
|
|
|
|
|
let mut hw_params = mem::uninitialized();
|
|
|
|
check_errors(alsa::snd_pcm_hw_params_malloc(&mut hw_params)).unwrap();
|
|
|
|
check_errors(alsa::snd_pcm_hw_params_any(playback_handle, hw_params)).unwrap();
|
|
|
|
check_errors(alsa::snd_pcm_hw_params_set_access(playback_handle, hw_params, alsa::SND_PCM_ACCESS_RW_INTERLEAVED)).unwrap();
|
|
|
|
check_errors(alsa::snd_pcm_hw_params_set_format(playback_handle, hw_params, alsa::SND_PCM_FORMAT_S16_LE)).unwrap(); // TODO: check endianess
|
|
|
|
check_errors(alsa::snd_pcm_hw_params_set_rate(playback_handle, hw_params, 44100, 0)).unwrap();
|
|
|
|
check_errors(alsa::snd_pcm_hw_params_set_channels(playback_handle, hw_params, 2)).unwrap();
|
|
|
|
check_errors(alsa::snd_pcm_hw_params(playback_handle, hw_params)).unwrap();
|
|
|
|
alsa::snd_pcm_hw_params_free(hw_params);
|
|
|
|
|
|
|
|
check_errors(alsa::snd_pcm_prepare(playback_handle)).unwrap();
|
|
|
|
|
2014-12-17 08:16:26 +00:00
|
|
|
Voice {
|
2014-12-16 15:45:45 +00:00
|
|
|
channel: playback_handle,
|
|
|
|
num_channels: 2,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_channels(&self) -> ::ChannelsCount {
|
|
|
|
self.num_channels
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_samples_rate(&self) -> ::SamplesRate {
|
|
|
|
::SamplesRate(44100)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_samples_format(&self) -> ::SampleFormat {
|
|
|
|
::SampleFormat::U16
|
|
|
|
}
|
|
|
|
|
2015-01-09 20:25:51 +00:00
|
|
|
pub fn append_data<'a, T>(&'a mut self, max_elements: usize) -> Buffer<'a, T> where T: Clone {
|
2014-12-16 15:45:45 +00:00
|
|
|
let available = unsafe { alsa::snd_pcm_avail(self.channel) };
|
|
|
|
let available = available * self.num_channels as alsa::snd_pcm_sframes_t;
|
|
|
|
|
2015-01-09 20:25:51 +00:00
|
|
|
let elements = ::std::cmp::min(available as usize, max_elements);
|
2014-12-16 15:45:45 +00:00
|
|
|
|
|
|
|
Buffer {
|
|
|
|
channel: self,
|
2015-01-08 19:34:27 +00:00
|
|
|
buffer: iter::repeat(unsafe { mem::uninitialized() }).take(elements).collect(),
|
2014-12-16 15:45:45 +00:00
|
|
|
}
|
|
|
|
}
|
2014-12-22 13:16:47 +00:00
|
|
|
|
|
|
|
pub fn play(&mut self) {
|
|
|
|
// already playing
|
|
|
|
//unimplemented!()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn pause(&mut self) {
|
|
|
|
unimplemented!()
|
|
|
|
}
|
2014-12-16 15:45:45 +00:00
|
|
|
}
|
|
|
|
|
2014-12-30 07:35:13 +00:00
|
|
|
unsafe impl Send for Voice {}
|
|
|
|
unsafe impl Sync for Voice {}
|
|
|
|
|
2014-12-17 08:16:26 +00:00
|
|
|
impl Drop for Voice {
|
2014-12-16 15:45:45 +00:00
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
alsa::snd_pcm_close(self.channel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T> Buffer<'a, T> {
|
|
|
|
pub fn get_buffer<'b>(&'b mut self) -> &'b mut [T] {
|
2015-03-30 09:06:46 +00:00
|
|
|
&mut self.buffer
|
2014-12-16 15:45:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn finish(self) {
|
2015-01-09 20:25:51 +00:00
|
|
|
let written = (self.buffer.len() / self.channel.num_channels as usize) as alsa::snd_pcm_uframes_t;
|
2014-12-16 15:45:45 +00:00
|
|
|
|
|
|
|
unsafe {
|
|
|
|
let result = alsa::snd_pcm_writei(self.channel.channel,
|
|
|
|
self.buffer.as_ptr() as *const libc::c_void,
|
|
|
|
written);
|
|
|
|
|
|
|
|
if result < 0 {
|
|
|
|
check_errors(result as libc::c_int).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_errors(err: libc::c_int) -> Result<(), String> {
|
2015-01-08 19:34:27 +00:00
|
|
|
use std::ffi;
|
2014-12-16 15:45:45 +00:00
|
|
|
|
|
|
|
if err < 0 {
|
|
|
|
unsafe {
|
2015-04-04 07:06:46 +00:00
|
|
|
let s = ffi::CStr::from_ptr(alsa::snd_strerror(err)).to_bytes().to_vec();
|
|
|
|
let s = String::from_utf8(s).unwrap();
|
|
|
|
return Err(s);
|
2014-12-16 15:45:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|