Commit 6548f4e2 authored by David Reid's avatar David Reid

Set up some infrastructure for separate in/out device IDs.

parent e8e41984
......@@ -1575,7 +1575,8 @@ typedef struct
typedef struct
{
mal_device_type deviceType;
mal_device_id* pDeviceID;
mal_device_id* pPlaybackDeviceID;
mal_device_id* pCaptureDeviceID;
mal_format format;
mal_uint32 channels;
mal_uint32 sampleRate;
......@@ -6121,6 +6122,14 @@ static mal_IMMNotificationClientVtbl g_malNotificationCientVtbl = {
};
#endif // MAL_WIN32_DESKTOP
#ifdef MAL_WIN32_DESKTOP
typedef mal_IMMDevice mal_WASAPIDeviceInterface;
#else
typedef mal_IUnknown mal_WASAPIDeviceInterface;
#endif
mal_bool32 mal_context_is_device_id_equal__wasapi(mal_context* pContext, const mal_device_id* pID0, const mal_device_id* pID1)
{
mal_assert(pContext != NULL);
......@@ -6144,84 +6153,6 @@ void mal_set_device_info_from_WAVEFORMATEX(const WAVEFORMATEX* pWF, mal_device_i
pInfo->maxSampleRate = pWF->nSamplesPerSec;
}
#ifndef MAL_WIN32_DESKTOP
mal_result mal_context_get_IAudioClient_UWP__wasapi(mal_context* pContext, mal_device_type deviceType, const mal_device_id* pDeviceID, mal_IAudioClient** ppAudioClient, mal_IUnknown** ppActivatedInterface)
{
mal_assert(pContext != NULL);
mal_assert(ppAudioClient != NULL);
mal_IActivateAudioInterfaceAsyncOperation *pAsyncOp = NULL;
mal_completion_handler_uwp completionHandler;
IID iid;
if (pDeviceID != NULL) {
mal_copy_memory(&iid, pDeviceID->wasapi, sizeof(iid));
} else {
if (deviceType == mal_device_type_playback) {
iid = MAL_IID_DEVINTERFACE_AUDIO_RENDER;
} else {
iid = MAL_IID_DEVINTERFACE_AUDIO_CAPTURE;
}
}
LPOLESTR iidStr;
#if defined(__cplusplus)
HRESULT hr = StringFromIID(iid, &iidStr);
#else
HRESULT hr = StringFromIID(&iid, &iidStr);
#endif
if (FAILED(hr)) {
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "[WASAPI] Failed to convert device IID to string for ActivateAudioInterfaceAsync(). Out of memory.", MAL_OUT_OF_MEMORY);
}
mal_result result = mal_completion_handler_uwp_init(&completionHandler);
if (result != MAL_SUCCESS) {
mal_CoTaskMemFree(pContext, iidStr);
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for waiting for ActivateAudioInterfaceAsync().", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
#if defined(__cplusplus)
hr = ActivateAudioInterfaceAsync(iidStr, MAL_IID_IAudioClient, NULL, (IActivateAudioInterfaceCompletionHandler*)&completionHandler, (IActivateAudioInterfaceAsyncOperation**)&pAsyncOp);
#else
hr = ActivateAudioInterfaceAsync(iidStr, &MAL_IID_IAudioClient, NULL, (IActivateAudioInterfaceCompletionHandler*)&completionHandler, (IActivateAudioInterfaceAsyncOperation**)&pAsyncOp);
#endif
if (FAILED(hr)) {
mal_completion_handler_uwp_uninit(&completionHandler);
mal_CoTaskMemFree(pContext, iidStr);
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "[WASAPI] ActivateAudioInterfaceAsync() failed.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
mal_CoTaskMemFree(pContext, iidStr);
// Wait for the async operation for finish.
mal_completion_handler_uwp_wait(&completionHandler);
mal_completion_handler_uwp_uninit(&completionHandler);
HRESULT activateResult;
mal_IUnknown* pActivatedInterface;
hr = mal_IActivateAudioInterfaceAsyncOperation_GetActivateResult(pAsyncOp, &activateResult, &pActivatedInterface);
mal_IActivateAudioInterfaceAsyncOperation_Release(pAsyncOp);
if (FAILED(hr) || FAILED(activateResult)) {
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
// Here is where we grab the IAudioClient interface.
hr = mal_IUnknown_QueryInterface(pActivatedInterface, &MAL_IID_IAudioClient, (void**)ppAudioClient);
if (FAILED(hr)) {
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "[WASAPI] Failed to query IAudioClient interface.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
if (ppActivatedInterface) {
*ppActivatedInterface = pActivatedInterface;
} else {
mal_IUnknown_Release(pActivatedInterface);
}
return MAL_SUCCESS;
}
#endif
mal_result mal_context_get_device_info_from_IAudioClient__wasapi(mal_context* pContext, /*mal_IMMDevice**/void* pMMDevice, mal_IAudioClient* pAudioClient, mal_share_mode shareMode, mal_device_info* pInfo)
{
mal_assert(pAudioClient != NULL);
......@@ -6452,6 +6383,116 @@ mal_result mal_context_enumerate_device_collection__wasapi(mal_context* pContext
}
#endif
#ifdef MAL_WIN32_DESKTOP
mal_result mal_context_get_IAudioClient_Desktop__wasapi(mal_context* pContext, mal_device_type deviceType, const mal_device_id* pDeviceID, mal_IAudioClient** ppAudioClient, mal_IMMDevice** ppMMDevice)
{
mal_result result;
HRESULT hr;
mal_assert(pContext != NULL);
mal_assert(ppAudioClient != NULL);
mal_assert(ppMMDevice != NULL);
result = mal_context_get_MMDevice__wasapi(pContext, deviceType, pDeviceID, ppMMDevice);
if (result != MAL_SUCCESS) {
return result;
}
hr = mal_IMMDevice_Activate(*ppMMDevice, &MAL_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)ppAudioClient);
if (FAILED(hr)) {
return MAL_FAILED_TO_OPEN_BACKEND_DEVICE;
}
return MAL_SUCCESS;
}
#else
mal_result mal_context_get_IAudioClient_UWP__wasapi(mal_context* pContext, mal_device_type deviceType, const mal_device_id* pDeviceID, mal_IAudioClient** ppAudioClient, mal_IUnknown** ppActivatedInterface)
{
mal_assert(pContext != NULL);
mal_assert(ppAudioClient != NULL);
mal_IActivateAudioInterfaceAsyncOperation *pAsyncOp = NULL;
mal_completion_handler_uwp completionHandler;
IID iid;
if (pDeviceID != NULL) {
mal_copy_memory(&iid, pDeviceID->wasapi, sizeof(iid));
} else {
if (deviceType == mal_device_type_playback) {
iid = MAL_IID_DEVINTERFACE_AUDIO_RENDER;
} else {
iid = MAL_IID_DEVINTERFACE_AUDIO_CAPTURE;
}
}
LPOLESTR iidStr;
#if defined(__cplusplus)
HRESULT hr = StringFromIID(iid, &iidStr);
#else
HRESULT hr = StringFromIID(&iid, &iidStr);
#endif
if (FAILED(hr)) {
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "[WASAPI] Failed to convert device IID to string for ActivateAudioInterfaceAsync(). Out of memory.", MAL_OUT_OF_MEMORY);
}
mal_result result = mal_completion_handler_uwp_init(&completionHandler);
if (result != MAL_SUCCESS) {
mal_CoTaskMemFree(pContext, iidStr);
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for waiting for ActivateAudioInterfaceAsync().", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
#if defined(__cplusplus)
hr = ActivateAudioInterfaceAsync(iidStr, MAL_IID_IAudioClient, NULL, (IActivateAudioInterfaceCompletionHandler*)&completionHandler, (IActivateAudioInterfaceAsyncOperation**)&pAsyncOp);
#else
hr = ActivateAudioInterfaceAsync(iidStr, &MAL_IID_IAudioClient, NULL, (IActivateAudioInterfaceCompletionHandler*)&completionHandler, (IActivateAudioInterfaceAsyncOperation**)&pAsyncOp);
#endif
if (FAILED(hr)) {
mal_completion_handler_uwp_uninit(&completionHandler);
mal_CoTaskMemFree(pContext, iidStr);
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "[WASAPI] ActivateAudioInterfaceAsync() failed.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
mal_CoTaskMemFree(pContext, iidStr);
// Wait for the async operation for finish.
mal_completion_handler_uwp_wait(&completionHandler);
mal_completion_handler_uwp_uninit(&completionHandler);
HRESULT activateResult;
mal_IUnknown* pActivatedInterface;
hr = mal_IActivateAudioInterfaceAsyncOperation_GetActivateResult(pAsyncOp, &activateResult, &pActivatedInterface);
mal_IActivateAudioInterfaceAsyncOperation_Release(pAsyncOp);
if (FAILED(hr) || FAILED(activateResult)) {
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
// Here is where we grab the IAudioClient interface.
hr = mal_IUnknown_QueryInterface(pActivatedInterface, &MAL_IID_IAudioClient, (void**)ppAudioClient);
if (FAILED(hr)) {
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "[WASAPI] Failed to query IAudioClient interface.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
if (ppActivatedInterface) {
*ppActivatedInterface = pActivatedInterface;
} else {
mal_IUnknown_Release(pActivatedInterface);
}
return MAL_SUCCESS;
}
#endif
mal_result mal_context_get_IAudioClient__wasapi(mal_context* pContext, mal_device_type deviceType, const mal_device_id* pDeviceID, mal_IAudioClient** ppAudioClient, mal_WASAPIDeviceInterface** ppDeviceInterface)
{
#ifdef MAL_WIN32_DESKTOP
return mal_context_get_IAudioClient_Desktop__wasapi(pContext, deviceType, pDeviceID, ppAudioClient, ppDeviceInterface);
#else
return mal_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, ppAudioClient, ppDeviceInterface);
#endif
}
mal_result mal_context_enumerate_devices__wasapi(mal_context* pContext, mal_enum_devices_callback_proc callback, void* pUserData)
{
mal_assert(pContext != NULL);
......@@ -6582,6 +6623,7 @@ void mal_device_uninit__wasapi(mal_device* pDevice)
}
}
typedef struct
{
// Input.
......@@ -6611,13 +6653,18 @@ typedef struct
char deviceName[256];
} mal_device_init_internal_data__wasapi;
mal_result mal_device_init_internal__wasapi(mal_context* pContext, mal_device_type deviceType, const mal_device_id* pDeviceID, mal_device_init_internal_data__wasapi* pData)
mal_result mal_device_init_internal__wasapi(mal_context* pContext, mal_device_type deviceType, const mal_device_id* pPlaybackDeviceID, const mal_device_id* pCaptureDeviceID, mal_device_init_internal_data__wasapi* pData)
{
(void)pContext;
mal_assert(pContext != NULL);
mal_assert(pData != NULL);
/* Not currently supporting full-duplex. */
if (deviceType == mal_device_type_duplex) {
return MAL_INVALID_ARGS;
}
pData->pAudioClient = NULL;
pData->pRenderClient = NULL;
pData->pCaptureClient = NULL;
......@@ -6630,10 +6677,35 @@ mal_result mal_device_init_internal__wasapi(mal_context* pContext, mal_device_ty
MAL_REFERENCE_TIME bufferDurationInMicroseconds;
mal_bool32 wasInitializedUsingIAudioClient3 = MAL_FALSE;
WAVEFORMATEXTENSIBLE wf;
//mal_WASAPIDeviceInterface* pDeviceInterfacePlayback = NULL;
//mal_WASAPIDeviceInterface* pDeviceInterfaceCapture = NULL;
mal_WASAPIDeviceInterface* pDeviceInterface = NULL; // TEMP: Will be split between playback and capture when full-duplex support is implemented.
#if 0
/*
We first try initializing the capture device if applicable. If the device is full-duplex we will try re-using the capture audio client, but
if that fails we'll need to initialize a separate playback audio client.
*/
if (deviceType == mal_device_type_capture || deviceType == mal_device_type_duplex) {
}
/* We may need a playback render client. If it's a duplex device we want to try re-using the same audio client. Otherwise we need a separate one. */
if (deviceType == mal_device_type_playback || deviceType == mal_device_type_duplex) {
if (deviceType == mal_device_type_duplex) {
if (pPlaybackDeviceID != NULL && pCaptureDeviceID != NULL && mal_context_is_device_id_equal__wasapi(pContext, pPlaybackDeviceID, pCaptureDeviceID)) {
}
}
/* Getting here means we need to initialize a separate playback audio client. */
}
#endif
#if 0
#ifdef MAL_WIN32_DESKTOP
mal_IMMDevice* pMMDevice = NULL;
result = mal_context_get_MMDevice__wasapi(pContext, deviceType, pDeviceID, &pMMDevice);
result = mal_context_get_MMDevice__wasapi(pContext, deviceType, (deviceType == mal_device_type_playback) ? pPlaybackDeviceID : pCaptureDeviceID, &pMMDevice);
if (result != MAL_SUCCESS) {
goto done;
}
......@@ -6645,12 +6717,20 @@ mal_result mal_device_init_internal__wasapi(mal_context* pContext, mal_device_ty
}
#else
mal_IUnknown* pActivatedInterface = NULL;
result = mal_context_get_IAudioClient_UWP__wasapi(pContext, type, pDeviceID, &pData->pAudioClient, &pActivatedInterface);
result = mal_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, &pData->pAudioClient, &pActivatedInterface);
if (result != MAL_SUCCESS) {
goto done;
}
#endif
#endif
/* TEMP: Will be replaced when full-duplex is added. */
result = mal_context_get_IAudioClient__wasapi(pContext, deviceType, (deviceType == mal_device_type_playback) ? pPlaybackDeviceID : pCaptureDeviceID, &pData->pAudioClient, &pDeviceInterface);
if (result != MAL_SUCCESS) {
goto done;
}
// Try enabling hardware offloading.
mal_IAudioClient2* pAudioClient2;
hr = mal_IAudioClient_QueryInterface(pData->pAudioClient, &MAL_IID_IAudioClient2, (void**)&pAudioClient2);
......@@ -6674,7 +6754,7 @@ mal_result mal_device_init_internal__wasapi(mal_context* pContext, mal_device_ty
#ifdef MAL_WIN32_DESKTOP
// In exclusive mode on desktop we always use the backend's native format.
mal_IPropertyStore* pStore = NULL;
hr = mal_IMMDevice_OpenPropertyStore(pMMDevice, STGM_READ, &pStore);
hr = mal_IMMDevice_OpenPropertyStore(pDeviceInterface, STGM_READ, &pStore);
if (SUCCEEDED(hr)) {
PROPVARIANT prop;
mal_PropVariantInit(&prop);
......@@ -6780,9 +6860,9 @@ mal_result mal_device_init_internal__wasapi(mal_context* pContext, mal_device_ty
mal_IAudioClient_Release((mal_IAudioClient*)pData->pAudioClient);
#ifdef MAL_WIN32_DESKTOP
hr = mal_IMMDevice_Activate(pMMDevice, &MAL_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pData->pAudioClient);
hr = mal_IMMDevice_Activate(pDeviceInterface, &MAL_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pData->pAudioClient);
#else
hr = mal_IUnknown_QueryInterface(pActivatedInterface, &MAL_IID_IAudioClient, (void**)&pData->pAudioClient);
hr = mal_IUnknown_QueryInterface(pDeviceInterface, &MAL_IID_IAudioClient, (void**)&pData->pAudioClient);
#endif
if (SUCCEEDED(hr)) {
......@@ -6876,7 +6956,7 @@ mal_result mal_device_init_internal__wasapi(mal_context* pContext, mal_device_ty
// Grab the name of the device.
#ifdef MAL_WIN32_DESKTOP
mal_IPropertyStore *pProperties;
hr = mal_IMMDevice_OpenPropertyStore(pMMDevice, STGM_READ, &pProperties);
hr = mal_IMMDevice_OpenPropertyStore(pDeviceInterface, STGM_READ, &pProperties);
if (SUCCEEDED(hr)) {
PROPVARIANT varName;
mal_PropVariantInit(&varName);
......@@ -6893,12 +6973,12 @@ mal_result mal_device_init_internal__wasapi(mal_context* pContext, mal_device_ty
done:
// Clean up.
#ifdef MAL_WIN32_DESKTOP
if (pMMDevice != NULL) {
mal_IMMDevice_Release(pMMDevice);
if (pDeviceInterface != NULL) {
mal_IMMDevice_Release(pDeviceInterface);
}
#else
if (pActivatedInterface != NULL) {
mal_IUnknown_Release(pActivatedInterface);
if (pDeviceInterface != NULL) {
mal_IUnknown_Release(pDeviceInterface);
}
#endif
......@@ -6937,7 +7017,7 @@ mal_result mal_device_reinit__wasapi(mal_device* pDevice)
data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
data.usingDefaultChannelMap = pDevice->usingDefaultChannelMap;
data.shareMode = pDevice->initConfig.shareMode;
mal_result result = mal_device_init_internal__wasapi(pDevice->pContext, pDevice->type, NULL, &data);
mal_result result = mal_device_init_internal__wasapi(pDevice->pContext, pDevice->type, NULL, NULL, &data);
if (result != MAL_SUCCESS) {
return result;
}
......@@ -7002,7 +7082,7 @@ mal_result mal_device_init__wasapi(mal_context* pContext, const mal_device_confi
data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
data.usingDefaultChannelMap = pDevice->usingDefaultChannelMap;
data.shareMode = pConfig->shareMode;
result = mal_device_init_internal__wasapi(pDevice->pContext, pConfig->deviceType, pConfig->pDeviceID, &data);
result = mal_device_init_internal__wasapi(pDevice->pContext, pConfig->deviceType, pConfig->pPlaybackDeviceID, pConfig->pCaptureDeviceID, &data);
if (result != MAL_SUCCESS) {
return result;
}
......@@ -7159,7 +7239,7 @@ mal_result mal_device__get_available_frames__wasapi(mal_device* pDevice, mal_uin
mal_bool32 mal_device_is_reroute_required__wasapi(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
return pDevice->wasapi.hasDefaultDeviceChanged && pDevice->isDefaultDevice;
return pDevice->wasapi.hasDefaultDeviceChanged;
}
mal_result mal_device_reroute__wasapi(mal_device* pDevice)
......@@ -8258,6 +8338,11 @@ mal_result mal_device_init__dsound(mal_context* pContext, const mal_device_confi
mal_assert(pDevice != NULL);
mal_zero_object(&pDevice->dsound);
/* Full-duplex is not yet implemented. */
if (pConfig->deviceType == mal_device_type_duplex) {
return MAL_INVALID_ARGS;
}
/* DirectSound should use a latency of about 20ms per period for low latency mode. */
if (pDevice->usingDefaultBufferSize) {
if (pConfig->performanceProfile == mal_performance_profile_low_latency) {
......@@ -8304,7 +8389,7 @@ mal_result mal_device_init__dsound(mal_context* pContext, const mal_device_confi
// Unfortunately DirectSound uses different APIs and data structures for playback and catpure devices :(
if (pConfig->deviceType == mal_device_type_playback) {
mal_result result = mal_context_create_IDirectSound__dsound(pContext, pConfig->shareMode, pConfig->pDeviceID, (mal_IDirectSound**)&pDevice->dsound.pPlayback);
mal_result result = mal_context_create_IDirectSound__dsound(pContext, pConfig->shareMode, pConfig->pPlaybackDeviceID, (mal_IDirectSound**)&pDevice->dsound.pPlayback);
if (result != MAL_SUCCESS) {
mal_device_uninit__dsound(pDevice);
return result;
......@@ -8418,7 +8503,7 @@ mal_result mal_device_init__dsound(mal_context* pContext, const mal_device_confi
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's secondary buffer.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
} else {
mal_result result = mal_context_create_IDirectSoundCapture__dsound(pContext, pConfig->shareMode, pConfig->pDeviceID, (mal_IDirectSoundCapture**)&pDevice->dsound.pCapture);
mal_result result = mal_context_create_IDirectSoundCapture__dsound(pContext, pConfig->shareMode, pConfig->pCaptureDeviceID, (mal_IDirectSoundCapture**)&pDevice->dsound.pCapture);
if (result != MAL_SUCCESS) {
mal_device_uninit__dsound(pDevice);
return result;
......@@ -9262,6 +9347,11 @@ mal_result mal_device_init__winmm(mal_context* pContext, const mal_device_config
mal_assert(pDevice != NULL);
mal_zero_object(&pDevice->winmm);
/* Full-duplex is not yet implemented. */
if (pConfig->deviceType == mal_device_type_duplex) {
return MAL_INVALID_ARGS;
}
/* No exlusive mode with WinMM. */
if (pConfig->shareMode == mal_share_mode_exclusive) {
return MAL_SHARE_MODE_NOT_SUPPORTED;
......@@ -9276,9 +9366,13 @@ mal_result mal_device_init__winmm(mal_context* pContext, const mal_device_config
}
}
UINT winMMDeviceID = 0;
if (pConfig->pDeviceID != NULL) {
winMMDeviceID = (UINT)pConfig->pDeviceID->winmm;
UINT winMMDeviceIDPlayback = 0;
UINT winMMDeviceIDCapture = 0;
if (pConfig->pPlaybackDeviceID != NULL) {
winMMDeviceIDPlayback = (UINT)pConfig->pPlaybackDeviceID->winmm;
}
if (pConfig->pCaptureDeviceID != NULL) {
winMMDeviceIDCapture = (UINT)pConfig->pCaptureDeviceID->winmm;
}
const char* errorMsg = "";
......@@ -9326,7 +9420,7 @@ mal_result mal_device_init__winmm(mal_context* pContext, const mal_device_config
WORD wChannels = 0;
if (pConfig->deviceType == mal_device_type_playback) {
WAVEOUTCAPSA caps;
if (((MAL_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(winMMDeviceID, &caps, sizeof(caps)) == MMSYSERR_NOERROR) {
if (((MAL_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(winMMDeviceIDPlayback, &caps, sizeof(caps)) == MMSYSERR_NOERROR) {
dwFormats = caps.dwFormats;
wChannels = caps.wChannels;
} else {
......@@ -9335,7 +9429,7 @@ mal_result mal_device_init__winmm(mal_context* pContext, const mal_device_config
}
} else {
WAVEINCAPSA caps;
if (((MAL_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(winMMDeviceID, &caps, sizeof(caps)) == MMSYSERR_NOERROR) {
if (((MAL_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(winMMDeviceIDCapture, &caps, sizeof(caps)) == MMSYSERR_NOERROR) {
dwFormats = caps.dwFormats;
wChannels = caps.wChannels;
} else {
......@@ -9370,13 +9464,13 @@ mal_result mal_device_init__winmm(mal_context* pContext, const mal_device_config
if (pConfig->deviceType == mal_device_type_playback) {
MMRESULT resultMM = ((MAL_PFN_waveOutOpen)pContext->winmm.waveOutOpen)((LPHWAVEOUT)&pDevice->winmm.hDevice, winMMDeviceID, &wf, (DWORD_PTR)pDevice->winmm.hEvent, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC);
MMRESULT resultMM = ((MAL_PFN_waveOutOpen)pContext->winmm.waveOutOpen)((LPHWAVEOUT)&pDevice->winmm.hDevice, winMMDeviceIDPlayback, &wf, (DWORD_PTR)pDevice->winmm.hEvent, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC);
if (resultMM != MMSYSERR_NOERROR) {
errorMsg = "[WinMM] Failed to open playback device.", errorCode = MAL_FAILED_TO_OPEN_BACKEND_DEVICE;
goto on_error;
}
} else {
MMRESULT resultMM = ((MAL_PFN_waveInOpen)pDevice->pContext->winmm.waveInOpen)((LPHWAVEIN)&pDevice->winmm.hDevice, winMMDeviceID, &wf, (DWORD_PTR)pDevice->winmm.hEvent, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC);
MMRESULT resultMM = ((MAL_PFN_waveInOpen)pDevice->pContext->winmm.waveInOpen)((LPHWAVEIN)&pDevice->winmm.hDevice, winMMDeviceIDCapture, &wf, (DWORD_PTR)pDevice->winmm.hEvent, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC);
if (resultMM != MMSYSERR_NOERROR) {
errorMsg = "[WinMM] Failed to open capture device.", errorCode = MAL_FAILED_TO_OPEN_BACKEND_DEVICE;
goto on_error;
......@@ -10990,12 +11084,17 @@ mal_result mal_device_init__alsa(mal_context* pContext, const mal_device_config*
{
(void)pContext;
/* Full-duplex is not yet implemented. */
if (pConfig->deviceType == mal_device_type_duplex) {
return MAL_INVALID_ARGS;
}
mal_assert(pDevice != NULL);
mal_zero_object(&pDevice->alsa);
mal_snd_pcm_format_t formatALSA = mal_convert_mal_format_to_alsa_format(pConfig->format);
mal_result result = mal_context_open_pcm__alsa(pContext, pConfig->shareMode, pConfig->deviceType, pConfig->pDeviceID, (mal_snd_pcm_t**)&pDevice->alsa.pPCM);
mal_result result = mal_context_open_pcm__alsa(pContext, pConfig->shareMode, pConfig->deviceType, (pConfig->deviceType == mal_device_type_playback) ? pConfig->pPlaybackDeviceID : pConfig->pCaptureDeviceID, (mal_snd_pcm_t**)&pDevice->alsa.pPCM);
if (result != MAL_SUCCESS) {
return result;
}
......@@ -12912,15 +13011,24 @@ mal_result mal_device_init__pulse(mal_context* pContext, const mal_device_config
mal_result result = MAL_SUCCESS;
int error = 0;
const char* devPlayback = NULL;
const char* devCapture = NULL;
/* Full-duplex is not yet implemented. */
if (pConfig->deviceType == mal_device_type_duplex) {
return MAL_INVALID_ARGS;
}
/* No exclusive mode with the PulseAudio backend. */
if (pConfig->shareMode == mal_share_mode_exclusive) {
return MAL_SHARE_MODE_NOT_SUPPORTED;
}
const char* dev = NULL;
if (pConfig->pDeviceID != NULL) {
dev = pConfig->pDeviceID->pulse;
if ((pConfig->deviceType == mal_device_type_playback || pConfig->deviceType == mal_device_type_duplex) && pConfig->pPlaybackDeviceID != NULL) {
devPlayback = pConfig->pPlaybackDeviceID->pulse;
}
if ((pConfig->deviceType == mal_device_type_capture || pConfig->deviceType == mal_device_type_duplex) && pConfig->pCaptureDeviceID != NULL) {
devCapture = pConfig->pCaptureDeviceID->pulse;
}
mal_uint32 bufferSizeInFrames = pConfig->bufferSizeInFrames;
......@@ -12996,9 +13104,9 @@ mal_result mal_device_init__pulse(mal_context* pContext, const mal_device_config
if (pConfig->deviceType == mal_device_type_playback) {
pOP = ((mal_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((mal_pa_context*)pDevice->pulse.pPulseContext, dev, mal_device_sink_info_callback, &sinkInfo);
pOP = ((mal_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((mal_pa_context*)pDevice->pulse.pPulseContext, devPlayback, mal_device_sink_info_callback, &sinkInfo);
} else {
pOP = ((mal_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((mal_pa_context*)pDevice->pulse.pPulseContext, dev, mal_device_source_info_callback, &sourceInfo);
pOP = ((mal_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((mal_pa_context*)pDevice->pulse.pPulseContext, devCapture, mal_device_source_info_callback, &sourceInfo);
}
if (pOP != NULL) {
......@@ -13058,14 +13166,15 @@ mal_result mal_device_init__pulse(mal_context* pContext, const mal_device_config
streamFlags = MAL_PA_STREAM_START_CORKED;
if (dev != NULL) {
if (((pConfig->deviceType == mal_device_type_playback) && devPlayback != NULL) ||
((pConfig->deviceType == mal_device_type_capture) && devCapture != NULL)) {
streamFlags |= MAL_PA_STREAM_DONT_MOVE | MAL_PA_STREAM_FIX_FORMAT | MAL_PA_STREAM_FIX_RATE | MAL_PA_STREAM_FIX_CHANNELS;
}
if (pConfig->deviceType == mal_device_type_playback) {
error = ((mal_pa_stream_connect_playback_proc)pContext->pulse.pa_stream_connect_playback)((mal_pa_stream*)pDevice->pulse.pStream, dev, &attr, streamFlags, NULL, NULL);
error = ((mal_pa_stream_connect_playback_proc)pContext->pulse.pa_stream_connect_playback)((mal_pa_stream*)pDevice->pulse.pStream, devPlayback, &attr, streamFlags, NULL, NULL);
} else {
error = ((mal_pa_stream_connect_record_proc)pContext->pulse.pa_stream_connect_record)((mal_pa_stream*)pDevice->pulse.pStream, dev, &attr, streamFlags);
error = ((mal_pa_stream_connect_record_proc)pContext->pulse.pa_stream_connect_record)((mal_pa_stream*)pDevice->pulse.pStream, devCapture, &attr, streamFlags);
}
if (error != MAL_PA_OK) {
......@@ -13134,18 +13243,23 @@ mal_result mal_device_init__pulse(mal_context* pContext, const mal_device_config
// Grab the name of the device if we can.
dev = ((mal_pa_stream_get_device_name_proc)pContext->pulse.pa_stream_get_device_name)((mal_pa_stream*)pDevice->pulse.pStream);
if (dev != NULL) {
mal_pa_operation* pOP = NULL;
if (pConfig->deviceType == mal_device_type_playback) {
pOP = ((mal_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((mal_pa_context*)pDevice->pulse.pPulseContext, dev, mal_device_sink_name_callback, pDevice);
} else {
pOP = ((mal_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((mal_pa_context*)pDevice->pulse.pPulseContext, dev, mal_device_source_name_callback, pDevice);
if (pDevice->type == mal_device_type_playback) {
devPlayback = ((mal_pa_stream_get_device_name_proc)pContext->pulse.pa_stream_get_device_name)((mal_pa_stream*)pDevice->pulse.pStream);
if (devPlayback != NULL) {
mal_pa_operation* pOP = ((mal_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((mal_pa_context*)pDevice->pulse.pPulseContext, devPlayback, mal_device_sink_name_callback, pDevice);
if (pOP != NULL) {
mal_device__wait_for_operation__pulse(pDevice, pOP);
((mal_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
}
}
if (pOP != NULL) {
mal_device__wait_for_operation__pulse(pDevice, pOP);
((mal_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
} else {
devCapture = ((mal_pa_stream_get_device_name_proc)pContext->pulse.pa_stream_get_device_name)((mal_pa_stream*)pDevice->pulse.pStream);
if (devCapture != NULL) {
mal_pa_operation* pOP = ((mal_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((mal_pa_context*)pDevice->pulse.pPulseContext, devCapture, mal_device_source_name_callback, pDevice);
if (pOP != NULL) {
mal_device__wait_for_operation__pulse(pDevice, pOP);
((mal_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
}
}
}
......@@ -13467,16 +13581,15 @@ mal_result mal_context_init__pulse(mal_context* pContext)
pContext->pulse.pa_stream_drop = (mal_proc)_pa_stream_drop;
#endif
pContext->onUninit = mal_context_uninit__pulse;
pContext->onDeviceIDEqual = mal_context_is_device_id_equal__pulse;
pContext->onEnumDevices = mal_context_enumerate_devices__pulse;
pContext->onGetDeviceInfo = mal_context_get_device_info__pulse;
pContext->onDeviceInit = mal_device_init__pulse;
pContext->onDeviceUninit = mal_device_uninit__pulse;
pContext->onDeviceStart = mal_device_start__pulse;
pContext->onDeviceStop = mal_device_stop__pulse;
pContext->onDeviceBreakMainLoop = mal_device_break_main_loop__pulse;
pContext->onDeviceMainLoop = mal_device_main_loop__pulse;
pContext->onUninit = mal_context_uninit__pulse;
pContext->onDeviceIDEqual = mal_context_is_device_id_equal__pulse;
pContext->onEnumDevices = mal_context_enumerate_devices__pulse;
pContext->onGetDeviceInfo = mal_context_get_device_info__pulse;
pContext->onDeviceInit = mal_device_init__pulse;
pContext->onDeviceUninit = mal_device_uninit__pulse;
pContext->onDeviceStart = mal_device_start__pulse;
pContext->onDeviceStop = mal_device_stop__pulse;
pContext->onDeviceMainLoop = mal_device_main_loop__pulse;
// Although we have found the libpulse library, it doesn't necessarily mean PulseAudio is useable. We need to initialize
......@@ -13780,8 +13893,14 @@ mal_result mal_device_init__jack(mal_context* pContext, const mal_device_config*
(void)pContext;
/* Full-duplex is not yet implemented. */
if (pConfig->deviceType == mal_device_type_duplex) {
return MAL_INVALID_ARGS;
}
/* Only supporting default devices with JACK. */
if (pConfig->pDeviceID != NULL && pConfig->pDeviceID->jack != 0) {
if (((pConfig->deviceType == mal_device_type_playback || pConfig->deviceType == mal_device_type_duplex) && pConfig->pPlaybackDeviceID != NULL && pConfig->pPlaybackDeviceID->jack != 0) ||
((pConfig->deviceType == mal_device_type_capture || pConfig->deviceType == mal_device_type_duplex) && pConfig->pCaptureDeviceID != NULL && pConfig->pCaptureDeviceID->jack != 0)) {
return MAL_NO_DEVICE;
}
......@@ -15678,11 +15797,16 @@ typedef struct
char deviceName[256];
} mal_device_init_internal_data__coreaudio;
mal_result mal_device_init_internal__coreaudio(mal_context* pContext, mal_device_type deviceType, const mal_device_id* pDeviceID, mal_device_init_internal_data__coreaudio* pData, void* pDevice_DoNotReference) /* <-- pDevice is typed as void* intentionally so as to avoid accidentally referencing it. */
mal_result mal_device_init_internal__coreaudio(mal_context* pContext, mal_device_type deviceType, const mal_device_id* pPlaybackDeviceID, const mal_device_id* pCaptureDeviceID, mal_device_init_internal_data__coreaudio* pData, void* pDevice_DoNotReference) /* <-- pDevice is typed as void* intentionally so as to avoid accidentally referencing it. */
{
/* Not currently supporting full-duplex. */
if (deviceType == mal_device_type_duplex) {
return MAL_INVALID_ARGS;
}
mal_assert(pContext != NULL);
mal_assert(deviceType == mal_device_type_playback || deviceType == mal_device_type_capture);
mal_assert(deviceType == mal_device_type_playback || deviceType == mal_device_type_capture || deviceType == mal_device_type_duplex);
#if defined(MAL_APPLE_DESKTOP)
pData->deviceObjectID = 0;
#endif
......@@ -15694,7 +15818,7 @@ mal_result mal_device_init_internal__coreaudio(mal_context* pContext, mal_device
#if defined(MAL_APPLE_DESKTOP)
AudioObjectID deviceObjectID;
result = mal_find_AudioObjectID(pContext, deviceType, pDeviceID, &deviceObjectID);
result = mal_find_AudioObjectID(pContext, deviceType, (deviceType == mal_device_type_playback) ? pPlaybackDeviceID : pCaptureDeviceID, &deviceObjectID);
if (result != MAL_SUCCESS) {
return result;
}
......@@ -16025,7 +16149,7 @@ mal_result mal_device_reinit_internal__coreaudio(mal_device* pDevice, mal_bool32
data.usingDefaultChannelMap = pDevice->usingDefaultChannelMap;
data.shareMode = pDevice->initConfig.shareMode;
mal_result result = mal_device_init_internal__coreaudio(pDevice->pContext, pDevice->type, NULL, &data, (void*)pDevice);
mal_result result = mal_device_init_internal__coreaudio(pDevice->pContext, pDevice->type, NULL, NULL, &data, (void*)pDevice);
if (result != MAL_SUCCESS) {
return result;
}
......@@ -16085,7 +16209,7 @@ mal_result mal_device_init__coreaudio(mal_context* pContext, const mal_device_co
data.usingDefaultChannelMap = pDevice->usingDefaultChannelMap;
data.shareMode = pDevice->initConfig.shareMode;
mal_result result = mal_device_init_internal__coreaudio(pDevice->pContext, pConfig->deviceType, pConfig->pDeviceID, &data, (void*)pDevice);
mal_result result = mal_device_init_internal__coreaudio(pDevice->pContext, pConfig->deviceType, pConfig->pPlaybackDeviceID, pConfig->pCaptureDeviceID, &data, (void*)pDevice);
if (result != MAL_SUCCESS) {
return result;
}
......@@ -16743,16 +16867,40 @@ mal_result mal_device_init__sndio(mal_context* pContext, const mal_device_config
mal_assert(pDevice != NULL);
mal_zero_object(&pDevice->sndio);
/* Full-duplex is not yet implemented. */
if (pConfig->deviceType == mal_device_type_duplex) {
return MAL_INVALID_ARGS;
}
const char* deviceName = MAL_SIO_DEVANY;
//#if defined(__FreeBSD__) || defined(__DragonFly__)
// deviceName = "rsnd/0";
//#else
if (pConfig->pDeviceID != NULL) {
deviceName = pConfig->pDeviceID->sndio;
const char* deviceNamePlayback = MAL_SIO_DEVANY;
const char* deviceNameCapture = MAL_SIO_DEVANY;
if (pConfig->pPlaybackDeviceID != NULL) {
deviceNamePlayback = pConfig->pPlaybackDeviceID->sndio;
}
if (pConfig->pCaptureDeviceID != NULL) {
deviceNameCapture = pConfig->pCaptureDeviceID->sndio;
}
if (pConfig->deviceType == mal_device_type_playback) {
pDevice->sndio.handle = (mal_ptr)((mal_sio_open_proc)pContext->sndio.sio_open)(deviceNamePlayback, MAL_SIO_PLAY, 0);
} else if (pConfig->deviceType == mal_device_type_capture) {
pDevice->sndio.handle = (mal_ptr)((mal_sio_open_proc)pContext->sndio.sio_open)(deviceNameCapture, MAL_SIO_REC, 0);
} else if (pConfig->deviceType == mal_device_type_duplex) {
/*
TODO: Handle this case.
- If the device names are the same, try opening in MAL_SIO_PLAY | MAL_SIO_REC mode.
- If the device names are different or MAL_SIO_PLAY | MAL_SIO_REC mode fails, fall back to separate device handles.
*/
mal_assert(MAL_FALSE);
return MAL_INVALID_ARGS;
} else {
mal_assert(MAL_FALSE); /* Should never hit this. */
return MAL_INVALID_ARGS;
}
pDevice->sndio.handle = (mal_ptr)((mal_sio_open_proc)pContext->sndio.sio_open)(deviceName, (pConfig->deviceType == mal_device_type_playback) ? MAL_SIO_PLAY : MAL_SIO_REC, 0);
if (pDevice->sndio.handle == NULL) {
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[sndio] Failed to open device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
......@@ -16782,6 +16930,13 @@ mal_result mal_device_init__sndio(mal_context* pContext, const mal_device_config
// value returned by mal_find_best_channels_from_sio_cap__sndio().
mal_uint32 desiredChannels = pDevice->channels;
if (pDevice->usingDefaultChannels) {
const char* deviceName;
if (pConfig->deviceType == mal_device_type_playback) {
deviceName = deviceNamePlayback;
} else {
deviceName = deviceNameCapture;
}
if (strlen(deviceName) > strlen("rsnd/") && strncmp(deviceName, "rsnd/", strlen("rsnd/")) == 0) {
desiredChannels = mal_find_best_channels_from_sio_cap__sndio(&caps, pConfig->deviceType, desiredFormat);
}
......@@ -17341,6 +17496,11 @@ mal_result mal_device_init__audio4(mal_context* pContext, const mal_device_confi
mal_zero_object(&pDevice->audio4);
pDevice->audio4.fd = -1;
/* Full-duplex is not yet implemented. */
if (pConfig->deviceType == mal_device_type_duplex) {
return MAL_INVALID_ARGS;
}
// The version of the operating system dictates whether or not the device is exclusive or shared. NetBSD
// introduced in-kernel mixing which means it's shared. All other BSD flavours are exclusive as far as
// I'm aware.
......@@ -17354,12 +17514,28 @@ mal_result mal_device_init__audio4(mal_context* pContext, const mal_device_confi
#endif
// The first thing to do is open the file.
const char* deviceName = "/dev/audio";
if (pConfig->pDeviceID != NULL) {
deviceName = pConfig->pDeviceID->audio4;
const char* deviceNamePlayback = "/dev/audio";
const char* deviceNameCapture = "/dev/audio";
if (pConfig->pPlaybackDeviceID != NULL) {
deviceNamePlayback = pConfig->pPlaybackDeviceID->audio4;
}
if (pConfig->pCaptureDeviceID != NULL) {
deviceNameCapture = pConfig->pCaptureDeviceID->audio4;
}
if (pConfig->deviceType == mal_device_type_playback) {
pDevice->audio4.fd = open(deviceNamePlayback, O_WRONLY | O_NONBLOCK, 0);
} else if (pConfig->deviceType == mal_device_type_capture) {
pDevice->audio4.fd = open(deviceNameCapture, O_RDONLY | O_NONBLOCK, 0);
} else if (pConfig->deviceType == mal_device_type_duplex) {
/* TOOD: Implement me. */
mal_assert(MAL_FALSE);
return MAL_INVALID_ARGS;
} else {
mal_assert(MAL_FALSE);
return MAL_INVALID_ARGS;
}
pDevice->audio4.fd = open(deviceName, ((pConfig->deviceType == mal_device_type_playback) ? O_WRONLY : O_RDONLY) | O_NONBLOCK, 0);
if (pDevice->audio4.fd == -1) {
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[audio4] Failed to open device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
......@@ -17633,7 +17809,7 @@ int mal_open_temp_device__oss()
return -1;
}
mal_result mal_context_open_device__oss(mal_context* pContext, mal_device_type deviceType, const mal_device_id* pDeviceID, int* pfd)
mal_result mal_context_open_device__oss(mal_context* pContext, mal_device_type deviceType, const mal_device_id* pPlaybackDeviceID, const mal_device_id* pCaptureDevice, int* pfd)
{
mal_assert(pContext != NULL);
mal_assert(pfd != NULL);
......@@ -17641,14 +17817,28 @@ mal_result mal_context_open_device__oss(mal_context* pContext, mal_device_type d
*pfd = -1;
char deviceName[64];
if (pDeviceID != NULL) {
mal_strncpy_s(deviceName, sizeof(deviceName), pDeviceID->oss, (size_t)-1);
const char* deviceNamePlayback = "/dev/dsp";
const char* deviceNameCapture = "/dev/dsp";
if (pPlaybackDeviceID != NULL) {
deviceNamePlayback = pPlaybackDeviceID->oss;
}
if (pCaptureDeviceID != NULL) {
deviceNameCapture = pCaptureDeviceID->oss;
}
if (deviceType == mal_device_type_playback) {
*pfd = open(deviceNamePlayback, O_WRONLY, 0);
} else if (deviceType == mal_device_type_capture) {
*pfd = open(deviceNameCapture, O_RDONLY, 0);
} else if (deviceType == mal_device_type_duplex) {
/* TODO: Implement me. */
mal_assert(MAL_FALSE);
return MAL_INVALID_ARGS;
} else {
mal_strncpy_s(deviceName, sizeof(deviceName), "/dev/dsp", (size_t)-1);
mal_assert(MAL_FALSE); /* Should never hit this. */
return MAL_INVALID_ARGS;
}
*pfd = open(deviceName, (deviceType == mal_device_type_playback) ? O_WRONLY : O_RDONLY, 0);
if (*pfd == -1) {
return MAL_FAILED_TO_OPEN_BACKEND_DEVICE;
}
......@@ -17832,7 +18022,12 @@ mal_result mal_device_init__oss(mal_context* pContext, const mal_device_config*
mal_assert(pDevice != NULL);
mal_zero_object(&pDevice->oss);
mal_result result = mal_context_open_device__oss(pContext, pConfig->deviceType, pConfig->pDeviceID, &pDevice->oss.fd);
/* Full-duplex is not yet implemented. */
if (pConfig->deviceType == mal_device_type_duplex) {
return MAL_INVALID_ARGS;
}
mal_result result = mal_context_open_device__oss(pContext, pConfig->deviceType, pConfig->pPlaybackDeviceID, pConfig->pCaptureDeviceID, &pDevice->oss.fd);
if (result != MAL_SUCCESS) {
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
}
......@@ -18344,6 +18539,11 @@ mal_result mal_device_init__aaudio(mal_context* pContext, const mal_device_confi
mal_assert(pDevice != NULL);
/* Full-duplex is not yet implemented. */
if (pConfig->deviceType == mal_device_type_duplex) {
return MAL_INVALID_ARGS;
}
/* No exclusive mode with AAudio. */
if (pConfig->shareMode == mal_share_mode_exclusive) {
return MAL_SHARE_MODE_NOT_SUPPORTED;
......@@ -18972,6 +19172,11 @@ mal_result mal_device_init__opensl(mal_context* pContext, const mal_device_confi
return MAL_NO_BACKEND;
#endif
/* Full-duplex is not yet implemented. */
if (pConfig->deviceType == mal_device_type_duplex) {
return MAL_INVALID_ARGS;
}
/* No exclusive mode with OpenSL|ES. */
if (pConfig->shareMode == mal_share_mode_exclusive) {
return MAL_SHARE_MODE_NOT_SUPPORTED;
......@@ -20216,7 +20421,7 @@ mal_result mal_context_init(const mal_backend backends[], mal_uint32 backendCoun
if (pConfig != NULL) {
pContext->config = *pConfig;
} else {
pContext->config = mal_context_config_init(NULL);
pContext->config = mal_context_config_init();
}
// Backend APIs need to be initialized first. This is where external libraries will be loaded and linked.
......@@ -20559,13 +20764,14 @@ mal_result mal_device_init(mal_context* pContext, const mal_device_config* pConf
pDevice->onData = config.dataCallback;
pDevice->onStop = config.stopCallback;
if (((size_t)pDevice % sizeof(pDevice)) != 0) {
if (((mal_uintptr)pDevice % sizeof(pDevice)) != 0) {
if (pContext->config.logCallback) {
pContext->config.logCallback(pContext, pDevice, MAL_LOG_LEVEL_WARNING, "WARNING: mal_device_init() called for a device that is not properly aligned. Thread safety is not supported.");
}
}
if (config.pDeviceID == NULL) {
/* TODO: This is only used in Core Audio. Move this to the Core Audio backend. Also, this logic does not handle full-duplex devices properly */
if (config.pPlaybackDeviceID == NULL || config.pCaptureDeviceID == NULL) {
pDevice->isDefaultDevice = MAL_TRUE;
}
......@@ -20650,22 +20856,14 @@ mal_result mal_device_init(mal_context* pContext, const mal_device_config* pConf
mal_device__post_init_setup(pDevice);
// If the backend did not fill out a name for the device, try a generic method.
// If the backend did not fill out a name for the device, try a generic method. TODO: Update this to support full-duplex devices. Need to split "name" out into "playbackDeviceName" and "captureDeviceName".
if (pDevice->name[0] == '\0') {
if (mal_context__try_get_device_name_by_id(pContext, config.deviceType, config.pDeviceID, pDevice->name, sizeof(pDevice->name)) != MAL_SUCCESS) {
if (mal_context__try_get_device_name_by_id(pContext, config.deviceType, (config.deviceType == mal_device_type_playback) ? config.pPlaybackDeviceID : config.pCaptureDeviceID, pDevice->name, sizeof(pDevice->name)) != MAL_SUCCESS) {
// We failed to get the device name, so fall back to some generic names.
if (config.pDeviceID == NULL) {
if (config.deviceType == mal_device_type_playback) {
mal_strncpy_s(pDevice->name, sizeof(pDevice->name), MAL_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
} else {
mal_strncpy_s(pDevice->name, sizeof(pDevice->name), MAL_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
}
if (config.deviceType == mal_device_type_playback) {
mal_strncpy_s(pDevice->name, sizeof(pDevice->name), (config.pPlaybackDeviceID == NULL) ? MAL_DEFAULT_PLAYBACK_DEVICE_NAME : "Playback Device", (size_t)-1);
} else {
if (config.deviceType == mal_device_type_playback) {
mal_strncpy_s(pDevice->name, sizeof(pDevice->name), "Playback Device", (size_t)-1);
} else {
mal_strncpy_s(pDevice->name, sizeof(pDevice->name), "Capture Device", (size_t)-1);
}
mal_strncpy_s(pDevice->name, sizeof(pDevice->name), (config.pCaptureDeviceID == NULL) ? MAL_DEFAULT_CAPTURE_DEVICE_NAME : "Capture Device", (size_t)-1);
}
}
}
......@@ -32,7 +32,9 @@ int main(int argc, char** argv)
mal_backend backend = mal_backend_wasapi;
mal_context_config contextConfig = mal_context_config_init(log_callback);
mal_context_config contextConfig = mal_context_config_init();
contextConfig.logCallback = log_callback;
mal_context context;
result = mal_context_init(&backend, 1, &contextConfig, &context);
if (result != MAL_SUCCESS) {
......@@ -41,7 +43,7 @@ int main(int argc, char** argv)
}
mal_device_config deviceConfig = mal_device_config_init(mal_device_type_duplex);
deviceConfig.pDeviceID = NULL;
deviceConfig.pPlaybackDeviceID = NULL;
deviceConfig.format = mal_format_f32;
deviceConfig.channels = 2;
deviceConfig.sampleRate = 44100;
......
......@@ -2117,7 +2117,8 @@ int do_backend_test(mal_backend backend)
// Context.
printf(" Creating Context... ");
{
mal_context_config contextConfig = mal_context_config_init(on_log);
mal_context_config contextConfig = mal_context_config_init();
contextConfig.logCallback = on_log;
result = mal_context_init(&backend, 1, &contextConfig, &context);
if (result == MAL_SUCCESS) {
......@@ -2285,7 +2286,9 @@ int do_playback_test(mal_backend backend)
// Device.
printf(" Opening Device... ");
{
mal_context_config contextConfig = mal_context_config_init(on_log);
mal_context_config contextConfig = mal_context_config_init();
contextConfig.logCallback = on_log;
mal_device_config deviceConfig = mal_device_config_init(mal_device_type_playback);
deviceConfig.pUserData = &callbackData;
deviceConfig.dataCallback = on_send__playback_test;
......
......@@ -319,12 +319,12 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="mal_duplex.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="mal_no_device_io.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
......@@ -359,12 +359,12 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="mal_test_0.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="mal_test_0.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment