Improvements to the NetBSD audio(4) backend.

* Device enumeration will now mark appropriate devices as default.
  * The onContextGetDeviceInfo backend callback has been removed so that
    all device info is retrieved from the enumeration process.
This commit is contained in:
David Reid
2025-07-18 08:25:16 +10:00
parent c468230e8f
commit c2b45b58af
+34 -98
View File
@@ -38347,38 +38347,6 @@ static void ma_construct_device_id__audio4(char* id, size_t idSize, const char*
ma_itoa_s(deviceIndex, id+baseLen, idSize-baseLen, 10);
}
static ma_result ma_extract_device_index_from_id__audio4(const char* id, const char* base, int* pIndexOut)
{
size_t idLen;
size_t baseLen;
const char* deviceIndexStr;
MA_ASSERT(id != NULL);
MA_ASSERT(base != NULL);
MA_ASSERT(pIndexOut != NULL);
idLen = strlen(id);
baseLen = strlen(base);
if (idLen <= baseLen) {
return MA_ERROR; /* Doesn't look like the id starts with the base. */
}
if (strncmp(id, base, baseLen) != 0) {
return MA_ERROR; /* ID does not begin with base. */
}
deviceIndexStr = id + baseLen;
if (deviceIndexStr[0] == '\0') {
return MA_ERROR; /* No index specified in the ID. */
}
if (pIndexOut) {
*pIndexOut = atoi(deviceIndexStr);
}
return MA_SUCCESS;
}
#if !defined(MA_AUDIO4_USE_NEW_API) /* Old API */
static ma_format ma_format_from_encoding__audio4(unsigned int encoding, unsigned int precision)
@@ -38519,21 +38487,27 @@ static ma_format ma_format_from_swpar__audio4(struct audio_swpar* par)
}
#endif
static ma_result ma_context_get_device_info_from_fd__audio4(ma_context* pContext, ma_device_type deviceType, int fd, ma_device_info* pDeviceInfo)
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;
MA_ASSERT(pContext != NULL);
MA_ASSERT(fd >= 0);
MA_ASSERT(pDeviceInfo != NULL);
(void)pContext;
(void)deviceType;
if (ioctl(fd, AUDIO_GETDEV, &fdDevice) < 0) {
return MA_ERROR; /* Failed to retrieve device info. */
}
MA_ZERO_OBJECT(pDeviceInfo);
/* Default. */
if ((stDefault->st_dev == stDevice->st_dev) && (stDefault->st_ino == stDevice->st_ino)) {
pDeviceInfo->isDefault = MA_TRUE;
}
/* ID. */
ma_construct_device_id__audio4(pDeviceInfo->id.audio4, sizeof(pDeviceInfo->id.audio4), "/dev/audio", deviceIndex);
/* Name. */
ma_strcpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), fdDevice.name);
@@ -38614,20 +38588,39 @@ static ma_result ma_context_get_device_info_from_fd__audio4(ma_context* pContext
return MA_SUCCESS;
}
static ma_bool32 ma_context_enumerate_device_from_fd___audio4(int fd, int deviceIndex, struct stat* stDevice, struct stat* stDefault, ma_device_type deviceType, ma_enum_devices_callback_proc callback, void* pUserData)
{
ma_result result;
ma_device_info deviceInfo;
result = ma_context_get_device_info_from_fd__audio4(fd, deviceIndex, stDevice, stDefault, deviceType, &deviceInfo);
if (result != MA_SUCCESS) {
return MA_TRUE;
}
return callback(deviceType, &deviceInfo, pUserData);
}
static ma_result ma_context_enumerate_devices__audio4(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
{
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;
}
/*
Every device will be named "/dev/audioN", with a "/dev/audioctlN" equivalent. We use the "/dev/audioctlN"
version here since we can open it even when another process has control of the "/dev/audioN" device.
*/
for (iDevice = 0; iDevice < maxDevices; ++iDevice) {
for (iDevice = 0; iDevice < maxDevices; iDevice += 1) {
struct stat st;
int fd;
ma_bool32 isTerminating = MA_FALSE;
@@ -38645,14 +38638,7 @@ static ma_result ma_context_enumerate_devices__audio4(ma_context* pContext, ma_e
if (!isTerminating) {
fd = open(devpath, O_RDONLY, 0);
if (fd >= 0) {
/* Supports playback. */
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
ma_construct_device_id__audio4(deviceInfo.id.audio4, sizeof(deviceInfo.id.audio4), "/dev/audio", iDevice);
if (ma_context_get_device_info_from_fd__audio4(pContext, ma_device_type_playback, fd, &deviceInfo) == MA_SUCCESS) {
isTerminating = !callback(ma_device_type_playback, &deviceInfo, pUserData);
}
isTerminating = !ma_context_enumerate_device_from_fd___audio4(fd, iDevice, &st, &stDefault, ma_device_type_playback, callback, pUserData);
close(fd);
}
}
@@ -38661,14 +38647,7 @@ static ma_result ma_context_enumerate_devices__audio4(ma_context* pContext, ma_e
if (!isTerminating) {
fd = open(devpath, O_WRONLY, 0);
if (fd >= 0) {
/* Supports capture. */
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
ma_construct_device_id__audio4(deviceInfo.id.audio4, sizeof(deviceInfo.id.audio4), "/dev/audio", iDevice);
if (ma_context_get_device_info_from_fd__audio4(pContext, ma_device_type_capture, fd, &deviceInfo) == MA_SUCCESS) {
isTerminating = !callback(ma_device_type_capture, &deviceInfo, pUserData);
}
isTerminating = !ma_context_enumerate_device_from_fd___audio4(fd, iDevice, &st, &stDefault, ma_device_type_capture, callback, pUserData);
close(fd);
}
}
@@ -38681,49 +38660,6 @@ static ma_result ma_context_enumerate_devices__audio4(ma_context* pContext, ma_e
return MA_SUCCESS;
}
static ma_result ma_context_get_device_info__audio4(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
{
int fd = -1;
int deviceIndex = -1;
char ctlid[256];
ma_result result;
MA_ASSERT(pContext != NULL);
/*
We need to open the "/dev/audioctlN" device to get the info. To do this we need to extract the number
from the device ID which will be in "/dev/audioN" format.
*/
if (pDeviceID == NULL) {
/* Default device. */
ma_strcpy_s(ctlid, sizeof(ctlid), "/dev/audioctl");
} else {
/* Specific device. We need to convert from "/dev/audioN" to "/dev/audioctlN". */
result = ma_extract_device_index_from_id__audio4(pDeviceID->audio4, "/dev/audio", &deviceIndex);
if (result != MA_SUCCESS) {
return result;
}
ma_construct_device_id__audio4(ctlid, sizeof(ctlid), "/dev/audioctl", deviceIndex);
}
fd = open(ctlid, (deviceType == ma_device_type_playback) ? O_WRONLY : O_RDONLY, 0);
if (fd == -1) {
return MA_NO_DEVICE;
}
if (deviceIndex == -1) {
ma_strcpy_s(pDeviceInfo->id.audio4, sizeof(pDeviceInfo->id.audio4), "/dev/audio");
} else {
ma_construct_device_id__audio4(pDeviceInfo->id.audio4, sizeof(pDeviceInfo->id.audio4), "/dev/audio", deviceIndex);
}
result = ma_context_get_device_info_from_fd__audio4(pContext, deviceType, fd, pDeviceInfo);
close(fd);
return result;
}
static ma_result ma_device_init_fd__audio4(ma_device* pDevice, ma_device_descriptor* pDescriptor, ma_device_type deviceType, int* pFD)
{
const char* pDefaultDeviceNames[] = {
@@ -39195,7 +39131,7 @@ static ma_device_backend_vtable ma_gDeviceBackendVTable_Audio4 =
ma_context_init__audio4,
ma_context_uninit__audio4,
ma_context_enumerate_devices__audio4,
ma_context_get_device_info__audio4,
NULL,
ma_device_init__audio4,
ma_device_uninit__audio4,
ma_device_start__audio4,