Add basic implementation for alsa

This commit is contained in:
Pierre Krieger 2014-12-16 16:45:45 +01:00
parent cf70b766f5
commit c2ed846765
2 changed files with 111 additions and 1 deletions

107
src/alsa/mod.rs Normal file
View File

@ -0,0 +1,107 @@
extern crate "alsa-sys" as alsa;
extern crate libc;
use std::{mem, ptr};
pub struct Channel {
channel: *mut alsa::snd_pcm_t,
num_channels: u16,
}
pub struct Buffer<'a, T> {
channel: &'a mut Channel,
buffer: Vec<T>,
}
impl Channel {
pub fn new() -> Channel {
unsafe {
let name = "default".to_c_str();
let mut playback_handle = mem::uninitialized();
check_errors(alsa::snd_pcm_open(&mut playback_handle, name.as_ptr(), alsa::SND_PCM_STREAM_PLAYBACK, alsa::SND_PCM_NONBLOCK)).unwrap();
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();
Channel {
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
}
pub fn append_data<'a, T>(&'a mut self, max_elements: uint) -> Buffer<'a, T> where T: Clone {
let available = unsafe { alsa::snd_pcm_avail(self.channel) };
let available = available * self.num_channels as alsa::snd_pcm_sframes_t;
let elements = ::std::cmp::min(available as uint, max_elements);
Buffer {
channel: self,
buffer: Vec::from_elem(elements, unsafe { mem::uninitialized() })
}
}
}
impl Drop for Channel {
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] {
self.buffer.as_mut_slice()
}
pub fn finish(self) {
let written = (self.buffer.len() / self.channel.num_channels as uint) as alsa::snd_pcm_uframes_t;
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> {
use std::c_str::CString;
if err < 0 {
unsafe {
let s = CString::new(alsa::snd_strerror(err), false);
return Err(s.to_string());
}
}
Ok(())
}

View File

@ -1,10 +1,13 @@
#![feature(unsafe_destructor)] #![feature(unsafe_destructor)]
#[cfg(all(not(windows)))] #[cfg(all(not(windows), not(unix)))]
use this_platform_is_not_supported; use this_platform_is_not_supported;
mod conversions; mod conversions;
#[cfg(unix)]
#[path="alsa/mod.rs"]
pub mod cpal_impl;
#[cfg(windows)] #[cfg(windows)]
#[path="wasapi/mod.rs"] #[path="wasapi/mod.rs"]
pub mod cpal_impl; pub mod cpal_impl;