diff --git a/pipewire-pulseaudio/src/context.c b/pipewire-pulseaudio/src/context.c index 4144608c5..da4247dfa 100644 --- a/pipewire-pulseaudio/src/context.c +++ b/pipewire-pulseaudio/src/context.c @@ -540,17 +540,13 @@ static void device_event_param(void *object, int seq, return; } - if (direction == SPA_DIRECTION_OUTPUT) - g->card_info.active_port_output = index; - else - g->card_info.active_port_input = index; - pw_log_debug("device %d: active %s route %d", g->id, direction == SPA_DIRECTION_OUTPUT ? "output" : "input", index); ng = find_node_for_route(c, g, device); if (props && ng) { + ng->node_info.active_port = index; parse_props(ng, props, true); emit_event(c, ng, PA_SUBSCRIPTION_EVENT_CHANGE); } @@ -684,6 +680,7 @@ static void device_sync_ports(struct global *g) n_ports = g->card_info.n_ports; i->ports = calloc(n_ports+1, sizeof(pa_card_port_info *)); g->card_info.card_ports = calloc(n_ports, sizeof(pa_card_port_info)); + g->card_info.port_devices = calloc(n_ports, sizeof(struct port_device)); i->n_ports = 0; pw_log_debug("context %p: info for %d", g->context, g->id); @@ -695,8 +692,9 @@ static void device_sync_ports(struct global *g) enum spa_direction direction; const char *name = NULL, *description = NULL; enum spa_param_availability available = SPA_PARAM_AVAILABILITY_unknown; - struct spa_pod *profiles = NULL, *info = NULL; + struct spa_pod *profiles = NULL, *info = NULL, *devices = NULL; pa_card_port_info *pi; + struct port_device *pd; if (spa_pod_parse_object(p->param, SPA_TYPE_OBJECT_ParamRoute, NULL, @@ -707,6 +705,7 @@ static void device_sync_ports(struct global *g) SPA_PARAM_ROUTE_priority, SPA_POD_OPT_Int(&priority), SPA_PARAM_ROUTE_available, SPA_POD_OPT_Id(&available), SPA_PARAM_ROUTE_info, SPA_POD_OPT_Pod(&info), + SPA_PARAM_ROUTE_devices, SPA_POD_OPT_Pod(&devices), SPA_PARAM_ROUTE_profiles, SPA_POD_OPT_Pod(&profiles)) < 0) { pw_log_warn("device %d: can't parse route", g->id); continue; @@ -760,6 +759,11 @@ static void device_sync_ports(struct global *g) pi->profiles = (pa_card_profile_info **)pi->profiles2; break; } + pd = &g->card_info.port_devices[j]; + pd->n_devices = 0; + pd->devices = NULL; + if (devices) + pd->devices = spa_pod_get_array(devices, &pd->n_devices); j++; } i->ports[j] = NULL; @@ -1083,8 +1087,6 @@ static int set_mask(pa_context *c, struct global *g) ginfo = &device_info; spa_list_init(&g->card_info.profiles); spa_list_init(&g->card_info.ports); - g->card_info.active_port_output = SPA_ID_INVALID; - g->card_info.active_port_input = SPA_ID_INVALID; } else if (strcmp(g->type, PW_TYPE_INTERFACE_Node) == 0) { if (g->props == NULL) return 0; @@ -1136,6 +1138,7 @@ static int set_mask(pa_context *c, struct global *g) g->node_info.mute = false; g->node_info.base_volume = 1.0f; g->node_info.volume_step = 1.0f / (PA_VOLUME_NORM+1); + g->node_info.active_port = SPA_ID_INVALID; } else if (strcmp(g->type, PW_TYPE_INTERFACE_Port) == 0) { if (g->props == NULL) return 0; diff --git a/pipewire-pulseaudio/src/internal.h b/pipewire-pulseaudio/src/internal.h index 00c79eae8..e46853451 100644 --- a/pipewire-pulseaudio/src/internal.h +++ b/pipewire-pulseaudio/src/internal.h @@ -230,6 +230,11 @@ struct param { #define PA_IDX_FLAG_DSP 0x800000U #define PA_IDX_MASK_DSP 0x7fffffU +struct port_device { + uint32_t n_devices; + uint32_t *devices; +}; + struct global; struct global_info { @@ -286,6 +291,7 @@ struct global { uint32_t profile_device_id; /* id in profile */ float base_volume; float volume_step; + uint32_t active_port; } node_info; struct { uint32_t node_id; @@ -302,8 +308,7 @@ struct global { unsigned int pending_profiles:1; pa_card_port_info *card_ports; unsigned int pending_ports:1; - uint32_t active_port_output; - uint32_t active_port_input; + struct port_device *port_devices; } card_info; struct { pa_module_info info; diff --git a/pipewire-pulseaudio/src/introspect.c b/pipewire-pulseaudio/src/introspect.c index e4cbb803a..a655e502e 100644 --- a/pipewire-pulseaudio/src/introspect.c +++ b/pipewire-pulseaudio/src/introspect.c @@ -81,6 +81,19 @@ static int has_profile(pa_card_profile_info2 **list, pa_card_profile_info2 *acti } return 0; } +static int has_device(struct port_device *devices, uint32_t id) +{ + uint32_t i; + + if (devices->devices == NULL || devices->n_devices == 0) + return 1; + + for (i = 0; i < devices->n_devices; i++) { + if (devices->devices[i] == id) + return 1; + } + return 0; +} static int sink_callback(pa_context *c, struct global *g, struct sink_data *d) { @@ -150,12 +163,15 @@ static int sink_callback(pa_context *c, struct global *g, struct sink_data *d) continue; if (!has_profile(ci->ports[n]->profiles2, ci->active_profile2)) continue; + if (!has_device(&cg->card_info.port_devices[n], g->node_info.profile_device_id)) + continue; + i.ports[j] = &spi[j]; spi[j].name = ci->ports[n]->name; spi[j].description = ci->ports[n]->description; spi[j].priority = ci->ports[n]->priority; spi[j].available = ci->ports[n]->available; - if (n == cg->card_info.active_port_output) + if (n == g->node_info.active_port) i.active_port = i.ports[j]; j++; } @@ -432,10 +448,7 @@ static int set_volume(pa_context *c, struct global *g, const pa_cvolume *volume, if (SPA_FLAG_IS_SET(g->node_info.flags, NODE_FLAG_DEVICE_VOLUME | NODE_FLAG_DEVICE_MUTE) && (cg = pa_context_find_global(c, card_id)) != NULL) { - if (mask & PA_SUBSCRIPTION_MASK_SINK) - id = cg->card_info.active_port_output; - else if (mask & PA_SUBSCRIPTION_MASK_SOURCE) - id = cg->card_info.active_port_input; + id = cg->node_info.active_port; } if (id != SPA_ID_INVALID && device_id != SPA_ID_INVALID) { res = set_device_volume(c, g, cg, id, device_id, volume, mute); @@ -877,12 +890,14 @@ static int source_callback(pa_context *c, struct global *g, struct source_data * continue; if (!has_profile(ci->ports[n]->profiles2, ci->active_profile2)) continue; + if (!has_device(&cg->card_info.port_devices[n], g->node_info.profile_device_id)) + continue; i.ports[j] = &spi[j]; spi[j].name = ci->ports[n]->name; spi[j].description = ci->ports[n]->description; spi[j].priority = ci->ports[n]->priority; spi[j].available = ci->ports[n]->available; - if (n == cg->card_info.active_port_input) + if (n == g->node_info.active_port) i.active_port = i.ports[j]; j++; } diff --git a/spa/include/spa/param/param.h b/spa/include/spa/param/param.h index 034b88197..28c845ae6 100644 --- a/spa/include/spa/param/param.h +++ b/spa/include/spa/param/param.h @@ -154,6 +154,7 @@ enum spa_param_route { * String : value)*)) */ SPA_PARAM_ROUTE_profiles, /**< associated profile indexes (Array of Int) */ SPA_PARAM_ROUTE_props, /**< properties SPA_TYPE_OBJECT_Props */ + SPA_PARAM_ROUTE_devices, /**< associated device indexes (Array of Int) */ }; diff --git a/spa/include/spa/param/type-info.h b/spa/include/spa/param/type-info.h index bacf21430..18863864a 100644 --- a/spa/include/spa/param/type-info.h +++ b/spa/include/spa/param/type-info.h @@ -335,6 +335,7 @@ static const struct spa_type_info spa_type_param_route[] = { { SPA_PARAM_ROUTE_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_ROUTE_BASE "info", NULL, }, { SPA_PARAM_ROUTE_profiles, SPA_TYPE_Array, SPA_TYPE_INFO_PARAM_ROUTE_BASE "profiles", NULL, }, { SPA_PARAM_ROUTE_props, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_ROUTE_BASE "props", NULL, }, + { SPA_PARAM_ROUTE_devices, SPA_TYPE_Array, SPA_TYPE_INFO_PARAM_ROUTE_BASE "devices", NULL, }, { 0, 0, NULL, NULL }, }; diff --git a/spa/plugins/alsa/acp/acp.c b/spa/plugins/alsa/acp/acp.c index 943ed6fb2..05433dca7 100644 --- a/spa/plugins/alsa/acp/acp.c +++ b/spa/plugins/alsa/acp/acp.c @@ -167,12 +167,6 @@ static void add_profiles(pa_card *impl) pa_hashmap_put(impl->profiles, cp->name, cp); } - PA_DYNARRAY_FOREACH(dev, &impl->out.devices, idx) { - PA_HASHMAP_FOREACH(dp, dev->ports, state) - pa_dynarray_append(&dev->port_array, dp); - dev->device.ports = dev->port_array.array.data; - dev->device.n_ports = pa_dynarray_size(&dev->port_array); - } pa_dynarray_init(&impl->out.ports, NULL); n_ports = 0; PA_HASHMAP_FOREACH(dp, impl->ports, state) { @@ -180,6 +174,7 @@ static void add_profiles(pa_card *impl) dp->card = impl; dp->port.index = n_ports++; pa_dynarray_init(&dp->prof, NULL); + pa_dynarray_init(&dp->devices, NULL); n_profiles = 0; PA_HASHMAP_FOREACH(cp, dp->profiles, state2) { pa_dynarray_append(&dp->prof, cp); @@ -192,6 +187,18 @@ static void add_profiles(pa_card *impl) pa_proplist_as_dict(dp->proplist, &dp->port.props); pa_dynarray_append(&impl->out.ports, dp); } + PA_DYNARRAY_FOREACH(dev, &impl->out.devices, idx) { + PA_HASHMAP_FOREACH(dp, dev->ports, state) { + pa_dynarray_append(&dev->port_array, dp); + pa_dynarray_append(&dp->devices, dev); + } + dev->device.ports = dev->port_array.array.data; + dev->device.n_ports = pa_dynarray_size(&dev->port_array); + } + PA_HASHMAP_FOREACH(dp, impl->ports, state) { + dp->port.devices = dp->devices.array.data; + dp->port.n_devices = pa_dynarray_size(&dp->devices); + } pa_hashmap_sort(impl->profiles, compare_profile); diff --git a/spa/plugins/alsa/acp/acp.h b/spa/plugins/alsa/acp/acp.h index c41dc9e90..a21f61613 100644 --- a/spa/plugins/alsa/acp/acp.h +++ b/spa/plugins/alsa/acp/acp.h @@ -153,6 +153,9 @@ struct acp_port { uint32_t n_profiles; struct acp_card_profile **profiles; + + uint32_t n_devices; + struct acp_device **devices; }; struct acp_device { diff --git a/spa/plugins/alsa/acp/device-port.h b/spa/plugins/alsa/acp/device-port.h index 0360f264c..48b825375 100644 --- a/spa/plugins/alsa/acp/device-port.h +++ b/spa/plugins/alsa/acp/device-port.h @@ -69,6 +69,8 @@ struct pa_device_port { pa_hashmap *profiles; pa_dynarray prof; + pa_dynarray devices; + void (*impl_free)(struct pa_device_port *port); void *user_data; }; diff --git a/spa/plugins/alsa/alsa-acp-device.c b/spa/plugins/alsa/alsa-acp-device.c index 7a969ccf0..249384886 100644 --- a/spa/plugins/alsa/alsa-acp-device.c +++ b/spa/plugins/alsa/alsa-acp-device.c @@ -380,6 +380,11 @@ static struct spa_pod *build_route(struct spa_pod_builder *b, uint32_t id, spa_pod_builder_pop(b, &f[1]); } + spa_pod_builder_prop(b, SPA_PARAM_ROUTE_devices, 0); + spa_pod_builder_push_array(b, &f[1]); + for (i = 0; i < p->n_devices; i++) + spa_pod_builder_int(b, p->devices[i]->index); + spa_pod_builder_pop(b, &f[1]); return spa_pod_builder_pop(b, &f[0]); }