mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	udev: check busy status of alsa cards before loading alsa modules and hence initiating profile probing
This commit is contained in:
		
							parent
							
								
									560da5b0a1
								
							
						
					
					
						commit
						d6fb8d1081
					
				
					 1 changed files with 130 additions and 15 deletions
				
			
		| 
						 | 
				
			
			@ -25,6 +25,7 @@
 | 
			
		|||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <dirent.h>
 | 
			
		||||
#include <sys/inotify.h>
 | 
			
		||||
#include <libudev.h>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -45,8 +46,7 @@ PA_MODULE_USAGE(
 | 
			
		|||
 | 
			
		||||
struct device {
 | 
			
		||||
    char *path;
 | 
			
		||||
    pa_bool_t accessible:1;
 | 
			
		||||
    pa_bool_t need_verify:1;
 | 
			
		||||
    pa_bool_t need_verify;
 | 
			
		||||
    char *card_name;
 | 
			
		||||
    char *args;
 | 
			
		||||
    uint32_t module;
 | 
			
		||||
| 
						 | 
				
			
			@ -99,26 +99,141 @@ static const char *path_get_card_id(const char *path) {
 | 
			
		|||
    return e + 5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static pa_bool_t is_card_busy(const char *id) {
 | 
			
		||||
    char *card_path = NULL, *pcm_path = NULL, *sub_status = NULL;
 | 
			
		||||
    DIR *card_dir = NULL, *pcm_dir = NULL;
 | 
			
		||||
    FILE *status_file = NULL;
 | 
			
		||||
    size_t len;
 | 
			
		||||
    struct dirent *space = NULL, *de;
 | 
			
		||||
    pa_bool_t busy = FALSE;
 | 
			
		||||
    int r;
 | 
			
		||||
 | 
			
		||||
    pa_assert(id);
 | 
			
		||||
 | 
			
		||||
    card_path = pa_sprintf_malloc("/proc/asound/card%s", id);
 | 
			
		||||
 | 
			
		||||
    if (!(card_dir = opendir(card_path))) {
 | 
			
		||||
        pa_log_warn("Failed to open %s: %s", card_path, pa_cstrerror(errno));
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    len = offsetof(struct dirent, d_name) + fpathconf(dirfd(card_dir), _PC_NAME_MAX) + 1;
 | 
			
		||||
    space = pa_xmalloc(len);
 | 
			
		||||
 | 
			
		||||
    for (;;) {
 | 
			
		||||
        de = NULL;
 | 
			
		||||
 | 
			
		||||
        if ((r = readdir_r(card_dir, space, &de)) != 0) {
 | 
			
		||||
            pa_log_warn("readdir_r() failed: %s", pa_cstrerror(r));
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!de)
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        if (!pa_startswith(de->d_name, "pcm"))
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        pa_xfree(pcm_path);
 | 
			
		||||
        pcm_path = pa_sprintf_malloc("%s/%s", card_path, de->d_name);
 | 
			
		||||
 | 
			
		||||
        if (pcm_dir)
 | 
			
		||||
            closedir(pcm_dir);
 | 
			
		||||
 | 
			
		||||
        if (!(pcm_dir = opendir(pcm_path))) {
 | 
			
		||||
            pa_log_warn("Failed to open %s: %s", pcm_path, pa_cstrerror(errno));
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (;;) {
 | 
			
		||||
            char line[32];
 | 
			
		||||
 | 
			
		||||
            if ((r = readdir_r(pcm_dir, space, &de)) != 0) {
 | 
			
		||||
                pa_log_warn("readdir_r() failed: %s", pa_cstrerror(r));
 | 
			
		||||
                goto fail;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!de)
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            if (!pa_startswith(de->d_name, "sub"))
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            pa_xfree(sub_status);
 | 
			
		||||
            sub_status = pa_sprintf_malloc("%s/%s/status", pcm_path, de->d_name);
 | 
			
		||||
 | 
			
		||||
            if (status_file)
 | 
			
		||||
                fclose(status_file);
 | 
			
		||||
 | 
			
		||||
            if (!(status_file = fopen(sub_status, "r"))) {
 | 
			
		||||
                pa_log_warn("Failed to open %s: %s", sub_status, pa_cstrerror(errno));
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!(fgets(line, sizeof(line)-1, status_file))) {
 | 
			
		||||
                pa_log_warn("Failed to read from %s: %s", sub_status, pa_cstrerror(errno));
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!pa_streq(line, "closed\n")) {
 | 
			
		||||
                busy = TRUE;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
 | 
			
		||||
    pa_xfree(card_path);
 | 
			
		||||
    pa_xfree(pcm_path);
 | 
			
		||||
    pa_xfree(sub_status);
 | 
			
		||||
    pa_xfree(space);
 | 
			
		||||
 | 
			
		||||
    if (card_dir)
 | 
			
		||||
        closedir(card_dir);
 | 
			
		||||
 | 
			
		||||
    if (pcm_dir)
 | 
			
		||||
        closedir(pcm_dir);
 | 
			
		||||
 | 
			
		||||
    if (status_file)
 | 
			
		||||
        fclose(status_file);
 | 
			
		||||
 | 
			
		||||
    return busy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void verify_access(struct userdata *u, struct device *d) {
 | 
			
		||||
    char *cd;
 | 
			
		||||
    pa_card *card;
 | 
			
		||||
    pa_bool_t accessible;
 | 
			
		||||
 | 
			
		||||
    pa_assert(u);
 | 
			
		||||
    pa_assert(d);
 | 
			
		||||
 | 
			
		||||
    cd = pa_sprintf_malloc("%s/snd/controlC%s", udev_get_dev_path(u->udev), path_get_card_id(d->path));
 | 
			
		||||
    d->accessible = access(cd, R_OK|W_OK) >= 0;
 | 
			
		||||
    accessible = access(cd, R_OK|W_OK) >= 0;
 | 
			
		||||
    pa_log_debug("%s is accessible: %s", cd, pa_yes_no(accessible));
 | 
			
		||||
 | 
			
		||||
    pa_log_info("%s is accessible: %s", cd, pa_yes_no(d->accessible));
 | 
			
		||||
    pa_xfree(cd);
 | 
			
		||||
 | 
			
		||||
    if (d->module == PA_INVALID_INDEX) {
 | 
			
		||||
 | 
			
		||||
        /* If we not loaded, try to load */
 | 
			
		||||
        /* If we are not loaded, try to load */
 | 
			
		||||
 | 
			
		||||
        if (d->accessible) {
 | 
			
		||||
        if (accessible) {
 | 
			
		||||
            pa_module *m;
 | 
			
		||||
            pa_bool_t busy;
 | 
			
		||||
 | 
			
		||||
            /* Check if any of the PCM devices that belong to this
 | 
			
		||||
             * card are currently busy. If they are, don't try to load
 | 
			
		||||
             * right now, to make sure the probing phase can
 | 
			
		||||
             * successfully complete. When the current user of the
 | 
			
		||||
             * device closes it we will get another notification via
 | 
			
		||||
             * inotify and can then recheck. */
 | 
			
		||||
 | 
			
		||||
            busy = is_card_busy(path_get_card_id(d->path));
 | 
			
		||||
            pa_log_debug("%s is busy: %s", d->path, pa_yes_no(busy));
 | 
			
		||||
 | 
			
		||||
            if (!busy) {
 | 
			
		||||
                pa_log_debug("Loading module-alsa-card with arguments '%s'", d->args);
 | 
			
		||||
                m = pa_module_load(u->core, "module-alsa-card", d->args);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -128,6 +243,7 @@ static void verify_access(struct userdata *u, struct device *d) {
 | 
			
		|||
                } else
 | 
			
		||||
                    pa_log_info("Card %s (%s) failed to load module.", d->path, d->card_name);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -135,7 +251,7 @@ static void verify_access(struct userdata *u, struct device *d) {
 | 
			
		|||
         * accessible boolean */
 | 
			
		||||
 | 
			
		||||
        if ((card = pa_namereg_get(u->core, d->card_name, PA_NAMEREG_CARD)))
 | 
			
		||||
            pa_card_suspend(card, !d->accessible, PA_SUSPEND_SESSION);
 | 
			
		||||
            pa_card_suspend(card, !accessible, PA_SUSPEND_SESSION);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -160,7 +276,6 @@ static void card_changed(struct userdata *u, struct udev_device *dev) {
 | 
			
		|||
 | 
			
		||||
    d = pa_xnew0(struct device, 1);
 | 
			
		||||
    d->path = pa_xstrdup(path);
 | 
			
		||||
    d->accessible = TRUE;
 | 
			
		||||
    d->module = PA_INVALID_INDEX;
 | 
			
		||||
 | 
			
		||||
    if (!(t = udev_device_get_property_value(dev, "PULSE_NAME")))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue