diff --git a/linux/alsa/JackAlsaDriver.cpp b/linux/alsa/JackAlsaDriver.cpp index 35dbb2ef..35bf7814 100644 --- a/linux/alsa/JackAlsaDriver.cpp +++ b/linux/alsa/JackAlsaDriver.cpp @@ -360,9 +360,29 @@ int JackAlsaDriver::Open(alsa_driver_info_t info) return -1; } - // ALSA driver may have changed the in/out values - fCaptureChannels = ((alsa_driver_t *)fDriver)->capture_nchannels; - fPlaybackChannels = ((alsa_driver_t *)fDriver)->playback_nchannels; + /* this feature caused driver to skip opening alsa devices, therefore populate channels from user input */ + if (info.features & ALSA_DRIVER_FEAT_START_CLOSED) { + for (size_t i = 0; i < std::max(info.devices_capture_size, info.devices_playback_size); ++i) { + if (i < info.devices_capture_size && info.devices[i].capture_channels < 1) { + jack_error ("invalid or missing channels parameter with '-x' option 'start-closed' for device C: '%s'", info.devices[i].capture_name); + Close(); + return -1; + } + + if (i < info.devices_playback_size && info.devices[i].playback_channels < 1) { + jack_error ("invalid or missing channels parameter with '-x' option 'start-closed' for device P: '%s'", info.devices[i].playback_name); + Close(); + return -1; + } + + fCaptureChannels += info.devices[i].capture_channels; + fPlaybackChannels += info.devices[i].playback_channels; + } + /* in case we really opened alsa devices, channel information is generated by driver */ + } else { + fCaptureChannels = ((alsa_driver_t *)fDriver)->capture_nchannels; + fPlaybackChannels = ((alsa_driver_t *)fDriver)->playback_nchannels; + } #ifndef __QNXNTO__ if (JackServerGlobals::on_device_reservation_loop != NULL) { @@ -565,7 +585,11 @@ int JackAlsaDriver::TargetState(int init, int connections_count) if (connections_count > 0) { state = SND_PCM_STATE_RUNNING; } else if (init) { - state = SND_PCM_STATE_RUNNING; + if (driver->features & ALSA_DRIVER_FEAT_START_CLOSED) { + state = SND_PCM_STATE_NOTREADY; + } else { + state = SND_PCM_STATE_RUNNING; + } } else if (driver->features & ALSA_DRIVER_FEAT_CLOSE_IDLE_DEVS) { state = SND_PCM_STATE_NOTREADY; } else { @@ -838,8 +862,8 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () NULL); strcpy(value.str, "none"); - jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamString, &value, NULL, "List of device capture channels (defaults to hardware max)", NULL); - jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamString, &value, NULL, "List of device playback channels (defaults to hardware max)", NULL); + jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamString, &value, NULL, "List of device capture channels (defaults to hw max)", NULL); + jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamString, &value, NULL, "List of device playback channels (defaults to hw max)", NULL); value.i = FALSE; jack_driver_descriptor_add_parameter(desc, &filler, "shorts", 'S', JackDriverParamBool, &value, NULL, "Try 16-bit samples before 32-bit", NULL); @@ -862,6 +886,9 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () "ALSA MIDI driver", NULL); + value.i = 0; + jack_driver_descriptor_add_parameter(desc, &filler, "start-closed", 'x', JackDriverParamBool, &value, NULL, "Start with all devices closed", NULL); + value.i = 0; jack_driver_descriptor_add_parameter(desc, &filler, "close-idle-devs", 'c', JackDriverParamBool, &value, NULL, "Close idle devices on alsa driver restart request", NULL); @@ -878,8 +905,7 @@ struct array_string_t discard_duplicate, }; - uint64_t size; - char **data; + std::vector data; }; void array_string_free(struct array_string_t *obj) @@ -887,49 +913,35 @@ void array_string_free(struct array_string_t *obj) if (obj == NULL) { return; } - if (obj->data == NULL) { - return; - } - for (size_t i = 0; i < obj->size; ++i) { + for (size_t i = 0; i < obj->data.size(); ++i) { free(obj->data[i]); } - free(obj->data); - obj->data = NULL; - obj->size = 0; } struct array_string_t array_string_split(const char *str, const char sep, array_string_t::flags flags = array_string_t::none) { struct array_string_t result; - result.size = 0; std::stringstream stream; stream << std::string(str); if (stream.str().find(sep) == std::string::npos) { - result.data = (char**) calloc(1, sizeof(char*)); - result.data[0] = (char*) calloc(JACK_CLIENT_NAME_SIZE + 1, sizeof(char)); - result.size = 1; + result.data.push_back((char*) calloc(JACK_CLIENT_NAME_SIZE + 1, sizeof(char))); strncpy(result.data[0], str, JACK_CLIENT_NAME_SIZE); result.data[0][JACK_CLIENT_NAME_SIZE] = '\0'; return result; } std::string driver; - std::vector drivers; while (std::getline(stream, driver, sep)) { driver.erase(std::remove_if(driver.begin(), driver.end(), isspace), driver.end()); - if (std::find(drivers.begin(), drivers.end(), driver) != drivers.end() && (flags & array_string_t::discard_duplicate)) + if (std::find(result.data.begin(), result.data.end(), driver) != result.data.end() && (flags & array_string_t::discard_duplicate)) continue; char *str = (char*) calloc(JACK_CLIENT_NAME_SIZE + 1, sizeof(char)); strncpy(str, driver.c_str(), JACK_CLIENT_NAME_SIZE); str[JACK_CLIENT_NAME_SIZE] = '\0'; - drivers.push_back(str); + result.data.push_back(str); } - result.data = (char**) calloc(driver.size(), sizeof(char*)); - result.size = drivers.size(); - memcpy(result.data, drivers.data(), result.size * sizeof(char*)); - return result; } @@ -1059,6 +1071,10 @@ SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLocke info.midi_name = strdup(param->value.str); break; + case 'x': + info.features |= param->value.i ? ALSA_DRIVER_FEAT_START_CLOSED : 0; + break; + case 'c': info.features |= param->value.i ? ALSA_DRIVER_FEAT_CLOSE_IDLE_DEVS : 0; break; @@ -1107,20 +1123,20 @@ SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLocke free(playback_channels_param); } - info.devices_capture_size = capture_names.size; - info.devices_playback_size = playback_names.size; + info.devices_capture_size = capture_names.data.size(); + info.devices_playback_size = playback_names.data.size(); info.devices = (alsa_device_info_t*) calloc(std::max(info.devices_capture_size, info.devices_playback_size), sizeof(alsa_device_info_t)); for (size_t i = 0; i < std::max(info.devices_capture_size, info.devices_playback_size); ++i) { - if (i < capture_names.size) { + if (i < capture_names.data.size()) { info.devices[i].capture_name = strdup(capture_names.data[i]); } - if (i < capture_channels.size) { + if (i < capture_channels.data.size()) { info.devices[i].capture_channels = atoi(capture_channels.data[i]); } - if (i < playback_names.size) { + if (i < playback_names.data.size()) { info.devices[i].playback_name = strdup(playback_names.data[i]); } - if (i < playback_channels.size) { + if (i < playback_channels.data.size()) { info.devices[i].playback_channels = atoi(playback_channels.data[i]); } } diff --git a/linux/alsa/alsa_driver.c b/linux/alsa/alsa_driver.c index 43191755..080d9dbb 100644 --- a/linux/alsa/alsa_driver.c +++ b/linux/alsa/alsa_driver.c @@ -1156,9 +1156,10 @@ alsa_driver_set_parameters (alsa_driver_t *driver, } #endif + alsa_driver_setup_io_function_pointers (driver, device); + /* do only on first start */ if (device->max_nchannels == 0) { - alsa_driver_setup_io_function_pointers (driver, device); /* Allocate and initialize structures that rely on the channels counts. @@ -1182,7 +1183,7 @@ alsa_driver_set_parameters (alsa_driver_t *driver, bitset_create (&device->channels_done, device->max_nchannels); bitset_create (&device->channels_not_done, device->max_nchannels); - if (device->playback_handle) { + if (device->playback_name) { device->playback_addr = (char **) malloc (sizeof (char *) * device->playback_nchannels); memset (device->playback_addr, 0, @@ -1206,7 +1207,7 @@ alsa_driver_set_parameters (alsa_driver_t *driver, driver->dither_state = (dither_state_t *) calloc (device->playback_nchannels, sizeof (dither_state_t)); } - if (device->capture_handle) { + if (device->capture_name) { device->capture_addr = (char **) malloc (sizeof (char *) * device->capture_nchannels); memset (device->capture_addr, 0, @@ -1388,7 +1389,7 @@ alsa_driver_open (alsa_driver_t *driver) alsa_device_t *device = &driver->devices[i]; int do_capture = 0, do_playback = 0; - if (!device->capture_handle && (i devices_c_count) && (device->capture_target_state != SND_PCM_STATE_NOTREADY)) { + if (!device->capture_handle && (i < driver->devices_c_count) && (device->capture_target_state != SND_PCM_STATE_NOTREADY)) { err = alsa_driver_open_device (driver, &driver->devices[i], SND_PCM_STREAM_CAPTURE); if (err < 0) { jack_error ("\n\nATTENTION: Opening of the capture device \"%s\" failed.", @@ -1399,7 +1400,7 @@ alsa_driver_open (alsa_driver_t *driver) do_capture = 1; } - if (!device->playback_handle && (i devices_p_count) && (device->playback_target_state != SND_PCM_STATE_NOTREADY)) { + if (!device->playback_handle && (i < driver->devices_p_count) && (device->playback_target_state != SND_PCM_STATE_NOTREADY)) { err = alsa_driver_open_device (driver, &driver->devices[i], SND_PCM_STREAM_PLAYBACK); if (err < 0) { jack_error ("\n\nATTENTION: Opening of the playback device \"%s\" failed.", diff --git a/linux/alsa/alsa_driver.h b/linux/alsa/alsa_driver.h index 1dca99d0..d5bf24f5 100644 --- a/linux/alsa/alsa_driver.h +++ b/linux/alsa/alsa_driver.h @@ -69,6 +69,7 @@ typedef int32_t alsa_driver_default_format_t; #define SND_PCM_STATE_NOTREADY (SND_PCM_STATE_LAST + 1) #endif +#define ALSA_DRIVER_FEAT_START_CLOSED (1 << 0) #define ALSA_DRIVER_FEAT_CLOSE_IDLE_DEVS (1 << 1) #define ALSA_DRIVER_FEAT_UNLINKED_DEVS (1 << 2)