mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-01 22:58:50 -04:00
context: update the Profiles and Routes in the card
Update the Profile and Route information directly into the card info. Use this info to fill the port info for the sink and sources.
This commit is contained in:
parent
42cc30e1ee
commit
1277e6cded
3 changed files with 376 additions and 194 deletions
|
|
@ -44,8 +44,8 @@ static void global_free(pa_context *c, struct global *g)
|
|||
{
|
||||
spa_list_remove(&g->link);
|
||||
|
||||
if (g->destroy)
|
||||
g->destroy(g);
|
||||
if (g->ginfo && g->ginfo->destroy)
|
||||
g->ginfo->destroy(g);
|
||||
if (g->proxy) {
|
||||
pw_proxy_destroy(g->proxy);
|
||||
}
|
||||
|
|
@ -255,6 +255,17 @@ static void emit_event(pa_context *c, struct global *g, pa_subscription_event_ty
|
|||
}
|
||||
}
|
||||
|
||||
static void remove_params(struct spa_list *params, uint32_t id)
|
||||
{
|
||||
struct param *p, *t;
|
||||
spa_list_for_each_safe(p, t, params, link) {
|
||||
if (id == SPA_ID_INVALID || p->id == id) {
|
||||
spa_list_remove(&p->link);
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void update_device_props(struct global *g)
|
||||
{
|
||||
pa_card_info *i = &g->card_info.info;
|
||||
|
|
@ -298,6 +309,9 @@ static void device_event_info(void *object, const struct pw_device_info *info)
|
|||
|
||||
switch (info->params[n].id) {
|
||||
case SPA_PARAM_EnumProfile:
|
||||
remove_params(&g->card_info.profiles, SPA_PARAM_EnumProfile);
|
||||
g->card_info.n_profiles = 0;
|
||||
g->card_info.pending_profiles = true;
|
||||
pw_device_enum_params((struct pw_device*)g->proxy,
|
||||
0, SPA_PARAM_EnumProfile, 0, -1, NULL);
|
||||
break;
|
||||
|
|
@ -306,6 +320,9 @@ static void device_event_info(void *object, const struct pw_device_info *info)
|
|||
0, SPA_PARAM_Profile, 0, -1, NULL);
|
||||
break;
|
||||
case SPA_PARAM_EnumRoute:
|
||||
remove_params(&g->card_info.ports, SPA_PARAM_EnumRoute);
|
||||
g->card_info.n_ports = 0;
|
||||
g->card_info.pending_ports = true;
|
||||
pw_device_enum_params((struct pw_device*)g->proxy,
|
||||
0, SPA_PARAM_EnumRoute, 0, -1, NULL);
|
||||
break;
|
||||
|
|
@ -392,6 +409,226 @@ static void device_event_param(void *object, int seq,
|
|||
}
|
||||
}
|
||||
|
||||
static void device_clear_profiles(struct global *g)
|
||||
{
|
||||
pa_card_info *i = &g->card_info.info;
|
||||
i->n_profiles = 0;
|
||||
free(i->profiles);
|
||||
i->profiles = NULL;
|
||||
free(g->card_info.card_profiles);
|
||||
g->card_info.card_profiles = NULL;
|
||||
free(i->profiles2);
|
||||
i->profiles2 = NULL;
|
||||
}
|
||||
|
||||
static void device_sync_profiles(struct global *g)
|
||||
{
|
||||
pa_card_info *i = &g->card_info.info;
|
||||
uint32_t n_profiles, j;
|
||||
struct param *p;
|
||||
|
||||
device_clear_profiles(g);
|
||||
|
||||
n_profiles = g->card_info.n_profiles;
|
||||
|
||||
i->profiles = calloc(n_profiles, sizeof(pa_card_profile_info));
|
||||
g->card_info.card_profiles = calloc(n_profiles, sizeof(pa_card_profile_info2));
|
||||
i->profiles2 = calloc(n_profiles + 1, sizeof(pa_card_profile_info2 *));
|
||||
i->n_profiles = 0;
|
||||
|
||||
pw_log_debug("context %p: info for %d", g->context, g->id);
|
||||
|
||||
j = 0;
|
||||
spa_list_for_each(p, &g->card_info.profiles, link) {
|
||||
uint32_t id, priority = 0, available = 0, n_cap = 0, n_play = 0;
|
||||
const char *name = NULL;
|
||||
const char *description = NULL;
|
||||
struct spa_pod *classes = NULL, *info = NULL;
|
||||
|
||||
if (spa_pod_parse_object(p->param,
|
||||
SPA_TYPE_OBJECT_ParamProfile, NULL,
|
||||
SPA_PARAM_PROFILE_index, SPA_POD_Int(&id),
|
||||
SPA_PARAM_PROFILE_name, SPA_POD_String(&name),
|
||||
SPA_PARAM_PROFILE_description, SPA_POD_OPT_String(&description),
|
||||
SPA_PARAM_PROFILE_priority, SPA_POD_OPT_Int(&priority),
|
||||
SPA_PARAM_PROFILE_available, SPA_POD_OPT_Id(&available),
|
||||
SPA_PARAM_PROFILE_info, SPA_POD_OPT_Pod(&info),
|
||||
SPA_PARAM_PROFILE_classes, SPA_POD_OPT_Pod(&classes)) < 0) {
|
||||
pw_log_warn("device %d: can't parse profile", g->id);
|
||||
continue;
|
||||
}
|
||||
if (classes != NULL) {
|
||||
struct spa_pod *iter;
|
||||
|
||||
SPA_POD_STRUCT_FOREACH(classes, iter) {
|
||||
struct spa_pod_parser prs;
|
||||
struct spa_pod_frame f[1];
|
||||
char *class;
|
||||
uint32_t count;
|
||||
|
||||
spa_pod_parser_pod(&prs, iter);
|
||||
if (spa_pod_parser_get_struct(&prs,
|
||||
SPA_POD_String(&class),
|
||||
SPA_POD_Int(&count)) < 0)
|
||||
continue;
|
||||
|
||||
if (strcmp(class, "Audio/Sink") == 0)
|
||||
n_play += count;
|
||||
else if (strcmp(class, "Audio/Source") == 0)
|
||||
n_cap += count;
|
||||
|
||||
spa_pod_parser_pop(&prs, &f[0]);
|
||||
}
|
||||
}
|
||||
|
||||
i->profiles[j].name = name;
|
||||
i->profiles[j].description = description ? description : name;
|
||||
i->profiles[j].n_sinks = n_play;
|
||||
i->profiles[j].n_sources = n_cap;
|
||||
i->profiles[j].priority = priority;
|
||||
|
||||
i->profiles2[j] = &g->card_info.card_profiles[j];
|
||||
i->profiles2[j]->name = i->profiles[j].name;
|
||||
i->profiles2[j]->description = i->profiles[j].description;
|
||||
i->profiles2[j]->n_sinks = i->profiles[j].n_sinks;
|
||||
i->profiles2[j]->n_sources = i->profiles[j].n_sources;
|
||||
i->profiles2[j]->priority = i->profiles[j].priority;
|
||||
i->profiles2[j]->available = available != SPA_PARAM_AVAILABILITY_no;
|
||||
|
||||
if (g->card_info.active_profile == id) {
|
||||
i->active_profile = &i->profiles[j];
|
||||
i->active_profile2 = i->profiles2[j];
|
||||
}
|
||||
j++;
|
||||
}
|
||||
i->profiles2[j] = NULL;
|
||||
i->n_profiles = j;
|
||||
}
|
||||
|
||||
static void device_clear_ports(struct global *g)
|
||||
{
|
||||
pa_card_info *i = &g->card_info.info;
|
||||
uint32_t n;
|
||||
|
||||
for (n = 0; n < i->n_ports; i++)
|
||||
free(i->ports[n]->profiles2);
|
||||
|
||||
i->n_ports = 0;
|
||||
free(i->ports);
|
||||
i->ports = NULL;
|
||||
free(g->card_info.card_ports);
|
||||
g->card_info.card_ports = NULL;
|
||||
}
|
||||
|
||||
static void device_sync_ports(struct global *g)
|
||||
{
|
||||
pa_card_info *i = &g->card_info.info;
|
||||
uint32_t n_ports, j;
|
||||
struct param *p;
|
||||
|
||||
device_clear_ports(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));
|
||||
i->n_ports = 0;
|
||||
g->card_info.active_port_input = SPA_ID_INVALID;
|
||||
g->card_info.active_port_output = SPA_ID_INVALID;
|
||||
|
||||
pw_log_debug("context %p: info for %d", g->context, g->id);
|
||||
|
||||
j = 0;
|
||||
|
||||
spa_list_for_each(p, &g->card_info.ports, link) {
|
||||
uint32_t id, priority;
|
||||
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;
|
||||
pa_card_port_info *pi;
|
||||
|
||||
if (spa_pod_parse_object(p->param,
|
||||
SPA_TYPE_OBJECT_ParamRoute, NULL,
|
||||
SPA_PARAM_ROUTE_index, SPA_POD_Int(&id),
|
||||
SPA_PARAM_ROUTE_direction, SPA_POD_Id(&direction),
|
||||
SPA_PARAM_ROUTE_name, SPA_POD_String(&name),
|
||||
SPA_PARAM_ROUTE_description, SPA_POD_OPT_String(&description),
|
||||
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_profiles, SPA_POD_OPT_Pod(&profiles)) < 0) {
|
||||
pw_log_warn("device %d: can't parse route", g->id);
|
||||
continue;
|
||||
}
|
||||
|
||||
pi = i->ports[j] = &g->card_info.card_ports[j];
|
||||
spa_zero(*pi);
|
||||
pi->name = name;
|
||||
pi->description = description;
|
||||
pi->priority = priority;
|
||||
pi->available = available;
|
||||
pi->direction = direction;
|
||||
pi->proplist = pa_proplist_new();
|
||||
while (info) {
|
||||
struct spa_pod_parser prs;
|
||||
struct spa_pod_frame f[1];
|
||||
uint32_t n, n_items;
|
||||
const char *key, *value;
|
||||
|
||||
spa_pod_parser_pod(&prs, info);
|
||||
if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
|
||||
spa_pod_parser_get_int(&prs, &n_items) < 0)
|
||||
break;
|
||||
|
||||
for (n = 0; n < n_items; n++) {
|
||||
if (spa_pod_parser_get(&prs,
|
||||
SPA_POD_String(&key),
|
||||
SPA_POD_String(&value),
|
||||
NULL) < 0)
|
||||
break;
|
||||
pa_proplist_sets(pi->proplist, key, value);
|
||||
}
|
||||
spa_pod_parser_pop(&prs, &f[0]);
|
||||
break;
|
||||
}
|
||||
pi->n_profiles = 0;
|
||||
pi->profiles = NULL;
|
||||
pi->profiles2 = NULL;
|
||||
while (profiles) {
|
||||
uint32_t *pr, n, n_pr;
|
||||
|
||||
pr = spa_pod_get_array(profiles, &n_pr);
|
||||
if (pr == NULL)
|
||||
break;
|
||||
|
||||
pi->n_profiles = n_pr;
|
||||
pi->profiles2 = calloc(n_pr + 1, sizeof(pa_card_profile_info2 *));
|
||||
for (n = 0; n < n_pr; n++)
|
||||
pi->profiles2[n] = i->profiles2[pr[n]];
|
||||
pi->profiles2[n_pr] = NULL;
|
||||
pi->profiles = (pa_card_profile_info **)pi->profiles2;
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
i->ports[j] = NULL;
|
||||
i->n_ports = j;
|
||||
if (i->n_ports == 0)
|
||||
i->ports = NULL;
|
||||
}
|
||||
|
||||
static void device_sync(struct global *g)
|
||||
{
|
||||
if (g->card_info.pending_profiles) {
|
||||
device_sync_profiles(g);
|
||||
g->card_info.pending_profiles = false;
|
||||
}
|
||||
if (g->card_info.pending_ports) {
|
||||
device_sync_ports(g);
|
||||
g->card_info.pending_ports = false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pw_device_events device_events = {
|
||||
PW_VERSION_DEVICE_EVENTS,
|
||||
.info = device_event_info,
|
||||
|
|
@ -401,22 +638,27 @@ static const struct pw_device_events device_events = {
|
|||
static void device_destroy(void *data)
|
||||
{
|
||||
struct global *global = data;
|
||||
struct param *p;
|
||||
|
||||
if (global->card_info.info.proplist)
|
||||
pa_proplist_free(global->card_info.info.proplist);
|
||||
spa_list_consume(p, &global->card_info.profiles, link) {
|
||||
spa_list_remove(&p->link);
|
||||
free(p);
|
||||
}
|
||||
spa_list_consume(p, &global->card_info.ports, link) {
|
||||
spa_list_remove(&p->link);
|
||||
free(p);
|
||||
}
|
||||
|
||||
device_clear_ports(global);
|
||||
device_clear_profiles(global);
|
||||
|
||||
remove_params(&global->card_info.ports, SPA_ID_INVALID);
|
||||
remove_params(&global->card_info.profiles, SPA_ID_INVALID);
|
||||
|
||||
if (global->info)
|
||||
pw_device_info_free(global->info);
|
||||
}
|
||||
|
||||
struct global_info device_info = {
|
||||
.version = PW_VERSION_DEVICE,
|
||||
.events = &device_events,
|
||||
.destroy = device_destroy,
|
||||
.sync = device_sync,
|
||||
};
|
||||
|
||||
static void node_event_info(void *object, const struct pw_node_info *info)
|
||||
{
|
||||
struct global *g = object;
|
||||
|
|
@ -513,6 +755,13 @@ static void node_destroy(void *data)
|
|||
pw_node_info_free(global->info);
|
||||
}
|
||||
|
||||
struct global_info node_info = {
|
||||
.version = PW_VERSION_NODE,
|
||||
.events = &node_events,
|
||||
.destroy = node_destroy,
|
||||
};
|
||||
|
||||
|
||||
static void module_event_info(void *object, const struct pw_module_info *info)
|
||||
{
|
||||
struct global *g = object;
|
||||
|
|
@ -551,6 +800,12 @@ static void module_destroy(void *data)
|
|||
pw_module_info_free(global->info);
|
||||
}
|
||||
|
||||
struct global_info module_info = {
|
||||
.version = PW_VERSION_MODULE,
|
||||
.events = &module_events,
|
||||
.destroy = module_destroy,
|
||||
};
|
||||
|
||||
static void client_event_info(void *object, const struct pw_client_info *info)
|
||||
{
|
||||
struct global *g = object;
|
||||
|
|
@ -591,6 +846,12 @@ static void client_destroy(void *data)
|
|||
pw_client_info_free(global->info);
|
||||
}
|
||||
|
||||
struct global_info client_info = {
|
||||
.version = PW_VERSION_CLIENT,
|
||||
.events = &client_events,
|
||||
.destroy = client_destroy,
|
||||
};
|
||||
|
||||
static void proxy_removed(void *data)
|
||||
{
|
||||
struct global *g = data;
|
||||
|
|
@ -611,6 +872,8 @@ static void proxy_done(void *data, int seq)
|
|||
pa_subscription_event_type_t event;
|
||||
|
||||
if (g->pending_seq == seq) {
|
||||
if (g->ginfo && g->ginfo->sync)
|
||||
g->ginfo->sync(g);
|
||||
if (g->init) {
|
||||
g->init = false;
|
||||
event = PA_SUBSCRIPTION_EVENT_NEW;
|
||||
|
|
@ -633,9 +896,7 @@ static int set_mask(pa_context *c, struct global *g)
|
|||
{
|
||||
const char *str;
|
||||
struct global *f;
|
||||
const void *events = NULL;
|
||||
pw_destroy_t destroy;
|
||||
uint32_t client_version;
|
||||
struct global_info *ginfo = NULL;
|
||||
|
||||
if (strcmp(g->type, PW_TYPE_INTERFACE_Device) == 0) {
|
||||
if (g->props == NULL)
|
||||
|
|
@ -648,12 +909,9 @@ static int set_mask(pa_context *c, struct global *g)
|
|||
pw_log_debug("found card %d", g->id);
|
||||
g->mask = PA_SUBSCRIPTION_MASK_CARD;
|
||||
g->event = PA_SUBSCRIPTION_EVENT_CARD;
|
||||
|
||||
events = &device_events;
|
||||
client_version = PW_VERSION_DEVICE;
|
||||
destroy = device_destroy;
|
||||
spa_list_init(&g->card_info.profiles);
|
||||
spa_list_init(&g->card_info.ports);
|
||||
ginfo = &device_info;
|
||||
spa_list_init(&g->card_info.profiles);
|
||||
spa_list_init(&g->card_info.ports);
|
||||
} else if (strcmp(g->type, PW_TYPE_INTERFACE_Node) == 0) {
|
||||
if (g->props == NULL)
|
||||
return 0;
|
||||
|
|
@ -693,9 +951,7 @@ static int set_mask(pa_context *c, struct global *g)
|
|||
if ((str = pw_properties_get(g->props, PW_KEY_DEVICE_ID)) != NULL)
|
||||
g->node_info.device_id = atoi(str);
|
||||
|
||||
events = &node_events;
|
||||
client_version = PW_VERSION_NODE;
|
||||
destroy = node_destroy;
|
||||
ginfo = &node_info;
|
||||
g->node_info.volume = 1.0;
|
||||
g->node_info.mute = false;
|
||||
} else if (strcmp(g->type, PW_TYPE_INTERFACE_Port) == 0) {
|
||||
|
|
@ -712,16 +968,12 @@ static int set_mask(pa_context *c, struct global *g)
|
|||
pw_log_debug("found module %d", g->id);
|
||||
g->mask = PA_SUBSCRIPTION_MASK_MODULE;
|
||||
g->event = PA_SUBSCRIPTION_EVENT_MODULE;
|
||||
events = &module_events;
|
||||
client_version = PW_VERSION_MODULE;
|
||||
destroy = module_destroy;
|
||||
ginfo = &module_info;
|
||||
} else if (strcmp(g->type, PW_TYPE_INTERFACE_Client) == 0) {
|
||||
pw_log_debug("found client %d", g->id);
|
||||
g->mask = PA_SUBSCRIPTION_MASK_CLIENT;
|
||||
g->event = PA_SUBSCRIPTION_EVENT_CLIENT;
|
||||
events = &client_events;
|
||||
client_version = PW_VERSION_CLIENT;
|
||||
destroy = client_destroy;
|
||||
ginfo = &client_info;
|
||||
} else if (strcmp(g->type, PW_TYPE_INTERFACE_Link) == 0) {
|
||||
if ((str = pw_properties_get(g->props, PW_KEY_LINK_OUTPUT_PORT)) == NULL)
|
||||
return 0;
|
||||
|
|
@ -752,17 +1004,17 @@ static int set_mask(pa_context *c, struct global *g)
|
|||
|
||||
pw_log_debug("global %p: id:%u mask %d/%d", g, g->id, g->mask, g->event);
|
||||
|
||||
if (events) {
|
||||
if (ginfo) {
|
||||
pw_log_debug("bind %d", g->id);
|
||||
|
||||
g->proxy = pw_registry_bind(c->registry, g->id, g->type,
|
||||
client_version, 0);
|
||||
ginfo->version, 0);
|
||||
if (g->proxy == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
pw_proxy_add_object_listener(g->proxy, &g->object_listener, events, g);
|
||||
pw_proxy_add_object_listener(g->proxy, &g->object_listener, ginfo->events, g);
|
||||
pw_proxy_add_listener(g->proxy, &g->proxy_listener, &proxy_events, g);
|
||||
g->destroy = destroy;
|
||||
g->ginfo = ginfo;
|
||||
global_sync(g);
|
||||
} else {
|
||||
emit_event(c, g, PA_SUBSCRIPTION_EVENT_NEW);
|
||||
|
|
|
|||
|
|
@ -223,6 +223,15 @@ struct param {
|
|||
#define PA_IDX_FLAG_DSP 0x800000U
|
||||
#define PA_IDX_MASK_DSP 0x7fffffU
|
||||
|
||||
struct global;
|
||||
|
||||
struct global_info {
|
||||
uint32_t version;
|
||||
const void *events;
|
||||
pw_destroy_t destroy;
|
||||
void (*sync) (struct global *g);
|
||||
};
|
||||
|
||||
struct global {
|
||||
struct spa_list link;
|
||||
uint32_t id;
|
||||
|
|
@ -239,7 +248,7 @@ struct global {
|
|||
int subscribed:1;
|
||||
|
||||
void *info;
|
||||
pw_destroy_t destroy;
|
||||
struct global_info *ginfo;
|
||||
|
||||
struct pw_proxy *proxy;
|
||||
struct spa_hook proxy_listener;
|
||||
|
|
@ -272,6 +281,12 @@ struct global {
|
|||
struct spa_list ports;
|
||||
uint32_t n_ports;
|
||||
pa_card_info info;
|
||||
pa_card_profile_info2 *card_profiles;
|
||||
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;
|
||||
} card_info;
|
||||
struct {
|
||||
pa_module_info info;
|
||||
|
|
|
|||
|
|
@ -91,12 +91,21 @@ static int wait_globals(pa_context *c, pa_subscription_mask_t mask, pa_operation
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int has_profile(pa_card_profile_info2 **list, pa_card_profile_info2 *active)
|
||||
{
|
||||
for(;*list; list++) {
|
||||
if (*list == active)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sink_callback(struct sink_data *d)
|
||||
{
|
||||
struct global *g = d->global;
|
||||
struct global *g = d->global, *cg;
|
||||
struct pw_node_info *info = g->info;
|
||||
const char *str;
|
||||
uint32_t n;
|
||||
uint32_t n, j;
|
||||
pa_sink_info i;
|
||||
pa_format_info ii[1];
|
||||
pa_format_info *ip[1];
|
||||
|
|
@ -138,10 +147,40 @@ static void sink_callback(struct sink_data *d)
|
|||
i.base_volume = PA_VOLUME_NORM;
|
||||
i.state = node_state_to_sink(info->state);
|
||||
i.n_volume_steps = PA_VOLUME_NORM+1;
|
||||
i.card = PA_INVALID_INDEX;
|
||||
if (info->props && (str = spa_dict_lookup(info->props, PW_KEY_DEVICE_ID)))
|
||||
i.card = atoi(str);
|
||||
else
|
||||
i.card = PA_INVALID_INDEX;
|
||||
i.n_ports = 0;
|
||||
i.ports = NULL;
|
||||
i.active_port = NULL;
|
||||
if ((cg = pa_context_find_global(d->context, i.card)) != NULL) {
|
||||
pa_sink_port_info *spi;
|
||||
pa_card_info *ci = &cg->card_info.info;
|
||||
|
||||
spi = alloca(ci->n_ports * sizeof(pa_sink_port_info));
|
||||
i.ports = alloca((ci->n_ports + 1) * sizeof(pa_sink_port_info *));
|
||||
|
||||
for (n = 0,j = 0; n < ci->n_ports; n++) {
|
||||
if (ci->ports[n]->direction != PA_DIRECTION_OUTPUT)
|
||||
continue;
|
||||
if (!has_profile(ci->ports[n]->profiles2, ci->active_profile2))
|
||||
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)
|
||||
i.active_port = i.ports[j];
|
||||
j++;
|
||||
}
|
||||
i.n_ports = j;
|
||||
if (i.n_ports == 0)
|
||||
i.ports = NULL;
|
||||
else
|
||||
i.ports[j] = NULL;
|
||||
}
|
||||
i.n_formats = 1;
|
||||
ii[0].encoding = PA_ENCODING_PCM;
|
||||
ii[0].plist = pa_proplist_new();
|
||||
|
|
@ -555,10 +594,10 @@ static pa_source_state_t node_state_to_source(enum pw_node_state s)
|
|||
}
|
||||
static void source_callback(struct source_data *d)
|
||||
{
|
||||
struct global *g = d->global;
|
||||
struct global *g = d->global, *cg;
|
||||
struct pw_node_info *info = g->info;
|
||||
const char *str;
|
||||
uint32_t n;
|
||||
uint32_t n, j;
|
||||
pa_source_info i;
|
||||
pa_format_info ii[1];
|
||||
pa_format_info *ip[1];
|
||||
|
|
@ -606,10 +645,40 @@ static void source_callback(struct source_data *d)
|
|||
i.base_volume = PA_VOLUME_NORM;
|
||||
i.state = node_state_to_source(info->state);
|
||||
i.n_volume_steps = PA_VOLUME_NORM+1;
|
||||
i.card = PA_INVALID_INDEX;
|
||||
if (info->props && (str = spa_dict_lookup(info->props, PW_KEY_DEVICE_ID)))
|
||||
i.card = atoi(str);
|
||||
else
|
||||
i.card = PA_INVALID_INDEX;
|
||||
i.n_ports = 0;
|
||||
i.ports = NULL;
|
||||
i.active_port = NULL;
|
||||
if ((cg = pa_context_find_global(d->context, i.card)) != NULL) {
|
||||
pa_source_port_info *spi;
|
||||
pa_card_info *ci = &cg->card_info.info;
|
||||
|
||||
spi = alloca(ci->n_ports * sizeof(pa_source_port_info));
|
||||
i.ports = alloca((ci->n_ports + 1) * sizeof(pa_source_port_info *));
|
||||
|
||||
for (n = 0,j = 0; n < ci->n_ports; n++) {
|
||||
if (ci->ports[n]->direction != PA_DIRECTION_INPUT)
|
||||
continue;
|
||||
if (!has_profile(ci->ports[n]->profiles2, ci->active_profile2))
|
||||
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)
|
||||
i.active_port = i.ports[j];
|
||||
j++;
|
||||
}
|
||||
i.n_ports = j;
|
||||
if (i.n_ports == 0)
|
||||
i.ports = NULL;
|
||||
else
|
||||
i.ports[j] = NULL;
|
||||
}
|
||||
i.n_formats = 1;
|
||||
ii[0].encoding = PA_ENCODING_PCM;
|
||||
ii[0].plist = pa_proplist_new();
|
||||
|
|
@ -1247,160 +1316,6 @@ static void card_callback(struct card_data *d)
|
|||
{
|
||||
struct global *g = d->global;
|
||||
pa_card_info *i = &g->card_info.info;
|
||||
int n_profiles, n_ports, j = 0;
|
||||
struct param *p;
|
||||
|
||||
n_profiles = g->card_info.n_profiles;
|
||||
|
||||
i->profiles = alloca(sizeof(pa_card_profile_info) * n_profiles);
|
||||
i->profiles2 = alloca(sizeof(pa_card_profile_info2 *) * (n_profiles + 1));
|
||||
i->n_profiles = 0;
|
||||
|
||||
pw_log_debug("context %p: info for %d", g->context, g->id);
|
||||
|
||||
spa_list_for_each(p, &g->card_info.profiles, link) {
|
||||
uint32_t id, priority = 0, available = 0, n_cap = 0, n_play = 0;
|
||||
const char *name = NULL;
|
||||
const char *description = NULL;
|
||||
struct spa_pod *classes = NULL;
|
||||
|
||||
if (spa_pod_parse_object(p->param,
|
||||
SPA_TYPE_OBJECT_ParamProfile, NULL,
|
||||
SPA_PARAM_PROFILE_index, SPA_POD_Int(&id),
|
||||
SPA_PARAM_PROFILE_name, SPA_POD_String(&name),
|
||||
SPA_PARAM_PROFILE_description, SPA_POD_OPT_String(&description),
|
||||
SPA_PARAM_PROFILE_priority, SPA_POD_OPT_Int(&priority),
|
||||
SPA_PARAM_PROFILE_available, SPA_POD_OPT_Id(&available),
|
||||
SPA_PARAM_PROFILE_classes, SPA_POD_OPT_Pod(&classes)) < 0) {
|
||||
pw_log_warn("device %d: can't parse profile", g->id);
|
||||
continue;
|
||||
}
|
||||
if (classes != NULL) {
|
||||
struct spa_pod *iter;
|
||||
|
||||
SPA_POD_STRUCT_FOREACH(classes, iter) {
|
||||
struct spa_pod_parser prs;
|
||||
struct spa_pod_frame f[1];
|
||||
char *class;
|
||||
uint32_t count;
|
||||
|
||||
spa_pod_parser_pod(&prs, iter);
|
||||
if (spa_pod_parser_get_struct(&prs,
|
||||
SPA_POD_String(&class),
|
||||
SPA_POD_Int(&count)) < 0)
|
||||
continue;
|
||||
|
||||
if (strcmp(class, "Audio/Sink") == 0)
|
||||
n_play += count;
|
||||
else if (strcmp(class, "Audio/Source") == 0)
|
||||
n_cap += count;
|
||||
|
||||
spa_pod_parser_pop(&prs, &f[0]);
|
||||
}
|
||||
}
|
||||
i->profiles[j].name = name;
|
||||
i->profiles[j].description = description ? description : name;
|
||||
i->profiles[j].n_sinks = n_play;
|
||||
i->profiles[j].n_sources = n_cap;
|
||||
i->profiles[j].priority = priority;
|
||||
|
||||
i->profiles2[j] = alloca(sizeof(pa_card_profile_info2));
|
||||
i->profiles2[j]->name = i->profiles[j].name;
|
||||
i->profiles2[j]->description = i->profiles[j].description;
|
||||
i->profiles2[j]->n_sinks = i->profiles[j].n_sinks;
|
||||
i->profiles2[j]->n_sources = i->profiles[j].n_sources;
|
||||
i->profiles2[j]->priority = i->profiles[j].priority;
|
||||
i->profiles2[j]->available = available != SPA_PARAM_AVAILABILITY_no;
|
||||
|
||||
if (g->card_info.active_profile == id) {
|
||||
i->active_profile = &i->profiles[j];
|
||||
i->active_profile2 = i->profiles2[j];
|
||||
}
|
||||
j = ++i->n_profiles;
|
||||
}
|
||||
i->profiles2[j] = NULL;
|
||||
|
||||
n_ports = g->card_info.n_ports;
|
||||
i->ports = alloca(sizeof(pa_card_port_info *) * (n_ports + 1));
|
||||
i->n_ports = 0;
|
||||
|
||||
j = 0;
|
||||
spa_list_for_each(p, &g->card_info.ports, link) {
|
||||
uint32_t id, priority;
|
||||
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;
|
||||
pa_card_port_info *pi;
|
||||
|
||||
if (spa_pod_parse_object(p->param,
|
||||
SPA_TYPE_OBJECT_ParamRoute, NULL,
|
||||
SPA_PARAM_ROUTE_index, SPA_POD_Int(&id),
|
||||
SPA_PARAM_ROUTE_direction, SPA_POD_Id(&direction),
|
||||
SPA_PARAM_ROUTE_name, SPA_POD_String(&name),
|
||||
SPA_PARAM_ROUTE_description, SPA_POD_OPT_String(&description),
|
||||
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_profiles, SPA_POD_OPT_Pod(&profiles)) < 0) {
|
||||
pw_log_warn("device %d: can't parse route", g->id);
|
||||
continue;
|
||||
}
|
||||
|
||||
pi = i->ports[j] = alloca(sizeof(pa_card_port_info));
|
||||
spa_zero(*pi);
|
||||
pi->name = name;
|
||||
pi->description = description;
|
||||
pi->priority = priority;
|
||||
pi->available = available;
|
||||
pi->direction = direction;
|
||||
pi->proplist = pa_proplist_new();
|
||||
while (info) {
|
||||
struct spa_pod_parser prs;
|
||||
struct spa_pod_frame f[1];
|
||||
uint32_t n, n_items;
|
||||
const char *key, *value;
|
||||
|
||||
spa_pod_parser_pod(&prs, info);
|
||||
if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
|
||||
spa_pod_parser_get_int(&prs, &n_items) < 0)
|
||||
break;
|
||||
|
||||
for (n = 0; n < n_items; n++) {
|
||||
if (spa_pod_parser_get(&prs,
|
||||
SPA_POD_String(&key),
|
||||
SPA_POD_String(&value),
|
||||
NULL) < 0)
|
||||
break;
|
||||
pa_proplist_sets(pi->proplist, key, value);
|
||||
}
|
||||
spa_pod_parser_pop(&prs, &f[0]);
|
||||
break;
|
||||
}
|
||||
while (profiles) {
|
||||
uint32_t *pr, n, n_pr;
|
||||
|
||||
pr = spa_pod_get_array(profiles, &n_pr);
|
||||
if (pr == NULL)
|
||||
break;
|
||||
|
||||
pi->n_profiles = n_pr;
|
||||
pi->profiles = alloca(sizeof(pa_card_profile_info *) * (n_pr + 1));
|
||||
pi->profiles2 = alloca(sizeof(pa_card_profile_info2 *) * (n_pr + 1));
|
||||
|
||||
for (n = 0; n < n_pr; n++) {
|
||||
pi->profiles[n] = (pa_card_profile_info*)i->profiles2[pr[n]];
|
||||
pi->profiles2[n] = i->profiles2[pr[n]];
|
||||
}
|
||||
pi->profiles[n_pr] = NULL;
|
||||
pi->profiles2[n_pr] = NULL;
|
||||
break;
|
||||
}
|
||||
j = ++i->n_ports;
|
||||
}
|
||||
i->ports[j] = NULL;
|
||||
if (i->n_ports == 0)
|
||||
i->ports = NULL;
|
||||
d->cb(d->context, i, 0, d->userdata);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue