diff --git a/src/context.c b/src/context.c index e9d84245c..299d3ab82 100644 --- a/src/context.c +++ b/src/context.c @@ -96,11 +96,53 @@ struct global *pa_context_find_global(pa_context *c, uint32_t id) 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) { const char *str; 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: if (g->props == NULL) return 0; diff --git a/src/internal.h b/src/internal.h index 389d6f8be..a37c83c8e 100644 --- a/src/internal.h +++ b/src/internal.h @@ -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_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 MASK_BUFFERS (MAX_BUFFERS-1) diff --git a/src/introspect.c b/src/introspect.c index 99bde7cb3..512489fd1 100644 --- a/src/introspect.c +++ b/src/introspect.c @@ -73,6 +73,18 @@ static const struct pw_client_proxy_events client_events = { .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) { uint32_t client_version; @@ -98,6 +110,11 @@ static int ensure_global(pa_context *c, struct global *g) client_version = PW_VERSION_CLIENT; destroy = (pw_destroy_t) pw_client_info_free; break; + case PW_TYPE_INTERFACE_Device: + events = &device_events; + client_version = PW_VERSION_DEVICE; + destroy = (pw_destroy_t) pw_device_info_free; + break; default: return -EINVAL; } @@ -851,12 +868,45 @@ struct card_data { pa_context *context; pa_card_info_cb_t cb; 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; - 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); } @@ -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(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->context = c; d->cb = cb; @@ -916,7 +969,7 @@ struct sink_input_data { 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; pa_sink_input_info i; pa_format_info ii[1]; @@ -933,11 +986,21 @@ static void sink_input_callback(struct sink_input_data *d) i.name = info->name; i.owner_module = PA_INVALID_INDEX; 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); if (s && s->sample_spec.channels > 0) { i.sample_spec = s->sample_spec; - i.channel_map = s->channel_map; + if (s->channel_map.channels == s->sample_spec.channels) + 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); i.format = s->format; } @@ -1159,7 +1222,7 @@ struct source_output_data { 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; pa_source_output_info i; pa_format_info ii[1]; @@ -1176,11 +1239,21 @@ static void source_output_callback(struct source_output_data *d) i.name = info->name; i.owner_module = PA_INVALID_INDEX; 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); if (s && s->sample_spec.channels > 0) { i.sample_spec = s->sample_spec; - i.channel_map = s->channel_map; + if (s->channel_map.channels == s->sample_spec.channels) + 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); i.format = s->format; } diff --git a/src/stream.c b/src/stream.c index ee3aca30d..1ed347c88 100644 --- a/src/stream.c +++ b/src/stream.c @@ -185,41 +185,12 @@ static void configure_buffers(pa_stream *s) 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) { struct global *g; 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) { s->device_index = PA_INVALID_INDEX; s->device_name = NULL;