mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
pulse-server: add more introspection
Add default nodes support and subscription events when it changes. Fix stream id. Fix node lookup. Fix node volume.
This commit is contained in:
parent
f75acc31d3
commit
a372e4e90e
4 changed files with 552 additions and 224 deletions
|
|
@ -239,3 +239,37 @@ enum {
|
|||
|
||||
COMMAND_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
SUBSCRIPTION_MASK_NULL = 0x0000U,
|
||||
SUBSCRIPTION_MASK_SINK = 0x0001U,
|
||||
SUBSCRIPTION_MASK_SOURCE = 0x0002U,
|
||||
SUBSCRIPTION_MASK_SINK_INPUT = 0x0004U,
|
||||
SUBSCRIPTION_MASK_SOURCE_OUTPUT = 0x0008U,
|
||||
SUBSCRIPTION_MASK_MODULE = 0x0010U,
|
||||
SUBSCRIPTION_MASK_CLIENT = 0x0020U,
|
||||
SUBSCRIPTION_MASK_SAMPLE_CACHE = 0x0040U,
|
||||
SUBSCRIPTION_MASK_SERVER = 0x0080U,
|
||||
SUBSCRIPTION_MASK_AUTOLOAD = 0x0100U,
|
||||
SUBSCRIPTION_MASK_CARD = 0x0200U,
|
||||
SUBSCRIPTION_MASK_ALL = 0x02ffU
|
||||
};
|
||||
|
||||
enum {
|
||||
SUBSCRIPTION_EVENT_SINK = 0x0000U,
|
||||
SUBSCRIPTION_EVENT_SOURCE = 0x0001U,
|
||||
SUBSCRIPTION_EVENT_SINK_INPUT = 0x0002U,
|
||||
SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 0x0003U,
|
||||
SUBSCRIPTION_EVENT_MODULE = 0x0004U,
|
||||
SUBSCRIPTION_EVENT_CLIENT = 0x0005U,
|
||||
SUBSCRIPTION_EVENT_SAMPLE_CACHE = 0x0006U,
|
||||
SUBSCRIPTION_EVENT_SERVER = 0x0007U,
|
||||
SUBSCRIPTION_EVENT_AUTOLOAD = 0x0008U,
|
||||
SUBSCRIPTION_EVENT_CARD = 0x0009U,
|
||||
SUBSCRIPTION_EVENT_FACILITY_MASK = 0x000FU,
|
||||
|
||||
SUBSCRIPTION_EVENT_NEW = 0x0000U,
|
||||
SUBSCRIPTION_EVENT_CHANGE = 0x0010U,
|
||||
SUBSCRIPTION_EVENT_REMOVE = 0x0020U,
|
||||
SUBSCRIPTION_EVENT_TYPE_MASK = 0x0030U
|
||||
};
|
||||
|
|
|
|||
|
|
@ -23,24 +23,22 @@
|
|||
*/
|
||||
|
||||
#include "manager.h"
|
||||
#include <extensions/metadata.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)
|
||||
#define manager_emit_metadata(m,s,k,t,v) spa_hook_list_call(&m->hooks, struct pw_manager_events, metadata,0,s,k,t,v)
|
||||
|
||||
struct manager {
|
||||
struct pw_core *core;
|
||||
struct pw_manager this;
|
||||
|
||||
struct spa_hook core_listener;
|
||||
struct spa_hook registry_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 {
|
||||
|
|
@ -54,7 +52,6 @@ struct object {
|
|||
struct pw_manager_object this;
|
||||
|
||||
struct manager *manager;
|
||||
struct spa_list link;
|
||||
|
||||
const struct object_info *info;
|
||||
|
||||
|
|
@ -66,13 +63,13 @@ struct object {
|
|||
|
||||
static void core_sync(struct manager *m)
|
||||
{
|
||||
m->sync_seq = pw_core_sync(m->core, PW_ID_CORE, m->sync_seq);
|
||||
m->sync_seq = pw_core_sync(m->this.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) {
|
||||
spa_list_for_each(o, &m->this.object_list, this.link) {
|
||||
if (o->this.id == id)
|
||||
return o;
|
||||
}
|
||||
|
|
@ -87,8 +84,8 @@ static void object_destroy(struct object *o)
|
|||
free(o->this.type);
|
||||
if (o->this.props)
|
||||
pw_properties_free(o->this.props);
|
||||
spa_list_remove(&o->link);
|
||||
m->n_objects--;
|
||||
spa_list_remove(&o->this.link);
|
||||
m->this.n_objects--;
|
||||
free(o);
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +109,7 @@ static void client_destroy(void *data)
|
|||
pw_client_info_free(o->this.info);
|
||||
}
|
||||
|
||||
struct object_info client_info = {
|
||||
static const struct object_info client_info = {
|
||||
.type = PW_TYPE_INTERFACE_Client,
|
||||
.version = PW_VERSION_CLIENT,
|
||||
.events = &client_events,
|
||||
|
|
@ -139,7 +136,7 @@ static void module_destroy(void *data)
|
|||
pw_module_info_free(o->this.info);
|
||||
}
|
||||
|
||||
struct object_info module_info = {
|
||||
static const struct object_info module_info = {
|
||||
.type = PW_TYPE_INTERFACE_Module,
|
||||
.version = PW_VERSION_MODULE,
|
||||
.events = &module_events,
|
||||
|
|
@ -166,7 +163,7 @@ static void device_destroy(void *data)
|
|||
pw_device_info_free(o->this.info);
|
||||
}
|
||||
|
||||
struct object_info device_info = {
|
||||
static const struct object_info device_info = {
|
||||
.type = PW_TYPE_INTERFACE_Device,
|
||||
.version = PW_VERSION_DEVICE,
|
||||
.events = &device_events,
|
||||
|
|
@ -176,9 +173,9 @@ struct object_info device_info = {
|
|||
/* node */
|
||||
static void node_event_info(void *object, const struct pw_node_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_node_info_update(o->this.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_node_info_update(o->this.info, info);
|
||||
}
|
||||
|
||||
static const struct pw_node_events node_events = {
|
||||
|
|
@ -193,19 +190,51 @@ static void node_destroy(void *data)
|
|||
pw_node_info_free(o->this.info);
|
||||
}
|
||||
|
||||
struct object_info node_info = {
|
||||
static const struct object_info node_info = {
|
||||
.type = PW_TYPE_INTERFACE_Node,
|
||||
.version = PW_VERSION_NODE,
|
||||
.events = &node_events,
|
||||
.destroy = node_destroy,
|
||||
};
|
||||
|
||||
/* link */
|
||||
static const struct object_info link_info = {
|
||||
.type = PW_TYPE_INTERFACE_Link,
|
||||
.version = PW_VERSION_LINK,
|
||||
};
|
||||
|
||||
/* metadata */
|
||||
static int metadata_property(void *object,
|
||||
uint32_t subject,
|
||||
const char *key,
|
||||
const char *type,
|
||||
const char *value)
|
||||
{
|
||||
struct object *o = object;
|
||||
struct manager *m = o->manager;
|
||||
manager_emit_metadata(m, subject, key, type, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pw_metadata_events metadata_events = {
|
||||
PW_VERSION_METADATA_EVENTS,
|
||||
.property = metadata_property,
|
||||
};
|
||||
|
||||
static const struct object_info metadata_info = {
|
||||
.type = PW_TYPE_INTERFACE_Metadata,
|
||||
.version = PW_VERSION_METADATA,
|
||||
.events = &metadata_events,
|
||||
};
|
||||
|
||||
static const struct object_info *objects[] =
|
||||
{
|
||||
&module_info,
|
||||
&client_info,
|
||||
&device_info,
|
||||
&node_info,
|
||||
&link_info,
|
||||
&metadata_info,
|
||||
};
|
||||
|
||||
static const struct object_info *find_info(const char *type, uint32_t version)
|
||||
|
|
@ -273,7 +302,7 @@ static void registry_event_global(void *data, uint32_t id,
|
|||
if (info == NULL)
|
||||
return;
|
||||
|
||||
proxy = pw_registry_bind(m->registry,
|
||||
proxy = pw_registry_bind(m->this.registry,
|
||||
id, type, info->version, 0);
|
||||
if (proxy == NULL)
|
||||
return;
|
||||
|
|
@ -295,12 +324,13 @@ static void registry_event_global(void *data, uint32_t id,
|
|||
o->manager = m;
|
||||
o->info = info;
|
||||
o->new = true;
|
||||
spa_list_append(&m->object_list, &o->link);
|
||||
m->n_objects++;
|
||||
spa_list_append(&m->this.object_list, &o->this.link);
|
||||
m->this.n_objects++;
|
||||
|
||||
pw_proxy_add_object_listener(proxy,
|
||||
&o->object_listener,
|
||||
o->info->events, o);
|
||||
if (info->events)
|
||||
pw_proxy_add_object_listener(proxy,
|
||||
&o->object_listener,
|
||||
o->info->events, o);
|
||||
pw_proxy_add_listener(proxy,
|
||||
&o->proxy_listener,
|
||||
&proxy_events, o);
|
||||
|
|
@ -331,9 +361,8 @@ 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) {
|
||||
if (m->sync_seq == seq)
|
||||
manager_emit_sync(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -344,44 +373,46 @@ static const struct pw_core_events core_events = {
|
|||
|
||||
struct pw_manager *pw_manager_new(struct pw_core *core)
|
||||
{
|
||||
struct manager *this;
|
||||
struct manager *m;
|
||||
|
||||
this = calloc(1, sizeof(*this));
|
||||
if (this == NULL)
|
||||
m = calloc(1, sizeof(*m));
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
|
||||
this->core = core;
|
||||
spa_hook_list_init(&this->hooks);
|
||||
m->this.core = core;
|
||||
spa_hook_list_init(&m->hooks);
|
||||
|
||||
spa_list_init(&this->object_list);
|
||||
spa_list_init(&m->this.object_list);
|
||||
|
||||
pw_core_add_listener(this->core,
|
||||
&this->core_listener,
|
||||
&core_events, this);
|
||||
this->registry = pw_core_get_registry(this->core,
|
||||
pw_core_add_listener(m->this.core,
|
||||
&m->core_listener,
|
||||
&core_events, m);
|
||||
m->this.registry = pw_core_get_registry(m->this.core,
|
||||
PW_VERSION_REGISTRY, 0);
|
||||
pw_registry_add_listener(this->registry,
|
||||
&this->registry_listener,
|
||||
®istry_events, this);
|
||||
pw_registry_add_listener(m->this.registry,
|
||||
&m->registry_listener,
|
||||
®istry_events, m);
|
||||
|
||||
return (struct pw_manager*)this;
|
||||
core_sync(m);
|
||||
|
||||
return &m->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 manager *m = SPA_CONTAINER_OF(manager, struct manager, this);
|
||||
spa_hook_list_append(&m->hooks, listener, events, data);
|
||||
}
|
||||
|
||||
struct pw_manager_object *pw_manager_find_object(struct pw_manager *manager,
|
||||
uint32_t id)
|
||||
{
|
||||
struct manager *this = (struct manager*)manager;
|
||||
struct manager *m = SPA_CONTAINER_OF(manager, struct manager, this);
|
||||
struct object *o;
|
||||
|
||||
o = find_object(this, id);
|
||||
o = find_object(m, id);
|
||||
if (o == NULL)
|
||||
return NULL;
|
||||
return (struct pw_manager_object*)o;
|
||||
|
|
@ -391,11 +422,11 @@ 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 manager *m = SPA_CONTAINER_OF(manager, struct manager, this);
|
||||
struct object *o;
|
||||
int res;
|
||||
|
||||
spa_list_for_each(o, &this->object_list, link) {
|
||||
spa_list_for_each(o, &m->this.object_list, this.link) {
|
||||
if ((res = callback(data, &o->this)) != 0)
|
||||
return res;
|
||||
}
|
||||
|
|
@ -404,17 +435,17 @@ int pw_manager_for_each_object(struct pw_manager *manager,
|
|||
|
||||
void pw_manager_destroy(struct pw_manager *manager)
|
||||
{
|
||||
struct manager *this = (struct manager*)manager;
|
||||
struct manager *m = SPA_CONTAINER_OF(manager, struct manager, this);
|
||||
struct object *o;
|
||||
|
||||
spa_hook_remove(&this->core_listener);
|
||||
spa_hook_remove(&m->core_listener);
|
||||
|
||||
spa_list_consume(o, &this->object_list, link)
|
||||
spa_list_consume(o, &m->this.object_list, this.link)
|
||||
object_destroy(o);
|
||||
|
||||
if (this->registry) {
|
||||
spa_hook_remove(&this->registry_listener);
|
||||
pw_proxy_destroy((struct pw_proxy*)this->registry);
|
||||
if (m->this.registry) {
|
||||
spa_hook_remove(&m->registry_listener);
|
||||
pw_proxy_destroy((struct pw_proxy*)m->this.registry);
|
||||
}
|
||||
free(this);
|
||||
free(m);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ extern "C" {
|
|||
|
||||
#include <pipewire/pipewire.h>
|
||||
|
||||
struct pw_manager;
|
||||
struct pw_manager_object;
|
||||
|
||||
struct pw_manager_events {
|
||||
|
|
@ -50,15 +49,27 @@ struct pw_manager_events {
|
|||
void (*updated) (void *data, struct pw_manager_object *object);
|
||||
|
||||
void (*removed) (void *data, struct pw_manager_object *object);
|
||||
|
||||
void (*metadata) (void *data, uint32_t subject, const char *key,
|
||||
const char *type, const char *value);
|
||||
};
|
||||
|
||||
struct pw_manager {
|
||||
struct pw_core *core;
|
||||
struct pw_registry *registry;
|
||||
|
||||
uint32_t n_objects;
|
||||
struct spa_list object_list;
|
||||
};
|
||||
|
||||
struct pw_manager_param {
|
||||
uint32_t id;
|
||||
struct spa_list link; /**< link in param_list */
|
||||
struct spa_list link; /**< link in manager_object param_list */
|
||||
struct spa_pod *param;
|
||||
};
|
||||
|
||||
struct pw_manager_object {
|
||||
struct spa_list link; /**< link in manager object_list */
|
||||
uint32_t id;
|
||||
uint32_t permissions;
|
||||
char *type;
|
||||
|
|
@ -78,8 +89,6 @@ void pw_manager_add_listener(struct pw_manager *manager,
|
|||
|
||||
void pw_manager_destroy(struct pw_manager *manager);
|
||||
|
||||
struct pw_manager_object *pw_manager_find_object(struct pw_manager *manager,
|
||||
uint32_t id);
|
||||
int pw_manager_for_each_object(struct pw_manager *manager,
|
||||
int (*callback) (void *data, struct pw_manager_object *object),
|
||||
void *data);
|
||||
|
|
|
|||
|
|
@ -87,6 +87,14 @@ struct client {
|
|||
struct pw_core *core;
|
||||
struct pw_manager *manager;
|
||||
struct spa_hook manager_listener;
|
||||
|
||||
uint32_t cookie;
|
||||
uint32_t default_rate;
|
||||
uint32_t subscribed;
|
||||
|
||||
uint32_t default_sink;
|
||||
uint32_t default_source;
|
||||
|
||||
uint32_t connect_tag;
|
||||
|
||||
uint32_t in_index;
|
||||
|
|
@ -114,6 +122,7 @@ struct buffer_attr {
|
|||
struct stream {
|
||||
uint32_t create_tag;
|
||||
uint32_t channel; /* index in map */
|
||||
uint32_t id; /* id of global */
|
||||
|
||||
struct impl *impl;
|
||||
struct client *client;
|
||||
|
|
@ -354,6 +363,22 @@ static int send_underflow(struct stream *stream, int64_t offset)
|
|||
return send_message(client, reply);
|
||||
}
|
||||
|
||||
static int send_subscribe_event(struct client *client, uint32_t event, uint32_t id)
|
||||
{
|
||||
struct message *reply;
|
||||
|
||||
pw_log_info(NAME" %p: SUBSCRIBE event:%08x id:%u", client, event, id);
|
||||
|
||||
reply = message_alloc(client, -1, 0);
|
||||
message_put(reply,
|
||||
TAG_U32, COMMAND_SUBSCRIBE_EVENT,
|
||||
TAG_U32, -1,
|
||||
TAG_U32, event,
|
||||
TAG_U32, id,
|
||||
TAG_INVALID);
|
||||
return send_message(client, reply);
|
||||
}
|
||||
|
||||
static int send_overflow(struct stream *stream)
|
||||
{
|
||||
struct client *client = stream->client;
|
||||
|
|
@ -466,11 +491,69 @@ static void manager_sync(void *data)
|
|||
}
|
||||
}
|
||||
|
||||
static void manager_added(void *data, struct pw_manager_object *o)
|
||||
{
|
||||
struct client *client = data;
|
||||
const char *str;
|
||||
|
||||
if (strcmp(o->type, PW_TYPE_INTERFACE_Core) == 0 && o->info != NULL) {
|
||||
struct pw_core_info *info = o->info;
|
||||
|
||||
if (info->props &&
|
||||
(str = spa_dict_lookup(info->props, "default.clock.rate")) != NULL)
|
||||
client->default_rate = atoi(str);
|
||||
client->cookie = info->cookie;
|
||||
}
|
||||
}
|
||||
|
||||
static void manager_metadata(void *data, uint32_t subject, const char *key,
|
||||
const char *type, const char *value)
|
||||
{
|
||||
struct client *client = data;
|
||||
uint32_t val;
|
||||
bool changed = false;
|
||||
|
||||
pw_log_debug("meta %d %s %s %s", subject, key, type, value);
|
||||
if (subject == PW_ID_CORE) {
|
||||
val = (key && value) ? (uint32_t)atoi(value) : SPA_ID_INVALID;
|
||||
if (key == NULL || strcmp(key, "default.audio.sink") == 0) {
|
||||
changed = client->default_sink != val;
|
||||
client->default_sink = val;
|
||||
}
|
||||
if (key == NULL || strcmp(key, "default.audio.source") == 0) {
|
||||
changed = client->default_source != val;
|
||||
client->default_source = val;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
if (client->subscribed & SUBSCRIPTION_MASK_SERVER) {
|
||||
send_subscribe_event(client,
|
||||
SUBSCRIPTION_EVENT_CHANGE |
|
||||
SUBSCRIPTION_EVENT_SERVER,
|
||||
-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pw_manager_events manager_events = {
|
||||
PW_VERSION_MANAGER_EVENTS,
|
||||
.sync = manager_sync,
|
||||
.added = manager_added,
|
||||
.metadata = manager_metadata,
|
||||
};
|
||||
|
||||
static struct stream *find_stream(struct client *client, uint32_t id)
|
||||
{
|
||||
union pw_map_item *item;
|
||||
pw_array_for_each(item, &client->streams.items) {
|
||||
struct stream *s = item->data;
|
||||
if (!pw_map_item_is_free(item) &&
|
||||
s->id == id)
|
||||
return s;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int do_set_client_name(struct client *client, uint32_t command, uint32_t tag, struct message *m)
|
||||
{
|
||||
struct impl *impl = client->impl;
|
||||
|
|
@ -538,6 +621,7 @@ static int do_subscribe(struct client *client, uint32_t command, uint32_t tag, s
|
|||
return res;
|
||||
|
||||
pw_log_info(NAME" %p: SUBSCRIBE mask:%08x", impl, mask);
|
||||
client->subscribed = mask;
|
||||
|
||||
reply = reply_new(client, tag);
|
||||
|
||||
|
|
@ -752,9 +836,9 @@ static int reply_create_playback_stream(struct stream *stream)
|
|||
|
||||
reply = reply_new(client, stream->create_tag);
|
||||
message_put(reply,
|
||||
TAG_U32, stream->channel, /* stream index/channel */
|
||||
TAG_U32, pw_stream_get_node_id(stream->stream), /* sink_input/stream index */
|
||||
TAG_U32, size, /* missing/requested bytes */
|
||||
TAG_U32, stream->channel, /* stream index/channel */
|
||||
TAG_U32, stream->id, /* sink_input/stream index */
|
||||
TAG_U32, size, /* missing/requested bytes */
|
||||
TAG_INVALID);
|
||||
|
||||
stream->pending = size;
|
||||
|
|
@ -841,7 +925,7 @@ static int reply_create_record_stream(struct stream *stream)
|
|||
reply = reply_new(client, stream->create_tag);
|
||||
message_put(reply,
|
||||
TAG_U32, stream->channel, /* stream index/channel */
|
||||
TAG_U32, pw_stream_get_node_id(stream->stream), /* source_output/stream index */
|
||||
TAG_U32, stream->id, /* source_output/stream index */
|
||||
TAG_INVALID);
|
||||
|
||||
if (client->version >= 9) {
|
||||
|
|
@ -959,6 +1043,8 @@ static void stream_param_changed(void *data, uint32_t id, const struct spa_pod *
|
|||
}
|
||||
|
||||
if (stream->create_tag != SPA_ID_INVALID) {
|
||||
stream->id = pw_stream_get_node_id(stream->stream);
|
||||
|
||||
if (stream->volume_set) {
|
||||
pw_stream_set_control(stream->stream,
|
||||
SPA_PROP_channelVolumes, stream->volume.channels, stream->volume.values, 0);
|
||||
|
|
@ -1146,56 +1232,96 @@ static const struct pw_stream_events stream_events =
|
|||
.drained = stream_drained,
|
||||
};
|
||||
|
||||
static struct pw_manager_object *find_node_by_name(struct impl *impl, const char *name)
|
||||
static bool is_client(struct pw_manager_object *o)
|
||||
{
|
||||
return NULL;
|
||||
return strcmp(o->type, PW_TYPE_INTERFACE_Client) == 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static struct device *find_device_by_name(struct impl *impl, const char *name)
|
||||
static bool is_module(struct pw_manager_object *o)
|
||||
{
|
||||
struct device *dev;
|
||||
if (strcmp(name, impl->default_source.name) == 0 ||
|
||||
strcmp(name, "@DEFAULT_SOURCE@") == 0 ||
|
||||
(uint32_t)atoi(name) == impl->default_source.index)
|
||||
dev = &impl->default_source;
|
||||
else if (strcmp(name, impl->default_sink.name) == 0 ||
|
||||
strcmp(name, "@DEFAULT_SINK@") == 0 ||
|
||||
(uint32_t)atoi(name) == impl->default_sink.index)
|
||||
dev = &impl->default_sink;
|
||||
else if (strcmp(name, impl->default_monitor.name) == 0 ||
|
||||
strcmp(name, "@DEFAULT_MONITOR@") == 0 ||
|
||||
(uint32_t)atoi(name) == impl->default_monitor.index)
|
||||
dev = &impl->default_monitor;
|
||||
else
|
||||
dev = NULL;
|
||||
return dev;
|
||||
return strcmp(o->type, PW_TYPE_INTERFACE_Module) == 0;
|
||||
}
|
||||
|
||||
static struct device *find_device_by_index(struct impl *impl, uint32_t index)
|
||||
static bool is_card(struct pw_manager_object *o)
|
||||
{
|
||||
struct device *dev;
|
||||
if (impl->default_source.index == index)
|
||||
dev = &impl->default_source;
|
||||
else if (impl->default_sink.index == index)
|
||||
dev = &impl->default_sink;
|
||||
else if (impl->default_monitor.index == index)
|
||||
dev = &impl->default_monitor;
|
||||
else
|
||||
dev = NULL;
|
||||
return dev;
|
||||
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 struct device *find_device(struct impl *impl, uint32_t idx, const char *name)
|
||||
static bool is_sink(struct pw_manager_object *o)
|
||||
{
|
||||
struct device *dev;
|
||||
if (idx != SPA_ID_INVALID)
|
||||
dev = find_device_by_index(impl, idx);
|
||||
else
|
||||
dev = find_device_by_name(impl, name);
|
||||
return dev;
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void fix_stream_properties(struct stream *stream, struct pw_properties *props)
|
||||
{
|
||||
|
|
@ -1853,67 +1979,156 @@ static int do_error_access(struct client *client, uint32_t command, uint32_t tag
|
|||
return reply_error(client, tag, ERR_ACCESS);
|
||||
}
|
||||
|
||||
static int set_node_volume(struct pw_manager_object *o, struct volume *vol)
|
||||
{
|
||||
char buf[1024];
|
||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
|
||||
|
||||
pw_node_set_param((struct pw_node*)o->proxy,
|
||||
SPA_PARAM_Props, 0,
|
||||
spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_Props, SPA_PARAM_Props,
|
||||
SPA_PROP_channelVolumes, SPA_POD_Array(sizeof(float),
|
||||
SPA_TYPE_Float,
|
||||
vol->channels,
|
||||
vol->values)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_node_mute(struct pw_manager_object *o, bool mute)
|
||||
{
|
||||
char buf[1024];
|
||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
|
||||
|
||||
pw_node_set_param((struct pw_node*)o->proxy,
|
||||
SPA_PARAM_Props, 0,
|
||||
spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_Props, SPA_PARAM_Props,
|
||||
SPA_PROP_mute, SPA_POD_Bool(mute)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_set_stream_volume(struct client *client, uint32_t command, uint32_t tag, struct message *m)
|
||||
{
|
||||
struct impl *impl = client->impl;
|
||||
uint32_t channel;
|
||||
uint32_t id;
|
||||
struct stream *stream;
|
||||
int res;
|
||||
struct volume volume;
|
||||
int res;
|
||||
|
||||
if ((res = message_get(m,
|
||||
TAG_U32, &channel,
|
||||
TAG_U32, &id,
|
||||
TAG_CVOLUME, &volume,
|
||||
TAG_INVALID)) < 0)
|
||||
return res;
|
||||
goto error_protocol;
|
||||
|
||||
pw_log_info(NAME" %p: DO_STREAM_VOLUME channel:%u",
|
||||
impl, channel);
|
||||
stream = pw_map_lookup(&client->streams, channel);
|
||||
if (stream == NULL)
|
||||
return -EINVAL;
|
||||
pw_log_info(NAME" %p: DO_STREAM_VOLUME index:%u", impl, id);
|
||||
|
||||
stream->volume = volume;
|
||||
stream->volume_set = true;
|
||||
stream = find_stream(client, id);
|
||||
if (stream != NULL) {
|
||||
stream->volume = volume;
|
||||
stream->volume_set = true;
|
||||
|
||||
pw_stream_set_control(stream->stream,
|
||||
SPA_PROP_channelVolumes, volume.channels, volume.values,
|
||||
0);
|
||||
pw_stream_set_control(stream->stream,
|
||||
SPA_PROP_channelVolumes, volume.channels, volume.values,
|
||||
0);
|
||||
} else {
|
||||
struct selector sel;
|
||||
struct pw_manager_object *o;
|
||||
|
||||
spa_zero(sel);
|
||||
sel.id = id;
|
||||
if (command == COMMAND_SET_SINK_INPUT_VOLUME)
|
||||
sel.type = is_sink_input;
|
||||
else
|
||||
sel.type = is_source_output;
|
||||
|
||||
o = select_object(client->manager, &sel);
|
||||
if (o == NULL)
|
||||
goto error_noentity;
|
||||
|
||||
if (!SPA_FLAG_IS_SET(o->permissions, PW_PERM_W | PW_PERM_X))
|
||||
goto error_access;
|
||||
|
||||
set_node_volume(o, &volume);
|
||||
}
|
||||
return reply_simple_ack(client, tag);
|
||||
|
||||
error_access:
|
||||
res = ERR_ACCESS;
|
||||
goto error;
|
||||
error_noentity:
|
||||
res = ERR_NOENTITY;
|
||||
goto error;
|
||||
error_protocol:
|
||||
res = ERR_PROTOCOL;
|
||||
goto error;
|
||||
error:
|
||||
return reply_error(client, -1, res);
|
||||
}
|
||||
|
||||
static int do_set_stream_mute(struct client *client, uint32_t command, uint32_t tag, struct message *m)
|
||||
{
|
||||
struct impl *impl = client->impl;
|
||||
uint32_t channel;
|
||||
uint32_t id;
|
||||
struct stream *stream;
|
||||
int res;
|
||||
bool mute;
|
||||
float val;
|
||||
|
||||
if ((res = message_get(m,
|
||||
TAG_U32, &channel,
|
||||
TAG_U32, &id,
|
||||
TAG_BOOLEAN, &mute,
|
||||
TAG_INVALID)) < 0)
|
||||
return res;
|
||||
goto error_protocol;
|
||||
|
||||
pw_log_info(NAME" %p: DO_SET_STREAM_MUTE channel:%u mute:%u",
|
||||
impl, channel, mute);
|
||||
pw_log_info(NAME" %p: DO_SET_STREAM_MUTE id:%u mute:%u",
|
||||
impl, id, mute);
|
||||
|
||||
stream = pw_map_lookup(&client->streams, channel);
|
||||
if (stream == NULL)
|
||||
return -EINVAL;
|
||||
stream = find_stream(client, id);
|
||||
if (stream != NULL) {
|
||||
float val;
|
||||
|
||||
stream->muted = mute;
|
||||
stream->muted_set = true;
|
||||
stream->muted = mute;
|
||||
stream->muted_set = true;
|
||||
|
||||
val = mute ? 1.0f : 0.0f;
|
||||
pw_stream_set_control(stream->stream,
|
||||
SPA_PROP_mute, 1, &val,
|
||||
0);
|
||||
val = mute ? 1.0f : 0.0f;
|
||||
|
||||
pw_stream_set_control(stream->stream,
|
||||
SPA_PROP_mute, 1, &val,
|
||||
0);
|
||||
} else {
|
||||
struct selector sel;
|
||||
struct pw_manager_object *o;
|
||||
|
||||
spa_zero(sel);
|
||||
sel.id = id;
|
||||
if (command == COMMAND_SET_SINK_INPUT_VOLUME)
|
||||
sel.type = is_sink_input;
|
||||
else
|
||||
sel.type = is_source_output;
|
||||
|
||||
o = select_object(client->manager, &sel);
|
||||
if (o == NULL)
|
||||
goto error_noentity;
|
||||
|
||||
if (!SPA_FLAG_IS_SET(o->permissions, PW_PERM_W | PW_PERM_X))
|
||||
goto error_access;
|
||||
|
||||
set_node_mute(o, mute);
|
||||
}
|
||||
return reply_simple_ack(client, tag);
|
||||
|
||||
error_access:
|
||||
res = ERR_ACCESS;
|
||||
goto error;
|
||||
error_noentity:
|
||||
res = ERR_NOENTITY;
|
||||
goto error;
|
||||
error_protocol:
|
||||
res = ERR_PROTOCOL;
|
||||
goto error;
|
||||
error:
|
||||
return reply_error(client, -1, res);
|
||||
}
|
||||
|
||||
static int do_set_stream_name(struct client *client, uint32_t command, uint32_t tag, struct message *m)
|
||||
|
|
@ -2058,6 +2273,46 @@ exit:
|
|||
return res;
|
||||
}
|
||||
|
||||
static void select_best(struct selector *s, struct pw_manager_object *o)
|
||||
{
|
||||
const char *str;
|
||||
int32_t prio = 0;
|
||||
|
||||
if (o->props &&
|
||||
(str = pw_properties_get(o->props, PW_KEY_PRIORITY_DRIVER)) != NULL) {
|
||||
prio = pw_properties_parse_int(str);
|
||||
if (prio > s->score) {
|
||||
s->best = o;
|
||||
s->score = prio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *get_default(struct client *client, bool sink)
|
||||
{
|
||||
struct selector sel;
|
||||
struct pw_manager_object *o;
|
||||
const char *def, *str;
|
||||
|
||||
spa_zero(sel);
|
||||
if (sink) {
|
||||
sel.type = is_sink;
|
||||
sel.id = client->default_sink;
|
||||
def = "@DEFAULT_SINK@";
|
||||
} else {
|
||||
sel.type = is_source;
|
||||
sel.id = client->default_source;
|
||||
def = "@DEFAULT_SOURCE@";
|
||||
}
|
||||
sel.accumulate = select_best;
|
||||
|
||||
o = select_object(client->manager, &sel);
|
||||
if (o == NULL || o->props == NULL ||
|
||||
((str = pw_properties_get(o->props, PW_KEY_NODE_NAME)) == NULL))
|
||||
return def;
|
||||
return str;
|
||||
}
|
||||
|
||||
static int do_get_server_info(struct client *client, uint32_t command, uint32_t tag, struct message *m)
|
||||
{
|
||||
struct impl *impl = client->impl;
|
||||
|
|
@ -2072,7 +2327,7 @@ static int do_get_server_info(struct client *client, uint32_t command, uint32_t
|
|||
|
||||
spa_zero(ss);
|
||||
ss.format = SAMPLE_FLOAT32LE;
|
||||
ss.rate = 44100;
|
||||
ss.rate = client->default_rate ? client->default_rate : 44100;
|
||||
ss.channels = 2;
|
||||
|
||||
spa_zero(map);
|
||||
|
|
@ -2087,9 +2342,9 @@ static int do_get_server_info(struct client *client, uint32_t command, uint32_t
|
|||
TAG_STRING, pw_get_user_name(),
|
||||
TAG_STRING, pw_get_host_name(),
|
||||
TAG_SAMPLE_SPEC, &ss,
|
||||
TAG_STRING, NULL, /* default sink name */
|
||||
TAG_STRING, NULL /* default source name */,
|
||||
TAG_U32, 0,
|
||||
TAG_STRING, get_default(client, true), /* default sink name */
|
||||
TAG_STRING, get_default(client, false), /* default source name */
|
||||
TAG_U32, client->cookie, /* cookie */
|
||||
TAG_INVALID);
|
||||
|
||||
if (client->version >= 15) {
|
||||
|
|
@ -2122,25 +2377,40 @@ static int do_stat(struct client *client, uint32_t command, uint32_t tag, struct
|
|||
static int do_lookup(struct client *client, uint32_t command, uint32_t tag, struct message *m)
|
||||
{
|
||||
struct impl *impl = client->impl;
|
||||
const char *name = NULL;
|
||||
struct message *reply;
|
||||
struct pw_manager_object *o;
|
||||
struct selector sel;
|
||||
int res;
|
||||
|
||||
spa_zero(sel);
|
||||
sel.key = PW_KEY_NODE_NAME;
|
||||
|
||||
if ((res = message_get(m,
|
||||
TAG_STRING, &name,
|
||||
TAG_STRING, &sel.value,
|
||||
TAG_INVALID)) < 0)
|
||||
return res;
|
||||
if (name == NULL)
|
||||
if (sel.value == NULL)
|
||||
goto error_invalid;
|
||||
|
||||
pw_log_info(NAME" %p: LOOKUP %s", impl, name);
|
||||
if ((o = find_node_by_name(impl, name)) == NULL)
|
||||
pw_log_info(NAME" %p: LOOKUP %s", impl, sel.value);
|
||||
|
||||
if (command == COMMAND_LOOKUP_SINK) {
|
||||
if (strcmp(sel.value, "@DEFAULT_SINK@"))
|
||||
sel.value = get_default(client, true);
|
||||
sel.type = is_sink;
|
||||
}
|
||||
else {
|
||||
if (strcmp(sel.value, "@DEFAULT_SOURCE@"))
|
||||
sel.value = get_default(client, false);
|
||||
sel.type = is_source;
|
||||
}
|
||||
|
||||
if ((o = select_object(client->manager, &sel)) == NULL)
|
||||
goto error_noentity;
|
||||
|
||||
reply = reply_new(client, tag);
|
||||
message_put(reply,
|
||||
TAG_U32, SPA_ID_INVALID,
|
||||
TAG_U32, o->id,
|
||||
TAG_INVALID);
|
||||
|
||||
return send_message(client, reply);
|
||||
|
|
@ -2184,8 +2454,7 @@ static int fill_client_info(struct client *client, struct message *m,
|
|||
{
|
||||
struct pw_client_info *info = o->info;
|
||||
|
||||
if (o == NULL ||
|
||||
strcmp(o->type, PW_TYPE_INTERFACE_Client) != 0)
|
||||
if (o == NULL || !is_client(o))
|
||||
return ERR_NOENTITY;
|
||||
|
||||
message_put(m,
|
||||
|
|
@ -2207,14 +2476,13 @@ static int fill_module_info(struct client *client, struct message *m,
|
|||
{
|
||||
struct pw_module_info *info = o->info;
|
||||
|
||||
if (o == NULL ||
|
||||
strcmp(o->type, PW_TYPE_INTERFACE_Module) != 0)
|
||||
if (o == NULL || info == NULL || !is_module(o))
|
||||
return ERR_NOENTITY;
|
||||
|
||||
message_put(m,
|
||||
TAG_U32, o->id, /* module index */
|
||||
TAG_STRING, info ? info->name : NULL,
|
||||
TAG_STRING, info ? info->args : NULL,
|
||||
TAG_STRING, info->name,
|
||||
TAG_STRING, info->args,
|
||||
TAG_U32, -1, /* n_used */
|
||||
TAG_INVALID);
|
||||
|
||||
|
|
@ -2225,7 +2493,7 @@ static int fill_module_info(struct client *client, struct message *m,
|
|||
}
|
||||
if (client->version >= 15) {
|
||||
message_put(m,
|
||||
TAG_PROPLIST, info ? info->props : NULL,
|
||||
TAG_PROPLIST, info->props,
|
||||
TAG_INVALID);
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -2238,11 +2506,7 @@ static int fill_card_info(struct client *client, struct message *m,
|
|||
const char *str;
|
||||
uint32_t module_id = SPA_ID_INVALID;
|
||||
|
||||
if (o == NULL ||
|
||||
strcmp(o->type, PW_TYPE_INTERFACE_Device) != 0 ||
|
||||
o->props == NULL || info == NULL || info->props == NULL ||
|
||||
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) == NULL ||
|
||||
strcmp(str, "Audio/Device") != 0)
|
||||
if (o == NULL || info == NULL || info->props == NULL || !is_card(o))
|
||||
return ERR_NOENTITY;
|
||||
|
||||
if ((str = spa_dict_lookup(info->props, PW_KEY_MODULE_ID)) != NULL)
|
||||
|
|
@ -2318,16 +2582,11 @@ static int fill_sink_info(struct client *client, struct message *m,
|
|||
struct pw_manager_object *o)
|
||||
{
|
||||
struct pw_node_info *info = o->info;
|
||||
const char *str;
|
||||
struct sample_spec ss;
|
||||
struct volume volume;
|
||||
struct channel_map map;
|
||||
|
||||
if (o == NULL ||
|
||||
strcmp(o->type, PW_TYPE_INTERFACE_Node) != 0 ||
|
||||
o->props == NULL || info == NULL || info->props == NULL ||
|
||||
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) == NULL ||
|
||||
strcmp(str, "Audio/Sink") != 0)
|
||||
if (o == NULL || info == NULL || info->props == NULL || !is_sink(o))
|
||||
return ERR_NOENTITY;
|
||||
|
||||
ss = (struct sample_spec) {
|
||||
|
|
@ -2397,21 +2656,14 @@ static int fill_source_info(struct client *client, struct message *m,
|
|||
struct pw_manager_object *o)
|
||||
{
|
||||
struct pw_node_info *info = o->info;
|
||||
const char *str;
|
||||
struct sample_spec ss;
|
||||
struct volume volume;
|
||||
struct channel_map map;
|
||||
bool is_monitor;
|
||||
|
||||
if (o == NULL ||
|
||||
strcmp(o->type, PW_TYPE_INTERFACE_Node) != 0 ||
|
||||
o->props == NULL || info == NULL || info->props == NULL ||
|
||||
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) == NULL)
|
||||
return ERR_NOENTITY;
|
||||
|
||||
is_monitor = strcmp(str, "Audio/Sink") == 0;
|
||||
if (strcmp(str, "Audio/Source") != 0 &&
|
||||
!is_monitor)
|
||||
is_monitor = is_sink(o);
|
||||
if (o == NULL || info == NULL || info->props == NULL ||
|
||||
(!is_source(o) && !is_monitor))
|
||||
return ERR_NOENTITY;
|
||||
|
||||
ss = (struct sample_spec) {
|
||||
|
|
@ -2481,16 +2733,11 @@ static int fill_sink_input_info(struct client *client, struct message *m,
|
|||
struct pw_manager_object *o)
|
||||
{
|
||||
struct pw_node_info *info = o->info;
|
||||
const char *str;
|
||||
struct sample_spec ss;
|
||||
struct volume volume;
|
||||
struct channel_map map;
|
||||
|
||||
if (o == NULL ||
|
||||
strcmp(o->type, PW_TYPE_INTERFACE_Node) != 0 ||
|
||||
o->props == NULL || info == NULL || info->props == NULL ||
|
||||
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) == NULL ||
|
||||
strcmp(str, "Stream/Output/Audio") != 0)
|
||||
if (o == NULL || info == NULL || info->props == NULL || !is_sink_input(o))
|
||||
return ERR_NOENTITY;
|
||||
|
||||
ss = (struct sample_spec) {
|
||||
|
|
@ -2552,16 +2799,11 @@ static int fill_source_output_info(struct client *client, struct message *m,
|
|||
struct pw_manager_object *o)
|
||||
{
|
||||
struct pw_node_info *info = o->info;
|
||||
const char *str;
|
||||
struct sample_spec ss;
|
||||
struct volume volume;
|
||||
struct channel_map map;
|
||||
|
||||
if (o == NULL ||
|
||||
strcmp(o->type, PW_TYPE_INTERFACE_Node) != 0 ||
|
||||
o->props == NULL || info == NULL || info->props == NULL ||
|
||||
(str = pw_properties_get(o->props, PW_KEY_MEDIA_CLASS)) == NULL ||
|
||||
strcmp(str, "Stream/Input/Audio") != 0)
|
||||
if (o == NULL || info == NULL || info->props == NULL || !is_source_output(o))
|
||||
return ERR_NOENTITY;
|
||||
|
||||
ss = (struct sample_spec) {
|
||||
|
|
@ -2617,71 +2859,79 @@ static int do_get_info(struct client *client, uint32_t command, uint32_t tag, st
|
|||
{
|
||||
struct impl *impl = client->impl;
|
||||
struct message *reply = NULL;
|
||||
uint32_t idx;
|
||||
const char *name = NULL;
|
||||
int res, err;
|
||||
struct pw_manager_object *o;
|
||||
struct selector sel;
|
||||
int (*fill_func) (struct client *client, struct message *m, struct pw_manager_object *o) = NULL;
|
||||
|
||||
spa_zero(sel);
|
||||
|
||||
if ((res = message_get(m,
|
||||
TAG_U32, &idx,
|
||||
TAG_U32, &sel.id,
|
||||
TAG_INVALID)) < 0)
|
||||
goto error_protocol;
|
||||
|
||||
switch (command) {
|
||||
case COMMAND_GET_SINK_INFO:
|
||||
case COMMAND_GET_SOURCE_INFO:
|
||||
case COMMAND_GET_CLIENT_INFO:
|
||||
sel.type = is_client;
|
||||
fill_func = fill_client_info;
|
||||
break;
|
||||
case COMMAND_GET_MODULE_INFO:
|
||||
sel.type = is_module;
|
||||
fill_func = fill_module_info;
|
||||
break;
|
||||
case COMMAND_GET_CARD_INFO:
|
||||
sel.type = is_card;
|
||||
sel.key = PW_KEY_DEVICE_NAME;
|
||||
fill_func = fill_card_info;
|
||||
break;
|
||||
case COMMAND_GET_SAMPLE_INFO:
|
||||
if ((res = message_get(m,
|
||||
TAG_STRING, &name,
|
||||
TAG_INVALID)) < 0)
|
||||
goto error_protocol;
|
||||
sel.key = "";
|
||||
break;
|
||||
case COMMAND_GET_SINK_INFO:
|
||||
sel.type = is_sink;
|
||||
sel.key = PW_KEY_NODE_NAME;
|
||||
fill_func = fill_sink_info;
|
||||
break;
|
||||
case COMMAND_GET_SOURCE_INFO:
|
||||
sel.type = is_source;
|
||||
sel.key = PW_KEY_NODE_NAME;
|
||||
fill_func = fill_source_info;
|
||||
break;
|
||||
case COMMAND_GET_SINK_INPUT_INFO:
|
||||
sel.type = is_sink_input;
|
||||
fill_func = fill_sink_input_info;
|
||||
break;
|
||||
case COMMAND_GET_SOURCE_OUTPUT_INFO:
|
||||
sel.type = is_source_output;
|
||||
fill_func = fill_source_output_info;
|
||||
break;
|
||||
}
|
||||
if (sel.key) {
|
||||
if ((res = message_get(m,
|
||||
TAG_STRING, &sel.value,
|
||||
TAG_INVALID)) < 0)
|
||||
goto error_protocol;
|
||||
}
|
||||
|
||||
if ((idx == SPA_ID_INVALID && name == NULL) ||
|
||||
(idx != SPA_ID_INVALID && name != NULL))
|
||||
if ((sel.id == SPA_ID_INVALID && sel.value == NULL) ||
|
||||
(sel.id != SPA_ID_INVALID && sel.value != NULL))
|
||||
goto error_invalid;
|
||||
|
||||
pw_log_info(NAME" %p: %s idx:%u name:%s", impl,
|
||||
commands[command].name, idx, name);
|
||||
commands[command].name, sel.id, sel.value);
|
||||
|
||||
o = pw_manager_find_object(client->manager, idx);
|
||||
o = select_object(client->manager, &sel);
|
||||
if (o == NULL)
|
||||
goto error_noentity;
|
||||
|
||||
reply = reply_new(client, tag);
|
||||
switch (command) {
|
||||
case COMMAND_GET_CLIENT_INFO:
|
||||
err = fill_client_info(client, reply, o);
|
||||
break;
|
||||
|
||||
case COMMAND_GET_MODULE_INFO:
|
||||
err = fill_module_info(client, reply, o);
|
||||
break;
|
||||
if (fill_func)
|
||||
err = fill_func(client, reply, o);
|
||||
else
|
||||
err = ERR_PROTOCOL;
|
||||
|
||||
case COMMAND_GET_CARD_INFO:
|
||||
err = fill_card_info(client, reply, o);
|
||||
break;
|
||||
|
||||
case COMMAND_GET_SAMPLE_INFO:
|
||||
err = ERR_NOENTITY;
|
||||
break;
|
||||
|
||||
case COMMAND_GET_SINK_INFO:
|
||||
err = fill_sink_info(client, reply, o);
|
||||
break;
|
||||
|
||||
case COMMAND_GET_SOURCE_INFO:
|
||||
err = fill_source_info(client, reply, o);
|
||||
break;
|
||||
case COMMAND_GET_SINK_INPUT_INFO:
|
||||
err = fill_sink_input_info(client, reply, o);
|
||||
break;
|
||||
case COMMAND_GET_SOURCE_OUTPUT_INFO:
|
||||
err = fill_source_output_info(client, reply, o);
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if (err != 0)
|
||||
goto error;
|
||||
|
||||
|
|
@ -2690,6 +2940,9 @@ static int do_get_info(struct client *client, uint32_t command, uint32_t tag, st
|
|||
error_protocol:
|
||||
err = ERR_PROTOCOL;
|
||||
goto error;
|
||||
error_noentity:
|
||||
err = ERR_NOENTITY;
|
||||
goto error;
|
||||
error_invalid:
|
||||
err = ERR_INVALID;
|
||||
goto error;
|
||||
|
|
@ -2719,6 +2972,7 @@ static int do_get_info_list(struct client *client, uint32_t command, uint32_t ta
|
|||
|
||||
pw_log_info(NAME" %p: %s", impl, commands[command].name);
|
||||
|
||||
spa_zero(info);
|
||||
info.client = client;
|
||||
info.reply = reply_new(client, tag);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue