stream: connect to source and sink

Stream: also connect to the right source, try to convert the name to
index when lookup fails, just like what pulseaudio does.
Implement more proplist functions, add some more info to the stream.
stream: handle NULL format
Improve introspection of the sink_input and source_output name, this
should be the media.name when possible.
This commit is contained in:
Wim Taymans 2018-12-04 11:48:15 +01:00
parent ad723e3793
commit 84a7bf671c
4 changed files with 89 additions and 27 deletions

View file

@ -97,6 +97,25 @@ struct global *pa_context_find_global(pa_context *c, uint32_t id)
return NULL;
}
struct global *pa_context_find_global_by_name(pa_context *c, uint32_t mask, const char *name)
{
struct global *g;
const char *str;
uint32_t id = atoi(name);
spa_list_for_each(g, &c->globals, link) {
if (!(g->mask & mask))
continue;
if (g->props != NULL &&
(str = pw_properties_get(g->props, "node.name")) != NULL &&
strcmp(str, name) == 0)
return g;
if (g->id == id)
return g;
}
return NULL;
}
struct global *pa_context_find_linked(pa_context *c, uint32_t idx)
{
struct global *g, *f;

View file

@ -363,24 +363,6 @@ static void sink_info(pa_operation *o, void *userdata)
pa_operation_done(o);
}
struct global *pa_context_find_global_by_name(pa_context *c, uint32_t mask, const char *name)
{
struct global *g;
const char *str;
spa_list_for_each(g, &c->globals, link) {
if (!(g->mask & mask))
continue;
if (g->props == NULL)
continue;
if ((str = pw_properties_get(g->props, "node.name")) == NULL)
continue;
if (strcmp(str, name) == 0)
return g;
}
return NULL;
}
pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata)
{
pa_operation *o;
@ -1269,6 +1251,7 @@ static void sink_input_callback(struct sink_input_data *d)
{
struct global *g = d->global, *l;
struct pw_node_info *info = g->info;
const char *name;
pa_sink_input_info i;
pa_format_info ii[1];
pa_stream *s;
@ -1279,9 +1262,17 @@ static void sink_input_callback(struct sink_input_data *d)
s = find_stream(d->context, g->id);
if (info->props) {
if ((name = spa_dict_lookup(info->props, "media.name")) == NULL &&
(name = spa_dict_lookup(info->props, "application.name")) == NULL)
name = info->name;
}
else
name = info->name;
spa_zero(i);
i.index = g->id;
i.name = info->name;
i.name = name ? name : "Unknown";
i.owner_module = PA_INVALID_INDEX;
i.client = g->parent_id;
if (s) {
@ -1525,6 +1516,7 @@ static void source_output_callback(struct source_output_data *d)
{
struct global *g = d->global, *l;
struct pw_node_info *info = g->info;
const char *name;
pa_source_output_info i;
pa_format_info ii[1];
pa_stream *s;
@ -1535,9 +1527,17 @@ static void source_output_callback(struct source_output_data *d)
s = find_stream(d->context, g->id);
if (info->props) {
if ((name = spa_dict_lookup(info->props, "media.name")) == NULL &&
(name = spa_dict_lookup(info->props, "application.name")) == NULL)
name = info->name;
}
else
name = info->name;
spa_zero(i);
i.index = g->id;
i.name = info->name;
i.name = name ? name : "Unknown";
i.owner_module = PA_INVALID_INDEX;
i.client = g->parent_id;
if (s) {

View file

@ -159,7 +159,13 @@ int pa_proplist_get(pa_proplist *p, const char *key, const void **data, size_t *
void pa_proplist_update(pa_proplist *p, pa_update_mode_t mode, const pa_proplist *other)
{
spa_assert(p);
pw_log_warn("Not Implemented");
spa_assert(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE);
spa_assert(other);
if (mode == PA_UPDATE_SET)
pa_proplist_clear(p);
pa_proplist_update_dict(p, &other->props->dict);
}
int pa_proplist_unset(pa_proplist *p, const char *key)
@ -274,7 +280,7 @@ int pa_proplist_contains(pa_proplist *p, const char *key)
void pa_proplist_clear(pa_proplist *p)
{
spa_assert(p);
pw_log_warn("Not Implemented");
pw_properties_clear(p->props);
}
pa_proplist* pa_proplist_copy(const pa_proplist *p)
@ -305,8 +311,27 @@ int pa_proplist_isempty(pa_proplist *p)
int pa_proplist_equal(pa_proplist *a, pa_proplist *b)
{
int i;
spa_assert(a);
spa_assert(b);
pw_log_warn("Not Implemented");
return 0;
if (a == b)
return 1;
if (pa_proplist_size(a) != pa_proplist_size(b))
return 0;
for (i = 0; i < a->props->dict.n_items; i++) {
const struct spa_dict_item *ai, *bi;
ai = &a->props->dict.items[i];
bi = spa_dict_lookup_item(&b->props->dict, ai->key);
if (bi == NULL || bi->value == NULL || ai->value == NULL)
return 0;
if (strcmp(ai->value, bi->value) != 0)
return 0;
}
return 1;
}

View file

@ -337,6 +337,11 @@ static void stream_format_changed(void *data, const struct spa_pod *format)
struct spa_audio_info info = { 0 };
int i, res;
if (format == NULL) {
res = 0;
goto done;
}
spa_format_parse(format, &info.media_type, &info.media_subtype);
if (info.media_type != SPA_MEDIA_TYPE_audio ||
@ -497,10 +502,11 @@ pa_stream* stream_new(pa_context *c, const char *name,
if (name)
pa_proplist_sets(s->proplist, PA_PROP_MEDIA_NAME, name);
else
name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
name = pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME);
props = pw_properties_new("client.api", "pulseaudio",
NULL);
pw_properties_update(props, &s->proplist->props->dict);
s->stream = pw_stream_new(c->remote, name, props);
s->refcount = 1;
@ -762,6 +768,8 @@ static int create_stream(pa_stream_direction_t direction,
spa_assert(s);
spa_assert(s->refcount >= 1);
pw_log_debug("stream %p: connect %s %08x", s, dev, flags);
s->direction = direction;
s->timing_info_valid = false;
s->disconnecting = false;
@ -824,8 +832,18 @@ static int create_stream(pa_stream_direction_t direction,
if ((str = getenv("PIPEWIRE_NODE")) != NULL)
devid = atoi(str);
}
else if ((g = pa_context_find_global_by_name(s->context, PA_SUBSCRIPTION_MASK_SINK, dev)) != NULL) {
devid = g->id;
else {
uint32_t mask;
if (direction == PA_STREAM_PLAYBACK)
mask = PA_SUBSCRIPTION_MASK_SINK;
else if (direction == PA_STREAM_RECORD)
mask = PA_SUBSCRIPTION_MASK_SOURCE;
else
mask = 0;
if ((g = pa_context_find_global_by_name(s->context, mask, dev)) != NULL)
devid = g->id;
}
if ((str = pa_proplist_gets(s->proplist, PA_PROP_MEDIA_ROLE)) == NULL)