Commit e3e1ab19 authored by David Reid's avatar David Reid

API CHANGE: Remove alsa.preferPlugHW config.

This config doesn't really make sense any more because we are now using
dmix/dsnoop for shared mode, and hw for exclusive mode. Format
conversion is now done via mini_al itself which makes plughw pretty
much useless for us at this point.
parent 330c5fe9
......@@ -574,7 +574,6 @@ typedef struct
struct
{
mal_bool32 preferPlugHW;
mal_bool32 noMMap; // Disables MMap mode.
} alsa;
} mal_device_config;
......@@ -5670,7 +5669,7 @@ static mal_result mal_enumerate_devices__alsa(mal_context* pContext, mal_device_
if (includeThisDevice) {
#if 1
#if 0
printf("NAME: %s\n", NAME);
printf("DESC: %s\n", DESC);
printf("IOID: %s\n", IOID);
......@@ -5683,9 +5682,20 @@ static mal_result mal_enumerate_devices__alsa(mal_context* pContext, mal_device_
char hwid[sizeof(pUniqueIDs->alsa)];
if (NAME != NULL) {
if (pContext->config.alsa.useVerboseDeviceEnumeration) {
// Verbose mode. Use the name exactly as-is.
mal_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
} else {
if (mal_convert_device_name_to_hw_format__alsa(pContext, hwid, sizeof(hwid), NAME) != 0) {
// Simplified mode. Use ":%d,%d" format.
if (mal_convert_device_name_to_hw_format__alsa(pContext, hwid, sizeof(hwid), NAME) == 0) {
// At this point, hwid looks like "hw:0,0". In simplified enumeration mode, we actually want to strip off the
// plugin name so it looks like ":0,0". The reason for this is that this special format is detected at device
// initialization time and is used as an indicator to try and use the most appropriate plugin depending on the
// device type and sharing mode.
char* dst = hwid;
char* src = hwid+2;
while (*dst++ = *src++);
} else {
// Conversion to "hw:%d,%d" failed. Just use the name as-is.
mal_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
}
......@@ -5786,56 +5796,102 @@ static mal_result mal_device_init__alsa(mal_context* pContext, mal_device_type t
mal_zero_object(&pDevice->alsa);
snd_pcm_format_t formatALSA = mal_convert_mal_format_to_alsa_format(pConfig->format);
snd_pcm_stream_t stream = (type == mal_device_type_playback) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE;
char deviceName[256];
if (pDeviceID == NULL) {
mal_strncpy_s(deviceName, sizeof(deviceName), "default", (size_t)-1);
} else {
if (!pConfig->alsa.preferPlugHW) {
mal_strncpy_s(deviceName, sizeof(deviceName), pDeviceID->alsa, (size_t)-1);
// We're opening the default device. I don't know if trying anything other than "default" is necessary, but it makes
// me feel better to try as hard as we can get to get _something_ working.
const char* defaultDeviceNames[] = {
"default",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
if (pConfig->preferExclusiveMode) {
defaultDeviceNames[1] = "hw";
defaultDeviceNames[2] = "hw:0";
defaultDeviceNames[3] = "hw:0,0";
} else {
// The client is preferencing a "plug" device, so we need to convert the device name to "plughw:%d,%d" format.
deviceName[0] = 'p';
deviceName[1] = 'l';
deviceName[2] = 'u';
deviceName[3] = 'g';
if (mal_convert_device_name_to_hw_format__alsa(pContext, deviceName+4, sizeof(deviceName)-4, pDeviceID->alsa) != 0) {
// Failed to convert to "hw:%d,%d" format. It could be set to "default", "pulse", "null", etc. This is not a critical error - just keep using the original name.
mal_strncpy_s(deviceName, sizeof(deviceName), pDeviceID->alsa, (size_t)-1);
if (type == mal_device_type_playback) {
defaultDeviceNames[1] = "dmix";
defaultDeviceNames[2] = "dmix:0";
defaultDeviceNames[3] = "dmix:0,0";
} else {
defaultDeviceNames[1] = "dsnoop";
defaultDeviceNames[2] = "dsnoop:0";
defaultDeviceNames[3] = "dsnoop:0,0";
}
defaultDeviceNames[4] = "hw";
defaultDeviceNames[5] = "hw:0";
defaultDeviceNames[6] = "hw:0,0";
}
}
// When opening the device, we first try opening it based on the name provided in deviceName. If this fails, fall back to the "hw:%d,%d".
snd_pcm_stream_t stream = (type == mal_device_type_playback) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE;
if (((mal_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)((snd_pcm_t**)&pDevice->alsa.pPCM, deviceName, stream, 0) < 0) {
//printf("Failed first attempt at opening device.\n");
if (mal_strcmp(deviceName, "default") == 0 || mal_strcmp(deviceName, "pulse") == 0) {
// We may have failed to open the default device. Try falling back to the "hw" or "plughw" device, depending on preferences.
if (pConfig->alsa.preferPlugHW) {
mal_strncpy_s(deviceName, sizeof(deviceName), "plughw:0,0", (size_t)-1);
} else {
mal_strncpy_s(deviceName, sizeof(deviceName), "hw:0,0", (size_t)-1);
mal_bool32 isDeviceOpen = MAL_FALSE;
for (size_t i = 0; i < mal_countof(defaultDeviceNames); ++i) {
if (defaultDeviceNames[i] != NULL && defaultDeviceNames[i][0] != '\0') {
if (((mal_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)((snd_pcm_t**)&pDevice->alsa.pPCM, defaultDeviceNames[i], stream, 0) == 0) {
isDeviceOpen = MAL_TRUE;
break;
}
}
}
if (((mal_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)((snd_pcm_t**)&pDevice->alsa.pPCM, deviceName, stream, 0) < 0) {
mal_device_uninit__alsa(pDevice);
return mal_post_error(pDevice, "[ALSA] snd_pcm_open() failed when trying to open the default device.", MAL_ALSA_FAILED_TO_OPEN_DEVICE);
if (!isDeviceOpen) {
mal_device_uninit__alsa(pDevice);
return mal_post_error(pDevice, "[ALSA] snd_pcm_open() failed when trying to open an appropriate default device.", MAL_ALSA_FAILED_TO_OPEN_DEVICE);
}
} else {
// We're trying to open a specific device. There's a few things to consider here:
//
// mini_al recongnizes a special format of device id that excludes the "hw", "dmix", etc. prefix. It looks like this: ":0,0", ":0,1", etc. When
// an ID of this format is specified, it indicates to mini_al that it can try different combinations of plugins ("hw", "dmix", etc.) until it
// finds an appropriate one that works. This comes in very handy when trying to open a device in shared mode ("dmix"), vs exclusive mode ("hw").
mal_bool32 isDeviceOpen = MAL_FALSE;
if (pDeviceID->alsa[0] != ':') {
// The ID is not in ":0,0" format. Use the ID exactly as-is.
if (((mal_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)((snd_pcm_t**)&pDevice->alsa.pPCM, pDeviceID->alsa, stream, 0) == 0) {
isDeviceOpen = MAL_TRUE;
}
} else {
// Try falling back to "hw:%d,%d" format.
// The ID is in ":0,0" format. Try different plugins depending on the shared mode.
if (pDeviceID->alsa[1] == '\0') {
pDeviceID->alsa[0] = '\0'; // An ID of ":" should be converted to "".
}
char hwid[256];
if (mal_convert_device_name_to_hw_format__alsa(pContext, hwid, sizeof(hwid), deviceName) != 0) {
mal_device_uninit__alsa(pDevice);
return mal_post_error(pDevice, "[ALSA] snd_pcm_open() failed.", MAL_ALSA_FAILED_TO_OPEN_DEVICE);
} else {
if (((mal_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)((snd_pcm_t**)&pDevice->alsa.pPCM, hwid, stream, 0) < 0) {
mal_device_uninit__alsa(pDevice);
return mal_post_error(pDevice, "[ALSA] snd_pcm_open() failed.", MAL_ALSA_FAILED_TO_OPEN_DEVICE);
if (!pConfig->preferExclusiveMode) {
if (type == mal_device_type_playback) {
mal_strcpy_s(hwid, sizeof(hwid), "dmix");
} else {
mal_strcpy_s(hwid, sizeof(hwid), "dsnoop");
}
if (mal_strcat_s(hwid, sizeof(hwid), pDeviceID->alsa) == 0) {
if (((mal_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)((snd_pcm_t**)&pDevice->alsa.pPCM, hwid, stream, 0) == 0) {
isDeviceOpen = MAL_TRUE;
}
}
}
// If at this point we still don't have an open device it means we're either preferencing exclusive mode or opening with "dmix"/"dsnoop" failed.
if (!isDeviceOpen) {
mal_strcpy_s(hwid, sizeof(hwid), "hw");
if (mal_strcat_s(hwid, sizeof(hwid), pDeviceID->alsa) == 0) {
if (((mal_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)((snd_pcm_t**)&pDevice->alsa.pPCM, hwid, stream, 0) == 0) {
isDeviceOpen = MAL_TRUE;
}
}
}
}
if (!isDeviceOpen) {
mal_device_uninit__alsa(pDevice);
return mal_post_error(pDevice, "[ALSA] snd_pcm_open() failed.", MAL_ALSA_FAILED_TO_OPEN_DEVICE);
}
}
......@@ -10150,9 +10206,15 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count)
// configuring the context. The works in the same kind of way as the device config. The rationale for this
// change is to give applications better control over context-level properties, add support for backend-
// specific configurations, and support extensibility without breaking the API.
// - API CHANGE: The alsa.preferPlugHW device config variable has been removed since it's not really useful for
// anything anymore.
// - ALSA: By default, device enumeration will now only enumerate over unique card/device pairs. Applications
// can enable verbose device enumeration by setting the alsa.useVerboseDeviceEnumeration context config
// variable.
// - ALSA: When opening a device in shared mode (the default), the dmix/dsnoop plugin will be prioritized. If
// this fails it will fall back to the hw plugin. With this change the preferExclusiveMode config is now
// honored. Note that this does not happen when alsa.useVerboseDeviceEnumeration is set to true (see above)
// which is by design.
// - ALSA: Add support for excluding the "null" device using the alsa.excludeNullDevice context config variable.
// - ALSA: Fix a bug with channel mapping which causes an assertion to fail.
//
......
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