mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
JACK: Refactoring.
* Devices are now enumerated properly. It will enumerate input or output ports depending on the device type, and then group by the client name. The client name will be considered a "device" from the perspective of miniaudio. The number of local ports will be the channel count. * The port auto-connection process is now done in init() rather than start(). I do not know why this was ever in start() in the first place. * Port auto-connection will now be restricted to the client ports. The old system would connect across multiple clients which is just a nonsensical way of doing. If more ports are requested than are available on the client, the excess ports will just not be connected.
This commit is contained in:
+228
-149
@@ -7507,7 +7507,7 @@ typedef union
|
||||
/*UINT_PTR*/ ma_uint32 winmm; /* When creating a device, WinMM expects a Win32 UINT_PTR for device identification. In practice it's actually just a UINT. */
|
||||
char alsa[256]; /* ALSA uses a name string for identification. */
|
||||
char pulse[256]; /* PulseAudio uses a name string for identification. */
|
||||
int jack; /* JACK always uses default devices. */
|
||||
char jack[256]; /* JACK uses a name string. */
|
||||
char coreaudio[256]; /* Core Audio uses a string for identification. */
|
||||
char sndio[256]; /* "snd/0", etc. */
|
||||
char audio4[256]; /* "/dev/audio", etc. */
|
||||
@@ -32533,7 +32533,7 @@ typedef struct ma_device_state_jack
|
||||
ma_jack_client_t* pClient;
|
||||
ma_jack_port_t** ppPortsPlayback;
|
||||
ma_jack_port_t** ppPortsCapture;
|
||||
float* pIntermediaryBuffer;
|
||||
float* pIntermediaryBuffer;
|
||||
} ma_device_state_jack;
|
||||
|
||||
static ma_result ma_context_open_client__jack(ma_context_state_jack* pContextStateJACK, ma_jack_client_t** ppClient)
|
||||
@@ -32743,54 +32743,83 @@ static void ma_context_uninit__jack(ma_context* pContext)
|
||||
ma_free(pContextStateJACK, ma_context_get_allocation_callbacks(pContext));
|
||||
}
|
||||
|
||||
static ma_device_enumeration_result ma_context_enumerate_device_from_client__jack(ma_context* pContext, ma_jack_client_t* pClient, ma_device_type deviceType, ma_enum_devices_callback_proc callback, void* pUserData)
|
||||
static ma_device_enumeration_result ma_context_enumerate_devices_from_client__jack(ma_context* pContext, ma_jack_client_t* pClient, ma_device_type deviceType, ma_enum_devices_callback_proc callback, void* pUserData)
|
||||
{
|
||||
ma_context_state_jack* pContextStateJACK = ma_context_get_backend_state__jack(pContext);
|
||||
ma_device_info deviceInfo;
|
||||
const char** ppPorts;
|
||||
ma_uint32 minChannels = 0;
|
||||
ma_uint32 maxChannels = 0;
|
||||
ma_uint32 channels;
|
||||
ma_uint32 sampleRate;
|
||||
|
||||
MA_ZERO_OBJECT(&deviceInfo);
|
||||
|
||||
/* Default. */
|
||||
deviceInfo.isDefault = MA_TRUE;
|
||||
|
||||
/* ID. */
|
||||
deviceInfo.id.jack = 0;
|
||||
|
||||
/* Name. */
|
||||
if (deviceType == ma_device_type_playback) {
|
||||
ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
|
||||
} else {
|
||||
ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
|
||||
}
|
||||
|
||||
/* Data Format. */
|
||||
ppPorts = pContextStateJACK->jack_get_ports(pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ((deviceType == ma_device_type_capture) ? ma_JackPortIsOutput : ma_JackPortIsInput));
|
||||
if (ppPorts != NULL) {
|
||||
maxChannels = 0;
|
||||
while (ppPorts[maxChannels] != NULL) {
|
||||
/*printf("PORT: %s\n", ppPorts[maxChannels]);*/
|
||||
maxChannels += 1;
|
||||
}
|
||||
|
||||
pContextStateJACK->jack_free((void*)ppPorts);
|
||||
}
|
||||
|
||||
if (maxChannels == 0) {
|
||||
minChannels = 1;
|
||||
maxChannels = MA_MAX_CHANNELS;
|
||||
} else {
|
||||
minChannels = maxChannels;
|
||||
}
|
||||
ma_device_enumeration_result cbResult = MA_DEVICE_ENUMERATION_CONTINUE;
|
||||
const char* pCurrentClientName = NULL;
|
||||
const char* pCurrentClientNameEnd = NULL;
|
||||
ma_bool32 hasEnumeratedDefaultDevice = MA_FALSE;
|
||||
int iPort;
|
||||
|
||||
sampleRate = pContextStateJACK->jack_get_sample_rate(pClient);
|
||||
|
||||
ma_device_info_add_native_data_format(&deviceInfo, ma_format_f32, minChannels, maxChannels, sampleRate, sampleRate);
|
||||
/*
|
||||
Our devices can be derived from the port names. We're going to assume each port name is in the
|
||||
format `<client_name>:<port_name>`. The client name will be our "device" name. Then we just
|
||||
use the client name as a filter for calcuating the channel count.
|
||||
*/
|
||||
ppPorts = pContextStateJACK->jack_get_ports(pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ((deviceType == ma_device_type_capture) ? ma_JackPortIsOutput : ma_JackPortIsInput));
|
||||
if (ppPorts == NULL) {
|
||||
return MA_DEVICE_ENUMERATION_ABORT;
|
||||
}
|
||||
|
||||
return callback(deviceType, &deviceInfo, pUserData);
|
||||
iPort = 0;
|
||||
while (ppPorts[iPort] != NULL) { /* For each JACK client. */
|
||||
pCurrentClientName = ppPorts[iPort];
|
||||
pCurrentClientNameEnd = strchr(pCurrentClientName, ':');
|
||||
|
||||
MA_ZERO_OBJECT(&deviceInfo);
|
||||
|
||||
/*
|
||||
Default. I'm not sure on a good way to do this with JACK. The JACK way of doing things just
|
||||
doesn't map very well with the miniaudio way. For now I'm just going to use the first client
|
||||
as the default.
|
||||
*/
|
||||
if (hasEnumeratedDefaultDevice == MA_FALSE) {
|
||||
hasEnumeratedDefaultDevice = MA_TRUE;
|
||||
deviceInfo.isDefault = MA_TRUE;
|
||||
} else {
|
||||
deviceInfo.isDefault = MA_FALSE;
|
||||
}
|
||||
|
||||
/* ID. This is just the client name. */
|
||||
ma_strncpy_s(deviceInfo.id.jack, sizeof(deviceInfo.id.jack), pCurrentClientName, (size_t)(pCurrentClientNameEnd - pCurrentClientName));
|
||||
|
||||
/* Name. This is the same as the ID. */
|
||||
ma_strcpy_s(deviceInfo.name, sizeof(deviceInfo.name), deviceInfo.id.jack);
|
||||
|
||||
/* For the native data format we need to count the number of ports to determine the channel count. */
|
||||
channels = 0;
|
||||
while (ppPorts[iPort] != NULL) {
|
||||
const char* pPortClientName = ppPorts[iPort];
|
||||
const char* pPortClientNameEnd = strchr(pPortClientName, ':');
|
||||
|
||||
if ((size_t)(pPortClientNameEnd - pPortClientName) != (size_t)(pCurrentClientNameEnd - pCurrentClientName)) {
|
||||
break; /* Lengths are no equal so it's impossible for the name to be the same. */
|
||||
}
|
||||
|
||||
if (memcmp(pPortClientName, pCurrentClientName, (size_t)(pCurrentClientNameEnd - pCurrentClientName)) != 0) {
|
||||
break; /* Names are not equal. */
|
||||
}
|
||||
|
||||
channels += 1;
|
||||
iPort += 1;
|
||||
}
|
||||
|
||||
ma_device_info_add_native_data_format(&deviceInfo, ma_format_f32, channels, channels, sampleRate, sampleRate);
|
||||
|
||||
cbResult = callback(deviceType, &deviceInfo, pUserData);
|
||||
if (cbResult == MA_DEVICE_ENUMERATION_ABORT) {
|
||||
return cbResult;
|
||||
}
|
||||
}
|
||||
|
||||
return MA_DEVICE_ENUMERATION_CONTINUE;
|
||||
}
|
||||
|
||||
static ma_result ma_context_enumerate_devices__jack(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
|
||||
@@ -32812,12 +32841,12 @@ static ma_result ma_context_enumerate_devices__jack(ma_context* pContext, ma_enu
|
||||
|
||||
/* Playback. */
|
||||
if (cbResult == MA_DEVICE_ENUMERATION_CONTINUE) {
|
||||
cbResult = ma_context_enumerate_device_from_client__jack(pContext, pClient, ma_device_type_playback, callback, pUserData);
|
||||
cbResult = ma_context_enumerate_devices_from_client__jack(pContext, pClient, ma_device_type_playback, callback, pUserData);
|
||||
}
|
||||
|
||||
/* Capture. */
|
||||
if (cbResult == MA_DEVICE_ENUMERATION_CONTINUE) {
|
||||
cbResult = ma_context_enumerate_device_from_client__jack(pContext, pClient, ma_device_type_capture, callback, pUserData);
|
||||
cbResult = ma_context_enumerate_devices_from_client__jack(pContext, pClient, ma_device_type_capture, callback, pUserData);
|
||||
}
|
||||
|
||||
(void)cbResult; /* For silencing a static analysis warning. */
|
||||
@@ -32931,6 +32960,73 @@ static int ma_device__jack_process_callback(ma_jack_nframes_t frameCount, void*
|
||||
|
||||
static void ma_device_uninit__jack(ma_device* pDevice);
|
||||
|
||||
static ma_result ma_get_port_range_by_device_id__jack(const char** ppPorts, const ma_device_id* pDeviceID, ma_uint32* pIndex, ma_uint32* pCount)
|
||||
{
|
||||
char pDefaultClientName[256];
|
||||
const char* pClientName;
|
||||
ma_uint32 index = 0;
|
||||
ma_uint32 count = 0;
|
||||
ma_uint32 iPort = 0;
|
||||
|
||||
if (pIndex != NULL) {
|
||||
*pIndex = 0;
|
||||
}
|
||||
if (pCount != NULL) {
|
||||
*pCount = 0;
|
||||
}
|
||||
|
||||
if (ppPorts == NULL || ppPorts[0] == NULL) {
|
||||
return MA_DOES_NOT_EXIST;
|
||||
}
|
||||
|
||||
if (pDeviceID == NULL) {
|
||||
const char* pPortClientNameEnd = strchr(ppPorts[0], ':');
|
||||
if (pPortClientNameEnd == NULL) {
|
||||
ma_strcpy_s(pDefaultClientName, sizeof(pDefaultClientName), ppPorts[0]);
|
||||
} else {
|
||||
ma_strncpy_s(pDefaultClientName, sizeof(pDefaultClientName), ppPorts[0], (size_t)(pPortClientNameEnd - ppPorts[0]));
|
||||
}
|
||||
|
||||
pClientName = pDefaultClientName;
|
||||
} else {
|
||||
pClientName = pDeviceID->jack;
|
||||
}
|
||||
|
||||
/* We need to first find the index, which is the first port with the name specified by the device ID. */
|
||||
while (ppPorts[iPort] != NULL) {
|
||||
const char* pPortClientName = ppPorts[iPort];
|
||||
const char* pPortClientNameEnd = strchr(pPortClientName, ':');
|
||||
|
||||
if (pPortClientNameEnd == NULL) {
|
||||
pPortClientNameEnd = pPortClientName + strlen(pPortClientName);
|
||||
}
|
||||
|
||||
if (memcmp(pClientName, pPortClientName, (size_t)(pPortClientNameEnd - pPortClientName)) == 0) {
|
||||
if (count == 0) {
|
||||
index = iPort;
|
||||
}
|
||||
|
||||
count += 1;
|
||||
} else {
|
||||
/* Not this port. Move on or get out. */
|
||||
if (count > 0) {
|
||||
break; /* Getting here means we've finished counting our ports. We're done. */
|
||||
}
|
||||
}
|
||||
|
||||
iPort += 1;
|
||||
}
|
||||
|
||||
if (pIndex != NULL) {
|
||||
*pIndex = index;
|
||||
}
|
||||
if (pCount != NULL) {
|
||||
*pCount = count;
|
||||
}
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_device_init__jack(ma_device* pDevice, const void* pDeviceBackendConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture, void** ppDeviceState)
|
||||
{
|
||||
ma_device_state_jack* pDeviceStateJACK;
|
||||
@@ -32942,6 +33038,7 @@ static ma_result ma_device_init__jack(ma_device* pDevice, const void* pDeviceBac
|
||||
ma_uint32 periodSizeInFrames;
|
||||
size_t bufferSizeCapture = 0;
|
||||
size_t bufferSizePlayback = 0;
|
||||
ma_uint32 sampleRate;
|
||||
|
||||
if (pDeviceConfigJACK == NULL) {
|
||||
defaultConfigJACK = ma_device_config_jack_init();
|
||||
@@ -32953,13 +33050,6 @@ static ma_result ma_device_init__jack(ma_device* pDevice, const void* pDeviceBac
|
||||
return MA_DEVICE_TYPE_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Only supporting default devices with JACK. */
|
||||
if (((deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) && pDescriptorPlayback->pDeviceID != NULL && pDescriptorPlayback->pDeviceID->jack != 0) ||
|
||||
((deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) && pDescriptorCapture->pDeviceID != NULL && pDescriptorCapture->pDeviceID->jack != 0)) {
|
||||
ma_log_post(pContextStateJACK->pLog, MA_LOG_LEVEL_ERROR, "[JACK] Only default devices are supported.");
|
||||
return MA_NO_DEVICE;
|
||||
}
|
||||
|
||||
/* No exclusive mode with the JACK backend. */
|
||||
if (((deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) ||
|
||||
((deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode == ma_share_mode_exclusive)) {
|
||||
@@ -32997,45 +33087,50 @@ static ma_result ma_device_init__jack(ma_device* pDevice, const void* pDeviceBac
|
||||
pContextStateJACK->jack_on_shutdown(pDeviceStateJACK->pClient, ma_device__jack_shutdown_callback, pDevice);
|
||||
|
||||
|
||||
/* The sample rate is always the same. */
|
||||
sampleRate = pContextStateJACK->jack_get_sample_rate(pDeviceStateJACK->pClient);
|
||||
|
||||
/* The buffer size in frames can change. */
|
||||
periodSizeInFrames = pContextStateJACK->jack_get_buffer_size(pDeviceStateJACK->pClient);
|
||||
|
||||
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
|
||||
const char** ppPorts;
|
||||
ma_uint32 iPort;
|
||||
ma_uint32 portIndex;
|
||||
ma_uint32 portCount;
|
||||
ma_uint32 portCountToAutoConnect;
|
||||
ma_uint32 channels;
|
||||
|
||||
pDescriptorCapture->format = ma_format_f32;
|
||||
pDescriptorCapture->sampleRate = pContextStateJACK->jack_get_sample_rate(pDeviceStateJACK->pClient);
|
||||
|
||||
/* If the application has requested the default channel count, make it equal to the number of output ports of the physical input device. */
|
||||
if (pDescriptorCapture->channels == 0) {
|
||||
const char** ppPorts;
|
||||
|
||||
ppPorts = pContextStateJACK->jack_get_ports(pDeviceStateJACK->pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsOutput);
|
||||
if (ppPorts == NULL) {
|
||||
ma_free(pDeviceStateJACK, ma_device_get_allocation_callbacks(pDevice));
|
||||
ma_log_post(pContextStateJACK->pLog, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.");
|
||||
return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
|
||||
}
|
||||
|
||||
/* Need to count the number of ports first so we can allocate some memory. */
|
||||
pDescriptorCapture->channels = 0;
|
||||
while (ppPorts[pDescriptorCapture->channels] != NULL) {
|
||||
pDescriptorCapture->channels += 1;
|
||||
}
|
||||
|
||||
pContextStateJACK->jack_free((void*)ppPorts);
|
||||
ppPorts = pContextStateJACK->jack_get_ports(pDeviceStateJACK->pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsOutput);
|
||||
if (ppPorts == NULL) {
|
||||
ma_log_post(pContextStateJACK->pLog, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical input ports.");
|
||||
return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
|
||||
}
|
||||
|
||||
ma_channel_map_init_standard(ma_standard_channel_map_alsa, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorCapture->channels);
|
||||
result = ma_get_port_range_by_device_id__jack(ppPorts, pDescriptorCapture->pDeviceID, &portIndex, &portCount);
|
||||
if (result != MA_SUCCESS) {
|
||||
pContextStateJACK->jack_free((void*)ppPorts);
|
||||
ma_log_postf(pContextStateJACK->pLog, MA_LOG_LEVEL_ERROR, "[JACK] Could not find ports for client \"%s\".", (pDescriptorCapture->pDeviceID != NULL) ? pDescriptorCapture->pDeviceID->jack : "");
|
||||
return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
|
||||
}
|
||||
|
||||
/* If the application has requested the default channel count, make it equal to the number of output ports of the physical input device. */
|
||||
channels = pDescriptorCapture->channels;
|
||||
if (channels == 0) {
|
||||
channels = portCount;
|
||||
}
|
||||
|
||||
pDeviceStateJACK->ppPortsCapture = (ma_jack_port_t**)ma_malloc(sizeof(*pDeviceStateJACK->ppPortsCapture) * pDescriptorCapture->channels, ma_device_get_allocation_callbacks(pDevice));
|
||||
/* We need to know how many ports to auto-connect. */
|
||||
portCountToAutoConnect = ma_min(portCount, channels);
|
||||
|
||||
pDeviceStateJACK->ppPortsCapture = (ma_jack_port_t**)ma_malloc(sizeof(*pDeviceStateJACK->ppPortsCapture) * channels, ma_device_get_allocation_callbacks(pDevice));
|
||||
if (pDeviceStateJACK->ppPortsCapture == NULL) {
|
||||
pContextStateJACK->jack_free((void*)ppPorts);
|
||||
ma_free(pDeviceStateJACK, ma_device_get_allocation_callbacks(pDevice));
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (iPort = 0; iPort < pDescriptorCapture->channels; iPort += 1) {
|
||||
for (iPort = 0; iPort < channels; iPort += 1) {
|
||||
char name[64];
|
||||
ma_strcpy_s(name, sizeof(name), "capture");
|
||||
ma_itoa_s((int)iPort, name+7, sizeof(name)-7, 10); /* 7 = length of "capture" */
|
||||
@@ -33043,11 +33138,27 @@ static ma_result ma_device_init__jack(ma_device* pDevice, const void* pDeviceBac
|
||||
pDeviceStateJACK->ppPortsCapture[iPort] = pContextStateJACK->jack_port_register(pDeviceStateJACK->pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsInput, 0);
|
||||
if (pDeviceStateJACK->ppPortsCapture[iPort] == NULL) {
|
||||
ma_device_uninit__jack(pDevice);
|
||||
pContextStateJACK->jack_free((void*)ppPorts);
|
||||
ma_log_post(pContextStateJACK->pLog, MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.");
|
||||
return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
|
||||
}
|
||||
|
||||
if (pDeviceConfigJACK->noAutoConnect == MA_FALSE) {
|
||||
if (iPort < portCountToAutoConnect) {
|
||||
const char* pServerPort = ppPorts[portIndex + iPort];
|
||||
const char* pClientPort = pContextStateJACK->jack_port_name(pDeviceStateJACK->ppPortsCapture[iPort]);
|
||||
|
||||
pContextStateJACK->jack_connect(pDeviceStateJACK->pClient, pServerPort, pClientPort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pContextStateJACK->jack_free((void*)ppPorts);
|
||||
|
||||
pDescriptorCapture->format = ma_format_f32;
|
||||
pDescriptorCapture->sampleRate = sampleRate;
|
||||
pDescriptorCapture->channels = channels;
|
||||
ma_channel_map_init_standard(ma_standard_channel_map_alsa, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorCapture->channels);
|
||||
pDescriptorCapture->periodSizeInFrames = periodSizeInFrames;
|
||||
pDescriptorCapture->periodCount = 1; /* There's no notion of a period in JACK. Just set to 1. */
|
||||
|
||||
@@ -33055,39 +33166,43 @@ static ma_result ma_device_init__jack(ma_device* pDevice, const void* pDeviceBac
|
||||
}
|
||||
|
||||
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
|
||||
const char** ppPorts;
|
||||
ma_uint32 iPort;
|
||||
ma_uint32 portIndex;
|
||||
ma_uint32 portCount;
|
||||
ma_uint32 portCountToAutoConnect;
|
||||
ma_uint32 channels;
|
||||
|
||||
pDescriptorPlayback->format = ma_format_f32;
|
||||
pDescriptorPlayback->sampleRate = pContextStateJACK->jack_get_sample_rate(pDeviceStateJACK->pClient);
|
||||
|
||||
/* If the application has requested the default channel count, make it equal to the number of input ports of the physical output device. */
|
||||
if (pDescriptorPlayback->channels == 0) {
|
||||
const char** ppPorts;
|
||||
|
||||
ppPorts = pContextStateJACK->jack_get_ports(pDeviceStateJACK->pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsInput);
|
||||
if (ppPorts == NULL) {
|
||||
ma_log_post(pContextStateJACK->pLog, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.");
|
||||
return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
|
||||
}
|
||||
|
||||
/* Need to count the number of ports first so we can allocate some memory. */
|
||||
while (ppPorts[pDescriptorPlayback->channels] != NULL) {
|
||||
pDescriptorPlayback->channels += 1;
|
||||
}
|
||||
|
||||
pContextStateJACK->jack_free((void*)ppPorts);
|
||||
ppPorts = pContextStateJACK->jack_get_ports(pDeviceStateJACK->pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsInput);
|
||||
if (ppPorts == NULL) {
|
||||
ma_log_post(pContextStateJACK->pLog, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical input ports.");
|
||||
return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
|
||||
}
|
||||
|
||||
ma_channel_map_init_standard(ma_standard_channel_map_alsa, pDescriptorPlayback->channelMap, ma_countof(pDescriptorPlayback->channelMap), pDescriptorPlayback->channels);
|
||||
result = ma_get_port_range_by_device_id__jack(ppPorts, pDescriptorPlayback->pDeviceID, &portIndex, &portCount);
|
||||
if (result != MA_SUCCESS) {
|
||||
pContextStateJACK->jack_free((void*)ppPorts);
|
||||
ma_log_postf(pContextStateJACK->pLog, MA_LOG_LEVEL_ERROR, "[JACK] Could not find ports for client \"%s\".", (pDescriptorPlayback->pDeviceID != NULL) ? pDescriptorPlayback->pDeviceID->jack : "");
|
||||
return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
|
||||
}
|
||||
|
||||
/* If the application has requested the default channel count, make it equal to the number of input ports of the physical output device. */
|
||||
channels = pDescriptorPlayback->channels;
|
||||
if (channels == 0) {
|
||||
channels = portCount;
|
||||
}
|
||||
|
||||
pDeviceStateJACK->ppPortsPlayback = (ma_jack_port_t**)ma_malloc(sizeof(*pDeviceStateJACK->ppPortsPlayback) * pDescriptorPlayback->channels, ma_device_get_allocation_callbacks(pDevice));
|
||||
/* We need to know how many ports to auto-connect. */
|
||||
portCountToAutoConnect = ma_min(portCount, channels);
|
||||
|
||||
pDeviceStateJACK->ppPortsPlayback = (ma_jack_port_t**)ma_malloc(sizeof(*pDeviceStateJACK->ppPortsPlayback) * channels, ma_device_get_allocation_callbacks(pDevice));
|
||||
if (pDeviceStateJACK->ppPortsPlayback == NULL) {
|
||||
pContextStateJACK->jack_free((void*)ppPorts);
|
||||
ma_free(pDeviceStateJACK->ppPortsCapture, ma_device_get_allocation_callbacks(pDevice));
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (iPort = 0; iPort < pDescriptorPlayback->channels; iPort += 1) {
|
||||
for (iPort = 0; iPort < channels; iPort += 1) {
|
||||
char name[64];
|
||||
ma_strcpy_s(name, sizeof(name), "playback");
|
||||
ma_itoa_s((int)iPort, name+8, sizeof(name)-8, 10); /* 8 = length of "playback" */
|
||||
@@ -33095,11 +33210,28 @@ static ma_result ma_device_init__jack(ma_device* pDevice, const void* pDeviceBac
|
||||
pDeviceStateJACK->ppPortsPlayback[iPort] = pContextStateJACK->jack_port_register(pDeviceStateJACK->pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsOutput, 0);
|
||||
if (pDeviceStateJACK->ppPortsPlayback[iPort] == NULL) {
|
||||
ma_device_uninit__jack(pDevice);
|
||||
pContextStateJACK->jack_free((void*)ppPorts);
|
||||
ma_log_post(pContextStateJACK->pLog, MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.");
|
||||
return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
|
||||
}
|
||||
|
||||
/* Connect the port if we're auto-connecting. */
|
||||
if (pDeviceConfigJACK->noAutoConnect == MA_FALSE) {
|
||||
if (iPort < portCountToAutoConnect) {
|
||||
const char* pServerPort = ppPorts[portIndex + iPort];
|
||||
const char* pClientPort = pContextStateJACK->jack_port_name(pDeviceStateJACK->ppPortsPlayback[iPort]);
|
||||
|
||||
pContextStateJACK->jack_connect(pDeviceStateJACK->pClient, pClientPort, pServerPort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pContextStateJACK->jack_free((void*)ppPorts);
|
||||
|
||||
pDescriptorPlayback->format = ma_format_f32;
|
||||
pDescriptorPlayback->sampleRate = sampleRate;
|
||||
pDescriptorPlayback->channels = channels;
|
||||
ma_channel_map_init_standard(ma_standard_channel_map_alsa, pDescriptorPlayback->channelMap, ma_countof(pDescriptorPlayback->channelMap), pDescriptorPlayback->channels);
|
||||
pDescriptorPlayback->periodSizeInFrames = periodSizeInFrames;
|
||||
pDescriptorPlayback->periodCount = 1; /* There's no notion of a period in JACK. Just set to 1. */
|
||||
|
||||
@@ -33146,7 +33278,6 @@ static void ma_device_uninit__jack(ma_device* pDevice)
|
||||
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
|
||||
ma_free(pDeviceStateJACK->ppPortsCapture, ma_device_get_allocation_callbacks(pDevice));
|
||||
}
|
||||
|
||||
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
|
||||
ma_free(pDeviceStateJACK->ppPortsPlayback, ma_device_get_allocation_callbacks(pDevice));
|
||||
}
|
||||
@@ -33166,9 +33297,7 @@ static ma_result ma_device_start__jack(ma_device* pDevice)
|
||||
{
|
||||
ma_device_state_jack* pDeviceStateJACK = ma_device_get_backend_state__jack(pDevice);
|
||||
ma_context_state_jack* pContextStateJACK = ma_context_get_backend_state__jack(ma_device_get_context(pDevice));
|
||||
ma_device_type deviceType = ma_device_get_type(pDevice);
|
||||
int resultJACK;
|
||||
size_t i;
|
||||
|
||||
resultJACK = pContextStateJACK->jack_activate(pDeviceStateJACK->pClient);
|
||||
if (resultJACK != 0) {
|
||||
@@ -33176,56 +33305,6 @@ static ma_result ma_device_start__jack(ma_device* pDevice)
|
||||
return MA_FAILED_TO_START_BACKEND_DEVICE;
|
||||
}
|
||||
|
||||
if (pDeviceStateJACK->noAutoConnect == MA_FALSE) {
|
||||
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
|
||||
const char** ppServerPorts = pContextStateJACK->jack_get_ports(pDeviceStateJACK->pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsOutput);
|
||||
if (ppServerPorts == NULL) {
|
||||
pContextStateJACK->jack_deactivate(pDeviceStateJACK->pClient);
|
||||
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.");
|
||||
return MA_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; ppServerPorts[i] != NULL && i < pDevice->capture.internalChannels; ++i) {
|
||||
const char* pServerPort = ppServerPorts[i];
|
||||
const char* pClientPort = pContextStateJACK->jack_port_name(pDeviceStateJACK->ppPortsCapture[i]);
|
||||
|
||||
resultJACK = pContextStateJACK->jack_connect(pDeviceStateJACK->pClient, pServerPort, pClientPort);
|
||||
if (resultJACK != 0) {
|
||||
pContextStateJACK->jack_free((void*)ppServerPorts);
|
||||
pContextStateJACK->jack_deactivate(pDeviceStateJACK->pClient);
|
||||
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.");
|
||||
return MA_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
pContextStateJACK->jack_free((void*)ppServerPorts);
|
||||
}
|
||||
|
||||
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
|
||||
const char** ppServerPorts = pContextStateJACK->jack_get_ports(pDeviceStateJACK->pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsInput);
|
||||
if (ppServerPorts == NULL) {
|
||||
pContextStateJACK->jack_deactivate(pDeviceStateJACK->pClient);
|
||||
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.");
|
||||
return MA_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; ppServerPorts[i] != NULL && i < pDevice->playback.internalChannels; ++i) {
|
||||
const char* pServerPort = ppServerPorts[i];
|
||||
const char* pClientPort = pContextStateJACK->jack_port_name(pDeviceStateJACK->ppPortsPlayback[i]);
|
||||
|
||||
resultJACK = pContextStateJACK->jack_connect(pDeviceStateJACK->pClient, pClientPort, pServerPort);
|
||||
if (resultJACK != 0) {
|
||||
pContextStateJACK->jack_free((void*)ppServerPorts);
|
||||
pContextStateJACK->jack_deactivate(pDeviceStateJACK->pClient);
|
||||
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.");
|
||||
return MA_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
pContextStateJACK->jack_free((void*)ppServerPorts);
|
||||
}
|
||||
}
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user