Update WASAPI backend for removal of `UnknownTypeBuffer`

This commit is contained in:
mitchmindtree 2020-01-16 01:17:01 +11:00
parent 5a619877f9
commit b5bfb8d422
2 changed files with 257 additions and 191 deletions

View File

@ -1,3 +1,18 @@
use crate::{
BackendSpecificError,
DefaultFormatError,
DeviceNameError,
DevicesError,
Format,
InputData,
OutputData,
Sample,
SampleFormat,
SampleRate,
SupportedFormat,
SupportedFormatsError,
COMMON_SAMPLE_RATES,
};
use std; use std;
use std::ffi::OsString; use std::ffi::OsString;
use std::fmt; use std::fmt;
@ -9,17 +24,6 @@ use std::ptr;
use std::slice; use std::slice;
use std::sync::{Arc, Mutex, MutexGuard, atomic::Ordering}; use std::sync::{Arc, Mutex, MutexGuard, atomic::Ordering};
use BackendSpecificError;
use DefaultFormatError;
use DeviceNameError;
use DevicesError;
use Format;
use SampleFormat;
use SampleRate;
use SupportedFormat;
use SupportedFormatsError;
use COMMON_SAMPLE_RATES;
use super::check_result; use super::check_result;
use super::check_result_backend_specific; use super::check_result_backend_specific;
use super::com; use super::com;
@ -54,7 +58,7 @@ use super::{
stream::{AudioClientFlow, Stream, StreamInner}, stream::{AudioClientFlow, Stream, StreamInner},
winapi::um::synchapi, winapi::um::synchapi,
}; };
use crate::{traits::DeviceTrait, BuildStreamError, StreamData, StreamError}; use crate::{traits::DeviceTrait, BuildStreamError, StreamError};
pub type SupportedInputFormats = std::vec::IntoIter<SupportedFormat>; pub type SupportedInputFormats = std::vec::IntoIter<SupportedFormat>;
pub type SupportedOutputFormats = std::vec::IntoIter<SupportedFormat>; pub type SupportedOutputFormats = std::vec::IntoIter<SupportedFormat>;
@ -102,38 +106,34 @@ impl DeviceTrait for Device {
Device::default_output_format(self) Device::default_output_format(self)
} }
fn build_input_stream<D, E>( fn build_input_stream<T, D, E>(
&self, &self,
format: &Format, format: &Format,
data_callback: D, data_callback: D,
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(StreamData) + Send + 'static, T: Sample,
D: FnMut(InputData<T>) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
Ok(Stream::new( let stream_inner = self.build_input_stream_inner(format)?;
self.build_input_stream_inner(format)?, Ok(Stream::new_input(stream_inner, data_callback, error_callback))
data_callback,
error_callback,
))
} }
fn build_output_stream<D, E>( fn build_output_stream<T, D, E>(
&self, &self,
format: &Format, format: &Format,
data_callback: D, data_callback: D,
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
where where
D: FnMut(StreamData) + Send + 'static, T: Sample,
D: FnMut(OutputData<T>) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
Ok(Stream::new( let stream_inner = self.build_output_stream_inner(format)?;
self.build_output_stream_inner(format)?, Ok(Stream::new_output(stream_inner, data_callback, error_callback))
data_callback,
error_callback,
))
} }
} }

View File

@ -1,3 +1,19 @@
use crate::{
BackendSpecificError,
InputData,
OutputData,
PauseStreamError,
PlayStreamError,
Sample,
SampleFormat,
StreamError,
};
use crate::traits::StreamTrait;
use std::mem;
use std::ptr;
use std::slice;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread::{self, JoinHandle};
use super::check_result; use super::check_result;
use super::winapi::shared::basetsd::UINT32; use super::winapi::shared::basetsd::UINT32;
use super::winapi::shared::minwindef::{BYTE, FALSE, WORD}; use super::winapi::shared::minwindef::{BYTE, FALSE, WORD};
@ -7,23 +23,6 @@ use super::winapi::um::synchapi;
use super::winapi::um::winbase; use super::winapi::um::winbase;
use super::winapi::um::winnt; use super::winapi::um::winnt;
use std::mem;
use std::ptr;
use std::slice;
use std::sync::mpsc::{channel, Receiver, Sender};
use crate::traits::StreamTrait;
use std::thread::{self, JoinHandle};
use BackendSpecificError;
use PauseStreamError;
use PlayStreamError;
use SampleFormat;
use StreamData;
use StreamError;
use UnknownTypeInputBuffer;
use UnknownTypeOutputBuffer;
pub struct Stream { pub struct Stream {
/// The high-priority audio processing thread calling callbacks. /// The high-priority audio processing thread calling callbacks.
/// Option used for moving out in destructor. /// Option used for moving out in destructor.
@ -86,13 +85,14 @@ pub struct StreamInner {
} }
impl Stream { impl Stream {
pub(crate) fn new<D, E>( pub(crate) fn new_input<T, D, E>(
stream_inner: StreamInner, stream_inner: StreamInner,
mut data_callback: D, mut data_callback: D,
mut error_callback: E, mut error_callback: E,
) -> Stream ) -> Stream
where where
D: FnMut(StreamData) + Send + 'static, T: Sample,
D: FnMut(InputData<T>) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
let pending_scheduled_event = let pending_scheduled_event =
@ -106,7 +106,37 @@ impl Stream {
}; };
let thread = let thread =
thread::spawn(move || run_inner(run_context, &mut data_callback, &mut error_callback)); thread::spawn(move || run_input(run_context, &mut data_callback, &mut error_callback));
Stream {
thread: Some(thread),
commands: tx,
pending_scheduled_event,
}
}
pub(crate) fn new_output<T, D, E>(
stream_inner: StreamInner,
mut data_callback: D,
mut error_callback: E,
) -> Stream
where
T: Sample,
D: FnMut(OutputData<T>) + Send + 'static,
E: FnMut(StreamError) + Send + 'static,
{
let pending_scheduled_event =
unsafe { synchapi::CreateEventA(ptr::null_mut(), 0, 0, ptr::null()) };
let (tx, rx) = channel();
let run_context = RunContext {
handles: vec![pending_scheduled_event, stream_inner.event],
stream: stream_inner,
commands: rx,
};
let thread =
thread::spawn(move || run_output(run_context, &mut data_callback, &mut error_callback));
Stream { Stream {
thread: Some(thread), thread: Some(thread),
@ -255,20 +285,70 @@ fn stream_error_from_hresult(hresult: winnt::HRESULT) -> Result<(), StreamError>
Ok(()) Ok(())
} }
fn run_inner( fn run_input<T>(
mut run_context: RunContext, mut run_ctxt: RunContext,
data_callback: &mut dyn FnMut(StreamData), data_callback: &mut dyn FnMut(InputData<T>),
error_callback: &mut dyn FnMut(StreamError), error_callback: &mut dyn FnMut(StreamError),
) { ) where
unsafe { T: Sample,
'stream_loop: loop { {
loop {
match process_commands_and_await_signal(&mut run_ctxt, error_callback) {
Some(ControlFlow::Break) => break,
Some(ControlFlow::Continue) => continue,
None => (),
}
let capture_client = match run_ctxt.stream.client_flow {
AudioClientFlow::Capture { capture_client } => capture_client,
_ => unreachable!(),
};
match process_input(&mut run_ctxt.stream, capture_client, data_callback, error_callback) {
ControlFlow::Break => break,
ControlFlow::Continue => continue,
}
}
}
fn run_output<T>(
mut run_ctxt: RunContext,
data_callback: &mut dyn FnMut(OutputData<T>),
error_callback: &mut dyn FnMut(StreamError),
) where
T: Sample,
{
loop {
match process_commands_and_await_signal(&mut run_ctxt, error_callback) {
Some(ControlFlow::Break) => break,
Some(ControlFlow::Continue) => continue,
None => (),
}
let render_client = match run_ctxt.stream.client_flow {
AudioClientFlow::Render { render_client } => render_client,
_ => unreachable!(),
};
match process_output(&mut run_ctxt.stream, render_client, data_callback, error_callback) {
ControlFlow::Break => break,
ControlFlow::Continue => continue,
}
}
}
enum ControlFlow {
Break,
Continue,
}
fn process_commands_and_await_signal(
run_context: &mut RunContext,
error_callback: &mut dyn FnMut(StreamError),
) -> Option<ControlFlow> {
// Process queued commands. // Process queued commands.
match process_commands(&mut run_context) { match process_commands(run_context) {
Ok(true) => (), Ok(true) => (),
Ok(false) => break, Ok(false) => return Some(ControlFlow::Break),
Err(err) => { Err(err) => {
error_callback(err); error_callback(err);
break 'stream_loop; return Some(ControlFlow::Break);
} }
}; };
@ -277,23 +357,31 @@ fn run_inner(
Ok(idx) => idx, Ok(idx) => idx,
Err(err) => { Err(err) => {
error_callback(err.into()); error_callback(err.into());
break 'stream_loop; return Some(ControlFlow::Break);
} }
}; };
// If `handle_idx` is 0, then it's `pending_scheduled_event` that was signalled in // If `handle_idx` is 0, then it's `pending_scheduled_event` that was signalled in
// order for us to pick up the pending commands. Otherwise, a stream needs data. // order for us to pick up the pending commands. Otherwise, a stream needs data.
if handle_idx == 0 { if handle_idx == 0 {
continue; return Some(ControlFlow::Continue);
} }
let stream = &mut run_context.stream; None
let sample_size = stream.sample_format.sample_size(); }
// Obtaining a pointer to the buffer. // The loop for processing pending input data.
match stream.client_flow { fn process_input<T>(
AudioClientFlow::Capture { capture_client } => { stream: &StreamInner,
capture_client: *mut audioclient::IAudioCaptureClient,
data_callback: &mut dyn FnMut(InputData<T>),
error_callback: &mut dyn FnMut(StreamError),
) -> ControlFlow
where
T: Sample,
{
let mut frames_available = 0; let mut frames_available = 0;
unsafe {
// Get the available data in the shared buffer. // Get the available data in the shared buffer.
let mut buffer: *mut BYTE = mem::uninitialized(); let mut buffer: *mut BYTE = mem::uninitialized();
let mut flags = mem::uninitialized(); let mut flags = mem::uninitialized();
@ -301,10 +389,10 @@ fn run_inner(
let hresult = (*capture_client).GetNextPacketSize(&mut frames_available); let hresult = (*capture_client).GetNextPacketSize(&mut frames_available);
if let Err(err) = stream_error_from_hresult(hresult) { if let Err(err) = stream_error_from_hresult(hresult) {
error_callback(err); error_callback(err);
break 'stream_loop; return ControlFlow::Break;
} }
if frames_available == 0 { if frames_available == 0 {
break; return ControlFlow::Continue;
} }
let hresult = (*capture_client).GetBuffer( let hresult = (*capture_client).GetBuffer(
&mut buffer, &mut buffer,
@ -319,96 +407,74 @@ fn run_inner(
continue; continue;
} else if let Err(err) = stream_error_from_hresult(hresult) { } else if let Err(err) = stream_error_from_hresult(hresult) {
error_callback(err); error_callback(err);
break 'stream_loop; return ControlFlow::Break;
} }
debug_assert!(!buffer.is_null()); debug_assert!(!buffer.is_null());
let buffer_len = frames_available as usize let buffer_len = frames_available as usize
* stream.bytes_per_frame as usize * stream.bytes_per_frame as usize
/ sample_size; / mem::size_of::<T>();
// Simplify the capture callback sample format branches. // Simplify the capture callback sample format branches.
macro_rules! capture_callback { let buffer_data = buffer as *mut _ as *const T;
($T:ty, $Variant:ident) => {{
let buffer_data = buffer as *mut _ as *const $T;
let slice = slice::from_raw_parts(buffer_data, buffer_len); let slice = slice::from_raw_parts(buffer_data, buffer_len);
let unknown_buffer = let input_data = InputData { buffer: slice };
UnknownTypeInputBuffer::$Variant(::InputBuffer { data_callback(input_data);
buffer: slice,
});
let data = StreamData::Input {
buffer: unknown_buffer,
};
data_callback(data);
// Release the buffer. // Release the buffer.
let hresult = (*capture_client).ReleaseBuffer(frames_available); let hresult = (*capture_client).ReleaseBuffer(frames_available);
if let Err(err) = stream_error_from_hresult(hresult) { if let Err(err) = stream_error_from_hresult(hresult) {
error_callback(err); error_callback(err);
break 'stream_loop; return ControlFlow::Break;
} }
}};
} }
}
}
match stream.sample_format { // The loop for writing output data.
SampleFormat::F32 => capture_callback!(f32, F32), fn process_output<T>(
SampleFormat::I16 => capture_callback!(i16, I16), stream: &StreamInner,
SampleFormat::U16 => capture_callback!(u16, U16), render_client: *mut audioclient::IAudioRenderClient,
} data_callback: &mut dyn FnMut(OutputData<T>),
} error_callback: &mut dyn FnMut(StreamError),
} ) -> ControlFlow
where
AudioClientFlow::Render { render_client } => { T: Sample,
{
// The number of frames available for writing. // The number of frames available for writing.
let frames_available = match get_available_frames(&stream) { let frames_available = match get_available_frames(&stream) {
Ok(0) => continue, // TODO: Can this happen? Ok(0) => return ControlFlow::Continue, // TODO: Can this happen?
Ok(n) => n, Ok(n) => n,
Err(err) => { Err(err) => {
error_callback(err); error_callback(err);
break 'stream_loop; return ControlFlow::Break;
} }
}; };
unsafe {
let mut buffer: *mut BYTE = mem::uninitialized(); let mut buffer: *mut BYTE = mem::uninitialized();
let hresult = let hresult =
(*render_client).GetBuffer(frames_available, &mut buffer as *mut *mut _); (*render_client).GetBuffer(frames_available, &mut buffer as *mut *mut _);
if let Err(err) = stream_error_from_hresult(hresult) { if let Err(err) = stream_error_from_hresult(hresult) {
error_callback(err); error_callback(err);
break 'stream_loop; return ControlFlow::Break;
} }
debug_assert!(!buffer.is_null()); debug_assert!(!buffer.is_null());
let buffer_len = let buffer_len =
frames_available as usize * stream.bytes_per_frame as usize / sample_size; frames_available as usize * stream.bytes_per_frame as usize / mem::size_of::<T>();
// Simplify the render callback sample format branches. let buffer_data = buffer as *mut T;
macro_rules! render_callback {
($T:ty, $Variant:ident) => {{
let buffer_data = buffer as *mut $T;
let slice = slice::from_raw_parts_mut(buffer_data, buffer_len); let slice = slice::from_raw_parts_mut(buffer_data, buffer_len);
let unknown_buffer = let output_data = OutputData { buffer: slice };
UnknownTypeOutputBuffer::$Variant(::OutputBuffer { buffer: slice }); data_callback(output_data);
let data = StreamData::Output { let hresult = (*render_client).ReleaseBuffer(frames_available as u32, 0);
buffer: unknown_buffer,
};
data_callback(data);
let hresult =
(*render_client).ReleaseBuffer(frames_available as u32, 0);
if let Err(err) = stream_error_from_hresult(hresult) { if let Err(err) = stream_error_from_hresult(hresult) {
error_callback(err); error_callback(err);
break 'stream_loop; return ControlFlow::Break;
} }
}};
} }
match stream.sample_format { ControlFlow::Continue
SampleFormat::F32 => render_callback!(f32, F32),
SampleFormat::I16 => render_callback!(i16, I16),
SampleFormat::U16 => render_callback!(u16, U16),
}
}
}
}
}
} }