mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	device-port: Make it impossible to have dual-direction ports
This commit is contained in:
		
							parent
							
								
									5ceb184e3e
								
							
						
					
					
						commit
						0bbef56976
					
				
					 7 changed files with 101 additions and 63 deletions
				
			
		| 
						 | 
				
			
			@ -2850,12 +2850,41 @@ void pa_alsa_path_set_set_callback(pa_alsa_path_set *ps, snd_mixer_t *m, snd_mix
 | 
			
		|||
        pa_alsa_path_set_callback(p, m, cb, userdata);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static pa_alsa_path *profile_set_get_path(pa_alsa_profile_set *ps, const char *path_name) {
 | 
			
		||||
    pa_alsa_path *path;
 | 
			
		||||
 | 
			
		||||
    pa_assert(ps);
 | 
			
		||||
    pa_assert(path_name);
 | 
			
		||||
 | 
			
		||||
    if ((path = pa_hashmap_get(ps->output_paths, path_name)))
 | 
			
		||||
        return path;
 | 
			
		||||
 | 
			
		||||
    return pa_hashmap_get(ps->input_paths, path_name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void profile_set_add_path(pa_alsa_profile_set *ps, pa_alsa_path *path) {
 | 
			
		||||
    pa_assert(ps);
 | 
			
		||||
    pa_assert(path);
 | 
			
		||||
 | 
			
		||||
    switch (path->direction) {
 | 
			
		||||
        case PA_ALSA_DIRECTION_OUTPUT:
 | 
			
		||||
            pa_assert_se(pa_hashmap_put(ps->output_paths, path->name, path) >= 0);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case PA_ALSA_DIRECTION_INPUT:
 | 
			
		||||
            pa_assert_se(pa_hashmap_put(ps->input_paths, path->name, path) >= 0);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            pa_assert_not_reached();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t direction, const char *paths_dir) {
 | 
			
		||||
    pa_alsa_path_set *ps;
 | 
			
		||||
    char **pn = NULL, **en = NULL, **ie;
 | 
			
		||||
    pa_alsa_decibel_fix *db_fix;
 | 
			
		||||
    void *state, *state2;
 | 
			
		||||
    pa_hashmap *cache;
 | 
			
		||||
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
    pa_assert(m->profile_set);
 | 
			
		||||
| 
						 | 
				
			
			@ -2869,14 +2898,10 @@ pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t d
 | 
			
		|||
    ps->direction = direction;
 | 
			
		||||
    ps->paths = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
 | 
			
		||||
 | 
			
		||||
    if (direction == PA_ALSA_DIRECTION_OUTPUT) {
 | 
			
		||||
    if (direction == PA_ALSA_DIRECTION_OUTPUT)
 | 
			
		||||
        pn = m->output_path_names;
 | 
			
		||||
        cache = m->profile_set->output_paths;
 | 
			
		||||
    }
 | 
			
		||||
    else if (direction == PA_ALSA_DIRECTION_INPUT) {
 | 
			
		||||
    else
 | 
			
		||||
        pn = m->input_path_names;
 | 
			
		||||
        cache = m->profile_set->input_paths;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (pn) {
 | 
			
		||||
        char **in;
 | 
			
		||||
| 
						 | 
				
			
			@ -2895,15 +2920,21 @@ pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t d
 | 
			
		|||
            if (duplicate)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            p = pa_hashmap_get(cache, *in);
 | 
			
		||||
            p = profile_set_get_path(m->profile_set, *in);
 | 
			
		||||
 | 
			
		||||
            if (p && p->direction != direction) {
 | 
			
		||||
                pa_log("Configuration error: Path %s is used both as an input and as an output path.", p->name);
 | 
			
		||||
                goto fail;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!p) {
 | 
			
		||||
                char *fn = pa_sprintf_malloc("%s.conf", *in);
 | 
			
		||||
                p = pa_alsa_path_new(paths_dir, fn, direction);
 | 
			
		||||
                pa_xfree(fn);
 | 
			
		||||
                if (p)
 | 
			
		||||
                    pa_hashmap_put(cache, *in, p);
 | 
			
		||||
                    profile_set_add_path(m->profile_set, p);
 | 
			
		||||
            }
 | 
			
		||||
            pa_assert(pa_hashmap_get(cache, *in) == p);
 | 
			
		||||
 | 
			
		||||
            if (p)
 | 
			
		||||
                pa_hashmap_put(ps->paths, p, p);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2914,13 +2945,11 @@ pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t d
 | 
			
		|||
 | 
			
		||||
    if (direction == PA_ALSA_DIRECTION_OUTPUT)
 | 
			
		||||
        en = m->output_element;
 | 
			
		||||
    else if (direction == PA_ALSA_DIRECTION_INPUT)
 | 
			
		||||
    else
 | 
			
		||||
        en = m->input_element;
 | 
			
		||||
 | 
			
		||||
    if (!en) {
 | 
			
		||||
        pa_alsa_path_set_free(ps);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (!en)
 | 
			
		||||
        goto fail;
 | 
			
		||||
 | 
			
		||||
    for (ie = en; *ie; ie++) {
 | 
			
		||||
        char **je;
 | 
			
		||||
| 
						 | 
				
			
			@ -2972,6 +3001,12 @@ finish:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    return ps;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
    if (ps)
 | 
			
		||||
        pa_alsa_path_set_free(ps);
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_alsa_path_set_dump(pa_alsa_path_set *ps) {
 | 
			
		||||
| 
						 | 
				
			
			@ -4444,13 +4479,13 @@ void pa_alsa_profile_set_drop_unsupported(pa_alsa_profile_set *ps) {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static pa_device_port* device_port_alsa_init(pa_hashmap *ports,
 | 
			
		||||
static pa_device_port* device_port_alsa_init(pa_hashmap *ports, /* card ports */
 | 
			
		||||
    const char* name,
 | 
			
		||||
    const char* description,
 | 
			
		||||
    pa_alsa_path *path,
 | 
			
		||||
    pa_alsa_setting *setting,
 | 
			
		||||
    pa_card_profile *cp,
 | 
			
		||||
    pa_hashmap *extra,
 | 
			
		||||
    pa_hashmap *extra, /* sink/source ports */
 | 
			
		||||
    pa_core *core) {
 | 
			
		||||
 | 
			
		||||
    pa_device_port *p;
 | 
			
		||||
| 
						 | 
				
			
			@ -4461,8 +4496,11 @@ static pa_device_port* device_port_alsa_init(pa_hashmap *ports,
 | 
			
		|||
 | 
			
		||||
    if (!p) {
 | 
			
		||||
        pa_alsa_port_data *data;
 | 
			
		||||
        pa_direction_t direction;
 | 
			
		||||
 | 
			
		||||
        p = pa_device_port_new(core, name, description, sizeof(pa_alsa_port_data));
 | 
			
		||||
        direction = path->direction == PA_ALSA_DIRECTION_OUTPUT ? PA_DIRECTION_OUTPUT : PA_DIRECTION_INPUT;
 | 
			
		||||
 | 
			
		||||
        p = pa_device_port_new(core, name, description, direction, sizeof(pa_alsa_port_data));
 | 
			
		||||
        pa_assert(p);
 | 
			
		||||
        pa_hashmap_put(ports, p->name, p);
 | 
			
		||||
        pa_proplist_update(p->proplist, PA_UPDATE_REPLACE, path->proplist);
 | 
			
		||||
| 
						 | 
				
			
			@ -4473,9 +4511,6 @@ static pa_device_port* device_port_alsa_init(pa_hashmap *ports,
 | 
			
		|||
        path->port = p;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    p->is_input |= path->direction == PA_ALSA_DIRECTION_ANY || path->direction == PA_ALSA_DIRECTION_INPUT;
 | 
			
		||||
    p->is_output |= path->direction == PA_ALSA_DIRECTION_ANY || path->direction == PA_ALSA_DIRECTION_OUTPUT;
 | 
			
		||||
 | 
			
		||||
    if (cp)
 | 
			
		||||
        pa_hashmap_put(p->profiles, cp->name, cp);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4490,8 +4525,8 @@ static pa_device_port* device_port_alsa_init(pa_hashmap *ports,
 | 
			
		|||
void pa_alsa_path_set_add_ports(
 | 
			
		||||
        pa_alsa_path_set *ps,
 | 
			
		||||
        pa_card_profile *cp,
 | 
			
		||||
        pa_hashmap *ports,
 | 
			
		||||
        pa_hashmap *extra,
 | 
			
		||||
        pa_hashmap *ports, /* card ports */
 | 
			
		||||
        pa_hashmap *extra, /* sink/source ports */
 | 
			
		||||
        pa_core *core) {
 | 
			
		||||
 | 
			
		||||
    pa_alsa_path *path;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -688,7 +688,7 @@ static void ucm_add_port_combination(
 | 
			
		|||
 | 
			
		||||
    port = pa_hashmap_get(ports, name);
 | 
			
		||||
    if (!port) {
 | 
			
		||||
        port = pa_device_port_new(core, pa_strna(name), desc, 0);
 | 
			
		||||
        port = pa_device_port_new(core, pa_strna(name), desc, is_sink ? PA_DIRECTION_OUTPUT : PA_DIRECTION_INPUT, 0);
 | 
			
		||||
        pa_assert(port);
 | 
			
		||||
 | 
			
		||||
        pa_hashmap_put(ports, port->name, port);
 | 
			
		||||
| 
						 | 
				
			
			@ -697,10 +697,6 @@ static void ucm_add_port_combination(
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    port->priority = priority;
 | 
			
		||||
    if (is_sink)
 | 
			
		||||
        port->is_output = TRUE;
 | 
			
		||||
    else
 | 
			
		||||
        port->is_input = TRUE;
 | 
			
		||||
 | 
			
		||||
    pa_xfree(name);
 | 
			
		||||
    pa_xfree(desc);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2140,16 +2140,12 @@ static void create_card_ports(struct userdata *u, pa_hashmap *ports) {
 | 
			
		|||
    u->output_port_name = pa_sprintf_malloc("%s-output", name_prefix);
 | 
			
		||||
    u->input_port_name = pa_sprintf_malloc("%s-input", name_prefix);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(port = pa_device_port_new(u->core, u->output_port_name, output_description, 0));
 | 
			
		||||
    pa_assert_se(port = pa_device_port_new(u->core, u->output_port_name, output_description, PA_DIRECTION_OUTPUT, 0));
 | 
			
		||||
    pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
 | 
			
		||||
    port->is_output = 1;
 | 
			
		||||
    port->is_input = 0;
 | 
			
		||||
    port->available = get_port_availability(u, PA_DIRECTION_OUTPUT);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(port = pa_device_port_new(u->core, u->input_port_name, input_description, 0));
 | 
			
		||||
    pa_assert_se(port = pa_device_port_new(u->core, u->input_port_name, input_description, PA_DIRECTION_OUTPUT, 0));
 | 
			
		||||
    pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
 | 
			
		||||
    port->is_output = 0;
 | 
			
		||||
    port->is_input = 1;
 | 
			
		||||
    port->available = get_port_availability(u, PA_DIRECTION_INPUT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,14 +94,13 @@ static int try_to_switch_profile(pa_device_port *port) {
 | 
			
		|||
    pa_log_debug("Finding best profile");
 | 
			
		||||
 | 
			
		||||
    PA_HASHMAP_FOREACH(profile, port->profiles, state) {
 | 
			
		||||
        pa_direction_t direction = port->is_output ? PA_DIRECTION_OUTPUT : PA_DIRECTION_INPUT;
 | 
			
		||||
        bool good;
 | 
			
		||||
 | 
			
		||||
        if (best_profile && best_profile->priority >= profile->priority)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        /* We make a best effort to keep other direction unchanged */
 | 
			
		||||
        switch (direction) {
 | 
			
		||||
        switch (port->direction) {
 | 
			
		||||
            case PA_DIRECTION_OUTPUT:
 | 
			
		||||
                good = profile_good_for_output(profile);
 | 
			
		||||
                break;
 | 
			
		||||
| 
						 | 
				
			
			@ -136,15 +135,19 @@ static void find_sink_and_source(pa_card *card, pa_device_port *port, pa_sink **
 | 
			
		|||
    pa_source *source = NULL;
 | 
			
		||||
    uint32_t state;
 | 
			
		||||
 | 
			
		||||
    if (port->is_output)
 | 
			
		||||
    switch (port->direction) {
 | 
			
		||||
        case PA_DIRECTION_OUTPUT:
 | 
			
		||||
            PA_IDXSET_FOREACH(sink, card->sinks, state)
 | 
			
		||||
                if (port == pa_hashmap_get(sink->ports, port->name))
 | 
			
		||||
                    break;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
    if (port->is_input)
 | 
			
		||||
        case PA_DIRECTION_INPUT:
 | 
			
		||||
            PA_IDXSET_FOREACH(source, card->sources, state)
 | 
			
		||||
                if (port == pa_hashmap_get(source->ports, port->name))
 | 
			
		||||
                    break;
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *si = sink;
 | 
			
		||||
    *so = source;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,7 +66,7 @@ static void device_port_free(pa_object *o) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
pa_device_port *pa_device_port_new(pa_core *c, const char *name, const char *description, size_t extra) {
 | 
			
		||||
pa_device_port *pa_device_port_new(pa_core *c, const char *name, const char *description, pa_direction_t direction, size_t extra) {
 | 
			
		||||
    pa_device_port *p;
 | 
			
		||||
 | 
			
		||||
    pa_assert(name);
 | 
			
		||||
| 
						 | 
				
			
			@ -74,6 +74,7 @@ pa_device_port *pa_device_port_new(pa_core *c, const char *name, const char *des
 | 
			
		|||
    p = PA_DEVICE_PORT(pa_object_new_internal(PA_ALIGN(sizeof(pa_device_port)) + extra, pa_device_port_type_id, pa_device_port_check_type));
 | 
			
		||||
    p->parent.free = device_port_free;
 | 
			
		||||
 | 
			
		||||
    p->core = c;
 | 
			
		||||
    p->name = pa_xstrdup(name);
 | 
			
		||||
    p->description = pa_xstrdup(description);
 | 
			
		||||
    p->core = c;
 | 
			
		||||
| 
						 | 
				
			
			@ -81,8 +82,7 @@ pa_device_port *pa_device_port_new(pa_core *c, const char *name, const char *des
 | 
			
		|||
    p->priority = 0;
 | 
			
		||||
    p->available = PA_AVAILABLE_UNKNOWN;
 | 
			
		||||
    p->profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
 | 
			
		||||
    p->is_input = FALSE;
 | 
			
		||||
    p->is_output = FALSE;
 | 
			
		||||
    p->direction = direction;
 | 
			
		||||
    p->latency_offset = 0;
 | 
			
		||||
    p->proplist = pa_proplist_new();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -100,25 +100,34 @@ void pa_device_port_set_latency_offset(pa_device_port *p, int64_t offset) {
 | 
			
		|||
 | 
			
		||||
    p->latency_offset = offset;
 | 
			
		||||
 | 
			
		||||
    if (p->is_output) {
 | 
			
		||||
    switch (p->direction) {
 | 
			
		||||
        case PA_DIRECTION_OUTPUT: {
 | 
			
		||||
            pa_sink *sink;
 | 
			
		||||
 | 
			
		||||
        PA_IDXSET_FOREACH(sink, p->core->sinks, state)
 | 
			
		||||
            PA_IDXSET_FOREACH(sink, p->core->sinks, state) {
 | 
			
		||||
                if (sink->active_port == p) {
 | 
			
		||||
                    pa_sink_set_latency_offset(sink, p->latency_offset);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        case PA_DIRECTION_INPUT: {
 | 
			
		||||
            pa_source *source;
 | 
			
		||||
 | 
			
		||||
        PA_IDXSET_FOREACH(source, p->core->sources, state)
 | 
			
		||||
            PA_IDXSET_FOREACH(source, p->core->sources, state) {
 | 
			
		||||
                if (source->active_port == p) {
 | 
			
		||||
                    pa_source_set_latency_offset(source, p->latency_offset);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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_LATENCY_OFFSET_CHANGED], p);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,8 +51,7 @@ struct pa_device_port {
 | 
			
		|||
 | 
			
		||||
    pa_proplist *proplist;
 | 
			
		||||
    pa_hashmap *profiles; /* Does not own the profiles */
 | 
			
		||||
    pa_bool_t is_input:1;
 | 
			
		||||
    pa_bool_t is_output:1;
 | 
			
		||||
    pa_direction_t direction;
 | 
			
		||||
    int64_t latency_offset;
 | 
			
		||||
 | 
			
		||||
    /* .. followed by some implementation specific data */
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +62,7 @@ PA_DECLARE_PUBLIC_CLASS(pa_device_port);
 | 
			
		|||
 | 
			
		||||
#define PA_DEVICE_PORT_DATA(d) ((void*) ((uint8_t*) d + PA_ALIGN(sizeof(pa_device_port))))
 | 
			
		||||
 | 
			
		||||
pa_device_port *pa_device_port_new(pa_core *c, const char *name, const char *description, size_t extra);
 | 
			
		||||
pa_device_port *pa_device_port_new(pa_core *c, const char *name, const char *description, pa_direction_t direction, size_t extra);
 | 
			
		||||
 | 
			
		||||
/* The port's available status has changed */
 | 
			
		||||
void pa_device_port_set_available(pa_device_port *p, pa_available_t available);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3302,7 +3302,7 @@ static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_car
 | 
			
		|||
        pa_tagstruct_puts(t, port->description);
 | 
			
		||||
        pa_tagstruct_putu32(t, port->priority);
 | 
			
		||||
        pa_tagstruct_putu32(t, port->available);
 | 
			
		||||
        pa_tagstruct_putu8(t, /* FIXME: port->direction */ (port->is_input ? PA_DIRECTION_INPUT : 0) | (port->is_output ? PA_DIRECTION_OUTPUT : 0));
 | 
			
		||||
        pa_tagstruct_putu8(t, port->direction);
 | 
			
		||||
        pa_tagstruct_put_proplist(t, port->proplist);
 | 
			
		||||
 | 
			
		||||
        pa_tagstruct_putu32(t, pa_hashmap_size(port->profiles));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue