kritzikratzi / Oscilloscope

Oscilloscope for Mac/Windows written in OF.
https://oscilloscopemusic.com/osci.php
MIT License
577 stars 47 forks source link

Allow capturing Loopback Audio on Windows #64

Closed s-ol closed 4 years ago

s-ol commented 5 years ago

Loopback Audio Recording is a feature that (I think?) everyone wants. Platform support is notoriously tricky and usually involves shady shareware or paid solutions on Mac and Windows.

On Linux it is usually not a problem, PulseAudio loopback streams are available by default and JACK makes it a non-problem entirely.

On OS X it seems like there (unfortunately) is really no way without a mock audio device and therefore a kernel extension, which is something out of scope for my personal contribution (and I suspect @kritzikratzi's project ambitions).

However on Windows there is native WASAPI support for loopback audio recording and it seems rather trivial to imlement!

from https://docs.microsoft.com/en-us/windows/win32/coreaudio/loopback-recording:

In loopback mode, a client of WASAPI can capture the audio stream that is being played by a rendering endpoint device. To open a stream in loopback mode, the client must:

  • Obtain an IMMDevice interface for the rendering endpoint device.
  • Initialize a capture stream in loopback mode on the rendering endpoint device. After following these steps, the client can call the IAudioClient::GetService method to obtain an IAudioCaptureClient interface on the rendering endpoint device.

WASAPI provides loopback mode primarily to support acoustic echo cancellation (AEC). However, other types of audio applications might find loopback mode useful for capturing the system mix that is being played by the audio engine.

In the code example in Capturing a Stream, the RecordAudioStream function can be easily modified to configure a loopback-mode capture stream. The required modifications are:

  • In the call to the IMMDeviceEnumerator::GetDefaultAudioEndpoint method, change the first parameter (dataFlow) from eCapture to eRender.
  • In the call to the IAudioClient::Initialize method, change the value of the second parameter (StreamFlags) from 0 to AUDCLNT_STREAMFLAGS_LOOPBACK.

(basically all that is necessary is to look for output devices instead of input devices when enumerating, and then to pass one extra flag when opening the stream - simple enough in theory 😛)

this could possibly be added as a modification to dr-soft/miniaudio that simply gives access to all output sources in the input selection as well (with a "Loopback: " name prefix or similar).

kritzikratzi commented 5 years ago

hey!

i have not looked at the diff yet, but this would be crazy good!

on osx i use either my external interface or soundflower

kritzikratzi commented 5 years ago

ps. yes, it should definitely be an addition to miniaudio itself

s-ol commented 5 years ago

just tested this with of10 on windows, much smoother to build and worked out of the box (on x64 only, since theres no precompiled libsamplerate x32) :) not sure about the ma_device_uninit hang you mentioned in the miniaudio thread, i couldn't reproduce it by just turning of the mic, but whatever 😛

kritzikratzi commented 5 years ago

no more support for 32 bits. i'm dropping it from all my projects.

the uninit hang might be a bit hardware dependent. i could only get it if no app was connected to the system mixer at all. anyways, now it's all good.

leaving this open until miniaudio-dev is merged into master, but i think this can be considered done.

thanks a lot for the initial implementation!