mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-24 09:14:04 +02:00
Win32: Link to ole32.dll dynamically at run-time.
This commit is contained in:
@@ -472,6 +472,21 @@ typedef struct
|
|||||||
int _unused;
|
int _unused;
|
||||||
} null_device;
|
} null_device;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/*HMODULE*/ mal_handle hOle32DLL;
|
||||||
|
mal_proc CoInitializeEx;
|
||||||
|
mal_proc CoUninitialize;
|
||||||
|
mal_proc CoCreateInstance;
|
||||||
|
mal_proc CoTaskMemFree;
|
||||||
|
mal_proc PropVariantClear;
|
||||||
|
} win32;
|
||||||
|
|
||||||
|
int _unused;
|
||||||
|
};
|
||||||
} mal_context;
|
} mal_context;
|
||||||
|
|
||||||
struct mal_device
|
struct mal_device
|
||||||
@@ -896,6 +911,16 @@ mal_uint32 mal_get_sample_size_in_bytes(mal_format format);
|
|||||||
#endif
|
#endif
|
||||||
typedef mal_thread_result (MAL_THREADCALL * mal_thread_entry_proc)(void* pData);
|
typedef mal_thread_result (MAL_THREADCALL * mal_thread_entry_proc)(void* pData);
|
||||||
|
|
||||||
|
#ifdef MAL_WIN32
|
||||||
|
typedef HRESULT (WINAPI * MAL_PFN_CoInitializeEx)(LPVOID pvReserved, DWORD dwCoInit);
|
||||||
|
typedef void (WINAPI * MAL_PFN_CoUninitialize)();
|
||||||
|
typedef HRESULT (WINAPI * MAL_PFN_CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv);
|
||||||
|
typedef void (WINAPI * MAL_PFN_CoTaskMemFree)(_In_opt_ LPVOID pv);
|
||||||
|
typedef HRESULT (WINAPI * MAL_PFN_PropVariantClear)(PROPVARIANT *pvar);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define MAL_STATE_UNINITIALIZED 0
|
#define MAL_STATE_UNINITIALIZED 0
|
||||||
#define MAL_STATE_STOPPED 1 // The device's default state after initialization.
|
#define MAL_STATE_STOPPED 1 // The device's default state after initialization.
|
||||||
#define MAL_STATE_STARTED 2 // The worker thread is in it's main loop waiting for the driver to request or deliver audio data.
|
#define MAL_STATE_STARTED 2 // The worker thread is in it's main loop waiting for the driver to request or deliver audio data.
|
||||||
@@ -1998,7 +2023,7 @@ mal_result mal_context_init__wasapi(mal_context* pContext)
|
|||||||
mal_assert(pContext != NULL);
|
mal_assert(pContext != NULL);
|
||||||
|
|
||||||
// Validate the WASAPI is available by grabbing an MMDeviceEnumerator object.
|
// Validate the WASAPI is available by grabbing an MMDeviceEnumerator object.
|
||||||
HRESULT hr = CoCreateInstance(g_malCLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, g_malIID_IMMDeviceEnumerator, (void**)&pContext->wasapi.pDeviceEnumerator);
|
HRESULT hr = ((MAL_PFN_CoCreateInstance)pContext->win32.CoCreateInstance)(g_malCLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, g_malIID_IMMDeviceEnumerator, (void**)&pContext->wasapi.pDeviceEnumerator);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
return MAL_NO_BACKEND;
|
return MAL_NO_BACKEND;
|
||||||
}
|
}
|
||||||
@@ -2075,7 +2100,7 @@ static mal_result mal_enumerate_devices__wasapi(mal_context* pContext, mal_devic
|
|||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
size_t idlen = wcslen(id);
|
size_t idlen = wcslen(id);
|
||||||
if (idlen+sizeof(wchar_t) > sizeof(pInfo->id.wstr)) {
|
if (idlen+sizeof(wchar_t) > sizeof(pInfo->id.wstr)) {
|
||||||
CoTaskMemFree(id);
|
((MAL_PFN_CoTaskMemFree)pContext->win32.CoTaskMemFree)(id);
|
||||||
mal_assert(MAL_FALSE); // NOTE: If this is triggered, please report it. It means the format of the ID must haved change and is too long to fit in our fixed sized buffer.
|
mal_assert(MAL_FALSE); // NOTE: If this is triggered, please report it. It means the format of the ID must haved change and is too long to fit in our fixed sized buffer.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2083,7 +2108,7 @@ static mal_result mal_enumerate_devices__wasapi(mal_context* pContext, mal_devic
|
|||||||
memcpy(pInfo->id.wstr, id, idlen * sizeof(wchar_t));
|
memcpy(pInfo->id.wstr, id, idlen * sizeof(wchar_t));
|
||||||
pInfo->id.wstr[idlen] = '\0';
|
pInfo->id.wstr[idlen] = '\0';
|
||||||
|
|
||||||
CoTaskMemFree(id);
|
((MAL_PFN_CoTaskMemFree)pContext->win32.CoTaskMemFree)(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Description / Friendly Name.
|
// Description / Friendly Name.
|
||||||
@@ -2103,7 +2128,7 @@ static mal_result mal_enumerate_devices__wasapi(mal_context* pContext, mal_devic
|
|||||||
#endif
|
#endif
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
WideCharToMultiByte(CP_UTF8, 0, varName.pwszVal, -1, pInfo->name, sizeof(pInfo->name), 0, FALSE);
|
WideCharToMultiByte(CP_UTF8, 0, varName.pwszVal, -1, pInfo->name, sizeof(pInfo->name), 0, FALSE);
|
||||||
PropVariantClear(&varName);
|
((MAL_PFN_PropVariantClear)pContext->win32.PropVariantClear)(&varName);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@@ -2174,7 +2199,7 @@ static mal_result mal_device_init__wasapi(mal_context* pContext, mal_device_type
|
|||||||
mal_zero_object(&pDevice->wasapi);
|
mal_zero_object(&pDevice->wasapi);
|
||||||
|
|
||||||
IMMDeviceEnumerator* pDeviceEnumerator;
|
IMMDeviceEnumerator* pDeviceEnumerator;
|
||||||
HRESULT hr = CoCreateInstance(g_malCLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, g_malIID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
|
HRESULT hr = ((MAL_PFN_CoCreateInstance)pContext->win32.CoCreateInstance)(g_malCLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, g_malIID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
mal_device_uninit__wasapi(pDevice);
|
mal_device_uninit__wasapi(pDevice);
|
||||||
return mal_post_error(pDevice, "[WASAPI] Failed to create IMMDeviceEnumerator.", MAL_WASAPI_FAILED_TO_CREATE_DEVICE_ENUMERATOR);
|
return mal_post_error(pDevice, "[WASAPI] Failed to create IMMDeviceEnumerator.", MAL_WASAPI_FAILED_TO_CREATE_DEVICE_ENUMERATOR);
|
||||||
@@ -2276,12 +2301,12 @@ static mal_result mal_device_init__wasapi(mal_context* pContext, mal_device_type
|
|||||||
hr = ((IAudioClient*)pDevice->wasapi.pAudioClient)->lpVtbl->Initialize((IAudioClient*)pDevice->wasapi.pAudioClient, AUDCLNT_SHAREMODE_SHARED, 0, bufferDurationInMicroseconds*10, 0, (WAVEFORMATEX*)&wf, NULL);
|
hr = ((IAudioClient*)pDevice->wasapi.pAudioClient)->lpVtbl->Initialize((IAudioClient*)pDevice->wasapi.pAudioClient, AUDCLNT_SHAREMODE_SHARED, 0, bufferDurationInMicroseconds*10, 0, (WAVEFORMATEX*)&wf, NULL);
|
||||||
#endif
|
#endif
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
CoTaskMemFree(pClosestWF);
|
((MAL_PFN_CoTaskMemFree)pContext->win32.CoTaskMemFree)(pClosestWF);
|
||||||
mal_device_uninit__wasapi(pDevice);
|
mal_device_uninit__wasapi(pDevice);
|
||||||
return mal_post_error(pDevice, "[WASAPI] Failed to activate device.", MAL_WASAPI_FAILED_TO_INITIALIZE_DEVICE);
|
return mal_post_error(pDevice, "[WASAPI] Failed to activate device.", MAL_WASAPI_FAILED_TO_INITIALIZE_DEVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
CoTaskMemFree(pClosestWF);
|
((MAL_PFN_CoTaskMemFree)pContext->win32.CoTaskMemFree)(pClosestWF);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
hr = ((IAudioClient*)pDevice->wasapi.pAudioClient)->GetBufferSize(&pDevice->bufferSizeInFrames);
|
hr = ((IAudioClient*)pDevice->wasapi.pAudioClient)->GetBufferSize(&pDevice->bufferSizeInFrames);
|
||||||
@@ -4940,7 +4965,7 @@ mal_thread_result MAL_THREADCALL mal_worker_thread(void* pData)
|
|||||||
mal_assert(pDevice != NULL);
|
mal_assert(pDevice != NULL);
|
||||||
|
|
||||||
#ifdef MAL_WIN32
|
#ifdef MAL_WIN32
|
||||||
CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
((MAL_PFN_CoInitializeEx)pDevice->pContext->win32.CoInitializeEx)(NULL, COINIT_MULTITHREADED);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This is only used to prevent posting onStop() when the device is first initialized.
|
// This is only used to prevent posting onStop() when the device is first initialized.
|
||||||
@@ -4999,7 +5024,7 @@ mal_thread_result MAL_THREADCALL mal_worker_thread(void* pData)
|
|||||||
mal_event_signal(&pDevice->stopEvent); // <-- Is this still needed?
|
mal_event_signal(&pDevice->stopEvent); // <-- Is this still needed?
|
||||||
|
|
||||||
#ifdef MAL_WIN32
|
#ifdef MAL_WIN32
|
||||||
CoUninitialize();
|
((MAL_PFN_CoUninitialize)pDevice->pContext->win32.CoUninitialize)();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return (mal_thread_result)0;
|
return (mal_thread_result)0;
|
||||||
@@ -5014,15 +5039,66 @@ mal_bool32 mal_device__is_initialized(mal_device* pDevice)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MAL_WIN32
|
||||||
|
mal_result mal_context_uninit_backend_apis__win32(mal_context* pContext)
|
||||||
|
{
|
||||||
|
((MAL_PFN_CoUninitialize)pContext->win32.CoUninitialize)();
|
||||||
|
mal_dlclose(pContext->win32.hOle32DLL);
|
||||||
|
|
||||||
|
return MAL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
mal_result mal_context_init_backend_apis__win32(mal_context* pContext)
|
||||||
|
{
|
||||||
|
// Ole32.dll
|
||||||
|
pContext->win32.hOle32DLL = mal_dlopen("ole32.dll");
|
||||||
|
if (pContext->win32.hOle32DLL == NULL) {
|
||||||
|
return MAL_FAILED_TO_INIT_BACKEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
pContext->win32.CoInitializeEx = (mal_proc)mal_dlsym(pContext->win32.hOle32DLL, "CoInitializeEx");
|
||||||
|
pContext->win32.CoUninitialize = (mal_proc)mal_dlsym(pContext->win32.hOle32DLL, "CoUninitialize");
|
||||||
|
pContext->win32.CoCreateInstance = (mal_proc)mal_dlsym(pContext->win32.hOle32DLL, "CoCreateInstance");
|
||||||
|
pContext->win32.CoTaskMemFree = (mal_proc)mal_dlsym(pContext->win32.hOle32DLL, "CoTaskMemFree");
|
||||||
|
pContext->win32.PropVariantClear = (mal_proc)mal_dlsym(pContext->win32.hOle32DLL, "PropVariantClear");
|
||||||
|
|
||||||
|
|
||||||
|
((MAL_PFN_CoInitializeEx)pContext->win32.CoInitializeEx)(NULL, COINIT_MULTITHREADED);
|
||||||
|
|
||||||
|
return MAL_SUCCESS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mal_result mal_context_init_backend_apis(mal_context* pContext)
|
||||||
|
{
|
||||||
|
mal_result result = MAL_NO_BACKEND;
|
||||||
|
#ifdef MAL_WIN32
|
||||||
|
result = mal_context_init_backend_apis__win32(pContext);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
mal_result mal_context_uninit_backend_apis(mal_context* pContext)
|
||||||
|
{
|
||||||
|
mal_result result = MAL_NO_BACKEND;
|
||||||
|
#ifdef MAL_WIN32
|
||||||
|
result = mal_context_uninit_backend_apis__win32(pContext);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal_context* pContext)
|
mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal_context* pContext)
|
||||||
{
|
{
|
||||||
if (pContext == NULL) return MAL_INVALID_ARGS;
|
if (pContext == NULL) return MAL_INVALID_ARGS;
|
||||||
mal_zero_object(pContext);
|
mal_zero_object(pContext);
|
||||||
|
|
||||||
// Keep it simple and always initialize COM.
|
// Backend APIs need to be initialized first. This is where external libraries will be loaded and linked.
|
||||||
#ifdef MAL_WIN32
|
mal_result result = mal_context_init_backend_apis(pContext);
|
||||||
CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
if (result != MAL_SUCCESS) {
|
||||||
#endif
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static mal_backend defaultBackends[] = {
|
static mal_backend defaultBackends[] = {
|
||||||
mal_backend_dsound,
|
mal_backend_dsound,
|
||||||
@@ -5158,9 +5234,7 @@ mal_result mal_context_uninit(mal_context* pContext)
|
|||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MAL_WIN32
|
mal_context_uninit_backend_apis(pContext);
|
||||||
CoUninitialize();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mal_assert(MAL_FALSE);
|
mal_assert(MAL_FALSE);
|
||||||
return MAL_NO_BACKEND;
|
return MAL_NO_BACKEND;
|
||||||
@@ -5595,7 +5669,7 @@ mal_uint32 mal_get_sample_size_in_bytes(mal_format format)
|
|||||||
// - Dropped support for f64, A-law and Mu-law formats since they just aren't common enough to justify the
|
// - Dropped support for f64, A-law and Mu-law formats since they just aren't common enough to justify the
|
||||||
// added maintenance cost.
|
// added maintenance cost.
|
||||||
// - DirectSound: Increased the default buffer size for capture devices.
|
// - DirectSound: Increased the default buffer size for capture devices.
|
||||||
// - Added initial implementation of the OpenSL|ES backend. This is unstable.
|
// - Added initial implementation of the OpenSL|ES backend.
|
||||||
//
|
//
|
||||||
// v0.1 - 2016-10-21
|
// v0.1 - 2016-10-21
|
||||||
// - Initial versioned release.
|
// - Initial versioned release.
|
||||||
@@ -5613,7 +5687,6 @@ mal_uint32 mal_get_sample_size_in_bytes(mal_format format)
|
|||||||
// - GetMixFormat() instead of IsFormatSupported().
|
// - GetMixFormat() instead of IsFormatSupported().
|
||||||
// - Requires a large suite of conversion routines including channel shuffling, SRC and format conversion.
|
// - Requires a large suite of conversion routines including channel shuffling, SRC and format conversion.
|
||||||
// - Look into event callbacks: AUDCLNT_STREAMFLAGS_EVENTCALLBACK
|
// - Look into event callbacks: AUDCLNT_STREAMFLAGS_EVENTCALLBACK
|
||||||
// - Link to ole32.lib at run time.
|
|
||||||
// - Clean up that terrible "__cplusplus" mess by implementing wrapper functions.
|
// - Clean up that terrible "__cplusplus" mess by implementing wrapper functions.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user