audio(4): Fix enumeration on OpenBSD.

This commit is contained in:
David Reid
2026-01-15 10:23:04 +10:00
parent 6c0c35387d
commit b4a26d21dd
+108 -5
View File
@@ -37972,6 +37972,7 @@ static void ma_context_uninit__audio4(ma_context* pContext)
ma_free(pContextStateAudio4, ma_context_get_allocation_callbacks(pContext));
}
#if !defined(MA_AUDIO4_USE_NEW_API) /* Old API */
static void ma_construct_device_id__audio4(char* id, size_t idSize, const char* base, int deviceIndex)
{
size_t baseLen;
@@ -37987,8 +37988,6 @@ static void ma_construct_device_id__audio4(char* id, size_t idSize, const char*
ma_itoa_s(deviceIndex, id+baseLen, idSize-baseLen, 10);
}
#if !defined(MA_AUDIO4_USE_NEW_API) /* Old API */
static ma_format ma_format_from_encoding__audio4(unsigned int encoding, unsigned int precision)
{
if (precision == 8 && (encoding == AUDIO_ENCODING_ULINEAR || encoding == AUDIO_ENCODING_ULINEAR || encoding == AUDIO_ENCODING_ULINEAR_LE || encoding == AUDIO_ENCODING_ULINEAR_BE)) {
@@ -38127,6 +38126,7 @@ static ma_format ma_format_from_swpar__audio4(struct audio_swpar* par)
}
#endif
#if !defined(MA_AUDIO4_USE_NEW_API) /* Old API */
static ma_result ma_context_get_device_info_from_fd__audio4(int fd, int deviceIndex, struct stat* stDevice, struct stat* stDefault, ma_device_type deviceType, ma_device_info* pDeviceInfo)
{
audio_device_t fdDevice;
@@ -38240,17 +38240,20 @@ static ma_device_enumeration_result ma_context_enumerate_device_from_fd___audio4
return callback(deviceType, &deviceInfo, pUserData);
}
#endif
static ma_result ma_context_enumerate_devices__audio4(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(callback != NULL);
#if !defined(MA_AUDIO4_USE_NEW_API) /* Old API */
{
const int maxDevices = 64;
char devpath[256];
int iDevice;
struct stat stDefault;
MA_ASSERT(pContext != NULL);
MA_ASSERT(callback != NULL);
if (stat("/dev/audioctl", &stDefault) < 0) {
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[audio4] Failed to open /dev/audioctl. Backend not usable.");
return MA_NO_BACKEND;
@@ -38296,6 +38299,98 @@ static ma_result ma_context_enumerate_devices__audio4(ma_context* pContext, ma_e
break;
}
}
}
#else
{
DIR *d = opendir("/dev");
struct dirent *e;
ma_bool32 isTerminating = MA_FALSE;
while ((e = readdir(d)) != NULL) {
size_t audioctlLen = strlen("audioctl");
if (isTerminating) {
break;
}
if (strncmp(e->d_name, "audioctl", audioctlLen) == 0 && strspn(e->d_name+audioctlLen, "0123456789") == strlen(e->d_name+audioctlLen)) {
char devnodectl[256];
int audioctlFD;
ma_strcpy_s(devnodectl, sizeof(devnodectl), "/dev/");
ma_strcat_s(devnodectl, sizeof(devnodectl), e->d_name);
audioctlFD = open(devnodectl, O_WRONLY);
if (audioctlFD >= 0) {
char devnode[256];
audio_device_t audioDevice;
struct audio_swpar audioPar;
ma_strcpy_s(devnode, sizeof(devnode), "/dev/audio");
ma_strcat_s(devnode, sizeof(devnode), e->d_name+audioctlLen);
MA_ZERO_OBJECT(&audioDevice);
if (ioctl(audioctlFD, AUDIO_GETDEV, &audioDevice) >= 0) {
ma_device_info deviceInfo;
int audioFD;
MA_ZERO_OBJECT(&deviceInfo);
/* We just treat `/dev/audio0` as the default. */
if (strcmp(e->d_name+audioctlLen, "0") == 0) {
deviceInfo.isDefault = MA_TRUE;
} else {
deviceInfo.isDefault = MA_FALSE;
}
/* ID. */
ma_strcpy_s(deviceInfo.id.audio4, sizeof(deviceInfo.id.audio4), devnode);
/* Name. */
ma_strcpy_s(deviceInfo.name, sizeof(deviceInfo.name), audioDevice.name);
/* Formats. */
if (ioctl(audioctlFD, AUDIO_GETPAR, &audioPar) >= 0) {
deviceInfo.nativeDataFormats[deviceInfo.nativeDataFormatCount].format = ma_format_from_swpar__audio4(&audioPar);
deviceInfo.nativeDataFormats[deviceInfo.nativeDataFormatCount].channels = 0; /* Filled out below because it's reported as separate values for capture and playback. */
deviceInfo.nativeDataFormats[deviceInfo.nativeDataFormatCount].sampleRate = audioPar.rate;
deviceInfo.nativeDataFormatCount += 1;
}
/* We need to try opening the device to check if it's a playback or capture device. */
if (!isTerminating) {
audioFD = open(devnode, O_WRONLY | O_NONBLOCK);
if (audioFD >= 0) {
deviceInfo.nativeDataFormats[0].channels = audioPar.pchan;
isTerminating = (callback(ma_device_type_playback, &deviceInfo, pUserData) == MA_DEVICE_ENUMERATION_ABORT);
}
close(audioFD);
}
if (!isTerminating) {
audioFD = open(devnode, O_RDONLY | O_NONBLOCK);
if (audioFD >= 0) {
deviceInfo.nativeDataFormats[0].channels = audioPar.rchan;
isTerminating = (callback(ma_device_type_capture, &deviceInfo, pUserData) == MA_DEVICE_ENUMERATION_ABORT);
}
close(audioFD);
}
} else {
/* AUDIO_GETDEV failed for audioctlN. */
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[audio4] AUDIO_GETDEV failed for %s.", devnodectl);
}
} else {
/* Failed to open audioctlN. */
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[audio4] Failed to open %s.", devnodectl);
}
}
}
closedir(d);
}
#endif
return MA_SUCCESS;
}
@@ -38727,11 +38822,19 @@ static ma_result ma_device_start__audio4(ma_device* pDevice)
return MA_INVALID_ARGS;
}
#if !defined(MA_AUDIO4_USE_NEW_API)
{
/* Old API. Do nothing here (will be started automatically). */
}
#else
{
if (ioctl(pDeviceStateAudio4->fdCapture, AUDIO_START, 0) < 0) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to start device. AUDIO_START failed. %s.", ma_result_description(ma_result_from_errno(errno)));
return ma_result_from_errno(errno);
}
}
#endif
}
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
if (pDeviceStateAudio4->fdPlayback == -1) {