Fix WASAPI capture logic
The buffer size handling differs from what render streams uses. Logic is based on https://github.com/microsoft/Windows-universal-samples/blob/master/Samples/WindowsAudioSession/cpp/WASAPICapture.cpp.
This commit is contained in:
parent
36dee482bd
commit
e9043c605a
|
@ -502,73 +502,84 @@ impl EventLoop {
|
||||||
let stream_idx = handle_idx - 1;
|
let stream_idx = handle_idx - 1;
|
||||||
let stream = &mut run_context.streams[stream_idx];
|
let stream = &mut run_context.streams[stream_idx];
|
||||||
|
|
||||||
// The number of frames available for reading/writing.
|
|
||||||
let mut frames_available = match get_available_frames(stream) {
|
|
||||||
Ok(0) => continue, // TODO: Can this happen?
|
|
||||||
Ok(n) => n,
|
|
||||||
Err(err) => {
|
|
||||||
streams_to_remove.push((stream.id.clone(), err));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let sample_size = stream.sample_format.sample_size();
|
let sample_size = stream.sample_format.sample_size();
|
||||||
|
|
||||||
// Obtaining a pointer to the buffer.
|
// Obtaining a pointer to the buffer.
|
||||||
match stream.client_flow {
|
match stream.client_flow {
|
||||||
|
|
||||||
AudioClientFlow::Capture { capture_client } => {
|
AudioClientFlow::Capture { capture_client } => {
|
||||||
|
let mut frames_available = 0;
|
||||||
// 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();
|
||||||
let hresult = (*capture_client).GetBuffer(
|
loop {
|
||||||
&mut buffer,
|
let hresult = (*capture_client).GetNextPacketSize(&mut frames_available);
|
||||||
&mut frames_available,
|
if let Err(err) = stream_error_from_hresult(hresult) {
|
||||||
&mut flags,
|
streams_to_remove.push((stream.id.clone(), err));
|
||||||
ptr::null_mut(),
|
break; // Identical to continuing the outer loop
|
||||||
ptr::null_mut(),
|
}
|
||||||
);
|
if frames_available == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let hresult = (*capture_client).GetBuffer(
|
||||||
|
&mut buffer,
|
||||||
|
&mut frames_available,
|
||||||
|
&mut flags,
|
||||||
|
ptr::null_mut(),
|
||||||
|
ptr::null_mut(),
|
||||||
|
);
|
||||||
|
|
||||||
// TODO: Can this happen?
|
// TODO: Can this happen?
|
||||||
if hresult == AUDCLNT_S_BUFFER_EMPTY {
|
if hresult == AUDCLNT_S_BUFFER_EMPTY {
|
||||||
continue;
|
continue;
|
||||||
} else if let Err(err) = stream_error_from_hresult(hresult) {
|
} else if let Err(err) = stream_error_from_hresult(hresult) {
|
||||||
streams_to_remove.push((stream.id.clone(), err));
|
streams_to_remove.push((stream.id.clone(), err));
|
||||||
continue;
|
break; // Identical to continuing the outer loop
|
||||||
}
|
}
|
||||||
|
|
||||||
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 / sample_size;
|
* stream.bytes_per_frame as usize / sample_size;
|
||||||
|
|
||||||
// Simplify the capture callback sample format branches.
|
// Simplify the capture callback sample format branches.
|
||||||
macro_rules! capture_callback {
|
macro_rules! capture_callback {
|
||||||
($T:ty, $Variant:ident) => {{
|
($T:ty, $Variant:ident) => {{
|
||||||
let buffer_data = buffer as *mut _ as *const $T;
|
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 = UnknownTypeInputBuffer::$Variant(::InputBuffer {
|
let unknown_buffer = UnknownTypeInputBuffer::$Variant(::InputBuffer {
|
||||||
buffer: slice,
|
buffer: slice,
|
||||||
});
|
});
|
||||||
let data = StreamData::Input { buffer: unknown_buffer };
|
let data = StreamData::Input { buffer: unknown_buffer };
|
||||||
callback(stream.id.clone(), Ok(data));
|
callback(stream.id.clone(), Ok(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) {
|
||||||
streams_to_remove.push((stream.id.clone(), err));
|
streams_to_remove.push((stream.id.clone(), err));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
match stream.sample_format {
|
match stream.sample_format {
|
||||||
SampleFormat::F32 => capture_callback!(f32, F32),
|
SampleFormat::F32 => capture_callback!(f32, F32),
|
||||||
SampleFormat::I16 => capture_callback!(i16, I16),
|
SampleFormat::I16 => capture_callback!(i16, I16),
|
||||||
SampleFormat::U16 => capture_callback!(u16, U16),
|
SampleFormat::U16 => capture_callback!(u16, U16),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
AudioClientFlow::Render { render_client } => {
|
AudioClientFlow::Render { render_client } => {
|
||||||
|
// The number of frames available for writing.
|
||||||
|
let frames_available = match get_available_frames(stream) {
|
||||||
|
Ok(0) => continue, // TODO: Can this happen?
|
||||||
|
Ok(n) => n,
|
||||||
|
Err(err) => {
|
||||||
|
streams_to_remove.push((stream.id.clone(), err));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut buffer: *mut BYTE = mem::uninitialized();
|
let mut buffer: *mut BYTE = mem::uninitialized();
|
||||||
let hresult = (*render_client).GetBuffer(
|
let hresult = (*render_client).GetBuffer(
|
||||||
frames_available,
|
frames_available,
|
||||||
|
|
Loading…
Reference in New Issue