context: list audio devices as cards

Find the sink/source a stream is linked to
This commit is contained in:
Wim Taymans 2018-11-28 11:13:21 +01:00
parent e8dfd22a6b
commit 08d6071693
4 changed files with 126 additions and 39 deletions

View file

@ -96,11 +96,53 @@ struct global *pa_context_find_global(pa_context *c, uint32_t id)
return NULL; return NULL;
} }
struct global *pa_context_find_linked(pa_context *c, uint32_t idx)
{
struct global *g, *f;
spa_list_for_each(g, &c->globals, link) {
if (g->type != PW_TYPE_INTERFACE_Link)
continue;
pw_log_debug("%d %d %d", idx,
g->link_info.src->parent_id,
g->link_info.dst->parent_id);
if (g->link_info.src->parent_id == idx)
f = pa_context_find_global(c, g->link_info.dst->parent_id);
else if (g->link_info.dst->parent_id == idx)
f = pa_context_find_global(c, g->link_info.src->parent_id);
else
continue;
if (f == NULL)
continue;
if (f->mask & PA_SUBSCRIPTION_MASK_DSP) {
f = f->dsp_info.session;
}
return f;
}
return NULL;
}
static int set_mask(pa_context *c, struct global *g) static int set_mask(pa_context *c, struct global *g)
{ {
const char *str; const char *str;
switch (g->type) { switch (g->type) {
case PW_TYPE_INTERFACE_Device:
if (g->props == NULL)
return 0;
if ((str = pw_properties_get(g->props, "media.class")) == NULL)
return 0;
if (strcmp(str, "Audio/Device") != 0)
return 0;
pw_log_debug("found card %d", g->id);
g->mask = PA_SUBSCRIPTION_MASK_CARD;
g->event = PA_SUBSCRIPTION_EVENT_CARD;
break;
case PW_TYPE_INTERFACE_Node: case PW_TYPE_INTERFACE_Node:
if (g->props == NULL) if (g->props == NULL)
return 0; return 0;

View file

@ -258,6 +258,7 @@ struct pa_context {
struct global *pa_context_find_global(pa_context *c, uint32_t id); struct global *pa_context_find_global(pa_context *c, uint32_t id);
struct global *pa_context_find_global_by_name(pa_context *c, uint32_t mask, const char *name); struct global *pa_context_find_global_by_name(pa_context *c, uint32_t mask, const char *name);
struct global *pa_context_find_linked(pa_context *c, uint32_t id);
#define MAX_BUFFERS 64 #define MAX_BUFFERS 64
#define MASK_BUFFERS (MAX_BUFFERS-1) #define MASK_BUFFERS (MAX_BUFFERS-1)

View file

@ -73,6 +73,18 @@ static const struct pw_client_proxy_events client_events = {
.info = client_event_info, .info = client_event_info,
}; };
static void device_event_info(void *object, struct pw_device_info *info)
{
struct global *g = object;
pw_log_debug("update %d", g->id);
g->info = pw_device_info_update(g->info, info);
}
static const struct pw_device_proxy_events device_events = {
PW_VERSION_DEVICE_PROXY_EVENTS,
.info = device_event_info,
};
static int ensure_global(pa_context *c, struct global *g) static int ensure_global(pa_context *c, struct global *g)
{ {
uint32_t client_version; uint32_t client_version;
@ -98,6 +110,11 @@ static int ensure_global(pa_context *c, struct global *g)
client_version = PW_VERSION_CLIENT; client_version = PW_VERSION_CLIENT;
destroy = (pw_destroy_t) pw_client_info_free; destroy = (pw_destroy_t) pw_client_info_free;
break; break;
case PW_TYPE_INTERFACE_Device:
events = &device_events;
client_version = PW_VERSION_DEVICE;
destroy = (pw_destroy_t) pw_device_info_free;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
@ -851,12 +868,45 @@ struct card_data {
pa_context *context; pa_context *context;
pa_card_info_cb_t cb; pa_card_info_cb_t cb;
void *userdata; void *userdata;
struct global *global;
}; };
static void card_info(pa_operation *o, void *userdata) static void card_callback(struct card_data *d)
{
struct global *g = d->global;
struct pw_device_info *info = g->info;
pa_card_info i;
spa_zero(i);
i.index = g->id;
i.name = info->name;
i.owner_module = g->parent_id;
i.driver = info->props ?
spa_dict_lookup(info->props, "device.api") : NULL;
i.n_profiles = 0;
i.profiles = NULL;
i.active_profile = NULL;
i.proplist = pa_proplist_new_dict(info->props);
i.n_ports = 0;
i.ports = NULL;
i.profiles2 = NULL;
i.active_profile = NULL;
d->cb(d->context, &i, 0, d->userdata);
}
static void card_info_list(pa_operation *o, void *userdata)
{ {
struct card_data *d = userdata; struct card_data *d = userdata;
d->cb(d->context, NULL, 1, d->userdata); pa_context *c = d->context;
struct global *g;
spa_list_for_each(g, &c->globals, link) {
if (!(g->mask & PA_SUBSCRIPTION_MASK_CARD))
continue;
d->global = g;
card_callback(d);
}
d->cb(c, NULL, 1, d->userdata);
pa_operation_done(o); pa_operation_done(o);
} }
@ -869,7 +919,10 @@ pa_operation* pa_context_get_card_info_list(pa_context *c, pa_card_info_cb_t cb,
pa_assert(c->refcount >= 1); pa_assert(c->refcount >= 1);
pa_assert(cb); pa_assert(cb);
o = pa_operation_new(c, NULL, card_info, sizeof(struct card_data)); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
ensure_types(c, PA_SUBSCRIPTION_MASK_CARD);
o = pa_operation_new(c, NULL, card_info_list, sizeof(struct card_data));
d = o->userdata; d = o->userdata;
d->context = c; d->context = c;
d->cb = cb; d->cb = cb;
@ -916,7 +969,7 @@ struct sink_input_data {
static void sink_input_callback(struct sink_input_data *d) static void sink_input_callback(struct sink_input_data *d)
{ {
struct global *g = d->global; struct global *g = d->global, *l;
struct pw_node_info *info = g->info; struct pw_node_info *info = g->info;
pa_sink_input_info i; pa_sink_input_info i;
pa_format_info ii[1]; pa_format_info ii[1];
@ -933,11 +986,21 @@ static void sink_input_callback(struct sink_input_data *d)
i.name = info->name; i.name = info->name;
i.owner_module = PA_INVALID_INDEX; i.owner_module = PA_INVALID_INDEX;
i.client = g->parent_id; i.client = g->parent_id;
i.sink = PA_INVALID_INDEX; if (s) {
i.sink = s->device_index;
}
else {
l = pa_context_find_linked(d->context, g->id);
i.sink = l ? l->id : PA_INVALID_INDEX;
}
pa_cvolume_init(&i.volume); pa_cvolume_init(&i.volume);
if (s && s->sample_spec.channels > 0) { if (s && s->sample_spec.channels > 0) {
i.sample_spec = s->sample_spec; i.sample_spec = s->sample_spec;
if (s->channel_map.channels == s->sample_spec.channels)
i.channel_map = s->channel_map; i.channel_map = s->channel_map;
else
pa_channel_map_init_auto(&i.channel_map,
i.sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
pa_cvolume_set(&i.volume, i.sample_spec.channels, s->volume * PA_VOLUME_NORM); pa_cvolume_set(&i.volume, i.sample_spec.channels, s->volume * PA_VOLUME_NORM);
i.format = s->format; i.format = s->format;
} }
@ -1159,7 +1222,7 @@ struct source_output_data {
static void source_output_callback(struct source_output_data *d) static void source_output_callback(struct source_output_data *d)
{ {
struct global *g = d->global; struct global *g = d->global, *l;
struct pw_node_info *info = g->info; struct pw_node_info *info = g->info;
pa_source_output_info i; pa_source_output_info i;
pa_format_info ii[1]; pa_format_info ii[1];
@ -1176,11 +1239,21 @@ static void source_output_callback(struct source_output_data *d)
i.name = info->name; i.name = info->name;
i.owner_module = PA_INVALID_INDEX; i.owner_module = PA_INVALID_INDEX;
i.client = g->parent_id; i.client = g->parent_id;
i.source = PA_INVALID_INDEX; if (s) {
i.source = s->device_index;
}
else {
l = pa_context_find_linked(d->context, g->id);
i.source = l ? l->id : PA_INVALID_INDEX;
}
pa_cvolume_init(&i.volume); pa_cvolume_init(&i.volume);
if (s && s->sample_spec.channels > 0) { if (s && s->sample_spec.channels > 0) {
i.sample_spec = s->sample_spec; i.sample_spec = s->sample_spec;
if (s->channel_map.channels == s->sample_spec.channels)
i.channel_map = s->channel_map; i.channel_map = s->channel_map;
else
pa_channel_map_init_auto(&i.channel_map,
i.sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
pa_cvolume_set(&i.volume, i.sample_spec.channels, s->volume * PA_VOLUME_NORM); pa_cvolume_set(&i.volume, i.sample_spec.channels, s->volume * PA_VOLUME_NORM);
i.format = s->format; i.format = s->format;
} }

View file

@ -185,41 +185,12 @@ static void configure_buffers(pa_stream *s)
dump_buffer_attr(s, &s->buffer_attr); dump_buffer_attr(s, &s->buffer_attr);
} }
static struct global *find_linked(pa_stream *s, uint32_t idx)
{
struct global *g, *f;
pa_context *c = s->context;
spa_list_for_each(g, &c->globals, link) {
if (g->type != PW_TYPE_INTERFACE_Link)
continue;
pw_log_debug("%d %d %d", idx,
g->link_info.src->parent_id,
g->link_info.dst->parent_id);
if (g->link_info.src->parent_id == idx)
f = pa_context_find_global(c, g->link_info.dst->parent_id);
else if (g->link_info.dst->parent_id == idx)
f = pa_context_find_global(c, g->link_info.src->parent_id);
else
continue;
if (f == NULL)
continue;
if (f->mask & PA_SUBSCRIPTION_MASK_DSP) {
f = f->dsp_info.session;
}
return f;
}
return NULL;
}
static void configure_device(pa_stream *s) static void configure_device(pa_stream *s)
{ {
struct global *g; struct global *g;
const char *str; const char *str;
g = find_linked(s, pa_stream_get_index(s)); g = pa_context_find_linked(s->context, pa_stream_get_index(s));
if (g == NULL) { if (g == NULL) {
s->device_index = PA_INVALID_INDEX; s->device_index = PA_INVALID_INDEX;
s->device_name = NULL; s->device_name = NULL;