pulse-server: fill linked sink/source in create_stream reply

This commit is contained in:
Wim Taymans 2020-10-26 16:39:49 +01:00
parent 1df7db5301
commit fd16eb450a

View file

@ -542,6 +542,134 @@ static const struct pw_manager_events manager_events = {
.metadata = manager_metadata, .metadata = manager_metadata,
}; };
static bool is_client(struct pw_manager_object *o)
{
return strcmp(o->type, PW_TYPE_INTERFACE_Client) == 0;
}
static bool is_module(struct pw_manager_object *o)
{
return strcmp(o->type, PW_TYPE_INTERFACE_Module) == 0;
}
static bool is_card(struct pw_manager_object *o)
{
const char *str;
return
strcmp(o->type, PW_TYPE_INTERFACE_Device) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
strcmp(str, "Audio/Device") == 0;
}
static bool is_sink(struct pw_manager_object *o)
{
const char *str;
return
strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
strcmp(str, "Audio/Sink") == 0;
}
static bool is_source(struct pw_manager_object *o)
{
const char *str;
return
strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
strcmp(str, "Audio/Source") == 0;
}
static bool is_sink_input(struct pw_manager_object *o)
{
const char *str;
return
strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
strcmp(str, "Stream/Output/Audio") == 0;
}
static bool is_source_output(struct pw_manager_object *o)
{
const char *str;
return
strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
strcmp(str, "Stream/Input/Audio") == 0;
}
static bool is_link(struct pw_manager_object *o)
{
return strcmp(o->type, PW_TYPE_INTERFACE_Link) == 0;
}
struct selector {
bool (*type) (struct pw_manager_object *o);
uint32_t id;
const char *key;
const char *value;
void (*accumulate) (struct selector *sel, struct pw_manager_object *o);
int32_t score;
struct pw_manager_object *best;
};
static struct pw_manager_object *select_object(struct pw_manager *m,
struct selector *s)
{
struct pw_manager_object *o;
const char *str;
spa_list_for_each(o, &m->object_list, link) {
if (s->type != NULL && !s->type(o))
continue;
if (o->id == s->id)
return o;
if (s->accumulate)
s->accumulate(s, o);
if (o->props && s->key != NULL && s->value != NULL &&
(str = pw_properties_get(o->props, s->key)) != NULL &&
strcmp(str, s->value) == 0)
return o;
}
return s->best;
}
static struct pw_manager_object *find_linked(struct client *client, uint32_t obj_id, enum pw_direction direction)
{
struct pw_manager *m = client->manager;
struct pw_manager_object *o, *p;
const char *str;
uint32_t in_node, out_node;
spa_list_for_each(o, &m->object_list, link) {
if (o->props == NULL || !is_link(o))
continue;
if ((str = pw_properties_get(o->props, PW_KEY_LINK_OUTPUT_NODE)) == NULL)
continue;
out_node = pw_properties_parse_int(str);
if ((str = pw_properties_get(o->props, PW_KEY_LINK_INPUT_NODE)) == NULL)
continue;
in_node = pw_properties_parse_int(str);
if (direction == PW_DIRECTION_OUTPUT && obj_id == out_node) {
struct selector sel = { .id = in_node, .type = is_sink, };
if ((p = select_object(m, &sel)) != NULL)
return p;
}
if (direction == PW_DIRECTION_INPUT && obj_id == in_node) {
struct selector sel = { .id = out_node, .type = is_source, };
if ((p = select_object(m, &sel)) != NULL)
return p;
}
}
return NULL;
}
static struct stream *find_stream(struct client *client, uint32_t id) static struct stream *find_stream(struct client *client, uint32_t id)
{ {
union pw_map_item *item; union pw_map_item *item;
@ -818,9 +946,11 @@ static int reply_create_playback_stream(struct stream *stream)
{ {
struct client *client = stream->client; struct client *client = stream->client;
struct message *reply; struct message *reply;
uint32_t size; uint32_t size, peer_id;
struct spa_dict_item items[1]; struct spa_dict_item items[1];
char latency[32]; char latency[32];
struct pw_manager_object *peer;
const char *peer_name;
fix_playback_buffer_attr(stream, &stream->attr); fix_playback_buffer_attr(stream, &stream->attr);
@ -843,6 +973,15 @@ static int reply_create_playback_stream(struct stream *stream)
stream->pending = size; stream->pending = size;
peer = find_linked(client, stream->id, stream->direction);
if (peer) {
peer_id = peer->id;
peer_name = pw_properties_get(peer->props, PW_KEY_NODE_NAME);
} else {
peer_id = SPA_ID_INVALID;
peer_name = NULL;
}
if (client->version >= 9) { if (client->version >= 9) {
message_put(reply, message_put(reply,
TAG_U32, stream->attr.maxlength, TAG_U32, stream->attr.maxlength,
@ -855,8 +994,8 @@ static int reply_create_playback_stream(struct stream *stream)
message_put(reply, message_put(reply,
TAG_SAMPLE_SPEC, &stream->ss, TAG_SAMPLE_SPEC, &stream->ss,
TAG_CHANNEL_MAP, &stream->map, TAG_CHANNEL_MAP, &stream->map,
TAG_U32, 0, /* sink index */ TAG_U32, peer_id, /* sink index */
TAG_STRING, "sink", /* sink name */ TAG_STRING, peer_name, /* sink name */
TAG_BOOLEAN, false, /* sink suspended state */ TAG_BOOLEAN, false, /* sink suspended state */
TAG_INVALID); TAG_INVALID);
} }
@ -911,6 +1050,9 @@ static int reply_create_record_stream(struct stream *stream)
struct message *reply; struct message *reply;
struct spa_dict_item items[1]; struct spa_dict_item items[1];
char latency[32]; char latency[32];
struct pw_manager_object *peer;
const char *peer_name;
uint32_t peer_id;
fix_record_buffer_attr(stream, &stream->attr); fix_record_buffer_attr(stream, &stream->attr);
@ -928,6 +1070,15 @@ static int reply_create_record_stream(struct stream *stream)
TAG_U32, stream->id, /* source_output/stream index */ TAG_U32, stream->id, /* source_output/stream index */
TAG_INVALID); TAG_INVALID);
peer = find_linked(client, stream->id, stream->direction);
if (peer) {
peer_id = peer->id;
peer_name = pw_properties_get(peer->props, PW_KEY_NODE_NAME);
} else {
peer_id = SPA_ID_INVALID;
peer_name = NULL;
}
if (client->version >= 9) { if (client->version >= 9) {
message_put(reply, message_put(reply,
TAG_U32, stream->attr.maxlength, TAG_U32, stream->attr.maxlength,
@ -938,8 +1089,8 @@ static int reply_create_record_stream(struct stream *stream)
message_put(reply, message_put(reply,
TAG_SAMPLE_SPEC, &stream->ss, TAG_SAMPLE_SPEC, &stream->ss,
TAG_CHANNEL_MAP, &stream->map, TAG_CHANNEL_MAP, &stream->map,
TAG_U32, SPA_ID_INVALID, /* source index */ TAG_U32, peer_id, /* source index */
TAG_STRING, NULL, /* source name */ TAG_STRING, peer_name, /* source name */
TAG_BOOLEAN, false, /* source suspended state */ TAG_BOOLEAN, false, /* source suspended state */
TAG_INVALID); TAG_INVALID);
} }
@ -1232,97 +1383,6 @@ static const struct pw_stream_events stream_events =
.drained = stream_drained, .drained = stream_drained,
}; };
static bool is_client(struct pw_manager_object *o)
{
return strcmp(o->type, PW_TYPE_INTERFACE_Client) == 0;
}
static bool is_module(struct pw_manager_object *o)
{
return strcmp(o->type, PW_TYPE_INTERFACE_Module) == 0;
}
static bool is_card(struct pw_manager_object *o)
{
const char *str;
return
strcmp(o->type, PW_TYPE_INTERFACE_Device) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
strcmp(str, "Audio/Device") == 0;
}
static bool is_sink(struct pw_manager_object *o)
{
const char *str;
return
strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
strcmp(str, "Audio/Sink") == 0;
}
static bool is_source(struct pw_manager_object *o)
{
const char *str;
return
strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
strcmp(str, "Audio/Source") == 0;
}
static bool is_sink_input(struct pw_manager_object *o)
{
const char *str;
return
strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
strcmp(str, "Stream/Output/Audio") == 0;
}
static bool is_source_output(struct pw_manager_object *o)
{
const char *str;
return
strcmp(o->type, PW_TYPE_INTERFACE_Node) == 0 &&
o->props != NULL &&
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) != NULL &&
strcmp(str, "Stream/Input/Audio") == 0;
}
struct selector {
bool (*type) (struct pw_manager_object *o);
uint32_t id;
const char *key;
const char *value;
void (*accumulate) (struct selector *sel, struct pw_manager_object *o);
int32_t score;
struct pw_manager_object *best;
};
static struct pw_manager_object *select_object(struct pw_manager *m,
struct selector *s)
{
struct pw_manager_object *o;
const char *str;
spa_list_for_each(o, &m->object_list, link) {
if (s->type != NULL && !s->type(o))
continue;
if (o->id == s->id)
return o;
if (s->accumulate)
s->accumulate(s, o);
if (o->props && s->key != NULL && s->value != NULL &&
(str = pw_properties_get(o->props, s->key)) != NULL &&
strcmp(str, s->value) == 0)
return o;
}
return s->best;
}
static void fix_stream_properties(struct stream *stream, struct pw_properties *props) static void fix_stream_properties(struct stream *stream, struct pw_properties *props)
{ {
const char *str; const char *str;