mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 08:14:04 +02:00
Initial untested work on an improved device enumeration API.
This commit is contained in:
@@ -648,7 +648,7 @@ typedef union
|
||||
int sdl; // SDL devices are identified with an index.
|
||||
#endif
|
||||
#ifdef MAL_SUPPORT_NULL
|
||||
int nullbackend; // Always 0.
|
||||
int nullbackend; // The null backend uses an integer for device IDs.
|
||||
#endif
|
||||
} mal_device_id;
|
||||
|
||||
@@ -791,10 +791,22 @@ typedef struct
|
||||
} jack;
|
||||
} mal_context_config;
|
||||
|
||||
typedef mal_bool32 (* mal_enum_devices_callback_proc)(mal_context* pContext, mal_device_type type, const mal_device_info* pInfo, void* pUserData);
|
||||
|
||||
struct mal_context
|
||||
{
|
||||
mal_backend backend; // DirectSound, ALSA, etc.
|
||||
mal_backend backend; // DirectSound, ALSA, etc.
|
||||
mal_context_config config;
|
||||
mal_mutex deviceEnumLock; // Used to make mal_context_get_devices() thread safe.
|
||||
mal_mutex deviceInfoLock; // Used to make mal_context_get_device_info() thread safe.
|
||||
mal_uint32 deviceInfoCapacity; // Total capacity of pDeviceInfos.
|
||||
mal_uint32 playbackDeviceInfoCount;
|
||||
mal_uint32 captureDeviceInfoCount;
|
||||
mal_device_info* pDeviceInfos; // Playback devices first, then capture.
|
||||
|
||||
mal_result (* onEnumDevices )(mal_context* pContext, mal_enum_devices_callback_proc callback, void* pUserData); // Return false from the callback to stop enumeration.
|
||||
mal_result (* onGetDeviceInfo)(mal_context* pContext, mal_device_type type, const mal_device_id* pDeviceID, mal_device_info* pDeviceInfo);
|
||||
mal_bool32 (* onDeviceIDEqual)(mal_context* pContext, const mal_device_id* pID0, const mal_device_id* pID1);
|
||||
|
||||
union
|
||||
{
|
||||
@@ -1140,7 +1152,7 @@ struct mal_device
|
||||
mal_format format;
|
||||
mal_uint32 channels;
|
||||
mal_uint32 sampleRate;
|
||||
mal_uint8 channelMap[MAL_MAX_CHANNELS];
|
||||
mal_channel channelMap[MAL_MAX_CHANNELS];
|
||||
mal_uint32 bufferSizeInFrames;
|
||||
mal_uint32 periods;
|
||||
mal_uint32 state;
|
||||
@@ -1166,7 +1178,7 @@ struct mal_device
|
||||
mal_format internalFormat;
|
||||
mal_uint32 internalChannels;
|
||||
mal_uint32 internalSampleRate;
|
||||
mal_uint8 internalChannelMap[MAL_MAX_CHANNELS];
|
||||
mal_channel internalChannelMap[MAL_MAX_CHANNELS];
|
||||
mal_dsp dsp; // Samples run through this to convert samples to a format suitable for use by the backend.
|
||||
mal_uint32 _dspFrameCount; // Internal use only. Used when running the device -> DSP -> client pipeline. See mal_device__on_read_from_device().
|
||||
const mal_uint8* _dspFrames; // ^^^ AS ABOVE ^^^
|
||||
@@ -1351,6 +1363,65 @@ mal_result mal_context_init(const mal_backend backends[], mal_uint32 backendCoun
|
||||
// Thread Safety: UNSAFE
|
||||
mal_result mal_context_uninit(mal_context* pContext);
|
||||
|
||||
// Enumerates over every device (both playback and capture).
|
||||
//
|
||||
// This is a lower-level enumeration function to the easier to use mal_context_get_devices(). Use
|
||||
// this if you would rather not incur an internal heap allocation, or it simply suits you program
|
||||
// better.
|
||||
//
|
||||
// Do _not_ assume the first device in the returned lists are the default devices.
|
||||
//
|
||||
// Some backends and platforms may only support default playback and capture devices.
|
||||
//
|
||||
// Note that this only retrieves the ID and name/description of the device. The reason for only
|
||||
// retrieving basic information is that it would otherwise require opening the backend device in
|
||||
// order to probe it for more detailed information which can be inefficient. Consider using
|
||||
// mal_context_get_device_info() for this, but do _not_ call it in the enumeration callback or
|
||||
// else you can end up in a deadlock. In general, you should not do anything complicated from
|
||||
// within the callback.
|
||||
//
|
||||
// Consider using mal_context_get_devices() for a simpler and safer API.
|
||||
//
|
||||
// Returning false from the callback will stop enumeration.
|
||||
//
|
||||
// Return Value:
|
||||
// MAL_SUCCESS if successful; any other error code otherwise.
|
||||
//
|
||||
// Thread Safety: SAFE
|
||||
// This is guarded using a simple mutex lock. You cannot call mal_context_get_device_info() from
|
||||
// within the callback because otherwise you can end up in a deadlock.
|
||||
mal_result mal_context_enumerate_devices(mal_context* pContext, mal_enum_devices_callback_proc callback, void* pUserData);
|
||||
|
||||
// Retrieves basic information about every active playback and/or capture device.
|
||||
//
|
||||
// You can pass in NULL for the playback or capture lists in which case they'll be ignored.
|
||||
//
|
||||
// The returned pointers will become invalid upon the next call this this function, or when the
|
||||
// context is uninitialized. Do not free the returned pointers.
|
||||
//
|
||||
// This function follows the same enumeration rules as mal_context_enumerate_devices(). See
|
||||
// documentation for mal_context_enumerate_devices() for more information.
|
||||
//
|
||||
// Return Value:
|
||||
// MAL_SUCCESS if successful; any other error code otherwise.
|
||||
//
|
||||
// Thread Safety: SAFE
|
||||
// Since each call to this function invalidates the pointers from the previous call, you
|
||||
// should not be calling this simultaneously across multiple threads. Instead, you need to
|
||||
// make a copy of the returned data with your own higher level synchronization.
|
||||
mal_result mal_context_get_devices(mal_context* pContext, mal_device_info** ppPlaybackDeviceInfos, mal_uint32* pPlaybackDeviceCount, mal_device_info** ppCaptureDeviceInfos, mal_uint32* pCaptureDeviceCount);
|
||||
|
||||
// Retrieves information about a device with the given ID.
|
||||
//
|
||||
// Do _not_ call this from within the mal_context_enumerate_devices_callback().
|
||||
//
|
||||
// Return Value:
|
||||
// MAL_SUCCESS if successful; any other error code otherwise.
|
||||
//
|
||||
// Thread Safety: SAFE
|
||||
// This is guarded using a simple mutex lock.
|
||||
mal_result mal_context_get_device_info(mal_context* pContext, mal_device_type type, const mal_device_id* pDeviceID, mal_device_info* pDeviceInfo);
|
||||
|
||||
// Enumerates over each device of the given type (playback or capture).
|
||||
//
|
||||
// It is _not_ safe to assume the first enumerated device is the default device.
|
||||
@@ -2099,6 +2170,9 @@ static mal_uint32 g_malStandardSampleRatePriorities[] = {
|
||||
MAL_SAMPLE_RATE_384000
|
||||
};
|
||||
|
||||
#define MAL_DEFAULT_PLAYBACK_DEVICE_NAME "Default Playback Device"
|
||||
#define MAL_DEFAULT_CAPTURE_DEVICE_NAME "Default Capture Device"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Standard Library Stuff
|
||||
@@ -3129,6 +3203,19 @@ static inline mal_uint32 mal_device__get_state(mal_device* pDevice)
|
||||
#endif
|
||||
|
||||
|
||||
static mal_bool32 mal_context__device_id_equal(mal_context* pContext, const mal_device_id* pID0, const mal_device_id* pID1)
|
||||
{
|
||||
mal_assert(pContext != NULL);
|
||||
|
||||
if (pID0 == pID1) return MAL_TRUE;
|
||||
|
||||
if (pContext->onDeviceIDEqual) {
|
||||
return pContext->onDeviceIDEqual(pContext, pID0, pID1);
|
||||
}
|
||||
|
||||
return MAL_FALSE;
|
||||
}
|
||||
|
||||
// Generic function for retrieving the name of a device by it's ID.
|
||||
//
|
||||
// This function simply enumerates every device and then retrieves the name of the first device that has the same ID.
|
||||
@@ -4185,10 +4272,10 @@ static mal_result mal_enumerate_devices__wasapi(mal_context* pContext, mal_devic
|
||||
if (infoSize > 0) {
|
||||
if (type == mal_device_type_playback) {
|
||||
mal_copy_memory(pInfo->id.wasapi, &MAL_IID_DEVINTERFACE_AUDIO_RENDER, sizeof(MAL_IID_DEVINTERFACE_AUDIO_RENDER));
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Playback Device", (size_t)-1);
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), MAL_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
|
||||
} else {
|
||||
mal_copy_memory(pInfo->id.wasapi, &MAL_IID_DEVINTERFACE_AUDIO_CAPTURE, sizeof(MAL_IID_DEVINTERFACE_AUDIO_CAPTURE));
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Capture Device", (size_t)-1);
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), MAL_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
|
||||
}
|
||||
|
||||
pInfo += 1;
|
||||
@@ -9687,9 +9774,9 @@ mal_result mal_enumerate_devices__jack(mal_context* pContext, mal_device_type ty
|
||||
if (infoSize > 0) {
|
||||
pInfo[0].id.jack = 0;
|
||||
if (type == mal_device_type_playback) {
|
||||
mal_strncpy_s(pInfo[0].name, sizeof(pInfo[0].name), "Default Playback Device", (size_t)-1);
|
||||
mal_strncpy_s(pInfo[0].name, sizeof(pInfo[0].name), MAL_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
|
||||
} else {
|
||||
mal_strncpy_s(pInfo[0].name, sizeof(pInfo[0].name), "Default Capture Device", (size_t)-1);
|
||||
mal_strncpy_s(pInfo[0].name, sizeof(pInfo[0].name), MAL_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
|
||||
}
|
||||
|
||||
*pCount = 1;
|
||||
@@ -10069,9 +10156,9 @@ static mal_result mal_enumerate_devices__oss(mal_context* pContext, mal_device_t
|
||||
if (infoSize > 0) {
|
||||
mal_strncpy_s(pInfo[0].id.oss, sizeof(pInfo[0].id.oss), "/dev/dsp", (size_t)-1);
|
||||
if (type == mal_device_type_playback) {
|
||||
mal_strncpy_s(pInfo[0].name, sizeof(pInfo[0].name), "Default Playback Device", (size_t)-1);
|
||||
mal_strncpy_s(pInfo[0].name, sizeof(pInfo[0].name), MAL_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
|
||||
} else {
|
||||
mal_strncpy_s(pInfo[0].name, sizeof(pInfo[0].name), "Default Capture Device", (size_t)-1);
|
||||
mal_strncpy_s(pInfo[0].name, sizeof(pInfo[0].name), MAL_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
|
||||
}
|
||||
|
||||
*pCount = 1;
|
||||
@@ -10584,10 +10671,10 @@ return_default_device:
|
||||
if (infoSize > 0) {
|
||||
if (type == mal_device_type_playback) {
|
||||
pInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOOUTPUT;
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Playback Device", (size_t)-1);
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), MAL_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
|
||||
} else {
|
||||
pInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOINPUT;
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Capture Device", (size_t)-1);
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), MAL_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11403,10 +11490,10 @@ mal_result mal_enumerate_devices__openal(mal_context* pContext, mal_device_type
|
||||
if (infoSize > 0) {
|
||||
if (type == mal_device_type_playback) {
|
||||
pInfo->id.sdl = 0;
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Playback Device", (size_t)-1);
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), MAL_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
|
||||
} else {
|
||||
pInfo->id.sdl = 0;
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Capture Device", (size_t)-1);
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), MAL_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
|
||||
}
|
||||
|
||||
pInfo += 1;
|
||||
@@ -12030,10 +12117,10 @@ mal_result mal_enumerate_devices__sdl(mal_context* pContext, mal_device_type typ
|
||||
// SDL1 uses default devices.
|
||||
if (type == mal_device_type_playback) {
|
||||
pInfo->id.sdl = 0;
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Playback Device", (size_t)-1);
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), MAL_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
|
||||
} else {
|
||||
pInfo->id.sdl = 0;
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Capture Device", (size_t)-1);
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), MAL_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
|
||||
}
|
||||
|
||||
pInfo += 1;
|
||||
@@ -12750,11 +12837,21 @@ mal_result mal_context_init(const mal_backend backends[], mal_uint32 backendCoun
|
||||
|
||||
// If this iteration was successful, return.
|
||||
if (result == MAL_SUCCESS) {
|
||||
result = mal_mutex_init(pContext, &pContext->deviceEnumLock);
|
||||
if (result != MAL_SUCCESS) {
|
||||
mal_context_post_error(pContext, NULL, "WARNING: Failed to initialize mutex for device enumeration. mal_context_get_devices() is not thread safe.", MAL_FAILED_TO_CREATE_MUTEX);
|
||||
}
|
||||
result = mal_mutex_init(pContext, &pContext->deviceInfoLock);
|
||||
if (result != MAL_SUCCESS) {
|
||||
mal_context_post_error(pContext, NULL, "WARNING: Failed to initialize mutex for device info retrieval. mal_context_get_device_info() is not thread safe.", MAL_FAILED_TO_CREATE_MUTEX);
|
||||
}
|
||||
|
||||
pContext->backend = backend;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here it means an error occurred.
|
||||
mal_zero_object(pContext); // Safety.
|
||||
return MAL_NO_BACKEND;
|
||||
}
|
||||
@@ -12835,12 +12932,196 @@ mal_result mal_context_uninit(mal_context* pContext)
|
||||
}
|
||||
|
||||
mal_context_uninit_backend_apis(pContext);
|
||||
mal_mutex_uninit(&pContext->deviceEnumLock);
|
||||
|
||||
mal_assert(MAL_FALSE);
|
||||
return MAL_NO_BACKEND;
|
||||
}
|
||||
|
||||
|
||||
mal_result mal_context_enumerate_devices(mal_context* pContext, mal_enum_devices_callback_proc callback, void* pUserData)
|
||||
{
|
||||
if (pContext == NULL || pContext->onEnumDevices == NULL || callback == NULL) return MAL_INVALID_ARGS;
|
||||
|
||||
mal_result result;
|
||||
mal_mutex_lock(&pContext->deviceEnumLock);
|
||||
{
|
||||
result = pContext->onEnumDevices(pContext, callback, pUserData);
|
||||
}
|
||||
mal_mutex_unlock(&pContext->deviceEnumLock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
mal_bool32 mal_context_get_devices__enum_callback(mal_context* pContext, mal_device_type type, const mal_device_info* pInfo, void* pUserData)
|
||||
{
|
||||
(void)pUserData;
|
||||
|
||||
// We need to insert the device info into our main internal buffer. Where it goes depends on the device type. If it's a capture device
|
||||
// it's just appended to the end. If it's a playback device it's inserted just before the first capture device.
|
||||
|
||||
// First make sure we have room. Since the number of devices we add to the list is usually relatively small I've decided to use a
|
||||
// simple fixed size increment for buffer expansion.
|
||||
const mal_uint32 bufferExpansionCount = 2;
|
||||
const mal_uint32 totalDeviceInfoCount = pContext->playbackDeviceInfoCount + pContext->captureDeviceInfoCount;
|
||||
|
||||
if (pContext->deviceInfoCapacity >= totalDeviceInfoCount) {
|
||||
mal_uint32 newCapacity = totalDeviceInfoCount + bufferExpansionCount;
|
||||
mal_device_info* pNewInfos = (mal_device_info*)mal_realloc(pContext->pDeviceInfos, sizeof(*pContext->pDeviceInfos)*newCapacity);
|
||||
if (pNewInfos == NULL) {
|
||||
return MAL_FALSE; // Out of memory.
|
||||
}
|
||||
|
||||
pContext->pDeviceInfos = pNewInfos;
|
||||
pContext->deviceInfoCapacity = newCapacity;
|
||||
}
|
||||
|
||||
if (type == mal_device_type_playback) {
|
||||
// Playback. Insert just before the first capture device.
|
||||
|
||||
// The first thing to do is move all of the capture devices down a slot.
|
||||
mal_uint32 iFirstCaptureDevice = pContext->playbackDeviceInfoCount;
|
||||
for (size_t iCaptureDevice = totalDeviceInfoCount; iCaptureDevice > iFirstCaptureDevice; --iCaptureDevice) {
|
||||
pContext->pDeviceInfos[iCaptureDevice] = pContext->pDeviceInfos[iCaptureDevice-1];
|
||||
}
|
||||
|
||||
// Now just insert where the first capture device was before moving it down a slot.
|
||||
pContext->pDeviceInfos[iFirstCaptureDevice] = *pInfo;
|
||||
pContext->playbackDeviceInfoCount += 1;
|
||||
} else {
|
||||
// Capture. Insert at the end.
|
||||
pContext->pDeviceInfos[totalDeviceInfoCount] = *pInfo;
|
||||
pContext->captureDeviceInfoCount += 1;
|
||||
}
|
||||
|
||||
return MAL_TRUE;
|
||||
}
|
||||
|
||||
mal_result mal_context_get_devices(mal_context* pContext, mal_device_info** ppPlaybackDeviceInfos, mal_uint32* pPlaybackDeviceCount, mal_device_info** ppCaptureDeviceInfos, mal_uint32* pCaptureDeviceCount)
|
||||
{
|
||||
// Safety.
|
||||
if (ppPlaybackDeviceInfos != NULL) *ppPlaybackDeviceInfos = NULL;
|
||||
if (pPlaybackDeviceCount != NULL) *pPlaybackDeviceCount = 0;
|
||||
if (ppCaptureDeviceInfos != NULL) *ppCaptureDeviceInfos = NULL;
|
||||
if (pCaptureDeviceCount != NULL) *pCaptureDeviceCount = 0;
|
||||
|
||||
if (pContext == NULL || pContext->onEnumDevices == NULL) return MAL_INVALID_ARGS;
|
||||
|
||||
// Note that we don't use mal_context_enumerate_devices() here because we want to do locking at a higher level.
|
||||
mal_result result;
|
||||
mal_mutex_lock(&pContext->deviceEnumLock);
|
||||
{
|
||||
// Reset everything first.
|
||||
pContext->playbackDeviceInfoCount = 0;
|
||||
pContext->captureDeviceInfoCount = 0;
|
||||
|
||||
// Now enumerate over available devices.
|
||||
result = pContext->onEnumDevices(pContext, mal_context_get_devices__enum_callback, NULL);
|
||||
if (result == MAL_SUCCESS) {
|
||||
// Playback devices.
|
||||
if (ppPlaybackDeviceInfos != NULL) {
|
||||
*ppPlaybackDeviceInfos = pContext->pDeviceInfos;
|
||||
}
|
||||
if (pPlaybackDeviceCount != NULL) {
|
||||
*pPlaybackDeviceCount = pContext->playbackDeviceInfoCount;
|
||||
}
|
||||
|
||||
// Capture devices.
|
||||
if (ppCaptureDeviceInfos != NULL) {
|
||||
*ppCaptureDeviceInfos = pContext->pDeviceInfos + pContext->playbackDeviceInfoCount; // Capture devices come after playback devices.
|
||||
}
|
||||
if (pCaptureDeviceCount != NULL) {
|
||||
*pCaptureDeviceCount = pContext->captureDeviceInfoCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
mal_mutex_unlock(&pContext->deviceEnumLock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mal_device_type type;
|
||||
const mal_device_id* pDeviceID;
|
||||
mal_device_info* pDeviceInfo;
|
||||
} mal_context_get_device_info__enum_callback_data;
|
||||
|
||||
static mal_bool32 mal_context_get_device_info__enum_callback(mal_context* pContext, mal_device_type type, const mal_device_info* pInfoIn, void* pUserData)
|
||||
{
|
||||
mal_context_get_device_info__enum_callback_data* pData = (mal_context_get_device_info__enum_callback_data*)pUserData;
|
||||
mal_assert(pData != NULL);
|
||||
|
||||
if (type == pData->type && mal_context__device_id_equal(pContext, &pInfoIn->id, pData->pDeviceID)) {
|
||||
// Found it. Copy the info and stop iteration.
|
||||
if (pData->pDeviceInfo != NULL) {
|
||||
*pData->pDeviceInfo = *pInfoIn;
|
||||
}
|
||||
|
||||
return MAL_FALSE; // Stop iteration.
|
||||
} else {
|
||||
// Didn't find it. Continue.
|
||||
return MAL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
mal_result mal_context_get_device_info(mal_context* pContext, mal_device_type type, const mal_device_id* pDeviceID, mal_device_info* pDeviceInfo)
|
||||
{
|
||||
// Safety.
|
||||
if (pDeviceInfo != NULL) {
|
||||
mal_zero_object(pDeviceInfo);
|
||||
}
|
||||
|
||||
if (pContext == NULL) return MAL_INVALID_ARGS;
|
||||
|
||||
// The backend may have an optimized device info retrieval function. If so, try that first.
|
||||
if (pContext->onGetDeviceInfo != NULL) {
|
||||
mal_result result;
|
||||
mal_mutex_lock(&pContext->deviceInfoLock);
|
||||
{
|
||||
result = pContext->onGetDeviceInfo(pContext, type, pDeviceID, pDeviceInfo);
|
||||
}
|
||||
mal_mutex_unlock(&pContext->deviceInfoLock);
|
||||
|
||||
if (result == MAL_SUCCESS) {
|
||||
return MAL_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here it means the backend does not have a method for retrieving detailed information about the
|
||||
// device. In this case we fall back to retrieving just basic information. To do this we enumerate over the
|
||||
// devices. If the device ID is null we just use a simple default name. This is where the potential for a
|
||||
// deadlock comes into play.
|
||||
if (pDeviceID != NULL) {
|
||||
mal_result result = MAL_NO_DEVICE;
|
||||
|
||||
if (pContext->onEnumDevices == NULL) {
|
||||
return MAL_NO_DEVICE;
|
||||
}
|
||||
|
||||
mal_context_get_device_info__enum_callback_data data;
|
||||
data.type = type;
|
||||
data.pDeviceID = pDeviceID;
|
||||
data.pDeviceInfo = pDeviceInfo;
|
||||
return mal_context_enumerate_devices(pContext, mal_context_get_device_info__enum_callback, &data);
|
||||
} else {
|
||||
// It's asking for the default device. We don't have a way to retrieve advanced info so we just stick
|
||||
// with the name.
|
||||
if (pDeviceInfo != NULL) {
|
||||
if (type == mal_device_type_playback) {
|
||||
mal_strcpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MAL_DEFAULT_PLAYBACK_DEVICE_NAME);
|
||||
} else {
|
||||
mal_strcpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MAL_DEFAULT_CAPTURE_DEVICE_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
return MAL_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mal_result mal_enumerate_devices(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo)
|
||||
{
|
||||
if (pCount == NULL) return mal_post_error(NULL, "mal_enumerate_devices() called with invalid arguments (pCount == 0).", MAL_INVALID_ARGS);
|
||||
@@ -13123,9 +13404,9 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi
|
||||
// We failed to get the device name, so fall back to some generic names.
|
||||
if (pDeviceID == NULL) {
|
||||
if (type == mal_device_type_playback) {
|
||||
mal_strncpy_s(pDevice->name, sizeof(pDevice->name), "Default Playback Device", (size_t)-1);
|
||||
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), "Default Capture Device", (size_t)-1);
|
||||
mal_strncpy_s(pDevice->name, sizeof(pDevice->name), MAL_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
|
||||
}
|
||||
} else {
|
||||
if (type == mal_device_type_playback) {
|
||||
|
||||
Reference in New Issue
Block a user