cpal/src/wasapi/mod.rs

257 lines
8.2 KiB
Rust
Raw Normal View History

2014-12-11 14:22:55 +01:00
extern crate libc;
extern crate winapi;
2015-03-30 11:06:46 +02:00
extern crate ole32;
2014-12-11 14:22:55 +01:00
2015-08-20 14:38:25 +02:00
use std::{cmp, slice, mem, ptr};
2015-02-22 10:31:25 +01:00
use std::marker::PhantomData;
2014-12-11 14:22:55 +01:00
2014-12-15 16:06:37 +01:00
// TODO: determine if should be NoSend or not
2014-12-17 09:16:26 +01:00
pub struct Voice {
2014-12-11 17:23:33 +01:00
audio_client: *mut winapi::IAudioClient,
render_client: *mut winapi::IAudioRenderClient,
max_frames_in_buffer: winapi::UINT32,
num_channels: winapi::WORD,
bytes_per_frame: winapi::WORD,
2014-12-11 19:07:58 +01:00
samples_per_second: winapi::DWORD,
bits_per_sample: winapi::WORD,
2014-12-22 14:16:47 +01:00
playing: bool,
2014-12-11 17:23:33 +01:00
}
2015-02-22 10:31:25 +01:00
pub struct Buffer<'a, T: 'a> {
2014-12-11 17:23:33 +01:00
render_client: *mut winapi::IAudioRenderClient,
2015-01-08 20:34:27 +01:00
buffer_data: *mut T,
2015-01-09 21:25:51 +01:00
buffer_len: usize,
2014-12-11 17:23:33 +01:00
frames: winapi::UINT32,
2015-02-22 10:31:25 +01:00
marker: PhantomData<&'a mut T>,
2014-12-11 17:23:33 +01:00
}
2014-12-17 09:16:26 +01:00
impl Voice {
pub fn new() -> Voice {
2014-12-11 17:23:33 +01:00
init().unwrap()
}
2014-12-11 19:02:04 +01:00
pub fn get_channels(&self) -> ::ChannelsCount {
self.num_channels as ::ChannelsCount
2014-12-11 17:23:33 +01:00
}
2014-12-15 11:45:38 +01:00
pub fn get_samples_rate(&self) -> ::SamplesRate {
::SamplesRate(self.samples_per_second as u32)
2014-12-11 19:07:58 +01:00
}
pub fn get_samples_format(&self) -> ::SampleFormat {
match self.bits_per_sample {
2015-07-22 14:28:45 +02:00
16 => ::SampleFormat::I16,
_ => panic!("{}-bit format not yet supported", self.bits_per_sample),
2014-12-11 19:07:58 +01:00
}
}
2015-01-09 21:25:51 +01:00
pub fn append_data<'a, T>(&'a mut self, max_elements: usize) -> Buffer<'a, T> {
2014-12-11 17:23:33 +01:00
unsafe {
loop {
//
let frames_available = {
let mut padding = mem::uninitialized();
let hresult = (*self.audio_client).GetCurrentPadding(&mut padding);
2014-12-11 17:23:33 +01:00
check_result(hresult).unwrap();
self.max_frames_in_buffer - padding
};
if frames_available == 0 {
// TODO:
2015-04-04 09:06:46 +02:00
::std::thread::sleep_ms(1);
2014-12-11 17:23:33 +01:00
continue;
}
2015-08-20 14:38:25 +02:00
let frames_available = cmp::min(frames_available,
max_elements as u32 * mem::size_of::<T>() as u32 /
self.bytes_per_frame as u32);
2014-12-15 16:26:55 +01:00
assert!(frames_available != 0);
2014-12-11 17:23:33 +01:00
// loading buffer
2015-01-08 20:34:27 +01:00
let (buffer_data, buffer_len) = {
2014-12-11 17:23:33 +01:00
let mut buffer: *mut winapi::BYTE = mem::uninitialized();
let hresult = (*self.render_client).GetBuffer(frames_available,
2014-12-11 17:23:33 +01:00
&mut buffer as *mut *mut libc::c_uchar);
check_result(hresult).unwrap();
assert!(!buffer.is_null());
2014-12-11 19:02:04 +01:00
2015-01-08 20:34:27 +01:00
(buffer as *mut T,
2015-01-09 21:25:51 +01:00
frames_available as usize * self.bytes_per_frame as usize
2015-01-08 20:34:27 +01:00
/ mem::size_of::<T>())
2014-12-11 17:23:33 +01:00
};
let buffer = Buffer {
render_client: self.render_client,
2015-01-08 20:34:27 +01:00
buffer_data: buffer_data,
buffer_len: buffer_len,
2014-12-11 17:23:33 +01:00
frames: frames_available,
2015-02-22 10:31:25 +01:00
marker: PhantomData,
2014-12-11 17:23:33 +01:00
};
return buffer;
}
}
}
2014-12-22 14:16:47 +01:00
pub fn play(&mut self) {
if !self.playing {
unsafe {
let hresult = (*self.audio_client).Start();
2014-12-22 14:16:47 +01:00
check_result(hresult).unwrap();
}
}
self.playing = true;
}
pub fn pause(&mut self) {
if self.playing {
unsafe {
let hresult = (*self.audio_client).Stop();
2014-12-22 14:16:47 +01:00
check_result(hresult).unwrap();
}
}
self.playing = false;
}
2014-12-11 17:23:33 +01:00
}
2014-12-30 08:35:13 +01:00
unsafe impl Send for Voice {}
unsafe impl Sync for Voice {}
2014-12-17 09:16:26 +01:00
impl Drop for Voice {
2014-12-11 19:42:04 +01:00
fn drop(&mut self) {
unsafe {
(*self.render_client).Release();
(*self.audio_client).Release();
2014-12-11 19:42:04 +01:00
}
}
}
2014-12-15 10:29:29 +01:00
impl<'a, T> Buffer<'a, T> {
2014-12-15 15:29:59 +01:00
pub fn get_buffer<'b>(&'b mut self) -> &'b mut [T] {
2015-01-08 20:34:27 +01:00
unsafe {
2015-02-19 21:22:07 +01:00
slice::from_raw_parts_mut(self.buffer_data, self.buffer_len)
2015-01-08 20:34:27 +01:00
}
2014-12-11 17:23:33 +01:00
}
2014-12-15 16:32:13 +01:00
pub fn finish(self) {
2014-12-11 17:23:33 +01:00
// releasing buffer
unsafe {
let hresult = (*self.render_client).ReleaseBuffer(self.frames as u32, 0);
2014-12-11 17:23:33 +01:00
check_result(hresult).unwrap();
};
}
}
2014-12-17 09:16:26 +01:00
fn init() -> Result<Voice, String> {
2014-12-11 16:28:26 +01:00
// FIXME: release everything
2014-12-11 14:22:55 +01:00
unsafe {
2015-08-20 14:38:25 +02:00
try!(check_result(ole32::CoInitializeEx(ptr::null_mut(), 0)));
2014-12-11 14:22:55 +01:00
2014-12-11 16:28:26 +01:00
// building the devices enumerator object
2014-12-11 14:22:55 +01:00
let enumerator = {
2015-08-20 14:38:25 +02:00
let mut enumerator: *mut winapi::IMMDeviceEnumerator = mem::uninitialized();
2014-12-11 14:22:55 +01:00
2015-01-20 16:45:47 +01:00
let hresult = ole32::CoCreateInstance(&winapi::CLSID_MMDeviceEnumerator,
2014-12-11 16:28:26 +01:00
ptr::null_mut(), winapi::CLSCTX_ALL,
&winapi::IID_IMMDeviceEnumerator,
mem::transmute(&mut enumerator));
2014-12-11 14:22:55 +01:00
try!(check_result(hresult));
2015-04-04 09:06:46 +02:00
&mut *enumerator
2014-12-11 14:22:55 +01:00
};
// getting the default end-point
let device = {
2014-12-11 16:28:26 +01:00
let mut device: *mut winapi::IMMDevice = mem::uninitialized();
let hresult = enumerator.GetDefaultAudioEndpoint(winapi::EDataFlow::eRender, winapi::ERole::eConsole,
2014-12-11 16:28:26 +01:00
mem::transmute(&mut device));
2014-12-11 14:22:55 +01:00
try!(check_result(hresult));
2015-04-04 09:06:46 +02:00
&mut *device
2014-12-11 14:22:55 +01:00
};
2014-12-11 16:28:26 +01:00
// activating in order to get a `IAudioClient`
2015-04-04 09:06:46 +02:00
let audio_client: &mut winapi::IAudioClient = {
2014-12-11 16:28:26 +01:00
let mut audio_client: *mut winapi::IAudioClient = mem::uninitialized();
let hresult = device.Activate(&winapi::IID_IAudioClient, winapi::CLSCTX_ALL,
2014-12-11 16:28:26 +01:00
ptr::null_mut(), mem::transmute(&mut audio_client));
try!(check_result(hresult));
2015-04-04 09:06:46 +02:00
&mut *audio_client
2014-12-11 16:28:26 +01:00
};
2014-12-11 17:23:33 +01:00
// computing the format and initializing the device
let format = {
let format_attempt = winapi::WAVEFORMATEX {
wFormatTag: 1, // WAVE_FORMAT_PCM ; TODO: replace by constant
nChannels: 2,
nSamplesPerSec: 44100,
nAvgBytesPerSec: 2 * 44100 * 2,
nBlockAlign: (2 * 16) / 8,
wBitsPerSample: 16,
cbSize: 0,
};
2014-12-11 16:28:26 +01:00
let mut format_ptr: *mut winapi::WAVEFORMATEX = mem::uninitialized();
let hresult = audio_client.IsFormatSupported(winapi::AUDCLNT_SHAREMODE::AUDCLNT_SHAREMODE_SHARED,
2014-12-11 17:23:33 +01:00
&format_attempt, &mut format_ptr);
2014-12-11 16:28:26 +01:00
try!(check_result(hresult));
2015-04-04 09:06:46 +02:00
let format = if format_ptr.is_null() {
&format_attempt
} else {
&*format_ptr
2014-12-11 17:23:33 +01:00
};
2014-12-15 10:16:18 +01:00
let format_copy = ptr::read(format);
2014-12-11 17:23:33 +01:00
let hresult = audio_client.Initialize(winapi::AUDCLNT_SHAREMODE::AUDCLNT_SHAREMODE_SHARED,
2014-12-11 17:23:33 +01:00
0, 10000000, 0, format, ptr::null());
if !format_ptr.is_null() {
2015-07-20 19:06:58 +02:00
ole32::CoTaskMemFree(format_ptr as *mut _);
2014-12-11 17:23:33 +01:00
}
2014-12-11 16:28:26 +01:00
try!(check_result(hresult));
2014-12-11 17:23:33 +01:00
format_copy
2014-12-11 16:28:26 +01:00
};
//
2014-12-11 17:23:33 +01:00
let max_frames_in_buffer = {
let mut max_frames_in_buffer = mem::uninitialized();
let hresult = audio_client.GetBufferSize(&mut max_frames_in_buffer);
2014-12-11 16:28:26 +01:00
try!(check_result(hresult));
2014-12-11 17:23:33 +01:00
max_frames_in_buffer
2014-12-11 14:22:55 +01:00
};
2014-12-11 16:28:26 +01:00
//
let render_client = {
let mut render_client: *mut winapi::IAudioRenderClient = mem::uninitialized();
let hresult = audio_client.GetService(&winapi::IID_IAudioRenderClient,
2014-12-11 16:28:26 +01:00
mem::transmute(&mut render_client));
try!(check_result(hresult));
2015-04-04 09:06:46 +02:00
&mut *render_client
2014-12-11 16:28:26 +01:00
};
2014-12-17 09:16:26 +01:00
Ok(Voice {
2014-12-11 17:23:33 +01:00
audio_client: audio_client,
render_client: render_client,
max_frames_in_buffer: max_frames_in_buffer,
num_channels: format.nChannels,
bytes_per_frame: format.nBlockAlign,
2014-12-11 19:07:58 +01:00
samples_per_second: format.nSamplesPerSec,
bits_per_sample: format.wBitsPerSample,
2014-12-22 14:16:47 +01:00
playing: false,
2014-12-11 17:23:33 +01:00
})
}
}
2014-12-11 14:22:55 +01:00
fn check_result(result: winapi::HRESULT) -> Result<(), String> {
2014-12-11 16:28:26 +01:00
if result < 0 {
2015-03-25 11:21:10 +01:00
return Err(format!("Error in winapi call")); // TODO:
2014-12-11 16:28:26 +01:00
}
2014-12-11 14:22:55 +01:00
Ok(())
}