No way to create a non-interleaved non-blocking stream
As far as I can see (although I may have missed something); there's no way to create a non-interleaved non-blocking stream with safe code (i.e. not transmute()ing the callback arg to &mut [&mut [f32]]). Am I correct here, and what could be done to resolve this problem?
I will add that providing data in interleaved form, in my use case, requires significant extra processing in the audio thread to do (loop through non-interleaved buffers, which must be preallocated & write to interleaved buffer).
Workaround, for anyone else (warning: untested, probably very unsafe):
const CHANNELS: usize = 2;
let callback = move |pa::stream::OutputCallbackArgs { buffer, frames, .. }| {
let buffr: &mut [*mut f32];
unsafe {
let buffer: *mut *mut f32 = ::std::mem::transmute(buffer.get_unchecked_mut(0));
buffr = ::std::slice::from_raw_parts_mut(buffer, CHANNELS);
let first_channel_buffer = ::std::slice::from_raw_parts_mut(buffr[0], frames);
let second_channel_buffer = ::std::slice::from_raw_parts_mut(buffr[1], frames);
}
pa::Continue
};
You're right, support for writing to non-interleaved buffers hasn't yet been added, though it would be a welcome addition!
Currently StreamParameters takes an is_interleaved bool at runtime (which is unhandled at the callback end as you've discovered). It would be nicer to have this moved to the type level so that the user receives errors about mis-use at compile time instead of runtime. I've been meaning to add something along the lines of a Buffer trait but haven't had time.
pub<S> trait Buffer<S> {
fn is_interleaved() -> bool;
// Other buffer handling methods.
}
impl<'a, S> Buffer<S> for [&'a [S]] {
fn is_interleaved() -> bool {
false
}
...
}
impl<S> Buffer<S> for [S] {
fn is_interleaved() -> bool {
true
}
...
}
Something like this might allow the compiler to infer whether or not the buffer is interleaved by examining the buffer type used in the callback args at compile time. This way we might be able to get away with removing the need for a is_interleaved bool param altogether.