mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	alsa: Move UCM port availability updating to the mixer code
Previously module-alsa-card assigned to pa_alsa_jack.plugged_in directly, and then did the port availability updating manually. The idea of pa_alsa_jack_set_plugged_in() is to move the availability updating to the mixer infrastructure, where it really belongs. Similarly, pa_alsa_jack.has_control was previously modified directly from several places. The has_control field affects the port availability, and pa_alsa_jack_set_has_control() takes care of updating the availability. For now, pa_alsa_jack_set_plugged_in() and pa_alsa_jack_set_has_control() only update the port availability when using UCM. My plan is to adapt the traditional mixer code later.
This commit is contained in:
		
							parent
							
								
									40714b6bcc
								
							
						
					
					
						commit
						c9557e6969
					
				
					 6 changed files with 112 additions and 17 deletions
				
			
		| 
						 | 
				
			
			@ -139,6 +139,36 @@ void pa_alsa_jack_free(pa_alsa_jack *jack) {
 | 
			
		|||
    pa_xfree(jack);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_alsa_jack_set_has_control(pa_alsa_jack *jack, bool has_control) {
 | 
			
		||||
    pa_alsa_ucm_device *device;
 | 
			
		||||
    unsigned idx;
 | 
			
		||||
 | 
			
		||||
    pa_assert(jack);
 | 
			
		||||
 | 
			
		||||
    if (has_control == jack->has_control)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    jack->has_control = has_control;
 | 
			
		||||
 | 
			
		||||
    PA_DYNARRAY_FOREACH(device, jack->ucm_devices, idx)
 | 
			
		||||
        pa_alsa_ucm_device_update_available(device);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_alsa_jack_set_plugged_in(pa_alsa_jack *jack, bool plugged_in) {
 | 
			
		||||
    pa_alsa_ucm_device *device;
 | 
			
		||||
    unsigned idx;
 | 
			
		||||
 | 
			
		||||
    pa_assert(jack);
 | 
			
		||||
 | 
			
		||||
    if (plugged_in == jack->plugged_in)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    jack->plugged_in = plugged_in;
 | 
			
		||||
 | 
			
		||||
    PA_DYNARRAY_FOREACH(device, jack->ucm_devices, idx)
 | 
			
		||||
        pa_alsa_ucm_device_update_available(device);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_alsa_jack_add_ucm_device(pa_alsa_jack *jack, pa_alsa_ucm_device *device) {
 | 
			
		||||
    pa_assert(jack);
 | 
			
		||||
    pa_assert(device);
 | 
			
		||||
| 
						 | 
				
			
			@ -1755,10 +1785,13 @@ static int element_probe(pa_alsa_element *e, snd_mixer_t *m) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static int jack_probe(pa_alsa_jack *j, snd_mixer_t *m) {
 | 
			
		||||
    bool has_control;
 | 
			
		||||
 | 
			
		||||
    pa_assert(j);
 | 
			
		||||
    pa_assert(j->path);
 | 
			
		||||
 | 
			
		||||
    j->has_control = pa_alsa_mixer_find(m, j->alsa_name, 0) != NULL;
 | 
			
		||||
    has_control = pa_alsa_mixer_find(m, j->alsa_name, 0) != NULL;
 | 
			
		||||
    pa_alsa_jack_set_has_control(j, has_control);
 | 
			
		||||
 | 
			
		||||
    if (j->has_control) {
 | 
			
		||||
        if (j->required_absent != PA_ALSA_REQUIRED_IGNORE)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -174,6 +174,8 @@ struct pa_alsa_jack {
 | 
			
		|||
 | 
			
		||||
pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name, const char *alsa_name);
 | 
			
		||||
void pa_alsa_jack_free(pa_alsa_jack *jack);
 | 
			
		||||
void pa_alsa_jack_set_has_control(pa_alsa_jack *jack, bool has_control);
 | 
			
		||||
void pa_alsa_jack_set_plugged_in(pa_alsa_jack *jack, bool plugged_in);
 | 
			
		||||
void pa_alsa_jack_add_ucm_device(pa_alsa_jack *jack, pa_alsa_ucm_device *device);
 | 
			
		||||
 | 
			
		||||
/* A path wraps a series of elements into a single entity which can be
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -90,6 +90,7 @@ struct ucm_port {
 | 
			
		|||
static struct ucm_port *ucm_port_new(pa_alsa_ucm_config *ucm, pa_device_port *core_port, pa_alsa_ucm_device **devices,
 | 
			
		||||
                                     unsigned n_devices);
 | 
			
		||||
static void ucm_port_free(struct ucm_port *port);
 | 
			
		||||
static void ucm_port_update_available(struct ucm_port *port);
 | 
			
		||||
 | 
			
		||||
static struct ucm_items item[] = {
 | 
			
		||||
    {"PlaybackPCM", PA_ALSA_PROP_UCM_SINK},
 | 
			
		||||
| 
						 | 
				
			
			@ -413,6 +414,7 @@ static int ucm_get_devices(pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr) {
 | 
			
		|||
        pa_proplist_sets(d->proplist, PA_ALSA_PROP_UCM_NAME, pa_strnull(dev_list[i]));
 | 
			
		||||
        pa_proplist_sets(d->proplist, PA_ALSA_PROP_UCM_DESCRIPTION, pa_strna(dev_list[i + 1]));
 | 
			
		||||
        d->ucm_ports = pa_dynarray_new(NULL);
 | 
			
		||||
        d->available = PA_AVAILABLE_UNKNOWN;
 | 
			
		||||
 | 
			
		||||
        PA_LLIST_PREPEND(pa_alsa_ucm_device, verb->devices, d);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1465,7 +1467,10 @@ static void ucm_mapping_jack_probe(pa_alsa_mapping *m) {
 | 
			
		|||
        return;
 | 
			
		||||
 | 
			
		||||
    PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) {
 | 
			
		||||
        dev->jack->has_control = pa_alsa_mixer_find(mixer_handle, dev->jack->alsa_name, 0) != NULL;
 | 
			
		||||
        bool has_control;
 | 
			
		||||
 | 
			
		||||
        has_control = pa_alsa_mixer_find(mixer_handle, dev->jack->alsa_name, 0) != NULL;
 | 
			
		||||
        pa_alsa_jack_set_has_control(dev->jack, has_control);
 | 
			
		||||
        pa_log_info("UCM jack %s has_control=%d", dev->jack->name, dev->jack->has_control);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1716,6 +1721,34 @@ static void device_set_jack(pa_alsa_ucm_device *device, pa_alsa_jack *jack) {
 | 
			
		|||
 | 
			
		||||
    device->jack = jack;
 | 
			
		||||
    pa_alsa_jack_add_ucm_device(jack, device);
 | 
			
		||||
 | 
			
		||||
    pa_alsa_ucm_device_update_available(device);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void device_set_available(pa_alsa_ucm_device *device, pa_available_t available) {
 | 
			
		||||
    struct ucm_port *port;
 | 
			
		||||
    unsigned idx;
 | 
			
		||||
 | 
			
		||||
    pa_assert(device);
 | 
			
		||||
 | 
			
		||||
    if (available == device->available)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    device->available = available;
 | 
			
		||||
 | 
			
		||||
    PA_DYNARRAY_FOREACH(port, device->ucm_ports, idx)
 | 
			
		||||
        ucm_port_update_available(port);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_alsa_ucm_device_update_available(pa_alsa_ucm_device *device) {
 | 
			
		||||
    pa_available_t available = PA_AVAILABLE_UNKNOWN;
 | 
			
		||||
 | 
			
		||||
    pa_assert(device);
 | 
			
		||||
 | 
			
		||||
    if (device->jack && device->jack->has_control)
 | 
			
		||||
        available = device->jack->plugged_in ? PA_AVAILABLE_YES : PA_AVAILABLE_NO;
 | 
			
		||||
 | 
			
		||||
    device_set_available(device, available);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct ucm_port *ucm_port_new(pa_alsa_ucm_config *ucm, pa_device_port *core_port, pa_alsa_ucm_device **devices,
 | 
			
		||||
| 
						 | 
				
			
			@ -1737,6 +1770,8 @@ static struct ucm_port *ucm_port_new(pa_alsa_ucm_config *ucm, pa_device_port *co
 | 
			
		|||
        device_add_ucm_port(devices[i], port);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ucm_port_update_available(port);
 | 
			
		||||
 | 
			
		||||
    return port;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1749,6 +1784,25 @@ static void ucm_port_free(struct ucm_port *port) {
 | 
			
		|||
    pa_xfree(port);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ucm_port_update_available(struct ucm_port *port) {
 | 
			
		||||
    pa_alsa_ucm_device *device;
 | 
			
		||||
    unsigned idx;
 | 
			
		||||
    pa_available_t available = PA_AVAILABLE_YES;
 | 
			
		||||
 | 
			
		||||
    pa_assert(port);
 | 
			
		||||
 | 
			
		||||
    PA_DYNARRAY_FOREACH(device, port->devices, idx) {
 | 
			
		||||
        if (device->available == PA_AVAILABLE_UNKNOWN)
 | 
			
		||||
            available = PA_AVAILABLE_UNKNOWN;
 | 
			
		||||
        else if (device->available == PA_AVAILABLE_NO) {
 | 
			
		||||
            available = PA_AVAILABLE_NO;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_device_port_set_available(port->core_port, available);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#else /* HAVE_ALSA_UCM */
 | 
			
		||||
 | 
			
		||||
/* Dummy functions for systems without UCM support */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -148,8 +148,11 @@ struct pa_alsa_ucm_device {
 | 
			
		|||
    pa_dynarray *ucm_ports; /* struct ucm_port */
 | 
			
		||||
 | 
			
		||||
    pa_alsa_jack *jack;
 | 
			
		||||
    pa_available_t available;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void pa_alsa_ucm_device_update_available(pa_alsa_ucm_device *device);
 | 
			
		||||
 | 
			
		||||
struct pa_alsa_ucm_modifier {
 | 
			
		||||
    PA_LLIST_FIELDS(pa_alsa_ucm_modifier);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -378,16 +378,17 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) {
 | 
			
		|||
 | 
			
		||||
    PA_HASHMAP_FOREACH(jack, u->jacks, state)
 | 
			
		||||
        if (jack->melem == melem) {
 | 
			
		||||
            jack->plugged_in = plugged_in;
 | 
			
		||||
            pa_alsa_jack_set_plugged_in(jack, plugged_in);
 | 
			
		||||
 | 
			
		||||
            if (u->use_ucm) {
 | 
			
		||||
                pa_assert(u->card->ports);
 | 
			
		||||
                port = pa_hashmap_get(u->card->ports, jack->name);
 | 
			
		||||
                pa_assert(port);
 | 
			
		||||
                /* When using UCM, pa_alsa_jack_set_plugged_in() maps the jack
 | 
			
		||||
                 * state to port availability. */
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                pa_assert(jack->path);
 | 
			
		||||
 | 
			
		||||
            /* When not using UCM, we have to do the jack state -> port
 | 
			
		||||
             * availability mapping ourselves. */
 | 
			
		||||
            pa_assert_se(port = jack->path->port);
 | 
			
		||||
            }
 | 
			
		||||
            report_port_state(port, u);
 | 
			
		||||
        }
 | 
			
		||||
    return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -515,7 +516,7 @@ static void init_jacks(struct userdata *u) {
 | 
			
		|||
            jack->melem = pa_alsa_mixer_find(u->mixer_handle, jack->alsa_name, 0);
 | 
			
		||||
            if (!jack->melem) {
 | 
			
		||||
                pa_log_warn("Jack '%s' seems to have disappeared.", jack->alsa_name);
 | 
			
		||||
                jack->has_control = false;
 | 
			
		||||
                pa_alsa_jack_set_has_control(jack, false);
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            snd_mixer_elem_set_callback(jack->melem, report_jack_state);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,8 +66,6 @@ void pa_device_port_new_data_done(pa_device_port_new_data *data) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void pa_device_port_set_available(pa_device_port *p, pa_available_t status) {
 | 
			
		||||
    pa_core *core;
 | 
			
		||||
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    if (p->available == status)
 | 
			
		||||
| 
						 | 
				
			
			@ -80,10 +78,14 @@ void pa_device_port_set_available(pa_device_port *p, pa_available_t status) {
 | 
			
		|||
       status == PA_AVAILABLE_NO ? "no" : "unknown");
 | 
			
		||||
 | 
			
		||||
    /* Post subscriptions to the card which owns us */
 | 
			
		||||
    pa_assert_se(core = p->core);
 | 
			
		||||
    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, p->card->index);
 | 
			
		||||
 | 
			
		||||
    pa_hook_fire(&core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED], p);
 | 
			
		||||
    /* XXX: We need to check p->card, because this function may be called
 | 
			
		||||
     * before the card object has been created. The card object should probably
 | 
			
		||||
     * be created before port objects, and then p->card could be non-NULL for
 | 
			
		||||
     * the whole lifecycle of pa_device_port. */
 | 
			
		||||
    if (p->card) {
 | 
			
		||||
        pa_subscription_post(p->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, p->card->index);
 | 
			
		||||
        pa_hook_fire(&p->core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED], p);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void device_port_free(pa_object *o) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue