Skip to content
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

change from COINIT_MULTITHREADED to COINIT_APARTMENTTHREADED in wasapi #504

Closed
wants to merge 1 commit into from

Conversation

JoshuaBatty
Copy link
Contributor

There is currently a problem in windows when trying to use cpal with winit 0.20.

Winit now uses COINIT_APARTMENTTHREADED because it is required by the OLE API they are using to properly handle file dropping. See this link for more information

@bolcom ran into this problem and submitted PR #330 to address this but it was never merged, and instead decided to spin up a whole separate thread for using winit. I also noted that @ishitatsuyuki was concerned that moving to apartment threading would require marshaling. I don't really understand what this means, would be nice to hear further clarification as to what this would actually involve.

It would be nice if cpal and winit could share the same threading model so users on windows didn't have to spin up separate threads. Keen to hear poeples thoughts.

@ishitatsuyuki
Copy link
Collaborator

See #348; I still have the same stance and I'm skeptical to the changes, as the Windows documentation on threading is very confusing and no one had the expertise to prove that changing the thread model would be safe under our Send/Sync implementations.

@JoshuaBatty
Copy link
Contributor Author

Just read through #348 again. Can you suggest any small actionable steps that can be taken in order to progress this then?

@ishitatsuyuki
Copy link
Collaborator

I don't know if you use drag and drop, but if you don't, then winit has already merged a PR allowing cpal to winit to co-exist if you initialize winit first: rust-windowing/winit#1524

Otherwise, I'm sorry but I don't think the situation would change unless someone can "prove" apartment threading is safe. Well, I don't know, if there's constant complaints that this need to change, then I might try the less safe way and see if it breaks in public use cases, but since winit has the compatibility code for now, I doubt that it's worth introducing some potential unsafety.

@dheijl
Copy link
Contributor

dheijl commented Dec 10, 2020

I don't know if you use drag and drop, but if you don't, then winit has already merged a PR allowing cpal to winit to co-exist if you initialize winit first: rust-windowing/winit#1524

Otherwise, I'm sorry but I don't think the situation would change unless someone can "prove" apartment threading is safe. Well, I don't know, if there's constant complaints that this need to change, then I might try the less safe way and see if it breaks in public use cases, but since winit has the compatibility code for now, I doubt that it's worth introducing some potential unsafety.

According to this link CoInitialzeEx has to be called once per thread, so I think it is up to the application to make sure that it doesn't use incompatible COM libraries in the same thread. Winit obviously has to live in the main (GUI) thread, but cpal (WasApi) should be able to initialized in another thread than the main thread and use COINIT_MULTITHREADED so that after that cpal calls can be called from whatever thread you like.
Perhaps documenting this is enough as a solution?

ishitatsuyuki added a commit to ishitatsuyuki/cpal that referenced this pull request Aug 6, 2021
COM can prevent undefined behavior in either concurrency model by
performing marshaling when necessary. As a result, CoInitializeEx can be
called with either concurrency model, and in this case STA provides better
compatibility with other code requiring STA, e.g. ASIO backend or winit
drag-and-drop.

To dive into the detail, the entry point of WASAPI, MMDeviceEnumerator, is
registered with "both" threading model, which means that COM objects are
created with whatever the thread's concurrency model is set to. This raises
the concern that when STA is used, marshaling might make audio buffer
operations block on the main thread, breaking continuous audio processing.
However, the implementation actually uses free-threaded marshaller for
interfaces dealing with buffer operations, which effectively bypasses COM's
compatibility marshaling behavior and perform any API calls on the caller's
thread instead. Therefore, the interfaces would operate just fine on either
concurrency model.

For more details on COM's threading model, see [1].

[1] https://thrysoee.dk/InsideCOM+/ch04d.htm

Co-Authored-By: Henrik Rydgård <hrydgard@gmail.com>

Close RustAudio#348
Close RustAudio#504
Close RustAudio#538
ishitatsuyuki added a commit to ishitatsuyuki/cpal that referenced this pull request Aug 6, 2021
COM can prevent undefined behavior in either concurrency model by
performing marshaling when necessary. As a result, CoInitializeEx can be
called with either concurrency model, and in this case STA provides better
compatibility with other code requiring STA, e.g. ASIO backend or winit
drag-and-drop.

To dive into the detail, the entry point of WASAPI, MMDeviceEnumerator, is
registered with "both" threading model, which means that COM objects are
created with whatever the thread's concurrency model is set to. This raises
the concern that when STA is used, marshaling might make audio buffer
operations block on the main thread, breaking continuous audio processing.
However, the implementation actually uses free-threaded marshaller for
interfaces dealing with buffer operations, which effectively bypasses COM's
compatibility marshaling behavior and perform any API calls on the caller's
thread instead. Therefore, the interfaces would operate just fine on either
concurrency model.

For more details on COM's threading model, see [1].

[1] https://thrysoee.dk/InsideCOM+/ch04d.htm

Co-Authored-By: Henrik Rydgård <hrydgard@gmail.com>

Close RustAudio#348
Close RustAudio#504
Close RustAudio#538
ishitatsuyuki added a commit to ishitatsuyuki/cpal that referenced this pull request Aug 6, 2021
COM can prevent undefined behavior in either concurrency model by
performing marshaling when necessary. As a result, CoInitializeEx can be
called with either concurrency model, and in this case STA provides better
compatibility with other code requiring STA, e.g. ASIO backend or winit
drag-and-drop.

To dive into the detail, the entry point of WASAPI, MMDeviceEnumerator, is
registered with "both" threading model, which means that COM objects are
created with whatever the thread's concurrency model is set to. This raises
the concern that when STA is used, marshaling might make audio buffer
operations block on the main thread, breaking continuous audio processing.
However, the implementation actually uses free-threaded marshaller for
interfaces dealing with buffer operations, which effectively bypasses COM's
compatibility marshaling behavior and perform any API calls on the caller's
thread instead. Therefore, the interfaces would operate just fine on either
concurrency model.

For more details on COM's threading model, see [1].

[1] https://thrysoee.dk/InsideCOM+/ch04d.htm

Co-Authored-By: Henrik Rydgård <hrydgard@gmail.com>

Close RustAudio#348
Close RustAudio#504
Close RustAudio#538
ishitatsuyuki added a commit to ishitatsuyuki/cpal that referenced this pull request Aug 8, 2021
COM can prevent undefined behavior in either concurrency model by
performing marshaling when necessary. As a result, CoInitializeEx can be
called with either concurrency model, and in this case STA provides better
compatibility with other code requiring STA, e.g. ASIO backend or winit
drag-and-drop.

To dive into the detail, the entry point of WASAPI, MMDeviceEnumerator, is
registered with "both" threading model, which means that COM objects are
created with whatever the thread's concurrency model is set to. This raises
the concern that when STA is used, marshaling might make audio buffer
operations block on the main thread, breaking continuous audio processing.
However, the implementation actually uses free-threaded marshaller for
interfaces dealing with buffer operations, which effectively bypasses COM's
compatibility marshaling behavior and perform any API calls on the caller's
thread instead. Therefore, the interfaces would operate just fine on either
concurrency model.

For more details on COM's threading model, see [1].

[1] https://thrysoee.dk/InsideCOM+/ch04d.htm

Co-Authored-By: Henrik Rydgård <hrydgard@gmail.com>

Close RustAudio#59
Close RustAudio#348
Close RustAudio#504
Close RustAudio#530
Close RustAudio#538
Close RustAudio#572
@est31 est31 closed this in #597 Aug 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants