mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
pulse-server: add introspection of clients and modules
Add manager object to collect object info Wait for object info until completing client connect Implement clients and modules list and info.
This commit is contained in:
parent
8ac9ce7947
commit
1cbad89862
5 changed files with 615 additions and 36 deletions
|
|
@ -90,7 +90,8 @@ pipewire_module_protocol_native = shared_library('pipewire-module-protocol-nativ
|
|||
|
||||
pipewire_module_protocol_pulse = shared_library('pipewire-module-protocol-pulse',
|
||||
[ 'module-protocol-pulse.c',
|
||||
'module-protocol-pulse/pulse-server.c' ],
|
||||
'module-protocol-pulse/pulse-server.c',
|
||||
'module-protocol-pulse/manager.c' ],
|
||||
c_args : pipewire_module_c_args,
|
||||
include_directories : [configinc, spa_inc],
|
||||
install : true,
|
||||
|
|
|
|||
368
src/modules/module-protocol-pulse/manager.c
Normal file
368
src/modules/module-protocol-pulse/manager.c
Normal file
|
|
@ -0,0 +1,368 @@
|
|||
/* PipeWire
|
||||
*
|
||||
* Copyright © 2020 Wim Taymans
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "manager.h"
|
||||
|
||||
#define manager_emit_sync(m) spa_hook_list_call(&m->hooks, struct pw_manager_events, sync, 0)
|
||||
#define manager_emit_added(m,o) spa_hook_list_call(&m->hooks, struct pw_manager_events, added, 0, o)
|
||||
#define manager_emit_updated(m,o) spa_hook_list_call(&m->hooks, struct pw_manager_events, updated, 0, o)
|
||||
#define manager_emit_removed(m,o) spa_hook_list_call(&m->hooks, struct pw_manager_events, removed, 0, o)
|
||||
|
||||
struct manager {
|
||||
struct pw_core *core;
|
||||
struct spa_hook core_listener;
|
||||
int sync_seq;
|
||||
|
||||
struct pw_registry *registry;
|
||||
struct spa_hook registry_listener;
|
||||
|
||||
struct spa_hook_list hooks;
|
||||
|
||||
uint32_t n_objects;
|
||||
struct spa_list object_list;
|
||||
};
|
||||
|
||||
struct object_info {
|
||||
const char *type;
|
||||
uint32_t version;
|
||||
const void *events;
|
||||
void (*destroy) (void *object);
|
||||
};
|
||||
|
||||
struct object {
|
||||
struct pw_manager_object this;
|
||||
|
||||
struct manager *manager;
|
||||
struct spa_list link;
|
||||
|
||||
const struct object_info *info;
|
||||
|
||||
struct spa_hook proxy_listener;
|
||||
struct spa_hook object_listener;
|
||||
|
||||
unsigned int new:1;
|
||||
};
|
||||
|
||||
static void core_sync(struct manager *m)
|
||||
{
|
||||
m->sync_seq = pw_core_sync(m->core, PW_ID_CORE, m->sync_seq);
|
||||
}
|
||||
|
||||
static struct object *find_object(struct manager *m, uint32_t id)
|
||||
{
|
||||
struct object *o;
|
||||
spa_list_for_each(o, &m->object_list, link) {
|
||||
if (o->this.id == id)
|
||||
return o;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void object_destroy(struct object *o)
|
||||
{
|
||||
struct manager *m = o->manager;
|
||||
if (o->this.proxy)
|
||||
pw_proxy_destroy(o->this.proxy);
|
||||
free(o->this.type);
|
||||
if (o->this.props)
|
||||
pw_properties_free(o->this.props);
|
||||
spa_list_remove(&o->link);
|
||||
m->n_objects--;
|
||||
free(o);
|
||||
}
|
||||
|
||||
/* client */
|
||||
static void client_event_info(void *object, const struct pw_client_info *info)
|
||||
{
|
||||
struct object *o = object;
|
||||
pw_log_debug("object %p: id:%d change-mask:%"PRIu64, o, o->this.id, info->change_mask);
|
||||
info = o->this.info = pw_client_info_update(o->this.info, info);
|
||||
}
|
||||
|
||||
static const struct pw_client_events client_events = {
|
||||
PW_VERSION_CLIENT_EVENTS,
|
||||
.info = client_event_info,
|
||||
};
|
||||
|
||||
static void client_destroy(void *data)
|
||||
{
|
||||
struct object *o = data;
|
||||
if (o->this.info)
|
||||
pw_client_info_free(o->this.info);
|
||||
}
|
||||
|
||||
struct object_info client_info = {
|
||||
.type = PW_TYPE_INTERFACE_Client,
|
||||
.version = PW_VERSION_CLIENT,
|
||||
.events = &client_events,
|
||||
.destroy = client_destroy,
|
||||
};
|
||||
|
||||
/* module */
|
||||
static void module_event_info(void *object, const struct pw_module_info *info)
|
||||
{
|
||||
struct object *o = object;
|
||||
pw_log_debug("object %p: id:%d change-mask:%"PRIu64, o, o->this.id, info->change_mask);
|
||||
info = o->this.info = pw_module_info_update(o->this.info, info);
|
||||
}
|
||||
|
||||
static const struct pw_module_events module_events = {
|
||||
PW_VERSION_MODULE_EVENTS,
|
||||
.info = module_event_info,
|
||||
};
|
||||
|
||||
static void module_destroy(void *data)
|
||||
{
|
||||
struct object *o = data;
|
||||
if (o->this.info)
|
||||
pw_module_info_free(o->this.info);
|
||||
}
|
||||
|
||||
struct object_info module_info = {
|
||||
.type = PW_TYPE_INTERFACE_Module,
|
||||
.version = PW_VERSION_MODULE,
|
||||
.events = &module_events,
|
||||
.destroy = module_destroy,
|
||||
};
|
||||
|
||||
|
||||
static const struct object_info *objects[] =
|
||||
{
|
||||
// &core_info,
|
||||
&module_info,
|
||||
&client_info,
|
||||
};
|
||||
|
||||
static const struct object_info *find_info(const char *type, uint32_t version)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < SPA_N_ELEMENTS(objects); i++) {
|
||||
if (strcmp(objects[i]->type, type) == 0 &&
|
||||
objects[i]->version <= version)
|
||||
return objects[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint32_t clear_params(struct spa_list *param_list, uint32_t id)
|
||||
{
|
||||
struct pw_manager_param *p, *t;
|
||||
uint32_t count = 0;
|
||||
|
||||
spa_list_for_each_safe(p, t, param_list, link) {
|
||||
if (id == SPA_ID_INVALID || p->id == id) {
|
||||
spa_list_remove(&p->link);
|
||||
free(p);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_removed(void *data)
|
||||
{
|
||||
struct object *o = data;
|
||||
pw_proxy_destroy(o->this.proxy);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_proxy(void *data)
|
||||
{
|
||||
struct object *o = data;
|
||||
|
||||
clear_params(&o->this.param_list, SPA_ID_INVALID);
|
||||
|
||||
if (o->info && o->info->destroy)
|
||||
o->info->destroy(o);
|
||||
|
||||
o->this.proxy = NULL;
|
||||
}
|
||||
|
||||
static const struct pw_proxy_events proxy_events = {
|
||||
PW_VERSION_PROXY_EVENTS,
|
||||
.removed = destroy_removed,
|
||||
.destroy = destroy_proxy,
|
||||
};
|
||||
|
||||
static void registry_event_global(void *data, uint32_t id,
|
||||
uint32_t permissions, const char *type, uint32_t version,
|
||||
const struct spa_dict *props)
|
||||
{
|
||||
struct manager *m = data;
|
||||
struct object *o;
|
||||
const struct object_info *info;
|
||||
struct pw_proxy *proxy;
|
||||
|
||||
info = find_info(type, version);
|
||||
if (info == NULL)
|
||||
return;
|
||||
|
||||
proxy = pw_registry_bind(m->registry,
|
||||
id, type, info->version, 0);
|
||||
if (proxy == NULL)
|
||||
return;
|
||||
|
||||
o = calloc(1, sizeof(*o));
|
||||
if (o == NULL) {
|
||||
pw_log_error("can't alloc object for %u %s/%d: %m", id, type, version);
|
||||
pw_proxy_destroy(proxy);
|
||||
return;
|
||||
}
|
||||
o->this.id = id;
|
||||
o->this.permissions = permissions;
|
||||
o->this.type = strdup(type);
|
||||
o->this.version = version;
|
||||
o->this.props = props ? pw_properties_new_dict(props) : NULL;
|
||||
o->this.proxy = proxy;
|
||||
spa_list_init(&o->this.param_list);
|
||||
|
||||
o->manager = m;
|
||||
o->info = info;
|
||||
o->new = true;
|
||||
spa_list_append(&m->object_list, &o->link);
|
||||
m->n_objects++;
|
||||
|
||||
pw_proxy_add_object_listener(proxy,
|
||||
&o->object_listener,
|
||||
o->info->events, o);
|
||||
pw_proxy_add_listener(proxy,
|
||||
&o->proxy_listener,
|
||||
&proxy_events, o);
|
||||
|
||||
core_sync(m);
|
||||
}
|
||||
|
||||
static void registry_event_global_remove(void *object, uint32_t id)
|
||||
{
|
||||
struct manager *m = object;
|
||||
struct object *o;
|
||||
|
||||
if ((o = find_object(m, id)) == NULL)
|
||||
return;
|
||||
|
||||
manager_emit_removed(m, &o->this);
|
||||
|
||||
object_destroy(o);
|
||||
}
|
||||
|
||||
static const struct pw_registry_events registry_events = {
|
||||
PW_VERSION_REGISTRY_EVENTS,
|
||||
.global = registry_event_global,
|
||||
.global_remove = registry_event_global_remove,
|
||||
};
|
||||
|
||||
static void on_core_done(void *data, uint32_t id, int seq)
|
||||
{
|
||||
struct manager *m = data;
|
||||
if (id == PW_ID_CORE) {
|
||||
if (m->sync_seq == seq) {
|
||||
manager_emit_sync(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pw_core_events core_events = {
|
||||
PW_VERSION_CORE_EVENTS,
|
||||
.done = on_core_done,
|
||||
};
|
||||
|
||||
struct pw_manager *pw_manager_new(struct pw_core *core)
|
||||
{
|
||||
struct manager *this;
|
||||
|
||||
this = calloc(1, sizeof(*this));
|
||||
if (this == NULL)
|
||||
return NULL;
|
||||
|
||||
this->core = core;
|
||||
spa_hook_list_init(&this->hooks);
|
||||
|
||||
spa_list_init(&this->object_list);
|
||||
|
||||
pw_core_add_listener(this->core,
|
||||
&this->core_listener,
|
||||
&core_events, this);
|
||||
this->registry = pw_core_get_registry(this->core,
|
||||
PW_VERSION_REGISTRY, 0);
|
||||
pw_registry_add_listener(this->registry,
|
||||
&this->registry_listener,
|
||||
®istry_events, this);
|
||||
|
||||
return (struct pw_manager*)this;
|
||||
}
|
||||
|
||||
void pw_manager_add_listener(struct pw_manager *manager,
|
||||
struct spa_hook *listener,
|
||||
const struct pw_manager_events *events, void *data)
|
||||
{
|
||||
struct manager *this = (struct manager*)manager;
|
||||
spa_hook_list_append(&this->hooks, listener, events, data);
|
||||
}
|
||||
|
||||
struct pw_manager_object *pw_manager_find_object(struct pw_manager *manager,
|
||||
const char *type, uint32_t id)
|
||||
{
|
||||
struct manager *this = (struct manager*)manager;
|
||||
struct object *o;
|
||||
|
||||
o = find_object(this, id);
|
||||
if (o == NULL)
|
||||
return NULL;
|
||||
if (type != NULL && strcmp(type, o->this.type) != 0)
|
||||
return NULL;
|
||||
return (struct pw_manager_object*)o;
|
||||
}
|
||||
|
||||
int pw_manager_for_each_object(struct pw_manager *manager,
|
||||
int (*callback) (void *data, struct pw_manager_object *object),
|
||||
void *data)
|
||||
{
|
||||
struct manager *this = (struct manager*)manager;
|
||||
struct object *o;
|
||||
int res;
|
||||
|
||||
spa_list_for_each(o, &this->object_list, link) {
|
||||
if ((res = callback(data, &o->this)) != 0)
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pw_manager_destroy(struct pw_manager *manager)
|
||||
{
|
||||
struct manager *this = (struct manager*)manager;
|
||||
struct object *o;
|
||||
|
||||
spa_hook_remove(&this->core_listener);
|
||||
|
||||
spa_list_consume(o, &this->object_list, link)
|
||||
object_destroy(o);
|
||||
|
||||
if (this->registry) {
|
||||
spa_hook_remove(&this->registry_listener);
|
||||
pw_proxy_destroy((struct pw_proxy*)this->registry);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
91
src/modules/module-protocol-pulse/manager.h
Normal file
91
src/modules/module-protocol-pulse/manager.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/* PipeWire
|
||||
*
|
||||
* Copyright © 2020 Wim Taymans
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PIPEWIRE_MANAGER_H
|
||||
#define PIPEWIRE_MANAGER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/pod/pod.h>
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
|
||||
struct pw_manager;
|
||||
struct pw_manager_object;
|
||||
|
||||
struct pw_manager_events {
|
||||
#define PW_VERSION_MANAGER_EVENTS 0
|
||||
uint32_t version;
|
||||
|
||||
void (*destroy) (void *data);
|
||||
|
||||
void (*sync) (void *data);
|
||||
|
||||
void (*added) (void *data, struct pw_manager_object *object);
|
||||
|
||||
void (*updated) (void *data, struct pw_manager_object *object);
|
||||
|
||||
void (*removed) (void *data, struct pw_manager_object *object);
|
||||
};
|
||||
|
||||
struct pw_manager_param {
|
||||
uint32_t id;
|
||||
struct spa_list link; /**< link in param_list */
|
||||
struct spa_pod *param;
|
||||
};
|
||||
|
||||
struct pw_manager_object {
|
||||
uint32_t id;
|
||||
uint32_t permissions;
|
||||
char *type;
|
||||
uint32_t version;
|
||||
struct pw_properties *props;
|
||||
|
||||
void *info;
|
||||
struct pw_proxy *proxy;
|
||||
struct spa_list param_list;
|
||||
};
|
||||
|
||||
struct pw_manager *pw_manager_new(struct pw_core *core);
|
||||
|
||||
void pw_manager_add_listener(struct pw_manager *manager,
|
||||
struct spa_hook *listener,
|
||||
const struct pw_manager_events *events, void *data);
|
||||
|
||||
void pw_manager_destroy(struct pw_manager *manager);
|
||||
|
||||
struct pw_manager_object *pw_manager_find_object(struct pw_manager *manager,
|
||||
const char *type, uint32_t id);
|
||||
int pw_manager_for_each_object(struct pw_manager *manager,
|
||||
int (*callback) (void *data, struct pw_manager_object *object),
|
||||
void *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* PIPEWIRE_MANAGER_H */
|
||||
|
|
@ -495,12 +495,12 @@ static void write_cvolume(struct message *m, struct volume *vol)
|
|||
write_32(m, volume_from_linear(vol->values[i]));
|
||||
}
|
||||
|
||||
static void write_props(struct message *m, struct pw_properties *props)
|
||||
static void write_dict(struct message *m, struct spa_dict *dict)
|
||||
{
|
||||
const struct spa_dict_item *it;
|
||||
write_8(m, TAG_PROPLIST);
|
||||
if (props != NULL) {
|
||||
spa_dict_for_each(it, &props->dict) {
|
||||
if (dict != NULL) {
|
||||
spa_dict_for_each(it, dict) {
|
||||
int l = strlen(it->value);
|
||||
write_string(m, it->key);
|
||||
write_u32(m, l+1);
|
||||
|
|
@ -514,7 +514,7 @@ static void write_format_info(struct message *m, struct format_info *info)
|
|||
{
|
||||
write_8(m, TAG_FORMAT_INFO);
|
||||
write_u8(m, (uint8_t) info->encoding);
|
||||
write_props(m, info->props);
|
||||
write_dict(m, info->props ? &info->props->dict : NULL);
|
||||
}
|
||||
|
||||
static int message_put(struct message *m, ...)
|
||||
|
|
@ -569,7 +569,7 @@ static int message_put(struct message *m, ...)
|
|||
write_cvolume(m, va_arg(va, struct volume*));
|
||||
break;
|
||||
case TAG_PROPLIST:
|
||||
write_props(m, va_arg(va, struct pw_properties*));
|
||||
write_dict(m, va_arg(va, struct spa_dict*));
|
||||
break;
|
||||
case TAG_VOLUME:
|
||||
write_volume(m, va_arg(va, double));
|
||||
|
|
|
|||
|
|
@ -58,12 +58,20 @@
|
|||
|
||||
#include "format.c"
|
||||
#include "message.c"
|
||||
#include "manager.h"
|
||||
|
||||
#define NAME "pulse-server"
|
||||
|
||||
struct impl;
|
||||
struct server;
|
||||
|
||||
struct operation {
|
||||
struct spa_list link;
|
||||
struct client *client;
|
||||
uint32_t tag;
|
||||
void (*callback) (struct operation *op);
|
||||
};
|
||||
|
||||
struct client {
|
||||
struct spa_list link;
|
||||
struct impl *impl;
|
||||
|
|
@ -71,11 +79,15 @@ struct client {
|
|||
|
||||
struct spa_source *source;
|
||||
|
||||
uint32_t id;
|
||||
uint32_t version;
|
||||
|
||||
struct pw_properties *props;
|
||||
|
||||
struct pw_core *core;
|
||||
struct pw_manager *manager;
|
||||
struct spa_hook manager_listener;
|
||||
uint32_t connect_tag;
|
||||
|
||||
uint32_t in_index;
|
||||
uint32_t out_index;
|
||||
|
|
@ -86,6 +98,8 @@ struct client {
|
|||
struct spa_list free_messages;
|
||||
struct spa_list out_messages;
|
||||
|
||||
struct spa_list operations;
|
||||
|
||||
unsigned int disconnecting:1;
|
||||
};
|
||||
|
||||
|
|
@ -449,10 +463,37 @@ static int do_command_auth(struct client *client, uint32_t command, uint32_t tag
|
|||
return send_message(client, reply);
|
||||
}
|
||||
|
||||
static int reply_set_client_name(struct client *client, uint32_t tag)
|
||||
{
|
||||
struct message *reply;
|
||||
reply = reply_new(client, tag);
|
||||
|
||||
if (client->version >= 13) {
|
||||
message_put(reply,
|
||||
TAG_U32, client->id, /* client index */
|
||||
TAG_INVALID);
|
||||
}
|
||||
return send_message(client, reply);
|
||||
}
|
||||
|
||||
static void manager_sync(void *data)
|
||||
{
|
||||
struct client *client = data;
|
||||
|
||||
if (client->connect_tag) {
|
||||
reply_set_client_name(client, client->connect_tag);
|
||||
client->connect_tag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pw_manager_events manager_events = {
|
||||
PW_VERSION_MANAGER_EVENTS,
|
||||
.sync = manager_sync,
|
||||
};
|
||||
|
||||
static int do_set_client_name(struct client *client, uint32_t command, uint32_t tag, struct message *m)
|
||||
{
|
||||
struct impl *impl = client->impl;
|
||||
struct message *reply;
|
||||
const char *name = NULL;
|
||||
int res, changed = 0;
|
||||
|
||||
|
|
@ -466,12 +507,15 @@ static int do_set_client_name(struct client *client, uint32_t command, uint32_t
|
|||
PW_KEY_APP_NAME, name);
|
||||
} else {
|
||||
if ((res = message_get(m,
|
||||
TAG_PROPLIST, client->props,
|
||||
TAG_PROPLIST, client->props ? &client->props->dict : NULL,
|
||||
TAG_INVALID)) < 0)
|
||||
return res;
|
||||
changed++;
|
||||
}
|
||||
|
||||
pw_log_info(NAME" %p: SET_CLIENT_NAME %s", impl,
|
||||
pw_properties_get(client->props, PW_KEY_APP_NAME));
|
||||
|
||||
if (client->core == NULL) {
|
||||
client->core = pw_context_connect(impl->context,
|
||||
pw_properties_copy(client->props), 0);
|
||||
|
|
@ -479,21 +523,22 @@ static int do_set_client_name(struct client *client, uint32_t command, uint32_t
|
|||
res = -errno;
|
||||
goto error;
|
||||
}
|
||||
} else if (changed){
|
||||
pw_core_update_properties(client->core, &client->props->dict);
|
||||
client->manager = pw_manager_new(client->core);
|
||||
if (client->manager == NULL) {
|
||||
res = -errno;
|
||||
goto error;
|
||||
}
|
||||
client->connect_tag = tag;
|
||||
pw_manager_add_listener(client->manager, &client->manager_listener,
|
||||
&manager_events, client);
|
||||
res = 0;
|
||||
} else {
|
||||
if (changed)
|
||||
pw_core_update_properties(client->core, &client->props->dict);
|
||||
|
||||
res = reply_set_client_name(client, tag);
|
||||
}
|
||||
|
||||
pw_log_info(NAME" %p: SET_CLIENT_NAME %s", impl,
|
||||
pw_properties_get(client->props, PW_KEY_APP_NAME));
|
||||
|
||||
reply = reply_new(client, tag);
|
||||
|
||||
if (client->version >= 13) {
|
||||
message_put(reply,
|
||||
TAG_U32, 0, /* client index */
|
||||
TAG_INVALID);
|
||||
}
|
||||
return send_message(client, reply);
|
||||
return res;
|
||||
error:
|
||||
pw_log_error(NAME" %p: failed to connect client: %m", impl);
|
||||
return res;
|
||||
|
|
@ -2145,17 +2190,44 @@ static int do_drain_stream(struct client *client, uint32_t command, uint32_t tag
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void fill_client_info(struct client *client, struct message *m)
|
||||
static void fill_client_info(struct client *client, struct message *m,
|
||||
struct pw_manager_object *o)
|
||||
{
|
||||
struct pw_client_info *info = o->info;
|
||||
|
||||
message_put(m,
|
||||
TAG_U32, 0, /* client index */
|
||||
TAG_STRING, pw_properties_get(client->props, PW_KEY_APP_NAME),
|
||||
TAG_U32, o->id, /* client index */
|
||||
TAG_STRING, pw_properties_get(o->props, PW_KEY_APP_NAME),
|
||||
TAG_U32, SPA_ID_INVALID, /* module */
|
||||
TAG_STRING, "PipeWire", /* driver */
|
||||
TAG_INVALID);
|
||||
if (client->version >= 13) {
|
||||
message_put(m,
|
||||
TAG_PROPLIST, client->props,
|
||||
TAG_PROPLIST, info ? info->props : NULL,
|
||||
TAG_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_module_info(struct client *client, struct message *m,
|
||||
struct pw_manager_object *o)
|
||||
{
|
||||
struct pw_module_info *info = o->info;
|
||||
|
||||
message_put(m,
|
||||
TAG_U32, o->id, /* module index */
|
||||
TAG_STRING, info ? info->name : NULL,
|
||||
TAG_STRING, info ? info->args : NULL,
|
||||
TAG_U32, -1, /* n_used */
|
||||
TAG_INVALID);
|
||||
|
||||
if (client->version < 15) {
|
||||
message_put(m,
|
||||
TAG_BOOLEAN, false, /* auto unload deprecated */
|
||||
TAG_INVALID);
|
||||
}
|
||||
if (client->version >= 15) {
|
||||
message_put(m,
|
||||
TAG_PROPLIST, info ? info->props : NULL,
|
||||
TAG_INVALID);
|
||||
}
|
||||
}
|
||||
|
|
@ -2182,7 +2254,7 @@ static void fill_sink_info(struct client *client, struct message *m, struct devi
|
|||
|
||||
if (client->version >= 13) {
|
||||
message_put(m,
|
||||
TAG_PROPLIST, sink->props,
|
||||
TAG_PROPLIST, sink->props ? &sink->props->dict : NULL,
|
||||
TAG_USEC, 0LL, /* requested latency */
|
||||
TAG_INVALID);
|
||||
}
|
||||
|
|
@ -2235,7 +2307,7 @@ static void fill_source_info(struct client *client, struct message *m, struct de
|
|||
|
||||
if (client->version >= 13) {
|
||||
message_put(m,
|
||||
TAG_PROPLIST, source->props,
|
||||
TAG_PROPLIST, source->props ? &source->props->dict : NULL,
|
||||
TAG_USEC, 0LL, /* requested latency */
|
||||
TAG_INVALID);
|
||||
}
|
||||
|
|
@ -2274,6 +2346,7 @@ static int do_get_info(struct client *client, uint32_t command, uint32_t tag, st
|
|||
const char *name = NULL;
|
||||
struct device *dev;
|
||||
int res;
|
||||
struct pw_manager_object *o;
|
||||
|
||||
if ((res = message_get(m,
|
||||
TAG_U32, &idx,
|
||||
|
|
@ -2301,9 +2374,17 @@ static int do_get_info(struct client *client, uint32_t command, uint32_t tag, st
|
|||
reply = reply_new(client, tag);
|
||||
switch (command) {
|
||||
case COMMAND_GET_CLIENT_INFO:
|
||||
fill_client_info(client, reply);
|
||||
o = pw_manager_find_object(client->manager, PW_TYPE_INTERFACE_Client, idx);
|
||||
if (o == NULL)
|
||||
return reply_error(client, -1, ERR_NOENTITY);
|
||||
fill_client_info(client, reply, o);
|
||||
break;
|
||||
case COMMAND_GET_MODULE_INFO:
|
||||
o = pw_manager_find_object(client->manager, PW_TYPE_INTERFACE_Module, idx);
|
||||
if (o == NULL)
|
||||
return reply_error(client, -1, ERR_NOENTITY);
|
||||
fill_module_info(client, reply, o);
|
||||
break;
|
||||
case COMMAND_GET_CARD_INFO:
|
||||
case COMMAND_GET_SAMPLE_INFO:
|
||||
return reply_error(client, -1, ERR_NOENTITY);
|
||||
|
|
@ -2340,28 +2421,60 @@ static int do_get_info(struct client *client, uint32_t command, uint32_t tag, st
|
|||
return send_message(client, reply);
|
||||
}
|
||||
|
||||
struct info_list_data {
|
||||
struct client *client;
|
||||
struct message *reply;
|
||||
};
|
||||
|
||||
static int do_list_clients(void *data, struct pw_manager_object *object)
|
||||
{
|
||||
struct info_list_data *info = data;
|
||||
|
||||
if (strcmp(object->type, PW_TYPE_INTERFACE_Client) != 0)
|
||||
return 0;
|
||||
|
||||
fill_client_info(info->client, info->reply, object);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_list_modules(void *data, struct pw_manager_object *object)
|
||||
{
|
||||
struct info_list_data *info = data;
|
||||
|
||||
if (strcmp(object->type, PW_TYPE_INTERFACE_Module) != 0)
|
||||
return 0;
|
||||
|
||||
fill_module_info(info->client, info->reply, object);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_get_info_list(struct client *client, uint32_t command, uint32_t tag, struct message *m)
|
||||
{
|
||||
struct impl *impl = client->impl;
|
||||
struct message *reply;
|
||||
struct info_list_data info;
|
||||
int (*list_func) (void *data, struct pw_manager_object *object) = NULL;
|
||||
|
||||
pw_log_info(NAME" %p: %s", impl, commands[command].name);
|
||||
|
||||
reply = reply_new(client, tag);
|
||||
info.client = client;
|
||||
info.reply = reply_new(client, tag);
|
||||
|
||||
switch (command) {
|
||||
case COMMAND_GET_CLIENT_INFO_LIST:
|
||||
fill_client_info(client, reply);
|
||||
list_func = do_list_clients;
|
||||
break;
|
||||
case COMMAND_GET_MODULE_INFO_LIST:
|
||||
list_func = do_list_modules;
|
||||
break;
|
||||
case COMMAND_GET_CARD_INFO_LIST:
|
||||
case COMMAND_GET_SAMPLE_INFO_LIST:
|
||||
break;
|
||||
case COMMAND_GET_SINK_INFO_LIST:
|
||||
fill_sink_info(client, reply, &impl->default_sink);
|
||||
fill_sink_info(client, info.reply, &impl->default_sink);
|
||||
break;
|
||||
case COMMAND_GET_SOURCE_INFO_LIST:
|
||||
fill_source_info(client, reply, &impl->default_source);
|
||||
fill_source_info(client, reply, &impl->default_monitor);
|
||||
fill_source_info(client, info.reply, &impl->default_source);
|
||||
fill_source_info(client, info.reply, &impl->default_monitor);
|
||||
break;
|
||||
case COMMAND_GET_SINK_INPUT_INFO_LIST:
|
||||
case COMMAND_GET_SOURCE_OUTPUT_INFO_LIST:
|
||||
|
|
@ -2370,7 +2483,10 @@ static int do_get_info_list(struct client *client, uint32_t command, uint32_t ta
|
|||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return send_message(client, reply);
|
||||
if (list_func)
|
||||
pw_manager_for_each_object(client->manager, list_func, &info);
|
||||
|
||||
return send_message(client, info.reply);
|
||||
}
|
||||
|
||||
static int do_set_stream_buffer_attr(struct client *client, uint32_t command, uint32_t tag, struct message *m)
|
||||
|
|
@ -2664,6 +2780,8 @@ static void client_free(struct client *client)
|
|||
message_free(client, msg, true, true);
|
||||
spa_list_consume(msg, &client->out_messages, link)
|
||||
message_free(client, msg, true, true);
|
||||
if (client->manager)
|
||||
pw_manager_destroy(client->manager);
|
||||
if (client->core) {
|
||||
client->disconnecting = true;
|
||||
pw_core_disconnect(client->core);
|
||||
|
|
@ -2906,6 +3024,7 @@ on_connect(void *data, int fd, uint32_t mask)
|
|||
pw_map_init(&client->streams, 16, 16);
|
||||
spa_list_init(&client->free_messages);
|
||||
spa_list_init(&client->out_messages);
|
||||
spa_list_init(&client->operations);
|
||||
|
||||
client->props = pw_properties_new(
|
||||
PW_KEY_CLIENT_API, "pipewire-pulse",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue