mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
acp: add per device port list
Add the list of possible ports for a device. Pass the allowed devices in the routes. Store the active port in the device. Fixes enumeration of ports on devices with UCM.
This commit is contained in:
parent
5d90fe26f3
commit
374210c890
9 changed files with 64 additions and 22 deletions
|
|
@ -540,17 +540,13 @@ static void device_event_param(void *object, int seq,
|
||||||
return;
|
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,
|
pw_log_debug("device %d: active %s route %d", g->id,
|
||||||
direction == SPA_DIRECTION_OUTPUT ? "output" : "input",
|
direction == SPA_DIRECTION_OUTPUT ? "output" : "input",
|
||||||
index);
|
index);
|
||||||
|
|
||||||
ng = find_node_for_route(c, g, device);
|
ng = find_node_for_route(c, g, device);
|
||||||
if (props && ng) {
|
if (props && ng) {
|
||||||
|
ng->node_info.active_port = index;
|
||||||
parse_props(ng, props, true);
|
parse_props(ng, props, true);
|
||||||
emit_event(c, ng, PA_SUBSCRIPTION_EVENT_CHANGE);
|
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;
|
n_ports = g->card_info.n_ports;
|
||||||
i->ports = calloc(n_ports+1, sizeof(pa_card_port_info *));
|
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.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;
|
i->n_ports = 0;
|
||||||
|
|
||||||
pw_log_debug("context %p: info for %d", g->context, g->id);
|
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;
|
enum spa_direction direction;
|
||||||
const char *name = NULL, *description = NULL;
|
const char *name = NULL, *description = NULL;
|
||||||
enum spa_param_availability available = SPA_PARAM_AVAILABILITY_unknown;
|
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;
|
pa_card_port_info *pi;
|
||||||
|
struct port_device *pd;
|
||||||
|
|
||||||
if (spa_pod_parse_object(p->param,
|
if (spa_pod_parse_object(p->param,
|
||||||
SPA_TYPE_OBJECT_ParamRoute, NULL,
|
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_priority, SPA_POD_OPT_Int(&priority),
|
||||||
SPA_PARAM_ROUTE_available, SPA_POD_OPT_Id(&available),
|
SPA_PARAM_ROUTE_available, SPA_POD_OPT_Id(&available),
|
||||||
SPA_PARAM_ROUTE_info, SPA_POD_OPT_Pod(&info),
|
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) {
|
SPA_PARAM_ROUTE_profiles, SPA_POD_OPT_Pod(&profiles)) < 0) {
|
||||||
pw_log_warn("device %d: can't parse route", g->id);
|
pw_log_warn("device %d: can't parse route", g->id);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -760,6 +759,11 @@ static void device_sync_ports(struct global *g)
|
||||||
pi->profiles = (pa_card_profile_info **)pi->profiles2;
|
pi->profiles = (pa_card_profile_info **)pi->profiles2;
|
||||||
break;
|
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++;
|
j++;
|
||||||
}
|
}
|
||||||
i->ports[j] = NULL;
|
i->ports[j] = NULL;
|
||||||
|
|
@ -1083,8 +1087,6 @@ static int set_mask(pa_context *c, struct global *g)
|
||||||
ginfo = &device_info;
|
ginfo = &device_info;
|
||||||
spa_list_init(&g->card_info.profiles);
|
spa_list_init(&g->card_info.profiles);
|
||||||
spa_list_init(&g->card_info.ports);
|
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) {
|
} else if (strcmp(g->type, PW_TYPE_INTERFACE_Node) == 0) {
|
||||||
if (g->props == NULL)
|
if (g->props == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1136,6 +1138,7 @@ static int set_mask(pa_context *c, struct global *g)
|
||||||
g->node_info.mute = false;
|
g->node_info.mute = false;
|
||||||
g->node_info.base_volume = 1.0f;
|
g->node_info.base_volume = 1.0f;
|
||||||
g->node_info.volume_step = 1.0f / (PA_VOLUME_NORM+1);
|
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) {
|
} else if (strcmp(g->type, PW_TYPE_INTERFACE_Port) == 0) {
|
||||||
if (g->props == NULL)
|
if (g->props == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,11 @@ struct param {
|
||||||
#define PA_IDX_FLAG_DSP 0x800000U
|
#define PA_IDX_FLAG_DSP 0x800000U
|
||||||
#define PA_IDX_MASK_DSP 0x7fffffU
|
#define PA_IDX_MASK_DSP 0x7fffffU
|
||||||
|
|
||||||
|
struct port_device {
|
||||||
|
uint32_t n_devices;
|
||||||
|
uint32_t *devices;
|
||||||
|
};
|
||||||
|
|
||||||
struct global;
|
struct global;
|
||||||
|
|
||||||
struct global_info {
|
struct global_info {
|
||||||
|
|
@ -286,6 +291,7 @@ struct global {
|
||||||
uint32_t profile_device_id; /* id in profile */
|
uint32_t profile_device_id; /* id in profile */
|
||||||
float base_volume;
|
float base_volume;
|
||||||
float volume_step;
|
float volume_step;
|
||||||
|
uint32_t active_port;
|
||||||
} node_info;
|
} node_info;
|
||||||
struct {
|
struct {
|
||||||
uint32_t node_id;
|
uint32_t node_id;
|
||||||
|
|
@ -302,8 +308,7 @@ struct global {
|
||||||
unsigned int pending_profiles:1;
|
unsigned int pending_profiles:1;
|
||||||
pa_card_port_info *card_ports;
|
pa_card_port_info *card_ports;
|
||||||
unsigned int pending_ports:1;
|
unsigned int pending_ports:1;
|
||||||
uint32_t active_port_output;
|
struct port_device *port_devices;
|
||||||
uint32_t active_port_input;
|
|
||||||
} card_info;
|
} card_info;
|
||||||
struct {
|
struct {
|
||||||
pa_module_info info;
|
pa_module_info info;
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,19 @@ static int has_profile(pa_card_profile_info2 **list, pa_card_profile_info2 *acti
|
||||||
}
|
}
|
||||||
return 0;
|
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)
|
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;
|
continue;
|
||||||
if (!has_profile(ci->ports[n]->profiles2, ci->active_profile2))
|
if (!has_profile(ci->ports[n]->profiles2, ci->active_profile2))
|
||||||
continue;
|
continue;
|
||||||
|
if (!has_device(&cg->card_info.port_devices[n], g->node_info.profile_device_id))
|
||||||
|
continue;
|
||||||
|
|
||||||
i.ports[j] = &spi[j];
|
i.ports[j] = &spi[j];
|
||||||
spi[j].name = ci->ports[n]->name;
|
spi[j].name = ci->ports[n]->name;
|
||||||
spi[j].description = ci->ports[n]->description;
|
spi[j].description = ci->ports[n]->description;
|
||||||
spi[j].priority = ci->ports[n]->priority;
|
spi[j].priority = ci->ports[n]->priority;
|
||||||
spi[j].available = ci->ports[n]->available;
|
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];
|
i.active_port = i.ports[j];
|
||||||
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) &&
|
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) {
|
(cg = pa_context_find_global(c, card_id)) != NULL) {
|
||||||
if (mask & PA_SUBSCRIPTION_MASK_SINK)
|
id = cg->node_info.active_port;
|
||||||
id = cg->card_info.active_port_output;
|
|
||||||
else if (mask & PA_SUBSCRIPTION_MASK_SOURCE)
|
|
||||||
id = cg->card_info.active_port_input;
|
|
||||||
}
|
}
|
||||||
if (id != SPA_ID_INVALID && device_id != SPA_ID_INVALID) {
|
if (id != SPA_ID_INVALID && device_id != SPA_ID_INVALID) {
|
||||||
res = set_device_volume(c, g, cg, id, device_id, volume, mute);
|
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;
|
continue;
|
||||||
if (!has_profile(ci->ports[n]->profiles2, ci->active_profile2))
|
if (!has_profile(ci->ports[n]->profiles2, ci->active_profile2))
|
||||||
continue;
|
continue;
|
||||||
|
if (!has_device(&cg->card_info.port_devices[n], g->node_info.profile_device_id))
|
||||||
|
continue;
|
||||||
i.ports[j] = &spi[j];
|
i.ports[j] = &spi[j];
|
||||||
spi[j].name = ci->ports[n]->name;
|
spi[j].name = ci->ports[n]->name;
|
||||||
spi[j].description = ci->ports[n]->description;
|
spi[j].description = ci->ports[n]->description;
|
||||||
spi[j].priority = ci->ports[n]->priority;
|
spi[j].priority = ci->ports[n]->priority;
|
||||||
spi[j].available = ci->ports[n]->available;
|
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];
|
i.active_port = i.ports[j];
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,7 @@ enum spa_param_route {
|
||||||
* String : value)*)) */
|
* String : value)*)) */
|
||||||
SPA_PARAM_ROUTE_profiles, /**< associated profile indexes (Array of Int) */
|
SPA_PARAM_ROUTE_profiles, /**< associated profile indexes (Array of Int) */
|
||||||
SPA_PARAM_ROUTE_props, /**< properties SPA_TYPE_OBJECT_Props */
|
SPA_PARAM_ROUTE_props, /**< properties SPA_TYPE_OBJECT_Props */
|
||||||
|
SPA_PARAM_ROUTE_devices, /**< associated device indexes (Array of Int) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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_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_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_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 },
|
{ 0, 0, NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -167,12 +167,6 @@ static void add_profiles(pa_card *impl)
|
||||||
pa_hashmap_put(impl->profiles, cp->name, cp);
|
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);
|
pa_dynarray_init(&impl->out.ports, NULL);
|
||||||
n_ports = 0;
|
n_ports = 0;
|
||||||
PA_HASHMAP_FOREACH(dp, impl->ports, state) {
|
PA_HASHMAP_FOREACH(dp, impl->ports, state) {
|
||||||
|
|
@ -180,6 +174,7 @@ static void add_profiles(pa_card *impl)
|
||||||
dp->card = impl;
|
dp->card = impl;
|
||||||
dp->port.index = n_ports++;
|
dp->port.index = n_ports++;
|
||||||
pa_dynarray_init(&dp->prof, NULL);
|
pa_dynarray_init(&dp->prof, NULL);
|
||||||
|
pa_dynarray_init(&dp->devices, NULL);
|
||||||
n_profiles = 0;
|
n_profiles = 0;
|
||||||
PA_HASHMAP_FOREACH(cp, dp->profiles, state2) {
|
PA_HASHMAP_FOREACH(cp, dp->profiles, state2) {
|
||||||
pa_dynarray_append(&dp->prof, cp);
|
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_proplist_as_dict(dp->proplist, &dp->port.props);
|
||||||
pa_dynarray_append(&impl->out.ports, dp);
|
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);
|
pa_hashmap_sort(impl->profiles, compare_profile);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,9 @@ struct acp_port {
|
||||||
|
|
||||||
uint32_t n_profiles;
|
uint32_t n_profiles;
|
||||||
struct acp_card_profile **profiles;
|
struct acp_card_profile **profiles;
|
||||||
|
|
||||||
|
uint32_t n_devices;
|
||||||
|
struct acp_device **devices;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct acp_device {
|
struct acp_device {
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,8 @@ struct pa_device_port {
|
||||||
pa_hashmap *profiles;
|
pa_hashmap *profiles;
|
||||||
pa_dynarray prof;
|
pa_dynarray prof;
|
||||||
|
|
||||||
|
pa_dynarray devices;
|
||||||
|
|
||||||
void (*impl_free)(struct pa_device_port *port);
|
void (*impl_free)(struct pa_device_port *port);
|
||||||
void *user_data;
|
void *user_data;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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_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]);
|
return spa_pod_builder_pop(b, &f[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue