-
Notifications
You must be signed in to change notification settings - Fork 537
Second round of correctness fixes on multiple backends #1335
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
fe994b3
c7c01e9
d043bab
200a8fb
18ba753
4fcca1b
6e4804e
af9a76c
1744ff6
7c41c1b
854312c
e003306
c8c6e53
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -223,8 +223,9 @@ impl Device { | |
| } | ||
| last_buffer_index = callback_info.buffer_index; | ||
|
|
||
| // There is 0% chance of lock contention the host only locks when recreating streams. | ||
| let stream_lock = asio_streams.lock().unwrap(); | ||
| let Ok(stream_lock) = asio_streams.lock() else { | ||
| return; | ||
| }; | ||
|
Comment on lines
225
to
+228
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The commit message says "do not block", but
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, I should have written "do not panic". |
||
| let asio_stream = match stream_lock.input { | ||
| Some(ref asio_stream) => asio_stream, | ||
| None => return, | ||
|
|
@@ -448,6 +449,8 @@ impl Device { | |
| let driver = Arc::new(driver); | ||
| let asio_streams = driver.streams(); | ||
|
|
||
| prefill_output_silence(&driver, &asio_streams); | ||
|
|
||
| if let Err(e) = driver.start() { | ||
| driver.remove_event_callback(driver_event_callback_id); | ||
| driver.remove_callback(callback_id); | ||
|
|
@@ -577,8 +580,9 @@ impl Device { | |
| } | ||
| last_buffer_index = callback_info.buffer_index; | ||
|
|
||
| // There is 0% chance of lock contention the host only locks when recreating streams. | ||
| let mut stream_lock = asio_streams.lock().unwrap(); | ||
| let Ok(mut stream_lock) = asio_streams.lock() else { | ||
| return; | ||
| }; | ||
| let asio_stream = match stream_lock.output { | ||
| Some(ref mut asio_stream) => asio_stream, | ||
| None => return, | ||
|
|
@@ -854,6 +858,8 @@ impl Device { | |
| let driver = Arc::new(driver); | ||
| let asio_streams = driver.streams(); | ||
|
|
||
| prefill_output_silence(&driver, &asio_streams); | ||
|
|
||
| if let Err(e) = driver.start() { | ||
| driver.remove_event_callback(driver_event_callback_id); | ||
| driver.remove_callback(callback_id); | ||
|
|
@@ -1273,6 +1279,27 @@ unsafe fn asio_channel_slice_mut<T>( | |
| unsafe { std::slice::from_raw_parts_mut(buff_ptr, channel_length) } | ||
| } | ||
|
|
||
| // ASIOStart() plays buffer half 1 immediately, before the first bufferSwitch can fill it; | ||
| // half 0 is covered by that first callback. | ||
| fn prefill_output_silence(driver: &sys::Driver, asio_streams: &Mutex<sys::AsioStreams>) { | ||
|
Comment on lines
+1282
to
+1284
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this use the data callback instead of generating silence? Also I think this isn't actually necessary at all: ASIO 2.3 specification, secion II.5:
To me this clearly states that pre-filling is the driver's responsibility, not the host's. In fact, if the initial callback invocations happen within
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What I based it on is https://github.com/dechamps/ASIOUtil/blob/master/BUFFERS.md which also states this and then goes on with two more pieces of the spec and conludes that:
It does not seem filled via Is this synthesis incorrect? I thought that this source was pretty authoritative but it'd be great if you could verify.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is an awesome resource, and I have a thing or two to say about it (will create an issue there). But it doesn't actually seem to contain the conclusion you quoted, Ctrl + F "it is not filled" yields 0 results. Is this paraphrased? My interpretation is still that the driver should invoke the callback right after buffer creation to populate the buffers, but it is indeed a bit ambiguous
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed the quote for what was my deduction.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I left a thorough comment there, I recommend you read it too. Bottom like is that the spec contradicts itself, but it can be somewhat shoehorned into what I said earlier |
||
| if let Ok(mut streams) = asio_streams.lock() { | ||
| if let Some(ref mut output) = streams.output { | ||
| if let Some(sample_format) = driver | ||
| .output_data_type() | ||
| .ok() | ||
| .and_then(|ty| super::device::convert_data_type(&ty)) | ||
| { | ||
| let byte_len = output.buffer_size as usize * sample_format.sample_size(); | ||
| for ch_ix in 0..output.buffer_infos.len() { | ||
| let channel = | ||
| unsafe { asio_channel_slice_mut::<u8>(output, 1, ch_ix, Some(byte_len)) }; | ||
| fill_equilibrium(channel, sample_format); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| fn load_driver_err(e: sys::LoadDriverError) -> Error { | ||
| match e { | ||
| sys::LoadDriverError::LoadDriverFailed | sys::LoadDriverError::DriverAlreadyExists => { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have a source for the claim that this was incorrect? I can't find anything that forbids WASAPI devices from using these formats
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't, the MSDN docs are woefully quiet about what's supported and what's not. I believe that 64-bit isn't a thing in WASAPI at all. As proof of the contrary I've not found any implementations of it either. Could you test on a Windows box?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Scratch that, I just realized that we're specifically talking about formats supported by
AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM, not by the device itself. Your commit is correct,i64andf64are not supported (IAudioClient::Initialize()returnsE_INVALIDARG). See also #1343