Implement WASAPI loopback support

This works by detecting output devices in build_input_stream() and
setting the AUDCLNT_STREAMFLAGS_LOOPBACK flag to enable loopback
recording.

closes #251
This commit is contained in:
lucy 2019-10-12 19:02:54 +02:00
parent be54ffff09
commit dcabad105b
3 changed files with 14 additions and 3 deletions

View File

@ -552,7 +552,7 @@ impl Device {
} }
} }
fn data_flow(&self) -> EDataFlow { pub(crate) fn data_flow(&self) -> EDataFlow {
let endpoint = Endpoint::from(self.device as *const _); let endpoint = Endpoint::from(self.device as *const _);
endpoint.data_flow() endpoint.data_flow()
} }

View File

@ -21,6 +21,10 @@ mod device;
mod stream; mod stream;
/// The WASAPI host, the default windows host type. /// The WASAPI host, the default windows host type.
///
/// Note: If you use a WASAPI output device as an input device it will
/// transparently enable loopback mode (see
/// https://docs.microsoft.com/en-us/windows/win32/coreaudio/loopback-recording).
#[derive(Debug)] #[derive(Debug)]
pub struct Host; pub struct Host;

View File

@ -6,7 +6,8 @@ use super::winapi::shared::ksmedia;
use super::winapi::shared::minwindef::{BYTE, DWORD, FALSE, WORD}; use super::winapi::shared::minwindef::{BYTE, DWORD, FALSE, WORD};
use super::winapi::shared::mmreg; use super::winapi::shared::mmreg;
use super::winapi::um::audioclient::{self, AUDCLNT_E_DEVICE_INVALIDATED, AUDCLNT_S_BUFFER_EMPTY}; use super::winapi::um::audioclient::{self, AUDCLNT_E_DEVICE_INVALIDATED, AUDCLNT_S_BUFFER_EMPTY};
use super::winapi::um::audiosessiontypes::{AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK}; use super::winapi::um::audiosessiontypes::{AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, AUDCLNT_STREAMFLAGS_LOOPBACK};
use super::winapi::um::mmdeviceapi::eRender;
use super::winapi::um::handleapi; use super::winapi::um::handleapi;
use super::winapi::um::synchapi; use super::winapi::um::synchapi;
use super::winapi::um::winbase; use super::winapi::um::winbase;
@ -151,10 +152,16 @@ impl EventLoop {
_ => (), _ => (),
} }
// Support capturing output devices.
let mut stream_flags: DWORD = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
if device.data_flow() == eRender {
stream_flags |= AUDCLNT_STREAMFLAGS_LOOPBACK;
}
// finally initializing the audio client // finally initializing the audio client
let hresult = (*audio_client).Initialize( let hresult = (*audio_client).Initialize(
share_mode, share_mode,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK, stream_flags,
0, 0,
0, 0,
&format_attempt.Format, &format_attempt.Format,