Fix WASAPI implementation when building in C++ mode.

This commit is contained in:
Raphaël Londeix 2015-12-07 03:31:14 +01:00
parent 699b00c427
commit 45cd6a7af2

View file

@ -5,11 +5,94 @@
* See http://opensource.org/licenses/MIT * See http://opensource.org/licenses/MIT
*/ */
#define INITGUID
#define CINTERFACE
#define COBJMACROS
#define CONST_VTABLE
#include <initguid.h>
#include <audioclient.h>
#include <endpointvolume.h>
#include <mmdeviceapi.h>
#include <mmreg.h>
#include <functiondiscoverykeys_devpkey.h>
#include "wasapi.h" #include "wasapi.h"
#include "soundio_private.h" #include "soundio_private.h"
#include <stdio.h> #include <stdio.h>
#ifdef __cplusplus
// In C++ mode, IsEqualGUID() takes its arguments by reference
#define IS_EQUAL_GUID(a, b) IsEqualGUID(*(a), *(b))
#define IS_EQUAL_IID(a, b) IsEqualIID((a), *(b))
// And some constants are passed by reference
#define IID_IAUDIOCLIENT (IID_IAudioClient)
#define IID_IMMENDPOINT (IID_IMMEndpoint)
#define IID_IAUDIOCLOCKADJUSTMENT (IID_IAudioClockAdjustment)
#define IID_IAUDIOSESSIONCONTROL (IID_IAudioSessionControl)
#define IID_IAUDIORENDERCLIENT (IID_IAudioRenderClient)
#define IID_IMMDEVICEENUMERATOR (IID_IMMDeviceEnumerator)
#define IID_IAUDIOCAPTURECLIENT (IID_IAudioCaptureClient)
#define CLSID_MMDEVICEENUMERATOR (CLSID_MMDeviceEnumerator)
#define PKEY_DEVICE_FRIENDLYNAME (PKEY_Device_FriendlyName)
#define PKEY_AUDIOENGINE_DEVICEFORMAT (PKEY_AudioEngine_DeviceFormat)
// And some GUID are never implemented (Ignoring the INITGUID define)
static const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
static const IID IID_IMMDeviceEnumerator = {
//MIDL_INTERFACE("A95664D2-9614-4F35-A746-DE8DB63617E6")
0xa95664d2, 0x9614, 0x4f35, {0xa7, 0x46, 0xde, 0x8d, 0xb6, 0x36, 0x17, 0xe6}
};
static const IID IID_IMMNotificationClient = {
//MIDL_INTERFACE("7991EEC9-7E89-4D85-8390-6C703CEC60C0")
0x7991eec9, 0x7e89, 0x4d85, {0x83, 0x90, 0x6c, 0x70, 0x3c, 0xec, 0x60, 0xc0}
};
static const IID IID_IAudioClient = {
//MIDL_INTERFACE("1CB9AD4C-DBFA-4c32-B178-C2F568A703B2")
0x1cb9ad4c, 0xdbfa, 0x4c32, {0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2}
};
static const IID IID_IAudioRenderClient = {
//MIDL_INTERFACE("F294ACFC-3146-4483-A7BF-ADDCA7C260E2")
0xf294acfc, 0x3146, 0x4483, {0xa7, 0xbf, 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2}
};
static const IID IID_IAudioSessionControl = {
//MIDL_INTERFACE("F4B1A599-7266-4319-A8CA-E70ACB11E8CD")
0xf4b1a599, 0x7266, 0x4319, {0xa8, 0xca, 0xe7, 0x0a, 0xcb, 0x11, 0xe8, 0xcd}
};
static const IID IID_IAudioSessionEvents = {
//MIDL_INTERFACE("24918ACC-64B3-37C1-8CA9-74A66E9957A8")
0x24918acc, 0x64b3, 0x37c1, {0x8c, 0xa9, 0x74, 0xa6, 0x6e, 0x99, 0x57, 0xa8}
};
static const IID IID_IMMEndpoint = {
//MIDL_INTERFACE("1BE09788-6894-4089-8586-9A2A6C265AC5")
0x1be09788, 0x6894, 0x4089, {0x85, 0x86, 0x9a, 0x2a, 0x6c, 0x26, 0x5a, 0xc5}
};
static const IID IID_IAudioClockAdjustment = {
//MIDL_INTERFACE("f6e4c0a0-46d9-4fb8-be21-57a3ef2b626c")
0xf6e4c0a0, 0x46d9, 0x4fb8, {0xbe, 0x21, 0x57, 0xa3, 0xef, 0x2b, 0x62, 0x6c}
};
static const IID IID_IAudioCaptureClient = {
//MIDL_INTERFACE("C8ADBD64-E71E-48a0-A4DE-185C395CD317")
0xc8adbd64, 0xe71e, 0x48a0, {0xa4, 0xde, 0x18, 0x5c, 0x39, 0x5c, 0xd3, 0x17}
};
#else
#define IS_EQUAL_GUID(a, b) IsEqualGUID((a), (b))
#define IS_EQUAL_IID(a, b) IsEqualIID((a), (b))
#define IID_IAUDIOCLIENT (&IID_IAudioClient)
#define IID_IMMENDPOINT (&IID_IMMEndpoint)
#define PKEY_DEVICE_FRIENDLYNAME (&PKEY_Device_FriendlyName)
#define PKEY_AUDIOENGINE_DEVICEFORMAT (&PKEY_AudioEngine_DeviceFormat)
#define CLSID_MMDEVICEENUMERATOR (&CLSID_MMDeviceEnumerator)
#define IID_IAUDIOCLOCKADJUSTMENT (&IID_IAudioClockAdjustment)
#define IID_IAUDIOSESSIONCONTROL (&IID_IAudioSessionControl)
#define IID_IAUDIORENDERCLIENT (&IID_IAudioRenderClient)
#define IID_IMMDEVICEENUMERATOR (&IID_IMMDeviceEnumerator)
#define IID_IAUDIOCAPTURECLIENT (&IID_IAudioCaptureClient)
#endif
// Attempting to use the Windows-supplied versions of these constants resulted // Attempting to use the Windows-supplied versions of these constants resulted
// in `undefined reference` linker errors. // in `undefined reference` linker errors.
const static GUID SOUNDIO_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { const static GUID SOUNDIO_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {
@ -204,8 +287,8 @@ static void from_wave_format_layout(WAVEFORMATEXTENSIBLE *wave_format, struct So
static enum SoundIoFormat from_wave_format_format(WAVEFORMATEXTENSIBLE *wave_format) { static enum SoundIoFormat from_wave_format_format(WAVEFORMATEXTENSIBLE *wave_format) {
assert(wave_format->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE); assert(wave_format->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE);
bool is_pcm = IsEqualGUID(&wave_format->SubFormat, &SOUNDIO_KSDATAFORMAT_SUBTYPE_PCM); bool is_pcm = IS_EQUAL_GUID(&wave_format->SubFormat, &SOUNDIO_KSDATAFORMAT_SUBTYPE_PCM);
bool is_float = IsEqualGUID(&wave_format->SubFormat, &SOUNDIO_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT); bool is_float = IS_EQUAL_GUID(&wave_format->SubFormat, &SOUNDIO_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT);
if (wave_format->Samples.wValidBitsPerSample == wave_format->Format.wBitsPerSample) { if (wave_format->Samples.wValidBitsPerSample == wave_format->Format.wBitsPerSample) {
if (wave_format->Format.wBitsPerSample == 8) { if (wave_format->Format.wBitsPerSample == 8) {
@ -352,7 +435,7 @@ static double from_reference_time(REFERENCE_TIME rt) {
} }
static REFERENCE_TIME to_reference_time(double seconds) { static REFERENCE_TIME to_reference_time(double seconds) {
return seconds * 10000000.0 + 0.5; return (REFERENCE_TIME)(seconds * 10000000.0 + 0.5);
} }
static void destruct_device(struct SoundIoDevicePrivate *dev) { static void destruct_device(struct SoundIoDevicePrivate *dev) {
@ -707,7 +790,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
IUnknown_Release(rd.audio_client); IUnknown_Release(rd.audio_client);
rd.audio_client = NULL; rd.audio_client = NULL;
} }
if (FAILED(hr = IMMDevice_Activate(rd.mm_device, &IID_IAudioClient, if (FAILED(hr = IMMDevice_Activate(rd.mm_device, IID_IAUDIOCLIENT,
CLSCTX_ALL, NULL, (void**)&rd.audio_client))) CLSCTX_ALL, NULL, (void**)&rd.audio_client)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
@ -733,7 +816,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
IMMEndpoint_Release(rd.endpoint); IMMEndpoint_Release(rd.endpoint);
rd.endpoint = NULL; rd.endpoint = NULL;
} }
if (FAILED(hr = IMMDevice_QueryInterface(rd.mm_device, &IID_IMMEndpoint, (void**)&rd.endpoint))) { if (FAILED(hr = IMMDevice_QueryInterface(rd.mm_device, IID_IMMENDPOINT, (void**)&rd.endpoint))) {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
@ -763,7 +846,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
PropVariantInit(&rd.prop_variant_value); PropVariantInit(&rd.prop_variant_value);
rd.prop_variant_value_inited = true; rd.prop_variant_value_inited = true;
if (FAILED(hr = IPropertyStore_GetValue(rd.prop_store, if (FAILED(hr = IPropertyStore_GetValue(rd.prop_store,
&PKEY_Device_FriendlyName, &rd.prop_variant_value))) PKEY_DEVICE_FRIENDLYNAME, &rd.prop_variant_value)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -793,7 +876,7 @@ static int refresh_devices(struct SoundIoPrivate *si) {
} }
PropVariantInit(&rd.prop_variant_value); PropVariantInit(&rd.prop_variant_value);
rd.prop_variant_value_inited = true; rd.prop_variant_value_inited = true;
if (FAILED(hr = IPropertyStore_GetValue(rd.prop_store, &PKEY_AudioEngine_DeviceFormat, if (FAILED(hr = IPropertyStore_GetValue(rd.prop_store, PKEY_AUDIOENGINE_DEVICEFORMAT,
&rd.prop_variant_value))) &rd.prop_variant_value)))
{ {
deinit_refresh_devices(&rd); deinit_refresh_devices(&rd);
@ -839,9 +922,9 @@ static int refresh_devices(struct SoundIoPrivate *si) {
// Let's pick some reasonable min and max values. // Let's pick some reasonable min and max values.
rd.device_shared->sample_rate_count = 1; rd.device_shared->sample_rate_count = 1;
rd.device_shared->sample_rates = &dev_shared->prealloc_sample_rate_range; rd.device_shared->sample_rates = &dev_shared->prealloc_sample_rate_range;
rd.device_shared->sample_rates[0].min = min(SOUNDIO_MIN_SAMPLE_RATE, rd.device_shared->sample_rates[0].min = soundio_int_min(SOUNDIO_MIN_SAMPLE_RATE,
rd.device_shared->sample_rate_current); rd.device_shared->sample_rate_current);
rd.device_shared->sample_rates[0].max = max(SOUNDIO_MAX_SAMPLE_RATE, rd.device_shared->sample_rates[0].max = soundio_int_max(SOUNDIO_MAX_SAMPLE_RATE,
rd.device_shared->sample_rate_current); rd.device_shared->sample_rate_current);
} else { } else {
// Shared mode input stream: mix format is all we can do. // Shared mode input stream: mix format is all we can do.
@ -935,8 +1018,8 @@ static void device_thread_run(void *arg) {
struct SoundIoWasapi *siw = &si->backend_data.wasapi; struct SoundIoWasapi *siw = &si->backend_data.wasapi;
int err; int err;
HRESULT hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, HRESULT hr = CoCreateInstance(CLSID_MMDEVICEENUMERATOR, NULL,
CLSCTX_ALL, &IID_IMMDeviceEnumerator, (void**)&siw->device_enumerator); CLSCTX_ALL, IID_IMMDEVICEENUMERATOR, (void**)&siw->device_enumerator);
if (FAILED(hr)) { if (FAILED(hr)) {
shutdown_backend(si, SoundIoErrorSystemResources); shutdown_backend(si, SoundIoErrorSystemResources);
return; return;
@ -1088,7 +1171,7 @@ static int outstream_do_open(struct SoundIoPrivate *si, struct SoundIoOutStreamP
struct SoundIoDeviceWasapi *dw = &dev->backend_data.wasapi; struct SoundIoDeviceWasapi *dw = &dev->backend_data.wasapi;
HRESULT hr; HRESULT hr;
if (FAILED(hr = IMMDevice_Activate(dw->mm_device, &IID_IAudioClient, if (FAILED(hr = IMMDevice_Activate(dw->mm_device, IID_IAUDIOCLIENT,
CLSCTX_ALL, NULL, (void**)&osw->audio_client))) CLSCTX_ALL, NULL, (void**)&osw->audio_client)))
{ {
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -1135,7 +1218,7 @@ static int outstream_do_open(struct SoundIoPrivate *si, struct SoundIoOutStreamP
} }
IUnknown_Release(osw->audio_client); IUnknown_Release(osw->audio_client);
osw->audio_client = NULL; osw->audio_client = NULL;
if (FAILED(hr = IMMDevice_Activate(dw->mm_device, &IID_IAudioClient, if (FAILED(hr = IMMDevice_Activate(dw->mm_device, IID_IAUDIOCLIENT,
CLSCTX_ALL, NULL, (void**)&osw->audio_client))) CLSCTX_ALL, NULL, (void**)&osw->audio_client)))
{ {
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -1195,7 +1278,7 @@ static int outstream_do_open(struct SoundIoPrivate *si, struct SoundIoOutStreamP
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
} else if (osw->need_resample) { } else if (osw->need_resample) {
if (FAILED(hr = IAudioClient_GetService(osw->audio_client, &IID_IAudioClockAdjustment, if (FAILED(hr = IAudioClient_GetService(osw->audio_client, IID_IAUDIOCLOCKADJUSTMENT,
(void**)&osw->audio_clock_adjustment))) (void**)&osw->audio_clock_adjustment)))
{ {
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -1208,7 +1291,7 @@ static int outstream_do_open(struct SoundIoPrivate *si, struct SoundIoOutStreamP
} }
if (outstream->name) { if (outstream->name) {
if (FAILED(hr = IAudioClient_GetService(osw->audio_client, &IID_IAudioSessionControl, if (FAILED(hr = IAudioClient_GetService(osw->audio_client, IID_IAUDIOSESSIONCONTROL,
(void **)&osw->audio_session_control))) (void **)&osw->audio_session_control)))
{ {
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -1225,7 +1308,7 @@ static int outstream_do_open(struct SoundIoPrivate *si, struct SoundIoOutStreamP
} }
} }
if (FAILED(hr = IAudioClient_GetService(osw->audio_client, &IID_IAudioRenderClient, if (FAILED(hr = IAudioClient_GetService(osw->audio_client, IID_IAUDIORENDERCLIENT,
(void **)&osw->audio_render_client))) (void **)&osw->audio_render_client)))
{ {
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -1250,7 +1333,7 @@ static void outstream_shared_run(struct SoundIoOutStreamPrivate *os) {
outstream->error_callback(outstream, SoundIoErrorStreaming); outstream->error_callback(outstream, SoundIoErrorStreaming);
return; return;
} }
int frame_count_min = max(0, (int)osw->min_padding_frames - (int)frames_used); int frame_count_min = soundio_int_max(0, (int)osw->min_padding_frames - (int)frames_used);
outstream->write_callback(outstream, frame_count_min, osw->writable_frame_count); outstream->write_callback(outstream, frame_count_min, osw->writable_frame_count);
if (FAILED(hr = IAudioClient_Start(osw->audio_client))) { if (FAILED(hr = IAudioClient_Start(osw->audio_client))) {
@ -1314,7 +1397,7 @@ static void outstream_shared_run(struct SoundIoOutStreamPrivate *os) {
if (osw->writable_frame_count > 0) { if (osw->writable_frame_count > 0) {
if (frames_used == 0 && !reset_buffer) if (frames_used == 0 && !reset_buffer)
outstream->underflow_callback(outstream); outstream->underflow_callback(outstream);
int frame_count_min = max(0, (int)osw->min_padding_frames - (int)frames_used); int frame_count_min = soundio_int_max(0, (int)osw->min_padding_frames - (int)frames_used);
outstream->write_callback(outstream, frame_count_min, osw->writable_frame_count); outstream->write_callback(outstream, frame_count_min, osw->writable_frame_count);
} }
} }
@ -1609,7 +1692,7 @@ static int instream_do_open(struct SoundIoPrivate *si, struct SoundIoInStreamPri
struct SoundIoDeviceWasapi *dw = &dev->backend_data.wasapi; struct SoundIoDeviceWasapi *dw = &dev->backend_data.wasapi;
HRESULT hr; HRESULT hr;
if (FAILED(hr = IMMDevice_Activate(dw->mm_device, &IID_IAudioClient, if (FAILED(hr = IMMDevice_Activate(dw->mm_device, IID_IAUDIOCLIENT,
CLSCTX_ALL, NULL, (void**)&isw->audio_client))) CLSCTX_ALL, NULL, (void**)&isw->audio_client)))
{ {
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -1657,7 +1740,7 @@ static int instream_do_open(struct SoundIoPrivate *si, struct SoundIoInStreamPri
} }
IUnknown_Release(isw->audio_client); IUnknown_Release(isw->audio_client);
isw->audio_client = NULL; isw->audio_client = NULL;
if (FAILED(hr = IMMDevice_Activate(dw->mm_device, &IID_IAudioClient, if (FAILED(hr = IMMDevice_Activate(dw->mm_device, IID_IAUDIOCLIENT,
CLSCTX_ALL, NULL, (void**)&isw->audio_client))) CLSCTX_ALL, NULL, (void**)&isw->audio_client)))
{ {
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -1711,7 +1794,7 @@ static int instream_do_open(struct SoundIoPrivate *si, struct SoundIoInStreamPri
} }
if (instream->name) { if (instream->name) {
if (FAILED(hr = IAudioClient_GetService(isw->audio_client, &IID_IAudioSessionControl, if (FAILED(hr = IAudioClient_GetService(isw->audio_client, IID_IAUDIOSESSIONCONTROL,
(void **)&isw->audio_session_control))) (void **)&isw->audio_session_control)))
{ {
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -1728,7 +1811,7 @@ static int instream_do_open(struct SoundIoPrivate *si, struct SoundIoInStreamPri
} }
} }
if (FAILED(hr = IAudioClient_GetService(isw->audio_client, &IID_IAudioCaptureClient, if (FAILED(hr = IAudioClient_GetService(isw->audio_client, IID_IAUDIOCAPTURECLIENT,
(void **)&isw->audio_capture_client))) (void **)&isw->audio_capture_client)))
{ {
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
@ -1938,7 +2021,7 @@ static int instream_begin_read_wasapi(struct SoundIoPrivate *si, struct SoundIoI
isw->read_buf = NULL; isw->read_buf = NULL;
} }
isw->read_frame_count = min(*frame_count, isw->read_buf_frames_left); isw->read_frame_count = soundio_int_min(*frame_count, isw->read_buf_frames_left);
*frame_count = isw->read_frame_count; *frame_count = isw->read_frame_count;
if (isw->read_buf) { if (isw->read_buf) {
@ -2017,7 +2100,7 @@ static inline struct SoundIoPrivate *soundio_MMNotificationClient_si(IMMNotifica
static STDMETHODIMP soundio_MMNotificationClient_QueryInterface(IMMNotificationClient *client, static STDMETHODIMP soundio_MMNotificationClient_QueryInterface(IMMNotificationClient *client,
REFIID riid, void **ppv) REFIID riid, void **ppv)
{ {
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMMNotificationClient)) { if (IS_EQUAL_IID(riid, &IID_IUnknown) || IS_EQUAL_IID(riid, &IID_IMMNotificationClient)) {
*ppv = client; *ppv = client;
IUnknown_AddRef(client); IUnknown_AddRef(client);
return S_OK; return S_OK;