Adds functions to turn on audio monitoring to allow the user to hear playback of an audio source over the user's speaker. It can be set to turn off monitoring and only output to stream, or it can be set to output only to monitoring, or it can be set to both. On windows, audio monitoring uses WASAPI. Windows also is capable of syncing the audio to the video according to when the video frame itself was played. On mac, it uses AudioQueue. On linux, it's not currently implemented and won't do anything (to be implemented).
106 lines
2.1 KiB
C
106 lines
2.1 KiB
C
#include "../../obs-internal.h"
|
|
|
|
#include "wasapi-output.h"
|
|
|
|
#include <propsys.h>
|
|
|
|
#ifdef __MINGW32__
|
|
|
|
#ifdef DEFINE_PROPERTYKEY
|
|
#undef DEFINE_PROPERTYKEY
|
|
#endif
|
|
#define DEFINE_PROPERTYKEY(id, a, b, c, d, e, f, g, h, i, j, k, l) \
|
|
const PROPERTYKEY id = { { a,b,c, { d,e,f,g,h,i,j,k, } }, l };
|
|
DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, \
|
|
0xa45c254e, 0xdf1c, 0x4efd, 0x80, \
|
|
0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14);
|
|
|
|
#else
|
|
|
|
#include <functiondiscoverykeys_devpkey.h>
|
|
|
|
#endif
|
|
|
|
static bool get_device_info(obs_enum_audio_device_cb cb, void *data,
|
|
IMMDeviceCollection *collection, UINT idx)
|
|
{
|
|
IPropertyStore *store = NULL;
|
|
IMMDevice *device = NULL;
|
|
PROPVARIANT name_var;
|
|
char utf8_name[512];
|
|
WCHAR *w_id = NULL;
|
|
char utf8_id[512];
|
|
bool cont = true;
|
|
HRESULT hr;
|
|
|
|
hr = collection->lpVtbl->Item(collection, idx, &device);
|
|
if (FAILED(hr)) {
|
|
goto fail;
|
|
}
|
|
|
|
hr = device->lpVtbl->GetId(device, &w_id);
|
|
if (FAILED(hr)) {
|
|
goto fail;
|
|
}
|
|
|
|
hr = device->lpVtbl->OpenPropertyStore(device, STGM_READ, &store);
|
|
if (FAILED(hr)) {
|
|
goto fail;
|
|
}
|
|
|
|
PropVariantInit(&name_var);
|
|
hr = store->lpVtbl->GetValue(store, &PKEY_Device_FriendlyName,
|
|
&name_var);
|
|
if (FAILED(hr)) {
|
|
goto fail;
|
|
}
|
|
|
|
os_wcs_to_utf8(w_id, 0, utf8_id, 512);
|
|
os_wcs_to_utf8(name_var.pwszVal, 0, utf8_name, 512);
|
|
|
|
cont = cb(data, utf8_name, utf8_id);
|
|
|
|
fail:
|
|
safe_release(store);
|
|
safe_release(device);
|
|
if (w_id)
|
|
CoTaskMemFree(w_id);
|
|
return cont;
|
|
}
|
|
|
|
void obs_enum_audio_monitoring_devices(obs_enum_audio_device_cb cb,
|
|
void *data)
|
|
{
|
|
IMMDeviceEnumerator *enumerator = NULL;
|
|
IMMDeviceCollection *collection = NULL;
|
|
UINT count;
|
|
HRESULT hr;
|
|
|
|
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
|
|
&IID_IMMDeviceEnumerator, &enumerator);
|
|
if (FAILED(hr)) {
|
|
goto fail;
|
|
}
|
|
|
|
hr = enumerator->lpVtbl->EnumAudioEndpoints(enumerator, eRender,
|
|
DEVICE_STATE_ACTIVE, &collection);
|
|
if (FAILED(hr)) {
|
|
goto fail;
|
|
}
|
|
|
|
hr = collection->lpVtbl->GetCount(collection, &count);
|
|
if (FAILED(hr)) {
|
|
goto fail;
|
|
}
|
|
|
|
for (UINT i = 0; i < count; i++) {
|
|
if (!get_device_info(cb, data, collection, i)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
fail:
|
|
safe_release(enumerator);
|
|
safe_release(collection);
|
|
}
|