Device reservation fixestags/1.9.9.5^0
| @@ -76,6 +76,8 @@ SERVER_EXPORT bool audio_acquire(const char * device_name) | |||||
| assert(gReserveCount < DEVICE_MAX); | assert(gReserveCount < DEVICE_MAX); | ||||
| dbus_error_init(&error); | |||||
| if ((ret= rd_acquire( | if ((ret= rd_acquire( | ||||
| &gReservedDevice[gReserveCount].reserved_device, | &gReservedDevice[gReserveCount].reserved_device, | ||||
| gConnection, | gConnection, | ||||
| @@ -86,6 +88,7 @@ SERVER_EXPORT bool audio_acquire(const char * device_name) | |||||
| &error)) < 0) { | &error)) < 0) { | ||||
| jack_error("Failed to acquire device name : %s error : %s", device_name, (error.message ? error.message : strerror(-ret))); | jack_error("Failed to acquire device name : %s error : %s", device_name, (error.message ? error.message : strerror(-ret))); | ||||
| dbus_error_free(&error); | |||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -377,6 +377,8 @@ on_device_acquire(const char * device_name) | |||||
| int ret; | int ret; | ||||
| DBusError error; | DBusError error; | ||||
| dbus_error_init(&error); | |||||
| ret = rd_acquire( | ret = rd_acquire( | ||||
| &g_reserved_device[g_device_count].reserved_device, | &g_reserved_device[g_device_count].reserved_device, | ||||
| g_connection, | g_connection, | ||||
| @@ -388,6 +390,7 @@ on_device_acquire(const char * device_name) | |||||
| if (ret < 0) | if (ret < 0) | ||||
| { | { | ||||
| jack_error("Failed to acquire device name : %s error : %s", device_name, (error.message ? error.message : strerror(-ret))); | jack_error("Failed to acquire device name : %s error : %s", device_name, (error.message ? error.message : strerror(-ret))); | ||||
| dbus_error_free(&error); | |||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -31,6 +31,11 @@ | |||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include "reserve.h" | #include "reserve.h" | ||||
| #include "jack/control.h" | |||||
| #define RESERVE_ERROR_NO_MEMORY "org.freedesktop.ReserveDevice1.Error.NoMemory" | |||||
| #define RESERVE_ERROR_PROTOCOL_VIOLATION "org.freedesktop.ReserveDevice1.Error.Protocol" | |||||
| #define RESERVE_ERROR_RELEASE_DENIED "org.freedesktop.ReserveDevice1.Error.ReleaseDenied" | |||||
| struct rd_device { | struct rd_device { | ||||
| int ref; | int ref; | ||||
| @@ -371,34 +376,51 @@ int rd_acquire( | |||||
| dbus_bool_t good; | dbus_bool_t good; | ||||
| vtable.message_function = object_handler; | vtable.message_function = object_handler; | ||||
| if (!error) | |||||
| if (!error) { | |||||
| error = &_error; | error = &_error; | ||||
| dbus_error_init(error); | |||||
| } | |||||
| dbus_error_init(error); | |||||
| if (!_d) | |||||
| return -EINVAL; | |||||
| if (!_d) { | |||||
| assert(0); | |||||
| r = -EINVAL; | |||||
| goto fail; | |||||
| } | |||||
| if (!connection) | |||||
| return -EINVAL; | |||||
| if (!connection) { | |||||
| assert(0); | |||||
| r = -EINVAL; | |||||
| goto fail; | |||||
| } | |||||
| if (!device_name) | |||||
| return -EINVAL; | |||||
| if (!device_name) { | |||||
| assert(0); | |||||
| r = -EINVAL; | |||||
| goto fail; | |||||
| } | |||||
| if (!request_cb && priority != INT32_MAX) | |||||
| return -EINVAL; | |||||
| if (!request_cb && priority != INT32_MAX) { | |||||
| assert(0); | |||||
| r = -EINVAL; | |||||
| goto fail; | |||||
| } | |||||
| if (!(d = (rd_device *)calloc(sizeof(rd_device), 1))) | |||||
| return -ENOMEM; | |||||
| if (!(d = (rd_device *)calloc(sizeof(rd_device), 1))) { | |||||
| dbus_set_error(error, RESERVE_ERROR_NO_MEMORY, "Cannot allocate memory for rd_device struct"); | |||||
| r = -ENOMEM; | |||||
| goto fail; | |||||
| } | |||||
| d->ref = 1; | d->ref = 1; | ||||
| if (!(d->device_name = strdup(device_name))) { | if (!(d->device_name = strdup(device_name))) { | ||||
| dbus_set_error(error, RESERVE_ERROR_NO_MEMORY, "Cannot duplicate device name string"); | |||||
| r = -ENOMEM; | r = -ENOMEM; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| if (!(d->application_name = strdup(application_name))) { | if (!(d->application_name = strdup(application_name))) { | ||||
| dbus_set_error(error, RESERVE_ERROR_NO_MEMORY, "Cannot duplicate application name string"); | |||||
| r = -ENOMEM; | r = -ENOMEM; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| @@ -408,12 +430,14 @@ int rd_acquire( | |||||
| d->request_cb = request_cb; | d->request_cb = request_cb; | ||||
| if (!(d->service_name = (char*)malloc(sizeof(SERVICE_PREFIX) + strlen(device_name)))) { | if (!(d->service_name = (char*)malloc(sizeof(SERVICE_PREFIX) + strlen(device_name)))) { | ||||
| dbus_set_error(error, RESERVE_ERROR_NO_MEMORY, "Cannot allocate memory for service name string"); | |||||
| r = -ENOMEM; | r = -ENOMEM; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| sprintf(d->service_name, SERVICE_PREFIX "%s", d->device_name); | sprintf(d->service_name, SERVICE_PREFIX "%s", d->device_name); | ||||
| if (!(d->object_path = (char*)malloc(sizeof(OBJECT_PREFIX) + strlen(device_name)))) { | if (!(d->object_path = (char*)malloc(sizeof(OBJECT_PREFIX) + strlen(device_name)))) { | ||||
| dbus_set_error(error, RESERVE_ERROR_NO_MEMORY, "Cannot allocate memory for object path string"); | |||||
| r = -ENOMEM; | r = -ENOMEM; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| @@ -425,20 +449,28 @@ int rd_acquire( | |||||
| DBUS_NAME_FLAG_DO_NOT_QUEUE| | DBUS_NAME_FLAG_DO_NOT_QUEUE| | ||||
| (priority < INT32_MAX ? DBUS_NAME_FLAG_ALLOW_REPLACEMENT : 0), | (priority < INT32_MAX ? DBUS_NAME_FLAG_ALLOW_REPLACEMENT : 0), | ||||
| error)) < 0) { | error)) < 0) { | ||||
| jack_error("dbus_bus_request_name() failed. (1)"); | |||||
| r = -EIO; | r = -EIO; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| if (k == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER || k == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER) | |||||
| switch (k) { | |||||
| case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: | |||||
| case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: | |||||
| goto success; | goto success; | ||||
| if (k != DBUS_REQUEST_NAME_REPLY_EXISTS) { | |||||
| case DBUS_REQUEST_NAME_REPLY_EXISTS: | |||||
| break; | |||||
| case DBUS_REQUEST_NAME_REPLY_IN_QUEUE : /* DBUS_NAME_FLAG_DO_NOT_QUEUE was specified */ | |||||
| default: /* unknown reply returned */ | |||||
| jack_error("request name reply with unexpected value %d.", k); | |||||
| assert(0); | |||||
| r = -EIO; | r = -EIO; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| if (priority <= INT32_MIN) { | if (priority <= INT32_MIN) { | ||||
| r = -EBUSY; | r = -EBUSY; | ||||
| dbus_set_error(error, RESERVE_ERROR_RELEASE_DENIED, "Device reservation request with priority %"PRIi32" denied for \"%s\"", priority, device_name); | |||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| @@ -447,6 +479,7 @@ int rd_acquire( | |||||
| d->object_path, | d->object_path, | ||||
| "org.freedesktop.ReserveDevice1", | "org.freedesktop.ReserveDevice1", | ||||
| "RequestRelease"))) { | "RequestRelease"))) { | ||||
| dbus_set_error(error, RESERVE_ERROR_NO_MEMORY, "Cannot allocate memory for RequestRelease method call"); | |||||
| r = -ENOMEM; | r = -ENOMEM; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| @@ -455,6 +488,7 @@ int rd_acquire( | |||||
| m, | m, | ||||
| DBUS_TYPE_INT32, &d->priority, | DBUS_TYPE_INT32, &d->priority, | ||||
| DBUS_TYPE_INVALID)) { | DBUS_TYPE_INVALID)) { | ||||
| dbus_set_error(error, RESERVE_ERROR_NO_MEMORY, "Cannot append args for RequestRelease method call"); | |||||
| r = -ENOMEM; | r = -ENOMEM; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| @@ -469,10 +503,12 @@ int rd_acquire( | |||||
| dbus_error_has_name(error, DBUS_ERROR_UNKNOWN_METHOD) || | dbus_error_has_name(error, DBUS_ERROR_UNKNOWN_METHOD) || | ||||
| dbus_error_has_name(error, DBUS_ERROR_NO_REPLY)) { | dbus_error_has_name(error, DBUS_ERROR_NO_REPLY)) { | ||||
| /* This must be treated as denied. */ | /* This must be treated as denied. */ | ||||
| jack_info("Device reservation request with priority %"PRIi32" denied for \"%s\": %s (%s)", priority, device_name, error->name, error->message); | |||||
| r = -EBUSY; | r = -EBUSY; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| jack_error("dbus_connection_send_with_reply_and_block(RequestRelease) failed."); | |||||
| r = -EIO; | r = -EIO; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| @@ -482,11 +518,13 @@ int rd_acquire( | |||||
| error, | error, | ||||
| DBUS_TYPE_BOOLEAN, &good, | DBUS_TYPE_BOOLEAN, &good, | ||||
| DBUS_TYPE_INVALID)) { | DBUS_TYPE_INVALID)) { | ||||
| jack_error("RequestRelease() reply is invalid."); | |||||
| r = -EIO; | r = -EIO; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| if (!good) { | if (!good) { | ||||
| dbus_set_error(error, RESERVE_ERROR_RELEASE_DENIED, "Device reservation request with priority %"PRIi32" denied for \"%s\" via RequestRelease()", priority, device_name); | |||||
| r = -EBUSY; | r = -EBUSY; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| @@ -498,11 +536,14 @@ int rd_acquire( | |||||
| (priority < INT32_MAX ? DBUS_NAME_FLAG_ALLOW_REPLACEMENT : 0)| | (priority < INT32_MAX ? DBUS_NAME_FLAG_ALLOW_REPLACEMENT : 0)| | ||||
| DBUS_NAME_FLAG_REPLACE_EXISTING, | DBUS_NAME_FLAG_REPLACE_EXISTING, | ||||
| error)) < 0) { | error)) < 0) { | ||||
| jack_error("dbus_bus_request_name() failed. (2)"); | |||||
| r = -EIO; | r = -EIO; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| if (k != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { | if (k != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { | ||||
| /* this is racy, another contender may have acquired the device */ | |||||
| dbus_set_error(error, RESERVE_ERROR_PROTOCOL_VIOLATION, "request name reply is not DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER but %d.", k); | |||||
| r = -EIO; | r = -EIO; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| @@ -510,11 +551,13 @@ int rd_acquire( | |||||
| success: | success: | ||||
| d->owning = 1; | d->owning = 1; | ||||
| if (!(dbus_connection_register_object_path( | |||||
| if (!(dbus_connection_try_register_object_path( | |||||
| d->connection, | d->connection, | ||||
| d->object_path, | d->object_path, | ||||
| &vtable, | &vtable, | ||||
| d))) { | |||||
| d, | |||||
| error))) { | |||||
| jack_error("cannot register object path \"%s\": %s", d->object_path, error->message); | |||||
| r = -ENOMEM; | r = -ENOMEM; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| @@ -526,6 +569,7 @@ success: | |||||
| filter_handler, | filter_handler, | ||||
| d, | d, | ||||
| NULL)) { | NULL)) { | ||||
| dbus_set_error(error, RESERVE_ERROR_NO_MEMORY, "Cannot add filter"); | |||||
| r = -ENOMEM; | r = -ENOMEM; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| @@ -31,7 +31,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
| #include <signal.h> | #include <signal.h> | ||||
| #include <sys/types.h> | #include <sys/types.h> | ||||
| #include <sys/time.h> | #include <sys/time.h> | ||||
| #include <regex.h> | |||||
| #include <string.h> | #include <string.h> | ||||
| #include "JackAlsaDriver.h" | #include "JackAlsaDriver.h" | ||||
| @@ -172,30 +171,31 @@ int JackAlsaDriver::Detach() | |||||
| return JackAudioDriver::Detach(); | return JackAudioDriver::Detach(); | ||||
| } | } | ||||
| static char* get_control_device_name(const char * device_name) | |||||
| extern "C" char* get_control_device_name(const char * device_name) | |||||
| { | { | ||||
| char * ctl_name; | char * ctl_name; | ||||
| regex_t expression; | |||||
| const char * comma; | |||||
| regcomp(&expression, "(plug)?hw:[0-9](,[0-9])?", REG_ICASE | REG_EXTENDED); | |||||
| /* the user wants a hw or plughw device, the ctl name | |||||
| * should be hw:x where x is the card identification. | |||||
| * We skip the subdevice suffix that starts with comma */ | |||||
| if (!regexec(&expression, device_name, 0, NULL, 0)) { | |||||
| /* the user wants a hw or plughw device, the ctl name | |||||
| * should be hw:x where x is the card number */ | |||||
| char tmp[5]; | |||||
| strncpy(tmp, strstr(device_name, "hw"), 4); | |||||
| tmp[4] = '\0'; | |||||
| jack_info("control device %s",tmp); | |||||
| ctl_name = strdup(tmp); | |||||
| } else { | |||||
| ctl_name = strdup(device_name); | |||||
| if (strncasecmp(device_name, "plughw:", 7) == 0) { | |||||
| /* skip the "plug" prefix" */ | |||||
| device_name += 4; | |||||
| } | } | ||||
| regfree(&expression); | |||||
| if (ctl_name == NULL) { | |||||
| jack_error("strdup(\"%s\") failed.", ctl_name); | |||||
| comma = strchr(device_name, ','); | |||||
| if (comma == NULL) { | |||||
| ctl_name = strdup(device_name); | |||||
| if (ctl_name == NULL) { | |||||
| jack_error("strdup(\"%s\") failed.", device_name); | |||||
| } | |||||
| } else { | |||||
| ctl_name = strndup(device_name, comma - device_name); | |||||
| if (ctl_name == NULL) { | |||||
| jack_error("strndup(\"%s\", %u) failed.", device_name, (unsigned int)(comma - device_name)); | |||||
| } | |||||
| } | } | ||||
| return ctl_name; | return ctl_name; | ||||
| @@ -278,16 +278,22 @@ int JackAlsaDriver::Open(jack_nframes_t nframes, | |||||
| int playback_card = card_to_num(playback_driver_name); | int playback_card = card_to_num(playback_driver_name); | ||||
| char audio_name[32]; | char audio_name[32]; | ||||
| snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card); | |||||
| if (!JackServerGlobals::on_device_acquire(audio_name)) { | |||||
| jack_error("Audio device %s cannot be acquired...", capture_driver_name); | |||||
| return -1; | |||||
| if (capture_card >= 0) { | |||||
| snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card); | |||||
| if (!JackServerGlobals::on_device_acquire(audio_name)) { | |||||
| jack_error("Audio device %s cannot be acquired...", capture_driver_name); | |||||
| return -1; | |||||
| } | |||||
| } | } | ||||
| if (playback_card != capture_card) { | |||||
| if (playback_card >= 0 && playback_card != capture_card) { | |||||
| snprintf(audio_name, sizeof(audio_name), "Audio%d", playback_card); | snprintf(audio_name, sizeof(audio_name), "Audio%d", playback_card); | ||||
| if (!JackServerGlobals::on_device_acquire(audio_name)) { | if (!JackServerGlobals::on_device_acquire(audio_name)) { | ||||
| jack_error("Audio device %s cannot be acquired...", playback_driver_name); | jack_error("Audio device %s cannot be acquired...", playback_driver_name); | ||||
| if (capture_card >= 0) { | |||||
| snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card); | |||||
| JackServerGlobals::on_device_release(audio_name); | |||||
| } | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| } | } | ||||
| @@ -39,15 +39,13 @@ class JackAlsaDriver : public JackAudioDriver | |||||
| private: | private: | ||||
| jack_driver_t* fDriver; | jack_driver_t* fDriver; | ||||
| int fReservedCaptureDevice; | |||||
| int fReservedPlaybackDevice; | |||||
| void UpdateLatencies(); | void UpdateLatencies(); | ||||
| public: | public: | ||||
| JackAlsaDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) | JackAlsaDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) | ||||
| : JackAudioDriver(name, alias, engine, table),fDriver(NULL),fReservedCaptureDevice(-1),fReservedPlaybackDevice(-1) | |||||
| : JackAudioDriver(name, alias, engine, table),fDriver(NULL) | |||||
| {} | {} | ||||
| virtual ~JackAlsaDriver() | virtual ~JackAlsaDriver() | ||||
| {} | {} | ||||
| @@ -32,7 +32,6 @@ | |||||
| #include <signal.h> | #include <signal.h> | ||||
| #include <sys/types.h> | #include <sys/types.h> | ||||
| #include <sys/time.h> | #include <sys/time.h> | ||||
| #include <regex.h> | |||||
| #include <string.h> | #include <string.h> | ||||
| #include "alsa_driver.h" | #include "alsa_driver.h" | ||||
| @@ -137,30 +136,18 @@ alsa_driver_check_capabilities (alsa_driver_t *driver) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| char* get_control_device_name(const char * device_name); | |||||
| static int | static int | ||||
| alsa_driver_check_card_type (alsa_driver_t *driver) | alsa_driver_check_card_type (alsa_driver_t *driver) | ||||
| { | { | ||||
| int err; | int err; | ||||
| snd_ctl_card_info_t *card_info; | snd_ctl_card_info_t *card_info; | ||||
| char * ctl_name; | char * ctl_name; | ||||
| regex_t expression; | |||||
| snd_ctl_card_info_alloca (&card_info); | snd_ctl_card_info_alloca (&card_info); | ||||
| regcomp(&expression,"(plug)?hw:[0-9](,[0-9])?",REG_ICASE|REG_EXTENDED); | |||||
| if (!regexec(&expression,driver->alsa_name_playback,0,NULL,0)) { | |||||
| /* the user wants a hw or plughw device, the ctl name | |||||
| * should be hw:x where x is the card number */ | |||||
| char tmp[5]; | |||||
| strncpy(tmp,strcasestr(driver->alsa_name_playback,"hw"),4); | |||||
| tmp[4]='\0'; | |||||
| jack_info("control device %s",tmp); | |||||
| ctl_name = strdup(tmp); | |||||
| } else { | |||||
| ctl_name = strdup(driver->alsa_name_playback); | |||||
| } | |||||
| ctl_name = get_control_device_name(driver->alsa_name_playback); | |||||
| // XXX: I don't know the "right" way to do this. Which to use | // XXX: I don't know the "right" way to do this. Which to use | ||||
| // driver->alsa_name_playback or driver->alsa_name_capture. | // driver->alsa_name_playback or driver->alsa_name_capture. | ||||
| @@ -175,7 +162,6 @@ alsa_driver_check_card_type (alsa_driver_t *driver) | |||||
| driver->alsa_driver = strdup(snd_ctl_card_info_get_driver (card_info)); | driver->alsa_driver = strdup(snd_ctl_card_info_get_driver (card_info)); | ||||
| regfree(&expression); | |||||
| free(ctl_name); | free(ctl_name); | ||||
| return alsa_driver_check_capabilities (driver); | return alsa_driver_check_capabilities (driver); | ||||