mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
Migrate the WASAPI backend over to the new callback system.
This includes changes to callbacks used by custom backends. It adds a `pConfig` parameter to both onContextInit and onDeviceInit. This allows custom backends to specify custom config properties.
This commit is contained in:
@@ -408,7 +408,7 @@ static ma_result ma_device_init_internal__sdl(ma_device_ex* pDeviceEx, ma_device
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_device_init__sdl(ma_device* pDevice, ma_device_type deviceType, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
|
||||
static ma_result ma_device_init__sdl(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
|
||||
{
|
||||
ma_device_ex* pDeviceEx = (ma_device_ex*)pDevice;
|
||||
ma_context_ex* pContextEx = (ma_context_ex*)pDevice->pContext;
|
||||
@@ -417,21 +417,21 @@ static ma_result ma_device_init__sdl(ma_device* pDevice, ma_device_type deviceTy
|
||||
MA_ASSERT(pDevice != NULL);
|
||||
|
||||
/* SDL does not support loopback mode, so must return MA_DEVICE_TYPE_NOT_SUPPORTED if it's requested. */
|
||||
if (deviceType == ma_device_type_loopback) {
|
||||
if (pConfig->deviceType == ma_device_type_loopback) {
|
||||
return MA_DEVICE_TYPE_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
|
||||
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
|
||||
result = ma_device_init_internal__sdl(pDeviceEx, ma_device_type_capture, pDescriptorCapture);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
|
||||
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
|
||||
result = ma_device_init_internal__sdl(pDeviceEx, ma_device_type_playback, pDescriptorPlayback);
|
||||
if (result != MA_SUCCESS) {
|
||||
if (deviceType == ma_device_type_duplex) {
|
||||
if (pConfig->deviceType == ma_device_type_duplex) {
|
||||
((MA_PFN_SDL_CloseAudioDevice)pContextEx->sdl.SDL_CloseAudioDevice)(pDeviceEx->sdl.deviceIDCapture);
|
||||
}
|
||||
|
||||
@@ -511,7 +511,7 @@ static ma_result ma_context_uninit__sdl(ma_context* pContext)
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_context_init__sdl(ma_context* pContext, ma_backend_callbacks* pCallbacks)
|
||||
static ma_result ma_context_init__sdl(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
|
||||
{
|
||||
ma_context_ex* pContextEx = (ma_context_ex*)pContext;
|
||||
int resultSDL;
|
||||
@@ -531,6 +531,8 @@ static ma_result ma_context_init__sdl(ma_context* pContext, ma_backend_callbacks
|
||||
|
||||
MA_ASSERT(pContext != NULL);
|
||||
|
||||
(void)pConfig;
|
||||
|
||||
/* Check if we have SDL2 installed somewhere. If not it's not usable and we need to abort. */
|
||||
for (iName = 0; iName < ma_countof(pSDLNames); iName += 1) {
|
||||
pContextEx->sdl.hSDL = ma_dlopen(pContext, pSDLNames[iName]);
|
||||
@@ -592,7 +594,7 @@ you want to handle backend selection.
|
||||
|
||||
This is used as the onContextInit() callback in the context config.
|
||||
*/
|
||||
static ma_result ma_context_init__custom_loader(ma_context* pContext, ma_backend_callbacks* pCallbacks)
|
||||
static ma_result ma_context_init__custom_loader(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
|
||||
{
|
||||
ma_result result = MA_NO_BACKEND;
|
||||
|
||||
@@ -603,7 +605,7 @@ static ma_result ma_context_init__custom_loader(ma_context* pContext, ma_backend
|
||||
/* SDL. */
|
||||
#if !defined(MA_NO_SDL)
|
||||
if (result != MA_SUCCESS) {
|
||||
result = ma_context_init__sdl(pContext, pCallbacks);
|
||||
result = ma_context_init__sdl(pContext, pConfig, pCallbacks);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -681,7 +683,7 @@ int main(int argc, char** argv)
|
||||
ma_waveform_init(&sineWaveConfig, &sineWave);
|
||||
|
||||
/* The device is created exactly as per normal. */
|
||||
deviceConfig = ma_device_config_init(ma_device_type_duplex);
|
||||
deviceConfig = ma_device_config_init(ma_device_type_playback);
|
||||
deviceConfig.playback.format = DEVICE_FORMAT;
|
||||
deviceConfig.playback.channels = DEVICE_CHANNELS;
|
||||
deviceConfig.capture.format = DEVICE_FORMAT;
|
||||
|
||||
+217
-176
@@ -3224,7 +3224,7 @@ typedef struct ma_context_config ma_context_config;
|
||||
typedef struct ma_device_config ma_device_config;
|
||||
typedef struct ma_backend_callbacks ma_backend_callbacks;
|
||||
|
||||
#define MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE (1U << 1); /* If set, this is supported in exclusive mode. Otherwise not natively supported by exclusive mode. */
|
||||
#define MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE (1U << 1) /* If set, this is supported in exclusive mode. Otherwise not natively supported by exclusive mode. */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -3447,11 +3447,11 @@ look at `ma_device_audio_thread__default_read_write()`.
|
||||
*/
|
||||
struct ma_backend_callbacks
|
||||
{
|
||||
ma_result (* onContextInit)(ma_context* pContext, ma_backend_callbacks* pCallbacks);
|
||||
ma_result (* onContextInit)(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks);
|
||||
ma_result (* onContextUninit)(ma_context* pContext);
|
||||
ma_result (* onContextEnumerateDevices)(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData);
|
||||
ma_result (* onContextGetDeviceInfo)(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo);
|
||||
ma_result (* onDeviceInit)(ma_device* pDevice, ma_device_type deviceType, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture);
|
||||
ma_result (* onDeviceInit)(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture);
|
||||
ma_result (* onDeviceUninit)(ma_device* pDevice);
|
||||
ma_result (* onDeviceStart)(ma_device* pDevice);
|
||||
ma_result (* onDeviceStop)(ma_device* pDevice);
|
||||
@@ -12614,52 +12614,55 @@ typedef ma_IUnknown ma_WASAPIDeviceInterface;
|
||||
#endif
|
||||
|
||||
|
||||
static void ma_set_device_info_from_WAVEFORMATEX(const WAVEFORMATEX* pWF, ma_device_info* pInfo)
|
||||
static void ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(const WAVEFORMATEX* pWF, ma_share_mode shareMode, ma_device_info* pInfo)
|
||||
{
|
||||
MA_ASSERT(pWF != NULL);
|
||||
MA_ASSERT(pInfo != NULL);
|
||||
|
||||
pInfo->formatCount = 1;
|
||||
pInfo->formats[0] = ma_format_from_WAVEFORMATEX(pWF);
|
||||
pInfo->minChannels = pWF->nChannels;
|
||||
pInfo->maxChannels = pWF->nChannels;
|
||||
pInfo->minSampleRate = pWF->nSamplesPerSec;
|
||||
pInfo->maxSampleRate = pWF->nSamplesPerSec;
|
||||
if (pInfo->nativeDataFormatCount >= ma_countof(pInfo->nativeDataFormats)) {
|
||||
return; /* Too many data formats. Need to ignore this one. Don't think this should ever happen with WASAPI. */
|
||||
}
|
||||
|
||||
static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context* pContext, /*ma_IMMDevice**/void* pMMDevice, ma_IAudioClient* pAudioClient, ma_share_mode shareMode, ma_device_info* pInfo)
|
||||
pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].format = ma_format_from_WAVEFORMATEX(pWF);
|
||||
pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].channels = pWF->nChannels;
|
||||
pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].sampleRate = pWF->nSamplesPerSec;
|
||||
pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].flags = (shareMode == ma_share_mode_exclusive) ? MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE : 0;
|
||||
pInfo->nativeDataFormatCount += 1;
|
||||
}
|
||||
|
||||
static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context* pContext, /*ma_IMMDevice**/void* pMMDevice, ma_IAudioClient* pAudioClient, ma_device_info* pInfo)
|
||||
{
|
||||
HRESULT hr;
|
||||
WAVEFORMATEX* pWF = NULL;
|
||||
#ifdef MA_WIN32_DESKTOP
|
||||
ma_IPropertyStore *pProperties;
|
||||
#endif
|
||||
|
||||
MA_ASSERT(pAudioClient != NULL);
|
||||
MA_ASSERT(pInfo != NULL);
|
||||
|
||||
/* We use a different technique to retrieve the device information depending on whether or not we are using shared or exclusive mode. */
|
||||
if (shareMode == ma_share_mode_shared) {
|
||||
/* Shared Mode. We use GetMixFormat() here. */
|
||||
WAVEFORMATEX* pWF = NULL;
|
||||
HRESULT hr = ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pAudioClient, (WAVEFORMATEX**)&pWF);
|
||||
hr = ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pAudioClient, (WAVEFORMATEX**)&pWF);
|
||||
if (SUCCEEDED(hr)) {
|
||||
ma_set_device_info_from_WAVEFORMATEX(pWF, pInfo);
|
||||
return MA_SUCCESS;
|
||||
ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(pWF, ma_share_mode_shared, pInfo);
|
||||
} else {
|
||||
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve mix format for device info retrieval.", ma_result_from_HRESULT(hr));
|
||||
}
|
||||
} else {
|
||||
|
||||
/* Exlcusive Mode. We repeatedly call IsFormatSupported() here. This is not currently support on UWP. */
|
||||
#ifdef MA_WIN32_DESKTOP
|
||||
/*
|
||||
The first thing to do is get the format from PKEY_AudioEngine_DeviceFormat. This should give us a channel count we assume is
|
||||
correct which will simplify our searching.
|
||||
*/
|
||||
ma_IPropertyStore *pProperties;
|
||||
HRESULT hr = ma_IMMDevice_OpenPropertyStore((ma_IMMDevice*)pMMDevice, STGM_READ, &pProperties);
|
||||
hr = ma_IMMDevice_OpenPropertyStore((ma_IMMDevice*)pMMDevice, STGM_READ, &pProperties);
|
||||
if (SUCCEEDED(hr)) {
|
||||
PROPVARIANT var;
|
||||
ma_PropVariantInit(&var);
|
||||
|
||||
hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_AudioEngine_DeviceFormat, &var);
|
||||
if (SUCCEEDED(hr)) {
|
||||
WAVEFORMATEX* pWF = (WAVEFORMATEX*)var.blob.pBlobData;
|
||||
ma_set_device_info_from_WAVEFORMATEX(pWF, pInfo);
|
||||
pWF = (WAVEFORMATEX*)var.blob.pBlobData;
|
||||
|
||||
/*
|
||||
In my testing, the format returned by PKEY_AudioEngine_DeviceFormat is suitable for exclusive mode so we check this format
|
||||
@@ -12668,7 +12671,10 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context
|
||||
hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, pWF, NULL);
|
||||
ma_PropVariantClear(pContext, &var);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
if (SUCCEEDED(hr)) {
|
||||
/* The format returned by PKEY_AudioEngine_DeviceFormat is not supported. */
|
||||
ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(pWF, ma_share_mode_exclusive, pInfo);
|
||||
} else {
|
||||
/*
|
||||
The format returned by PKEY_AudioEngine_DeviceFormat is not supported, so fall back to a search. We assume the channel
|
||||
count returned by MA_PKEY_AudioEngine_DeviceFormat is valid and correct. For simplicity we're only returning one format.
|
||||
@@ -12720,7 +12726,7 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context
|
||||
|
||||
hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wf, NULL);
|
||||
if (SUCCEEDED(hr)) {
|
||||
ma_set_device_info_from_WAVEFORMATEX((WAVEFORMATEX*)&wf, pInfo);
|
||||
ma_add_native_data_format_to_device_info_from_WAVEFORMATEX((WAVEFORMATEX*)&wf, ma_share_mode_exclusive, pInfo);
|
||||
found = MA_TRUE;
|
||||
break;
|
||||
}
|
||||
@@ -12745,13 +12751,9 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context
|
||||
} else {
|
||||
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to open property store for device info retrieval.", ma_result_from_HRESULT(hr));
|
||||
}
|
||||
#endif
|
||||
|
||||
return MA_SUCCESS;
|
||||
#else
|
||||
/* Exclusive mode not fully supported in UWP right now. */
|
||||
return MA_ERROR;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MA_WIN32_DESKTOP
|
||||
@@ -12867,7 +12869,7 @@ static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_context_get_device_info_from_MMDevice__wasapi(ma_context* pContext, ma_IMMDevice* pMMDevice, ma_share_mode shareMode, LPWSTR pDefaultDeviceID, ma_bool32 onlySimpleInfo, ma_device_info* pInfo)
|
||||
static ma_result ma_context_get_device_info_from_MMDevice__wasapi(ma_context* pContext, ma_IMMDevice* pMMDevice, LPWSTR pDefaultDeviceID, ma_bool32 onlySimpleInfo, ma_device_info* pInfo)
|
||||
{
|
||||
LPWSTR pDeviceID;
|
||||
HRESULT hr;
|
||||
@@ -12922,7 +12924,7 @@ static ma_result ma_context_get_device_info_from_MMDevice__wasapi(ma_context* pC
|
||||
ma_IAudioClient* pAudioClient;
|
||||
hr = ma_IMMDevice_Activate(pMMDevice, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioClient);
|
||||
if (SUCCEEDED(hr)) {
|
||||
ma_result result = ma_context_get_device_info_from_IAudioClient__wasapi(pContext, pMMDevice, pAudioClient, shareMode, pInfo);
|
||||
ma_result result = ma_context_get_device_info_from_IAudioClient__wasapi(pContext, pMMDevice, pAudioClient, pInfo);
|
||||
|
||||
ma_IAudioClient_Release(pAudioClient);
|
||||
return result;
|
||||
@@ -12966,7 +12968,7 @@ static ma_result ma_context_enumerate_devices_by_type__wasapi(ma_context* pConte
|
||||
|
||||
hr = ma_IMMDeviceCollection_Item(pDeviceCollection, iDevice, &pMMDevice);
|
||||
if (SUCCEEDED(hr)) {
|
||||
result = ma_context_get_device_info_from_MMDevice__wasapi(pContext, pMMDevice, ma_share_mode_shared, pDefaultDeviceID, MA_TRUE, &deviceInfo); /* MA_TRUE = onlySimpleInfo. */
|
||||
result = ma_context_get_device_info_from_MMDevice__wasapi(pContext, pMMDevice, pDefaultDeviceID, MA_TRUE, &deviceInfo); /* MA_TRUE = onlySimpleInfo. */
|
||||
|
||||
ma_IMMDevice_Release(pMMDevice);
|
||||
if (result == MA_SUCCESS) {
|
||||
@@ -13156,7 +13158,7 @@ static ma_result ma_context_enumerate_devices__wasapi(ma_context* pContext, ma_e
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_context_get_device_info__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
|
||||
static ma_result ma_context_get_device_info__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
|
||||
{
|
||||
#ifdef MA_WIN32_DESKTOP
|
||||
ma_result result;
|
||||
@@ -13171,7 +13173,7 @@ static ma_result ma_context_get_device_info__wasapi(ma_context* pContext, ma_dev
|
||||
/* We need the default device ID so we can set the isDefault flag in the device info. */
|
||||
pDefaultDeviceID = ma_context_get_default_device_id__wasapi(pContext, deviceType);
|
||||
|
||||
result = ma_context_get_device_info_from_MMDevice__wasapi(pContext, pMMDevice, shareMode, pDefaultDeviceID, MA_FALSE, pDeviceInfo); /* MA_FALSE = !onlySimpleInfo. */
|
||||
result = ma_context_get_device_info_from_MMDevice__wasapi(pContext, pMMDevice, pDefaultDeviceID, MA_FALSE, pDeviceInfo); /* MA_FALSE = !onlySimpleInfo. */
|
||||
|
||||
if (pDefaultDeviceID != NULL) {
|
||||
ma_CoTaskMemFree(pContext, pDefaultDeviceID);
|
||||
@@ -13202,7 +13204,7 @@ static ma_result ma_context_get_device_info__wasapi(ma_context* pContext, ma_dev
|
||||
return result;
|
||||
}
|
||||
|
||||
result = ma_context_get_device_info_from_IAudioClient__wasapi(pContext, NULL, pAudioClient, shareMode, pDeviceInfo);
|
||||
result = ma_context_get_device_info_from_IAudioClient__wasapi(pContext, NULL, pAudioClient, pDeviceInfo);
|
||||
|
||||
pDeviceInfo->isDefault = MA_TRUE; /* UWP only supports default devices. */
|
||||
|
||||
@@ -13211,7 +13213,7 @@ static ma_result ma_context_get_device_info__wasapi(ma_context* pContext, ma_dev
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ma_device_uninit__wasapi(ma_device* pDevice)
|
||||
static ma_result ma_device_uninit__wasapi(ma_device* pDevice)
|
||||
{
|
||||
MA_ASSERT(pDevice != NULL);
|
||||
|
||||
@@ -13242,6 +13244,8 @@ static void ma_device_uninit__wasapi(ma_device* pDevice)
|
||||
if (pDevice->wasapi.hEventCapture) {
|
||||
CloseHandle(pDevice->wasapi.hEventCapture);
|
||||
}
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -13255,10 +13259,10 @@ typedef struct
|
||||
ma_uint32 periodSizeInFramesIn;
|
||||
ma_uint32 periodSizeInMillisecondsIn;
|
||||
ma_uint32 periodsIn;
|
||||
ma_bool32 usingDefaultFormat;
|
||||
/*ma_bool32 usingDefaultFormat;
|
||||
ma_bool32 usingDefaultChannels;
|
||||
ma_bool32 usingDefaultSampleRate;
|
||||
ma_bool32 usingDefaultChannelMap;
|
||||
ma_bool32 usingDefaultChannelMap;*/
|
||||
ma_share_mode shareMode;
|
||||
ma_bool32 noAutoConvertSRC;
|
||||
ma_bool32 noDefaultQualitySRC;
|
||||
@@ -13305,10 +13309,10 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device
|
||||
pData->pCaptureClient = NULL;
|
||||
|
||||
streamFlags = MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
|
||||
if (!pData->noAutoConvertSRC && !pData->usingDefaultSampleRate && pData->shareMode != ma_share_mode_exclusive) { /* <-- Exclusive streams must use the native sample rate. */
|
||||
if (!pData->noAutoConvertSRC && pData->sampleRateIn != 0 && pData->shareMode != ma_share_mode_exclusive) { /* <-- Exclusive streams must use the native sample rate. */
|
||||
streamFlags |= MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM;
|
||||
}
|
||||
if (!pData->noDefaultQualitySRC && !pData->usingDefaultSampleRate && (streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) != 0) {
|
||||
if (!pData->noDefaultQualitySRC && pData->sampleRateIn != 0 && (streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) != 0) {
|
||||
streamFlags |= MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
|
||||
}
|
||||
if (deviceType == ma_device_type_loopback) {
|
||||
@@ -13409,7 +13413,7 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device
|
||||
*/
|
||||
nativeSampleRate = wf.Format.nSamplesPerSec;
|
||||
if (streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) {
|
||||
wf.Format.nSamplesPerSec = pData->sampleRateIn;
|
||||
wf.Format.nSamplesPerSec = (pData->sampleRateIn != 0) ? pData->sampleRateIn : MA_DEFAULT_SAMPLE_RATE;
|
||||
wf.Format.nAvgBytesPerSec = wf.Format.nSamplesPerSec * wf.Format.nBlockAlign;
|
||||
}
|
||||
|
||||
@@ -13437,7 +13441,7 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device
|
||||
ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pData->channelsOut, pData->channelMapOut);
|
||||
|
||||
/* Period size. */
|
||||
pData->periodsOut = pData->periodsIn;
|
||||
pData->periodsOut = (pData->periodsIn != 0) ? pData->periodsIn : MA_DEFAULT_PERIODS;
|
||||
pData->periodSizeInFramesOut = pData->periodSizeInFramesIn;
|
||||
if (pData->periodSizeInFramesOut == 0) {
|
||||
pData->periodSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn, wf.Format.nSamplesPerSec);
|
||||
@@ -13702,21 +13706,14 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev
|
||||
data.channelsIn = pDevice->playback.channels;
|
||||
MA_COPY_MEMORY(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap));
|
||||
data.shareMode = pDevice->playback.shareMode;
|
||||
data.usingDefaultFormat = pDevice->playback.usingDefaultFormat;
|
||||
data.usingDefaultChannels = pDevice->playback.usingDefaultChannels;
|
||||
data.usingDefaultChannelMap = pDevice->playback.usingDefaultChannelMap;
|
||||
} else {
|
||||
data.formatIn = pDevice->capture.format;
|
||||
data.channelsIn = pDevice->capture.channels;
|
||||
MA_COPY_MEMORY(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap));
|
||||
data.shareMode = pDevice->capture.shareMode;
|
||||
data.usingDefaultFormat = pDevice->capture.usingDefaultFormat;
|
||||
data.usingDefaultChannels = pDevice->capture.usingDefaultChannels;
|
||||
data.usingDefaultChannelMap = pDevice->capture.usingDefaultChannelMap;
|
||||
}
|
||||
|
||||
data.sampleRateIn = pDevice->sampleRate;
|
||||
data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
|
||||
data.periodSizeInFramesIn = pDevice->wasapi.originalPeriodSizeInFrames;
|
||||
data.periodSizeInMillisecondsIn = pDevice->wasapi.originalPeriodSizeInMilliseconds;
|
||||
data.periodsIn = pDevice->wasapi.originalPeriods;
|
||||
@@ -13804,7 +13801,7 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_device_init__wasapi(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
|
||||
static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_config* pConfig2, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
|
||||
{
|
||||
ma_result result = MA_SUCCESS;
|
||||
|
||||
@@ -13813,57 +13810,42 @@ static ma_result ma_device_init__wasapi(ma_context* pContext, const ma_device_co
|
||||
ma_IMMDeviceEnumerator* pDeviceEnumerator;
|
||||
#endif
|
||||
|
||||
(void)pContext;
|
||||
|
||||
MA_ASSERT(pContext != NULL);
|
||||
MA_ASSERT(pDevice != NULL);
|
||||
|
||||
MA_ZERO_OBJECT(&pDevice->wasapi);
|
||||
pDevice->wasapi.originalPeriodSizeInFrames = pConfig->periodSizeInFrames;
|
||||
pDevice->wasapi.originalPeriodSizeInMilliseconds = pConfig->periodSizeInMilliseconds;
|
||||
pDevice->wasapi.originalPeriods = pConfig->periods;
|
||||
pDevice->wasapi.noAutoConvertSRC = pConfig->wasapi.noAutoConvertSRC;
|
||||
pDevice->wasapi.noDefaultQualitySRC = pConfig->wasapi.noDefaultQualitySRC;
|
||||
pDevice->wasapi.noHardwareOffloading = pConfig->wasapi.noHardwareOffloading;
|
||||
pDevice->wasapi.noAutoConvertSRC = pConfig2->wasapi.noAutoConvertSRC;
|
||||
pDevice->wasapi.noDefaultQualitySRC = pConfig2->wasapi.noDefaultQualitySRC;
|
||||
pDevice->wasapi.noHardwareOffloading = pConfig2->wasapi.noHardwareOffloading;
|
||||
|
||||
/* Exclusive mode is not allowed with loopback. */
|
||||
if (pConfig->deviceType == ma_device_type_loopback && pConfig->playback.shareMode == ma_share_mode_exclusive) {
|
||||
if (pConfig2->deviceType == ma_device_type_loopback && pConfig2->playback.shareMode == ma_share_mode_exclusive) {
|
||||
return MA_INVALID_DEVICE_CONFIG;
|
||||
}
|
||||
|
||||
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) {
|
||||
if (pConfig2->deviceType == ma_device_type_capture || pConfig2->deviceType == ma_device_type_duplex || pConfig2->deviceType == ma_device_type_loopback) {
|
||||
ma_device_init_internal_data__wasapi data;
|
||||
data.formatIn = pConfig->capture.format;
|
||||
data.channelsIn = pConfig->capture.channels;
|
||||
data.sampleRateIn = pConfig->sampleRate;
|
||||
MA_COPY_MEMORY(data.channelMapIn, pConfig->capture.channelMap, sizeof(pConfig->capture.channelMap));
|
||||
data.usingDefaultFormat = pDevice->capture.usingDefaultFormat;
|
||||
data.usingDefaultChannels = pDevice->capture.usingDefaultChannels;
|
||||
data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
|
||||
data.usingDefaultChannelMap = pDevice->capture.usingDefaultChannelMap;
|
||||
data.shareMode = pConfig->capture.shareMode;
|
||||
data.periodSizeInFramesIn = pConfig->periodSizeInFrames;
|
||||
data.periodSizeInMillisecondsIn = pConfig->periodSizeInMilliseconds;
|
||||
data.periodsIn = pConfig->periods;
|
||||
data.noAutoConvertSRC = pConfig->wasapi.noAutoConvertSRC;
|
||||
data.noDefaultQualitySRC = pConfig->wasapi.noDefaultQualitySRC;
|
||||
data.noHardwareOffloading = pConfig->wasapi.noHardwareOffloading;
|
||||
data.formatIn = pDescriptorCapture->format;
|
||||
data.channelsIn = pDescriptorCapture->channels;
|
||||
data.sampleRateIn = pDescriptorCapture->sampleRate;
|
||||
MA_COPY_MEMORY(data.channelMapIn, pDescriptorCapture->channelMap, sizeof(pDescriptorCapture->channelMap));
|
||||
data.periodSizeInFramesIn = pDescriptorCapture->periodSizeInFrames;
|
||||
data.periodSizeInMillisecondsIn = pDescriptorCapture->periodSizeInMilliseconds;
|
||||
data.periodsIn = pDescriptorCapture->periodCount;
|
||||
data.shareMode = pDescriptorCapture->shareMode;
|
||||
data.noAutoConvertSRC = pConfig2->wasapi.noAutoConvertSRC;
|
||||
data.noDefaultQualitySRC = pConfig2->wasapi.noDefaultQualitySRC;
|
||||
data.noHardwareOffloading = pConfig2->wasapi.noHardwareOffloading;
|
||||
|
||||
result = ma_device_init_internal__wasapi(pDevice->pContext, (pConfig->deviceType == ma_device_type_loopback) ? ma_device_type_loopback : ma_device_type_capture, pConfig->capture.pDeviceID, &data);
|
||||
result = ma_device_init_internal__wasapi(pDevice->pContext, (pConfig2->deviceType == ma_device_type_loopback) ? ma_device_type_loopback : ma_device_type_capture, pDescriptorCapture->pDeviceID, &data);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
pDevice->wasapi.pAudioClientCapture = data.pAudioClient;
|
||||
pDevice->wasapi.pCaptureClient = data.pCaptureClient;
|
||||
|
||||
pDevice->capture.internalFormat = data.formatOut;
|
||||
pDevice->capture.internalChannels = data.channelsOut;
|
||||
pDevice->capture.internalSampleRate = data.sampleRateOut;
|
||||
MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
|
||||
pDevice->capture.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
|
||||
pDevice->capture.internalPeriods = data.periodsOut;
|
||||
ma_strcpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), data.deviceName);
|
||||
pDevice->wasapi.originalPeriodSizeInMilliseconds = pDescriptorCapture->periodSizeInMilliseconds;
|
||||
pDevice->wasapi.originalPeriodSizeInFrames = pDescriptorCapture->periodSizeInFrames;
|
||||
pDevice->wasapi.originalPeriods = pDescriptorCapture->periodCount;
|
||||
|
||||
/*
|
||||
The event for capture needs to be manual reset for the same reason as playback. We keep the initial state set to unsignaled,
|
||||
@@ -13888,29 +13870,33 @@ static ma_result ma_device_init__wasapi(ma_context* pContext, const ma_device_co
|
||||
|
||||
pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut;
|
||||
ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualPeriodSizeInFramesCapture);
|
||||
|
||||
/* The descriptor needs to be updated with actual values. */
|
||||
pDescriptorCapture->format = data.formatOut;
|
||||
pDescriptorCapture->channels = data.channelsOut;
|
||||
pDescriptorCapture->sampleRate = data.sampleRateOut;
|
||||
MA_COPY_MEMORY(pDescriptorCapture->channelMap, data.channelMapOut, sizeof(data.channelMapOut));
|
||||
pDescriptorCapture->periodSizeInFrames = data.periodSizeInFramesOut;
|
||||
pDescriptorCapture->periodCount = data.periodsOut;
|
||||
}
|
||||
|
||||
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
|
||||
if (pConfig2->deviceType == ma_device_type_playback || pConfig2->deviceType == ma_device_type_duplex) {
|
||||
ma_device_init_internal_data__wasapi data;
|
||||
data.formatIn = pConfig->playback.format;
|
||||
data.channelsIn = pConfig->playback.channels;
|
||||
data.sampleRateIn = pConfig->sampleRate;
|
||||
MA_COPY_MEMORY(data.channelMapIn, pConfig->playback.channelMap, sizeof(pConfig->playback.channelMap));
|
||||
data.usingDefaultFormat = pDevice->playback.usingDefaultFormat;
|
||||
data.usingDefaultChannels = pDevice->playback.usingDefaultChannels;
|
||||
data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
|
||||
data.usingDefaultChannelMap = pDevice->playback.usingDefaultChannelMap;
|
||||
data.shareMode = pConfig->playback.shareMode;
|
||||
data.periodSizeInFramesIn = pConfig->periodSizeInFrames;
|
||||
data.periodSizeInMillisecondsIn = pConfig->periodSizeInMilliseconds;
|
||||
data.periodsIn = pConfig->periods;
|
||||
data.noAutoConvertSRC = pConfig->wasapi.noAutoConvertSRC;
|
||||
data.noDefaultQualitySRC = pConfig->wasapi.noDefaultQualitySRC;
|
||||
data.noHardwareOffloading = pConfig->wasapi.noHardwareOffloading;
|
||||
data.formatIn = pDescriptorPlayback->format;
|
||||
data.channelsIn = pDescriptorPlayback->channels;
|
||||
data.sampleRateIn = pDescriptorPlayback->sampleRate;
|
||||
MA_COPY_MEMORY(data.channelMapIn, pDescriptorPlayback->channelMap, sizeof(pDescriptorPlayback->channelMap));
|
||||
data.periodSizeInFramesIn = pDescriptorPlayback->periodSizeInFrames;
|
||||
data.periodSizeInMillisecondsIn = pDescriptorPlayback->periodSizeInMilliseconds;
|
||||
data.periodsIn = pDescriptorPlayback->periodCount;
|
||||
data.shareMode = pDescriptorPlayback->shareMode;
|
||||
data.noAutoConvertSRC = pConfig2->wasapi.noAutoConvertSRC;
|
||||
data.noDefaultQualitySRC = pConfig2->wasapi.noDefaultQualitySRC;
|
||||
data.noHardwareOffloading = pConfig2->wasapi.noHardwareOffloading;
|
||||
|
||||
result = ma_device_init_internal__wasapi(pDevice->pContext, ma_device_type_playback, pConfig->playback.pDeviceID, &data);
|
||||
result = ma_device_init_internal__wasapi(pDevice->pContext, ma_device_type_playback, pDescriptorPlayback->pDeviceID, &data);
|
||||
if (result != MA_SUCCESS) {
|
||||
if (pConfig->deviceType == ma_device_type_duplex) {
|
||||
if (pConfig2->deviceType == ma_device_type_duplex) {
|
||||
if (pDevice->wasapi.pCaptureClient != NULL) {
|
||||
ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
|
||||
pDevice->wasapi.pCaptureClient = NULL;
|
||||
@@ -13928,14 +13914,9 @@ static ma_result ma_device_init__wasapi(ma_context* pContext, const ma_device_co
|
||||
|
||||
pDevice->wasapi.pAudioClientPlayback = data.pAudioClient;
|
||||
pDevice->wasapi.pRenderClient = data.pRenderClient;
|
||||
|
||||
pDevice->playback.internalFormat = data.formatOut;
|
||||
pDevice->playback.internalChannels = data.channelsOut;
|
||||
pDevice->playback.internalSampleRate = data.sampleRateOut;
|
||||
MA_COPY_MEMORY(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
|
||||
pDevice->playback.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
|
||||
pDevice->playback.internalPeriods = data.periodsOut;
|
||||
ma_strcpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), data.deviceName);
|
||||
pDevice->wasapi.originalPeriodSizeInMilliseconds = pDescriptorPlayback->periodSizeInMilliseconds;
|
||||
pDevice->wasapi.originalPeriodSizeInFrames = pDescriptorPlayback->periodSizeInFrames;
|
||||
pDevice->wasapi.originalPeriods = pDescriptorPlayback->periodCount;
|
||||
|
||||
/*
|
||||
The event for playback is needs to be manual reset because we want to explicitly control the fact that it becomes signalled
|
||||
@@ -13948,7 +13929,7 @@ static ma_result ma_device_init__wasapi(ma_context* pContext, const ma_device_co
|
||||
if (pDevice->wasapi.hEventPlayback == NULL) {
|
||||
result = ma_result_from_GetLastError(GetLastError());
|
||||
|
||||
if (pConfig->deviceType == ma_device_type_duplex) {
|
||||
if (pConfig2->deviceType == ma_device_type_duplex) {
|
||||
if (pDevice->wasapi.pCaptureClient != NULL) {
|
||||
ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
|
||||
pDevice->wasapi.pCaptureClient = NULL;
|
||||
@@ -13977,6 +13958,15 @@ static ma_result ma_device_init__wasapi(ma_context* pContext, const ma_device_co
|
||||
|
||||
pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut;
|
||||
ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualPeriodSizeInFramesPlayback);
|
||||
|
||||
|
||||
/* The descriptor needs to be updated with actual values. */
|
||||
pDescriptorPlayback->format = data.formatOut;
|
||||
pDescriptorPlayback->channels = data.channelsOut;
|
||||
pDescriptorPlayback->sampleRate = data.sampleRateOut;
|
||||
MA_COPY_MEMORY(pDescriptorPlayback->channelMap, data.channelMapOut, sizeof(data.channelMapOut));
|
||||
pDescriptorPlayback->periodSizeInFrames = data.periodSizeInFramesOut;
|
||||
pDescriptorPlayback->periodCount = data.periodsOut;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -13985,16 +13975,16 @@ static ma_result ma_device_init__wasapi(ma_context* pContext, const ma_device_co
|
||||
stop the device outright and let the application handle it.
|
||||
*/
|
||||
#ifdef MA_WIN32_DESKTOP
|
||||
if (pConfig->wasapi.noAutoStreamRouting == MA_FALSE) {
|
||||
if ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.pDeviceID == NULL) {
|
||||
if (pConfig2->wasapi.noAutoStreamRouting == MA_FALSE) {
|
||||
if ((pConfig2->deviceType == ma_device_type_capture || pConfig2->deviceType == ma_device_type_duplex) && pConfig2->capture.pDeviceID == NULL) {
|
||||
pDevice->wasapi.allowCaptureAutoStreamRouting = MA_TRUE;
|
||||
}
|
||||
if ((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.pDeviceID == NULL) {
|
||||
if ((pConfig2->deviceType == ma_device_type_playback || pConfig2->deviceType == ma_device_type_duplex) && pConfig2->playback.pDeviceID == NULL) {
|
||||
pDevice->wasapi.allowPlaybackAutoStreamRouting = MA_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
|
||||
hr = ma_CoCreateInstance(pDevice->pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
|
||||
if (FAILED(hr)) {
|
||||
ma_device_uninit__wasapi(pDevice);
|
||||
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.", ma_result_from_HRESULT(hr));
|
||||
@@ -14122,7 +14112,7 @@ static ma_result ma_device_stop__wasapi(ma_device* pDevice)
|
||||
}
|
||||
|
||||
|
||||
static ma_result ma_device_main_loop__wasapi(ma_device* pDevice)
|
||||
static ma_result ma_device_audio_thread__wasapi(ma_device* pDevice)
|
||||
{
|
||||
ma_result result;
|
||||
HRESULT hr;
|
||||
@@ -14742,7 +14732,7 @@ static ma_result ma_context_uninit__wasapi(ma_context* pContext)
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_context_init__wasapi(const ma_context_config* pConfig, ma_context* pContext)
|
||||
static ma_result ma_context_init__wasapi(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
|
||||
{
|
||||
ma_result result = MA_SUCCESS;
|
||||
|
||||
@@ -14755,7 +14745,7 @@ static ma_result ma_context_init__wasapi(const ma_context_config* pConfig, ma_co
|
||||
WASAPI is only supported in Vista SP1 and newer. The reason for SP1 and not the base version of Vista is that event-driven
|
||||
exclusive mode does not work until SP1.
|
||||
|
||||
Unfortunately older compilers don't define these functions so we need to dynamically load them in order to avoid a lin error.
|
||||
Unfortunately older compilers don't define these functions so we need to dynamically load them in order to avoid a link error.
|
||||
*/
|
||||
{
|
||||
ma_OSVERSIONINFOEXW osvi;
|
||||
@@ -14794,6 +14784,19 @@ static ma_result ma_context_init__wasapi(const ma_context_config* pConfig, ma_co
|
||||
return result;
|
||||
}
|
||||
|
||||
pCallbacks->onContextInit = ma_context_init__wasapi;
|
||||
pCallbacks->onContextUninit = ma_context_uninit__wasapi;
|
||||
pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__wasapi;
|
||||
pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__wasapi;
|
||||
pCallbacks->onDeviceInit = ma_device_init__wasapi;
|
||||
pCallbacks->onDeviceUninit = ma_device_uninit__wasapi;
|
||||
pCallbacks->onDeviceStart = NULL; /* Not used. Started in onDeviceAudioThread. */
|
||||
pCallbacks->onDeviceStop = ma_device_stop__wasapi; /* Required to ensure the capture event is signalled when stopping a loopback device while nothing is playing. */
|
||||
pCallbacks->onDeviceRead = NULL; /* Not used. Reading is done manually in the audio thread. */
|
||||
pCallbacks->onDeviceWrite = NULL; /* Not used. Writing is done manually in the audio thread. */
|
||||
pCallbacks->onDeviceAudioThread = ma_device_audio_thread__wasapi;
|
||||
|
||||
#if 0
|
||||
pContext->onUninit = ma_context_uninit__wasapi;
|
||||
pContext->onEnumDevices = ma_context_enumerate_devices__wasapi;
|
||||
pContext->onGetDeviceInfo = ma_context_get_device_info__wasapi;
|
||||
@@ -14802,6 +14805,7 @@ static ma_result ma_context_init__wasapi(const ma_context_config* pConfig, ma_co
|
||||
pContext->onDeviceStart = NULL; /* Not used. Started in onDeviceMainLoop. */
|
||||
pContext->onDeviceStop = ma_device_stop__wasapi; /* Required to ensure the capture event is signalled when stopping a loopback device while nothing is playing. */
|
||||
pContext->onDeviceMainLoop = ma_device_main_loop__wasapi;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -31841,7 +31845,7 @@ MA_API ma_context_config ma_context_config_init()
|
||||
MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pConfig, ma_context* pContext)
|
||||
{
|
||||
ma_result result;
|
||||
ma_context_config config;
|
||||
ma_context_config defaultConfig;
|
||||
ma_backend defaultBackends[ma_backend_null+1];
|
||||
ma_uint32 iBackend;
|
||||
ma_backend* pBackendsToIterate;
|
||||
@@ -31854,18 +31858,17 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC
|
||||
MA_ZERO_OBJECT(pContext);
|
||||
|
||||
/* Always make sure the config is set first to ensure properties are available as soon as possible. */
|
||||
if (pConfig != NULL) {
|
||||
config = *pConfig;
|
||||
} else {
|
||||
config = ma_context_config_init();
|
||||
if (pConfig == NULL) {
|
||||
defaultConfig = ma_context_config_init();
|
||||
pConfig = &defaultConfig;
|
||||
}
|
||||
|
||||
pContext->logCallback = config.logCallback;
|
||||
pContext->threadPriority = config.threadPriority;
|
||||
pContext->threadStackSize = config.threadStackSize;
|
||||
pContext->pUserData = config.pUserData;
|
||||
pContext->logCallback = pConfig->logCallback;
|
||||
pContext->threadPriority = pConfig->threadPriority;
|
||||
pContext->threadStackSize = pConfig->threadStackSize;
|
||||
pContext->pUserData = pConfig->pUserData;
|
||||
|
||||
result = ma_allocation_callbacks_init_copy(&pContext->allocationCallbacks, &config.allocationCallbacks);
|
||||
result = ma_allocation_callbacks_init_copy(&pContext->allocationCallbacks, &pConfig->allocationCallbacks);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
@@ -31906,11 +31909,17 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC
|
||||
|
||||
/* These backends are using the new callback system. */
|
||||
switch (backend) {
|
||||
#ifdef MA_HAS_WASAPI
|
||||
case ma_backend_wasapi:
|
||||
{
|
||||
pContext->callbacks.onContextInit = ma_context_init__wasapi;
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MA_HAS_CUSTOM
|
||||
case ma_backend_custom:
|
||||
{
|
||||
/* Slightly different logic for custom backends. Custom backends can optionally set all of their callbacks in the config. */
|
||||
pContext->callbacks = config.custom;
|
||||
pContext->callbacks = pConfig->custom;
|
||||
} break;
|
||||
#endif
|
||||
|
||||
@@ -31918,7 +31927,7 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC
|
||||
}
|
||||
|
||||
if (pContext->callbacks.onContextInit != NULL) {
|
||||
result = pContext->callbacks.onContextInit(pContext, &pContext->callbacks);
|
||||
result = pContext->callbacks.onContextInit(pContext, pConfig, &pContext->callbacks);
|
||||
} else {
|
||||
result = MA_NO_BACKEND;
|
||||
|
||||
@@ -31927,91 +31936,91 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC
|
||||
#ifdef MA_HAS_WASAPI
|
||||
case ma_backend_wasapi:
|
||||
{
|
||||
result = ma_context_init__wasapi(&config, pContext);
|
||||
/*result = ma_context_init__wasapi(&config, pContext);*/
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MA_HAS_DSOUND
|
||||
case ma_backend_dsound:
|
||||
{
|
||||
result = ma_context_init__dsound(&config, pContext);
|
||||
result = ma_context_init__dsound(pConfig, pContext);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MA_HAS_WINMM
|
||||
case ma_backend_winmm:
|
||||
{
|
||||
result = ma_context_init__winmm(&config, pContext);
|
||||
result = ma_context_init__winmm(pConfig, pContext);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MA_HAS_ALSA
|
||||
case ma_backend_alsa:
|
||||
{
|
||||
result = ma_context_init__alsa(&config, pContext);
|
||||
result = ma_context_init__alsa(pConfig, pContext);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MA_HAS_PULSEAUDIO
|
||||
case ma_backend_pulseaudio:
|
||||
{
|
||||
result = ma_context_init__pulse(&config, pContext);
|
||||
result = ma_context_init__pulse(pConfig, pContext);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MA_HAS_JACK
|
||||
case ma_backend_jack:
|
||||
{
|
||||
result = ma_context_init__jack(&config, pContext);
|
||||
result = ma_context_init__jack(pConfig, pContext);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MA_HAS_COREAUDIO
|
||||
case ma_backend_coreaudio:
|
||||
{
|
||||
result = ma_context_init__coreaudio(&config, pContext);
|
||||
result = ma_context_init__coreaudio(pConfig, pContext);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MA_HAS_SNDIO
|
||||
case ma_backend_sndio:
|
||||
{
|
||||
result = ma_context_init__sndio(&config, pContext);
|
||||
result = ma_context_init__sndio(pConfig, pContext);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MA_HAS_AUDIO4
|
||||
case ma_backend_audio4:
|
||||
{
|
||||
result = ma_context_init__audio4(&config, pContext);
|
||||
result = ma_context_init__audio4(pConfig, pContext);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MA_HAS_OSS
|
||||
case ma_backend_oss:
|
||||
{
|
||||
result = ma_context_init__oss(&config, pContext);
|
||||
result = ma_context_init__oss(pConfig, pContext);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MA_HAS_AAUDIO
|
||||
case ma_backend_aaudio:
|
||||
{
|
||||
result = ma_context_init__aaudio(&config, pContext);
|
||||
result = ma_context_init__aaudio(pConfig, pContext);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MA_HAS_OPENSL
|
||||
case ma_backend_opensl:
|
||||
{
|
||||
result = ma_context_init__opensl(&config, pContext);
|
||||
result = ma_context_init__opensl(pConfig, pContext);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MA_HAS_WEBAUDIO
|
||||
case ma_backend_webaudio:
|
||||
{
|
||||
result = ma_context_init__webaudio(&config, pContext);
|
||||
result = ma_context_init__webaudio(pConfig, pContext);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MA_HAS_CUSTOM
|
||||
case ma_backend_custom:
|
||||
{
|
||||
/*result = ma_context_init__custom(&config, pContext);*/
|
||||
/*result = ma_context_init__custom(pConfig, pContext);*/
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MA_HAS_NULL
|
||||
case ma_backend_null:
|
||||
{
|
||||
result = ma_context_init__null(&config, pContext);
|
||||
result = ma_context_init__null(pConfig, pContext);
|
||||
} break;
|
||||
#endif
|
||||
|
||||
@@ -32054,7 +32063,15 @@ MA_API ma_result ma_context_uninit(ma_context* pContext)
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (ma_context__is_using_new_callbacks(pContext)) {
|
||||
if (pContext->callbacks.onContextUninit != NULL) {
|
||||
pContext->callbacks.onContextUninit(pContext);
|
||||
}
|
||||
} else {
|
||||
if (pContext->onUninit != NULL) {
|
||||
pContext->onUninit(pContext);
|
||||
}
|
||||
}
|
||||
|
||||
ma_mutex_uninit(&pContext->deviceEnumLock);
|
||||
ma_mutex_uninit(&pContext->deviceInfoLock);
|
||||
@@ -32163,7 +32180,7 @@ MA_API ma_result ma_context_get_devices(ma_context* pContext, ma_device_info** p
|
||||
if (ppCaptureDeviceInfos != NULL) *ppCaptureDeviceInfos = NULL;
|
||||
if (pCaptureDeviceCount != NULL) *pCaptureDeviceCount = 0;
|
||||
|
||||
if (pContext == NULL || pContext->onEnumDevices == NULL) {
|
||||
if (pContext == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
@@ -32572,6 +32589,11 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
|
||||
descriptorPlayback.periodSizeInMilliseconds = pConfig->periodSizeInMilliseconds;
|
||||
descriptorPlayback.periodCount = pConfig->periods;
|
||||
|
||||
if (descriptorPlayback.periodSizeInMilliseconds == 0 && descriptorPlayback.periodSizeInFrames == 0) {
|
||||
descriptorPlayback.periodSizeInMilliseconds = (pConfig->performanceProfile == ma_performance_profile_low_latency) ? MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY : MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE;
|
||||
}
|
||||
|
||||
|
||||
MA_ZERO_OBJECT(&descriptorCapture);
|
||||
descriptorCapture.pDeviceID = pConfig->capture.pDeviceID;
|
||||
descriptorCapture.shareMode = pConfig->capture.shareMode;
|
||||
@@ -32583,7 +32605,12 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
|
||||
descriptorCapture.periodSizeInMilliseconds = pConfig->periodSizeInMilliseconds;
|
||||
descriptorCapture.periodCount = pConfig->periods;
|
||||
|
||||
result = pContext->callbacks.onDeviceInit(pDevice, config.deviceType, &descriptorPlayback, &descriptorCapture);
|
||||
if (descriptorCapture.periodSizeInMilliseconds == 0 && descriptorCapture.periodSizeInFrames == 0) {
|
||||
descriptorCapture.periodSizeInMilliseconds = (pConfig->performanceProfile == ma_performance_profile_low_latency) ? MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY : MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE;
|
||||
}
|
||||
|
||||
|
||||
result = pContext->callbacks.onDeviceInit(pDevice, pConfig, &descriptorPlayback, &descriptorCapture);
|
||||
if (result != MA_SUCCESS) {
|
||||
ma_event_uninit(&pDevice->startEvent);
|
||||
ma_event_uninit(&pDevice->wakeupEvent);
|
||||
@@ -32596,8 +32623,6 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
|
||||
the requested format and the internal format.
|
||||
*/
|
||||
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) {
|
||||
ma_device_info deviceInfo; /* For retrieving the name. */
|
||||
|
||||
if (!ma_device_descriptor_is_valid(&descriptorCapture)) {
|
||||
ma_device_uninit(pDevice);
|
||||
return MA_INVALID_ARGS;
|
||||
@@ -32613,24 +32638,9 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
|
||||
if (pDevice->capture.internalPeriodSizeInFrames == 0) {
|
||||
pDevice->capture.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(descriptorCapture.periodSizeInMilliseconds, descriptorCapture.sampleRate);
|
||||
}
|
||||
|
||||
/* The name of the device can be retrieved from device info. This may be temporary and replaced with a `ma_device_get_info()` instead. */
|
||||
result = ma_context_get_device_info(pContext, ma_device_type_capture, descriptorCapture.pDeviceID, descriptorCapture.shareMode, &deviceInfo);
|
||||
if (result == MA_SUCCESS) {
|
||||
ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), deviceInfo.name, (size_t)-1);
|
||||
} else {
|
||||
/* We failed to retrieve the device info. Fall back to a default name. */
|
||||
if (descriptorCapture.pDeviceID == NULL) {
|
||||
ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
|
||||
} else {
|
||||
ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), "Capture Device", (size_t)-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
|
||||
ma_device_info deviceInfo; /* For retrieving the name. */
|
||||
|
||||
if (!ma_device_descriptor_is_valid(&descriptorPlayback)) {
|
||||
ma_device_uninit(pDevice);
|
||||
return MA_INVALID_ARGS;
|
||||
@@ -32646,8 +32656,31 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
|
||||
if (pDevice->playback.internalPeriodSizeInFrames == 0) {
|
||||
pDevice->playback.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(descriptorPlayback.periodSizeInMilliseconds, descriptorPlayback.sampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
/* The name of the device can be retrieved from device info. This may be temporary and replaced with a `ma_device_get_info(pDevice, deviceType)` instead. */
|
||||
|
||||
/*
|
||||
The name of the device can be retrieved from device info. This may be temporary and replaced with a `ma_device_get_info(pDevice, deviceType)` instead.
|
||||
For loopback devices, we need to retrieve the name of the playback device.
|
||||
*/
|
||||
{
|
||||
ma_device_info deviceInfo;
|
||||
|
||||
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) {
|
||||
result = ma_context_get_device_info(pContext, (pConfig->deviceType == ma_device_type_loopback) ? ma_device_type_playback : ma_device_type_capture, descriptorCapture.pDeviceID, descriptorCapture.shareMode, &deviceInfo);
|
||||
if (result == MA_SUCCESS) {
|
||||
ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), deviceInfo.name, (size_t)-1);
|
||||
} else {
|
||||
/* We failed to retrieve the device info. Fall back to a default name. */
|
||||
if (descriptorCapture.pDeviceID == NULL) {
|
||||
ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
|
||||
} else {
|
||||
ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), "Capture Device", (size_t)-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
|
||||
result = ma_context_get_device_info(pContext, ma_device_type_playback, descriptorPlayback.pDeviceID, descriptorPlayback.shareMode, &deviceInfo);
|
||||
if (result == MA_SUCCESS) {
|
||||
ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), deviceInfo.name, (size_t)-1);
|
||||
@@ -32660,16 +32693,6 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the backend is asynchronous and the device is duplex, we'll need an intermediary ring buffer. */
|
||||
if (ma_context_is_backend_asynchronous(pContext)) {
|
||||
if (pConfig->deviceType == ma_device_type_duplex) {
|
||||
result = ma_duplex_rb_init(pDevice->sampleRate, pDevice->capture.internalFormat, pDevice->capture.internalChannels, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->duplexRB);
|
||||
if (result != MA_SUCCESS) {
|
||||
ma_device_uninit(pDevice);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = pContext->onDeviceInit(pContext, &config, pDevice);
|
||||
@@ -32697,6 +32720,22 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
|
||||
/* Wait for the worker thread to put the device into it's stopped state for real. */
|
||||
ma_event_wait(&pDevice->stopEvent);
|
||||
} else {
|
||||
/*
|
||||
If the backend is asynchronous and the device is duplex, we'll need an intermediary ring buffer. Note that this needs to be done
|
||||
after ma_device__post_init_setup().
|
||||
*/
|
||||
if (ma_context__is_using_new_callbacks(pContext)) { /* <-- TEMP: Will be removed once all asynchronous backends have been converted to the new callbacks. */
|
||||
if (ma_context_is_backend_asynchronous(pContext)) {
|
||||
if (pConfig->deviceType == ma_device_type_duplex) {
|
||||
result = ma_duplex_rb_init(pDevice->sampleRate, pDevice->capture.internalFormat, pDevice->capture.internalChannels, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->duplexRB);
|
||||
if (result != MA_SUCCESS) {
|
||||
ma_device_uninit(pDevice);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ma_device__set_state(pDevice, MA_STATE_STOPPED);
|
||||
}
|
||||
|
||||
@@ -63817,6 +63856,8 @@ REVISION HISTORY
|
||||
v0.10.25 - TBD
|
||||
- PulseAudio: Fix a bug where the stop callback isn't fired.
|
||||
- WebAudio: Fix an error that occurs when Emscripten increases the size of it's heap.
|
||||
- Custom Backends: Change the onContextInit and onDeviceInit callbacks to take a parameter which is a pointer to the config that was
|
||||
passed into ma_context_init() and ma_device_init(). This replaces the deviceType parameter of onDeviceInit.
|
||||
- Fix compilation warnings on older versions of GCC.
|
||||
|
||||
v0.10.24 - 2020-11-10
|
||||
|
||||
Reference in New Issue
Block a user