()
| 630 | |
| 631 | #[cfg(windows)] |
| 632 | unsafe fn wasapi_audio_thread() { |
| 633 | use windows::Win32::Media::Audio::*; |
| 634 | use windows::Win32::System::Com::*; |
| 635 | use windows::core::*; |
| 636 | use std::sync::atomic::Ordering; |
| 637 | |
| 638 | // Initialize COM on this thread |
| 639 | let _ = CoInitializeEx(None, COINIT_MULTITHREADED); |
| 640 | |
| 641 | // Create device enumerator and get default output device |
| 642 | let enumerator: IMMDeviceEnumerator = match CoCreateInstance( |
| 643 | &MMDeviceEnumerator, |
| 644 | None, |
| 645 | CLSCTX_ALL, |
| 646 | ) { |
| 647 | Ok(e) => e, |
| 648 | Err(_) => return, |
| 649 | }; |
| 650 | |
| 651 | let device = match enumerator.GetDefaultAudioEndpoint(eRender, eConsole) { |
| 652 | Ok(d) => d, |
| 653 | Err(_) => return, |
| 654 | }; |
| 655 | |
| 656 | let audio_client: IAudioClient = match device.Activate(CLSCTX_ALL, None) { |
| 657 | Ok(c) => c, |
| 658 | Err(_) => return, |
| 659 | }; |
| 660 | |
| 661 | // Get mix format |
| 662 | let mix_format_ptr = match audio_client.GetMixFormat() { |
| 663 | Ok(f) => f, |
| 664 | Err(_) => return, |
| 665 | }; |
| 666 | let mix_format = &*mix_format_ptr; |
| 667 | let sample_rate = mix_format.nSamplesPerSec; |
| 668 | let channels = mix_format.nChannels as usize; |
| 669 | |
| 670 | // Initialize in shared mode with 20ms buffer |
| 671 | let buffer_duration = 200_000; // 20ms in 100-nanosecond units |
| 672 | if audio_client.Initialize( |
| 673 | AUDCLNT_SHAREMODE_SHARED, |
| 674 | 0, |
| 675 | buffer_duration, |
| 676 | 0, |
| 677 | mix_format_ptr, |
| 678 | None, |
| 679 | ).is_err() { |
| 680 | return; |
| 681 | } |
| 682 | |
| 683 | let buffer_size = match audio_client.GetBufferSize() { |
| 684 | Ok(s) => s as usize, |
| 685 | Err(_) => return, |
| 686 | }; |
| 687 | |
| 688 | let render_client: IAudioRenderClient = match audio_client.GetService() { |
| 689 | Ok(r) => r, |
no test coverage detected