summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Taymans <wtaymans@redhat.com>2019-11-14 18:35:29 +0100
committerWim Taymans <wtaymans@redhat.com>2019-11-29 13:34:07 +0100
commit161cf46898a3068bc77ca8d9b743d7218dbc1d39 (patch)
tree2ab734464ffeec30155f97f10ba874b5e43273e6
parent3f3dfbc67e2dc41569365321f5d81a9c4ae8d37d (diff)
media-session: add media session helpers
Move all the media-session object monitoring into one place and provide an API to get to the session objects. Make API to add module specific info to objects. Add methods to export and create objects in the session. This should make it possible to link proxy to implementation and avoid a server roundtrip in some cases.
-rw-r--r--src/examples/media-session/alsa-endpoint.c12
-rw-r--r--src/examples/media-session/alsa-monitor.c21
-rw-r--r--src/examples/media-session/bluez-monitor.c11
-rw-r--r--src/examples/media-session/media-session.c701
-rw-r--r--src/examples/media-session/media-session.h173
-rw-r--r--src/examples/media-session/monitor.c132
-rw-r--r--src/examples/media-session/policy-ep.c704
-rw-r--r--src/examples/media-session/stream-monitor.c432
-rw-r--r--src/examples/media-session/v4l2-monitor.c8
9 files changed, 1140 insertions, 1054 deletions
diff --git a/src/examples/media-session/alsa-endpoint.c b/src/examples/media-session/alsa-endpoint.c
index a6dcaaee..94f37aad 100644
--- a/src/examples/media-session/alsa-endpoint.c
+++ b/src/examples/media-session/alsa-endpoint.c
@@ -114,6 +114,8 @@ static int client_endpoint_create_link(void *object, const struct spa_dict *prop
struct spa_pod_builder b = { 0, };
struct spa_pod *param;
+ pw_log_debug(NAME" %p: endpoint %p", impl, endpoint);
+
p = pw_properties_new_dict(props);
if (endpoint->info.direction == PW_DIRECTION_OUTPUT) {
@@ -145,7 +147,7 @@ static int client_endpoint_create_link(void *object, const struct spa_dict *prop
endpoint->active = true;
}
- pw_core_proxy_create_object(impl->core_proxy,
+ sm_media_session_create_object(impl->session,
"link-factory",
PW_TYPE_INTERFACE_Link,
PW_VERSION_LINK_PROXY,
@@ -234,7 +236,7 @@ static struct endpoint *make_endpoint(struct alsa_node *obj)
pw_properties_set(props, PW_KEY_ENDPOINT_ICON_NAME, str);
}
- proxy = pw_core_proxy_create_object(impl->core_proxy,
+ proxy = sm_media_session_create_object(impl->session,
"client-endpoint",
PW_TYPE_INTERFACE_ClientEndpoint,
PW_VERSION_CLIENT_ENDPOINT_PROXY,
@@ -251,14 +253,14 @@ static struct endpoint *make_endpoint(struct alsa_node *obj)
endpoint->info.version = PW_VERSION_ENDPOINT_INFO;
endpoint->info.name = (char*)pw_properties_get(endpoint->props, PW_KEY_ENDPOINT_NAME);
endpoint->info.media_class = (char*)pw_properties_get(obj->props, PW_KEY_MEDIA_CLASS);
- endpoint->info.session_id = impl->client_session_info.id;
+ endpoint->info.session_id = impl->session->info.id;
endpoint->info.direction = obj->direction;
endpoint->info.flags = 0;
endpoint->info.change_mask =
PW_ENDPOINT_CHANGE_MASK_STREAMS |
PW_ENDPOINT_CHANGE_MASK_SESSION |
PW_ENDPOINT_CHANGE_MASK_PROPS;
- endpoint->info.n_streams = 1;
+ endpoint->info.n_streams = 0;
endpoint->info.props = &endpoint->props->dict;
spa_list_init(&endpoint->stream_list);
@@ -295,6 +297,7 @@ static int setup_alsa_fallback_endpoint(struct alsa_object *obj)
return -errno;
spa_list_append(&endpoint->stream_list, &s->link);
+ endpoint->info.n_streams++;
s->props = pw_properties_new(NULL, NULL);
if ((str = pw_properties_get(n->props, PW_KEY_MEDIA_CLASS)) != NULL)
@@ -372,7 +375,6 @@ close_exit:
exit:
free(name_free);
return res;
-
}
static int setup_alsa_endpoint(struct alsa_object *obj)
diff --git a/src/examples/media-session/alsa-monitor.c b/src/examples/media-session/alsa-monitor.c
index 6d9b80f2..3362359a 100644
--- a/src/examples/media-session/alsa-monitor.c
+++ b/src/examples/media-session/alsa-monitor.c
@@ -219,7 +219,7 @@ static struct alsa_node *alsa_create_node(struct alsa_object *obj, uint32_t id,
node->monitor = monitor;
node->object = obj;
node->id = id;
- node->proxy = pw_core_proxy_create_object(impl->core_proxy,
+ node->proxy = sm_media_session_create_object(impl->session,
"adapter",
PW_TYPE_INTERFACE_Node,
PW_VERSION_NODE_PROXY,
@@ -418,7 +418,7 @@ static void set_profile(struct alsa_object *obj, int index)
static void remove_jack_timeout(struct impl *impl)
{
- struct pw_loop *main_loop = pw_core_get_main_loop(impl->core);
+ struct pw_loop *main_loop = impl->session->loop->loop;
if (impl->jack_timeout) {
pw_loop_destroy_source(main_loop, impl->jack_timeout);
@@ -436,7 +436,7 @@ static void jack_timeout(void *data, uint64_t expirations)
static void add_jack_timeout(struct impl *impl)
{
struct timespec value;
- struct pw_loop *main_loop = pw_core_get_main_loop(impl->core);
+ struct pw_loop *main_loop = impl->session->loop->loop;
if (impl->jack_timeout == NULL)
impl->jack_timeout = pw_loop_add_timer(main_loop, jack_timeout, impl);
@@ -467,6 +467,7 @@ static void sync_complete_done(void *data, int seq)
struct monitor *monitor = obj->monitor;
struct impl *impl = monitor->impl;
+ pw_log_debug("%d %d", obj->seq, seq);
if (seq != obj->seq)
return;
@@ -510,7 +511,7 @@ static struct alsa_object *alsa_create_object(struct monitor *monitor, uint32_t
const struct spa_device_object_info *info)
{
struct impl *impl = monitor->impl;
- struct pw_core *core = impl->core;
+ struct pw_core *core = impl->session->core;
struct alsa_object *obj;
struct spa_handle *handle;
int res;
@@ -552,8 +553,10 @@ static struct alsa_object *alsa_create_object(struct monitor *monitor, uint32_t
obj->priority = 1000;
update_device_props(obj);
- obj->proxy = pw_remote_export(impl->remote,
- info->type, pw_properties_copy(obj->props), obj->device, 0);
+ obj->proxy = sm_media_session_export(impl->session,
+ info->type,
+ pw_properties_copy(obj->props),
+ obj->device, 0);
if (obj->proxy == NULL) {
res = -errno;
goto clean_object;
@@ -651,7 +654,7 @@ static int alsa_start_midi_bridge(struct impl *impl)
SPA_KEY_NODE_NAME, "Midi-Bridge",
NULL);
- impl->midi_bridge = pw_core_proxy_create_object(impl->core_proxy,
+ impl->midi_bridge = sm_media_session_create_object(impl->session,
"spa-node-factory",
PW_TYPE_INTERFACE_Node,
PW_VERSION_NODE_PROXY,
@@ -667,7 +670,7 @@ static int alsa_start_midi_bridge(struct impl *impl)
static int alsa_start_monitor(struct impl *impl, struct monitor *monitor)
{
struct spa_handle *handle;
- struct pw_core *core = impl->core;
+ struct pw_core *core = impl->session->core;
int res;
void *iface;
@@ -707,7 +710,7 @@ static int alsa_start_jack_device(struct impl *impl)
SPA_KEY_NODE_NAME, "JACK-Device",
NULL);
- impl->jack_device = pw_core_proxy_create_object(impl->core_proxy,
+ impl->jack_device = sm_media_session_create_object(impl->session,
"spa-device-factory",
PW_TYPE_INTERFACE_Device,
PW_VERSION_DEVICE_PROXY,
diff --git a/src/examples/media-session/bluez-monitor.c b/src/examples/media-session/bluez-monitor.c
index c755d1a4..50ffbc94 100644
--- a/src/examples/media-session/bluez-monitor.c
+++ b/src/examples/media-session/bluez-monitor.c
@@ -95,6 +95,7 @@ static struct bluez5_node *bluez5_create_node(struct bluez5_object *obj, uint32_
struct bluez5_node *node;
struct monitor *monitor = obj->monitor;
struct impl *impl = monitor->impl;
+ struct pw_core *core = impl->session->core;
struct pw_factory *factory;
int res;
const char *str;
@@ -131,7 +132,7 @@ static struct bluez5_node *bluez5_create_node(struct bluez5_object *obj, uint32_
node->object = obj;
node->id = id;
- factory = pw_core_find_factory(impl->core, "adapter");
+ factory = pw_core_find_factory(core, "adapter");
if (factory == NULL) {
pw_log_error("no adapter factory found");
res = -EIO;
@@ -147,7 +148,7 @@ static struct bluez5_node *bluez5_create_node(struct bluez5_object *obj, uint32_
res = -errno;
goto clean_node;
}
- node->proxy = pw_remote_export(impl->remote,
+ node->proxy = sm_media_session_export(impl->session,
PW_TYPE_INTERFACE_Node,
pw_properties_copy(node->props),
node->adapter, 0);
@@ -226,7 +227,7 @@ static struct bluez5_object *bluez5_create_object(struct monitor *monitor, uint3
const struct spa_device_object_info *info)
{
struct impl *impl = monitor->impl;
- struct pw_core *core = impl->core;
+ struct pw_core *core = impl->session->core;
struct bluez5_object *obj;
struct spa_handle *handle;
int res;
@@ -264,7 +265,7 @@ static struct bluez5_object *bluez5_create_object(struct monitor *monitor, uint3
obj->handle = handle;
obj->device = iface;
obj->props = pw_properties_new_dict(info->props);
- obj->proxy = pw_remote_export(impl->remote,
+ obj->proxy = sm_media_session_export(impl->session,
info->type, pw_properties_copy(obj->props), obj->device, 0);
if (obj->proxy == NULL) {
res = -errno;
@@ -336,7 +337,7 @@ static const struct spa_device_events bluez5_enum_callbacks =
static int bluez5_start_monitor(struct impl *impl, struct monitor *monitor)
{
struct spa_handle *handle;
- struct pw_core *core = impl->core;
+ struct pw_core *core = impl->session->core;
int res;
void *iface;
diff --git a/src/examples/media-session/media-session.c b/src/examples/media-session/media-session.c
index 5b7893bb..b26f90ee 100644
--- a/src/examples/media-session/media-session.c
+++ b/src/examples/media-session/media-session.c
@@ -43,40 +43,684 @@
#include <dbus/dbus.h>
+#include "media-session.h"
+
#define NAME "media-session"
-int sm_monitor_start(struct pw_remote *remote);
-int sm_policy_start(struct pw_remote *remote);
-int sm_policy_ep_start(struct pw_remote *remote);
+#define sm_media_session_emit(s,m,v,...) spa_hook_list_call(&s->hooks, struct sm_media_session_events, m, v, ##__VA_ARGS__)
+
+#define sm_media_session_emit_update(s,obj) sm_media_session_emit(s, update, 0, obj)
+#define sm_media_session_emit_remove(s,obj) sm_media_session_emit(s, remove, 0, obj)
+#define sm_media_session_emit_rescan(s,seq) sm_media_session_emit(s, rescan, 0, seq)
+
+int sm_monitor_start(struct sm_media_session *sess);
+int sm_policy_ep_start(struct sm_media_session *sess);
+
+/** user data to add to an object */
+struct data {
+ struct spa_list link;
+ const char *id;
+ size_t size;
+};
struct impl {
- struct pw_main_loop *loop;
- struct pw_core *core;
+ struct sm_media_session this;
struct pw_remote *monitor_remote;
struct spa_hook monitor_listener;
struct pw_remote *policy_remote;
struct spa_hook policy_listener;
+
+ struct pw_core_proxy *core_proxy;
+ struct spa_hook core_listener;
+
+ struct pw_registry_proxy *registry_proxy;
+ struct spa_hook registry_listener;
+
+ struct pw_map globals;
+ struct spa_hook_list hooks;
+
+ struct pw_client_session_proxy *client_session;
+ struct spa_hook client_session_listener;
+
+ int seq;
+};
+
+static void add_object(struct impl *impl, struct sm_object *obj)
+{
+ size_t size = pw_map_get_size(&impl->globals);
+ while (obj->id > size)
+ pw_map_insert_at(&impl->globals, size++, NULL);
+ pw_map_insert_at(&impl->globals, obj->id, obj);
+}
+
+static void remove_object(struct impl *impl, struct sm_object *obj)
+{
+ pw_map_insert_at(&impl->globals, obj->id, NULL);
+}
+
+static void *find_object(struct impl *impl, uint32_t id)
+{
+ void *obj;
+ if ((obj = pw_map_lookup(&impl->globals, id)) != NULL)
+ return obj;
+ return NULL;
+}
+
+static struct data *object_find_data(struct sm_object *obj, const char *id)
+{
+ struct data *d;
+ spa_list_for_each(d, &obj->data, link) {
+ if (strcmp(d->id, id) == 0)
+ return d;
+ }
+ return NULL;
+}
+
+void *sm_object_add_data(struct sm_object *obj, const char *id, size_t size)
+{
+ struct data *d;
+
+ d = object_find_data(obj, id);
+ if (d != NULL) {
+ if (d->size == size)
+ goto done;
+ spa_list_remove(&d->link);
+ free(d);
+ }
+ d = calloc(1, sizeof(struct data) + size);
+ d->id = id;
+ d->size = size;
+
+ spa_list_append(&obj->data, &d->link);
+done:
+ return SPA_MEMBER(d, sizeof(struct data), void);
+}
+
+void *sm_object_get_data(struct sm_object *obj, const char *id)
+{
+ struct data *d;
+ d = object_find_data(obj, id);
+ if (d == NULL)
+ return NULL;
+ return SPA_MEMBER(d, sizeof(struct data), void);
+}
+
+int sm_object_remove_data(struct sm_object *obj, const char *id)
+{
+ struct data *d;
+ d = object_find_data(obj, id);
+ if (d == NULL)
+ return -ENOENT;
+ spa_list_remove(&d->link);
+ free(d);
+ return 0;
+}
+
+/**
+ * Clients
+ */
+static void client_event_info(void *object, const struct pw_client_info *info)
+{
+ struct sm_client *client = object;
+ struct impl *impl = SPA_CONTAINER_OF(client->obj.session, struct impl, this);
+
+ pw_log_debug(NAME" %p: client %d info", impl, client->obj.id);
+ client->info = pw_client_info_update(client->info, info);
+
+ client->avail |= SM_CLIENT_CHANGE_MASK_INFO;
+ client->changed |= SM_CLIENT_CHANGE_MASK_INFO;
+ sm_media_session_emit_update(impl, &client->obj);
+ client->changed = 0;
+}
+
+static const struct pw_client_proxy_events client_events = {
+ PW_VERSION_CLIENT_PROXY_EVENTS,
+ .info = client_event_info,
+};
+
+static void client_destroy(void *object)
+{
+ struct sm_client *client = object;
+ if (client->info)
+ pw_client_info_free(client->info);
+}
+
+/**
+ * Node
+ */
+static void node_event_info(void *object, const struct pw_node_info *info)
+{
+ struct sm_node *node = object;
+ struct impl *impl = SPA_CONTAINER_OF(node->obj.session, struct impl, this);
+
+ pw_log_debug(NAME" %p: node %d info", impl, node->obj.id);
+ node->info = pw_node_info_update(node->info, info);
+
+ node->avail |= SM_NODE_CHANGE_MASK_INFO;
+ node->changed |= SM_NODE_CHANGE_MASK_INFO;
+ sm_media_session_emit_update(impl, &node->obj);
+ node->changed = 0;
+}
+
+static const struct pw_node_proxy_events node_events = {
+ PW_VERSION_NODE_PROXY_EVENTS,
+ .info = node_event_info,
+};
+
+static void node_destroy(void *object)
+{
+ struct sm_node *node = object;
+ struct sm_port *port;
+
+ spa_list_consume(port, &node->port_list, link) {
+ port->node = NULL;
+ spa_list_remove(&port->link);
+ }
+ if (node->info)
+ pw_node_info_free(node->info);
+}
+
+/**
+ * Port
+ */
+static void port_event_info(void *object, const struct pw_port_info *info)
+{
+ struct sm_port *port = object;
+ struct impl *impl = SPA_CONTAINER_OF(port->obj.session, struct impl, this);
+
+ pw_log_debug(NAME" %p: port %d info", impl, port->obj.id);
+ port->info = pw_port_info_update(port->info, info);
+
+ port->avail |= SM_PORT_CHANGE_MASK_INFO;
+ port->changed |= SM_PORT_CHANGE_MASK_INFO;
+ sm_media_session_emit_update(impl, &port->obj);
+ port->changed = 0;
+}
+
+static const struct pw_port_proxy_events port_events = {
+ PW_VERSION_PORT_PROXY_EVENTS,
+ .info = port_event_info,
+};
+
+static void port_destroy(void *object)
+{
+ struct sm_port *port = object;
+ if (port->info)
+ pw_port_info_free(port->info);
+ if (port->node) {
+ spa_list_remove(&port->link);
+ port->node->changed |= SM_NODE_CHANGE_MASK_PORTS;
+ }
+}
+
+/**
+ * Endpoint
+ */
+static void endpoint_event_info(void *object, const struct pw_endpoint_info *info)
+{
+ struct sm_endpoint *endpoint = object;
+ struct impl *impl = SPA_CONTAINER_OF(endpoint->obj.session, struct impl, this);
+ struct pw_endpoint_info *i = endpoint->info;
+ const char *str;
+
+ pw_log_debug(NAME" %p: endpoint %d info", impl, endpoint->obj.id);
+ if (i == NULL && info) {
+ i = endpoint->info = calloc(1, sizeof(struct pw_endpoint_info));
+ i->id = info->id;
+ i->name = info->name ? strdup(info->name) : NULL;
+ i->media_class = info->media_class ? strdup(info->media_class) : NULL;
+ i->direction = info->direction;
+ i->flags = info->flags;
+ }
+ i->change_mask = info->change_mask;
+ if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_SESSION) {
+ i->session_id = info->session_id;
+ }
+ if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) {
+ if (i->props)
+ pw_properties_free ((struct pw_properties *)i->props);
+ i->props = (struct spa_dict *) pw_properties_new_dict (info->props);
+ if ((str = spa_dict_lookup(i->props, PW_KEY_PRIORITY_SESSION)) != NULL)
+ endpoint->priority = pw_properties_parse_int(str);
+ }
+
+ endpoint->avail |= SM_ENDPOINT_CHANGE_MASK_INFO;
+ endpoint->changed |= SM_ENDPOINT_CHANGE_MASK_INFO;
+ sm_media_session_emit_update(impl, &endpoint->obj);
+ endpoint->changed = 0;
+}
+
+static const struct pw_endpoint_proxy_events endpoint_events = {
+ PW_VERSION_ENDPOINT_PROXY_EVENTS,
+ .info = endpoint_event_info,
+};
+
+static void endpoint_destroy(void *object)
+{
+ struct sm_endpoint *endpoint = object;
+ struct sm_endpoint_stream *stream;
+
+ if (endpoint->info) {
+ free(endpoint->info->name);
+ free(endpoint->info->media_class);
+ free(endpoint->info);
+ }
+
+ spa_list_consume(stream, &endpoint->stream_list, link) {
+ stream->endpoint = NULL;
+ spa_list_remove(&stream->link);
+ }
+}
+
+/**
+ * Endpoint Stream
+ */
+static void endpoint_stream_event_info(void *object, const struct pw_endpoint_stream_info *info)
+{
+ struct sm_endpoint_stream *stream = object;
+ struct impl *impl = SPA_CONTAINER_OF(stream->obj.session, struct impl, this);
+
+ pw_log_debug(NAME" %p: endpoint stream %d info", impl, stream->obj.id);
+ if (stream->info == NULL && info) {
+ stream->info = calloc(1, sizeof(struct pw_endpoint_stream_info));
+ stream->info->version = PW_VERSION_ENDPOINT_STREAM_INFO;
+ stream->info->id = info->id;
+ stream->info->endpoint_id = info->endpoint_id;
+ stream->info->name = info->name ? strdup(info->name) : NULL;
+ }
+ stream->info->change_mask = info->change_mask;
+
+ stream->avail |= SM_ENDPOINT_CHANGE_MASK_INFO;
+ stream->changed |= SM_ENDPOINT_CHANGE_MASK_INFO;
+ sm_media_session_emit_update(impl, &stream->obj);
+ stream->changed = 0;
+}
+
+static const struct pw_endpoint_stream_proxy_events endpoint_stream_events = {
+ PW_VERSION_ENDPOINT_PROXY_EVENTS,
+ .info = endpoint_stream_event_info,
+};
+
+static void endpoint_stream_destroy(void *object)
+{
+ struct sm_endpoint_stream *stream = object;
+
+ if (stream->info) {
+ free(stream->info->name);
+ free(stream->info);
+ }
+ if (stream->endpoint) {
+ stream->endpoint = NULL;
+ spa_list_remove(&stream->link);
+ }
+}
+/**
+ * Proxy
+ */
+static void
+destroy_proxy (void *data)
+{
+ struct sm_object *obj = data;
+ struct impl *impl = SPA_CONTAINER_OF(obj->session, struct impl, this);
+
+ sm_media_session_emit_remove(impl, obj);
+
+ if (obj->destroy)
+ obj->destroy(obj);
+}
+
+static const struct pw_proxy_events proxy_events = {
+ PW_VERSION_PROXY_EVENTS,
+ .destroy = destroy_proxy,
+};
+
+static void
+registry_global(void *data,uint32_t id,
+ uint32_t permissions, uint32_t type, uint32_t version,
+ const struct spa_dict *props)
+{
+ struct impl *impl = data;
+ int res;
+ const void *events;
+ uint32_t client_version;
+ pw_destroy_t destroy;
+ struct sm_object *obj;
+ struct pw_proxy *proxy;
+ size_t user_data_size;
+ const char *str;
+
+ pw_log_debug(NAME " %p: new global '%d' %d", impl, id, type);
+
+ switch (type) {
+ case PW_TYPE_INTERFACE_Client:
+ events = &client_events;
+ client_version = PW_VERSION_CLIENT_PROXY;
+ destroy = (pw_destroy_t) client_destroy;
+ user_data_size = sizeof(struct sm_client);
+ break;
+
+ case PW_TYPE_INTERFACE_Node:
+ events = &node_events;
+ client_version = PW_VERSION_NODE_PROXY;
+ destroy = (pw_destroy_t) node_destroy;
+ user_data_size = sizeof(struct sm_node);
+ break;
+
+ case PW_TYPE_INTERFACE_Port:
+ events = &port_events;
+ client_version = PW_VERSION_PORT_PROXY;
+ destroy = (pw_destroy_t) port_destroy;
+ user_data_size = sizeof(struct sm_port);
+ break;
+
+ case PW_TYPE_INTERFACE_Endpoint:
+ events = &endpoint_events;
+ client_version = PW_VERSION_ENDPOINT_PROXY;
+ destroy = (pw_destroy_t) endpoint_destroy;
+ user_data_size = sizeof(struct sm_endpoint);
+ break;
+
+ case PW_TYPE_INTERFACE_EndpointStream:
+ events = &endpoint_stream_events;
+ client_version = PW_VERSION_ENDPOINT_STREAM_PROXY;
+ destroy = (pw_destroy_t) endpoint_stream_destroy;
+ user_data_size = sizeof(struct sm_endpoint_stream);
+ break;
+
+ default:
+ return;
+ }
+
+ proxy = pw_registry_proxy_bind(impl->registry_proxy,
+ id, type, client_version, user_data_size);
+ if (proxy == NULL) {
+ res = -errno;
+ goto error;
+ }
+
+ obj = pw_proxy_get_user_data(proxy);
+ obj->session = &impl->this;
+ obj->id = id;
+ obj->type = type;
+ obj->props = props ? pw_properties_new_dict(props) : pw_properties_new(NULL, NULL);
+ obj->proxy = proxy;
+ obj->destroy = destroy;
+ obj->mask = SM_OBJECT_CHANGE_MASK_PROPERTIES | SM_OBJECT_CHANGE_MASK_BIND;
+ obj->avail = obj->mask;
+ spa_list_init(&obj->data);
+
+ add_object(impl, obj);
+ pw_proxy_add_listener(proxy, &obj->proxy_listener, &proxy_events, obj);
+
+ switch (type) {
+ case PW_TYPE_INTERFACE_Node:
+ {
+ struct sm_node *node = (struct sm_node*) obj;
+ spa_list_init(&node->port_list);
+ break;
+ }
+ case PW_TYPE_INTERFACE_Port:
+ {
+ struct sm_port *port = (struct sm_port*) obj;
+
+ if (props) {
+ if ((str = spa_dict_lookup(props, PW_KEY_PORT_DIRECTION)) != NULL)
+ port->direction = strcmp(str, "out") ?
+ PW_DIRECTION_OUTPUT : PW_DIRECTION_INPUT;
+ if ((str = spa_dict_lookup(props, PW_KEY_NODE_ID)) != NULL)
+ port->node = find_object(impl, atoi(str));
+
+ pw_log_debug(NAME" %p: port %d parent node %s", impl, id, str);
+ if (port->node) {
+ spa_list_append(&port->node->port_list, &port->link);
+ port->node->changed |= SM_NODE_CHANGE_MASK_PORTS;
+ }
+ }
+ break;
+ }
+ case PW_TYPE_INTERFACE_Endpoint:
+ {
+ struct sm_endpoint *endpoint = (struct sm_endpoint*) obj;
+ spa_list_init(&endpoint->stream_list);
+ break;
+ }
+ case PW_TYPE_INTERFACE_EndpointStream:
+ {
+ struct sm_endpoint_stream *stream = (struct sm_endpoint_stream*) obj;
+
+ if (props) {
+ if ((str = spa_dict_lookup(props, PW_KEY_ENDPOINT_ID)) != NULL)
+ stream->endpoint = find_object(impl, atoi(str));
+ pw_log_debug(NAME" %p: stream %d parent endpoint %s", impl, id, str);
+ if (stream->endpoint) {
+ spa_list_append(&stream->endpoint->stream_list, &stream->link);
+ stream->endpoint->changed |= SM_ENDPOINT_CHANGE_MASK_STREAMS;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ sm_media_session_emit_update(impl, obj);
+
+ pw_proxy_add_object_listener(proxy, &obj->object_listener, events, obj);
+
+ return;
+
+error:
+ pw_log_warn(NAME" %p: can't handle global %d: %s", impl, id, spa_strerror(res));
+}
+
+int sm_media_session_add_listener(struct sm_media_session *sess, struct spa_hook *listener,
+ const struct sm_media_session_events *events, void *data)
+{
+ struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this);
+ spa_hook_list_append(&impl->hooks, listener, events, data);
+ return 0;
+}
+
+struct sm_object *sm_media_session_find_object(struct sm_media_session *sess, uint32_t id)
+{
+ struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this);
+ return find_object(impl, id);
+}
+
+int sm_media_session_schedule_rescan(struct sm_media_session *sess)
+{
+ struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this);
+ if (impl->core_proxy)
+ impl->seq = pw_core_proxy_sync(impl->core_proxy, 0, impl->seq);
+ return impl->seq;
+}
+
+static void
+registry_global_remove(void *data, uint32_t id)
+{
+ struct impl *impl = data;
+ struct sm_object *obj;
+
+ pw_log_debug(NAME " %p: remove global '%d'", impl, id);
+
+ if ((obj = find_object(impl, id)) == NULL)
+ return;
+
+ remove_object(impl, obj);
+}
+
+static const struct pw_registry_proxy_events registry_events = {
+ PW_VERSION_REGISTRY_PROXY_EVENTS,
+ .global = registry_global,
+ .global_remove = registry_global_remove,
+};
+
+struct pw_proxy *sm_media_session_export(struct sm_media_session *sess,
+ uint32_t type, struct pw_properties *properties,
+ void *object, size_t user_data_size)
+{
+ struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this);
+ return pw_remote_export(impl->monitor_remote, type,
+ properties, object, user_data_size);
+}
+
+struct pw_proxy *sm_media_session_create_object(struct sm_media_session *sess,
+ const char *factory_name, uint32_t type, uint32_t version,
+ const struct spa_dict *props, size_t user_data_size)
+{
+ struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this);
+ return pw_core_proxy_create_object(impl->core_proxy,
+ factory_name, type, version, props, user_data_size);
+}
+
+
+/**
+ * Session implementation
+ */
+static int client_session_set_id(void *object, uint32_t id)
+{
+ struct impl *impl = object;
+
+ pw_log_debug("got sesssion id:%d", id);
+ impl->this.info.id = id;
+
+ pw_client_session_proxy_update(impl->client_session,
+ PW_CLIENT_SESSION_UPDATE_INFO,
+ 0, NULL,
+ &impl->this.info);
+
+ return sm_monitor_start(&impl->this);
+}
+
+static int client_session_set_param(void *object, uint32_t id, uint32_t flags,
+ const struct spa_pod *param)
+{
+ struct impl *impl = object;
+ pw_proxy_error((struct pw_proxy*)impl->client_session,
+ -ENOTSUP, "Session:SetParam not supported");
+ return -ENOTSUP;
+}
+
+static int client_session_link_set_param(void *object, uint32_t link_id, uint32_t id, uint32_t flags,
+ const struct spa_pod *param)
+{
+ struct impl *impl = object;
+ pw_proxy_error((struct pw_proxy*)impl->client_session,
+ -ENOTSUP, "Session:LinkSetParam not supported");
+ return -ENOTSUP;
+}
+
+static int client_session_link_request_state(void *object, uint32_t link_id, uint32_t state)
+{
+ return -ENOTSUP;
+}
+
+static const struct pw_client_session_proxy_events client_session_events = {
+ PW_VERSION_CLIENT_SESSION_PROXY_METHODS,
+ .set_id = client_session_set_id,
+ .set_param = client_session_set_param,
+ .link_set_param = client_session_link_set_param,
+ .link_request_state = client_session_link_request_state,
+};
+
+static int start_session(struct impl *impl)
+{
+ impl->client_session = pw_core_proxy_create_object(impl->core_proxy,
+ "client-session",
+ PW_TYPE_INTERFACE_ClientSession,
+ PW_VERSION_CLIENT_SESSION_PROXY,
+ NULL, 0);
+ impl->this.info.version = PW_VERSION_SESSION_INFO;
+
+ pw_client_session_proxy_add_listener(impl->client_session,
+ &impl->client_session_listener,
+ &client_session_events,
+ impl);
+
+ return 0;
+}
+
+static int start_policy(struct impl *impl)
+{
+ return sm_policy_ep_start(&impl->this);
+}
+
+static void core_done(void *data, uint32_t id, int seq)
+{
+ struct impl *impl = data;
+ pw_log_debug(NAME" %p: sync %u %d/%d", impl, id, seq, impl->seq);
+ if (impl->seq == seq)
+ sm_media_session_emit_rescan(impl, seq);
+}
+
+static const struct pw_core_proxy_events core_events = {
+ PW_VERSION_CORE_EVENTS,
+ .done = core_done
+};
+
+static void on_monitor_state_changed(void *_data, enum pw_remote_state old,
+ enum pw_remote_state state, const char *error)
+{
+ struct impl *impl = _data;
+ struct sm_media_session *sess = &impl->this;
+
+ switch (state) {
+ case PW_REMOTE_STATE_ERROR:
+ pw_log_error(NAME" %p: remote error: %s", impl, error);
+ pw_main_loop_quit(sess->loop);
+ break;
+
+ case PW_REMOTE_STATE_CONNECTED:
+ pw_log_info(NAME" %p: connected", impl);
+ impl->core_proxy = pw_remote_get_core_proxy(impl->monitor_remote);
+ pw_core_proxy_add_listener(impl->core_proxy,
+ &impl->core_listener,
+ &core_events, impl);
+ impl->registry_proxy = pw_core_proxy_get_registry(impl->core_proxy,
+ PW_VERSION_REGISTRY_PROXY, 0);
+ pw_registry_proxy_add_listener(impl->registry_proxy,
+ &impl->registry_listener,
+ &registry_events, impl);
+ start_session(impl);
+ break;
+
+ case PW_REMOTE_STATE_UNCONNECTED:
+ pw_log_info(NAME" %p: disconnected", impl);
+ pw_main_loop_quit(sess->loop);
+ break;
+
+ default:
+ printf("remote state: \"%s\"\n", pw_remote_state_as_string(state));
+ break;
+ }
+}
+
+static const struct pw_remote_events monitor_remote_events = {
+ PW_VERSION_REMOTE_EVENTS,
+ .state_changed = on_monitor_state_changed,
};
-static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remote_state state, const char *error)
+static void on_policy_state_changed(void *_data, enum pw_remote_state old,
+ enum pw_remote_state state, const char *error)
{
struct impl *impl = _data;
+ struct sm_media_session *sess = &impl->this;
switch (state) {
case PW_REMOTE_STATE_ERROR:
pw_log_error(NAME" %p: remote error: %s", impl, error);
- pw_main_loop_quit(impl->loop);
+ pw_main_loop_quit(sess->loop);
break;
case PW_REMOTE_STATE_CONNECTED:
pw_log_info(NAME" %p: connected", impl);
+ start_policy(impl);
break;
case PW_REMOTE_STATE_UNCONNECTED:
pw_log_info(NAME" %p: disconnected", impl);
- pw_main_loop_quit(impl->loop);
+ pw_main_loop_quit(sess->loop);
break;
default:
@@ -85,9 +729,9 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo
}
}
-static const struct pw_remote_events remote_events = {
+static const struct pw_remote_events policy_remote_events = {
PW_VERSION_REMOTE_EVENTS,
- .state_changed = on_state_changed,
+ .state_changed = on_policy_state_changed,
};
int main(int argc, char *argv[])
@@ -97,37 +741,36 @@ int main(int argc, char *argv[])
pw_init(&argc, &argv);
- impl.loop = pw_main_loop_new(NULL);
- impl.core = pw_core_new(pw_main_loop_get_loop(impl.loop), NULL, 0);
+ impl.this.loop = pw_main_loop_new(NULL);
+ impl.this.core = pw_core_new(pw_main_loop_get_loop(impl.this.loop), NULL, 0);
- pw_core_add_spa_lib(impl.core, "api.bluez5.*", "bluez5/libspa-bluez5");
- pw_core_add_spa_lib(impl.core, "api.alsa.*", "alsa/libspa-alsa");
- pw_core_add_spa_lib(impl.core, "api.v4l2.*", "v4l2/libspa-v4l2");
+ pw_core_add_spa_lib(impl.this.core, "api.bluez5.*", "bluez5/libspa-bluez5");
+ pw_core_add_spa_lib(impl.this.core, "api.alsa.*", "alsa/libspa-alsa");
+ pw_core_add_spa_lib(impl.this.core, "api.v4l2.*", "v4l2/libspa-v4l2");
- impl.monitor_remote = pw_remote_new(impl.core, NULL, 0);
- pw_remote_add_listener(impl.monitor_remote, &impl.monitor_listener, &remote_events, &impl);
+ impl.monitor_remote = pw_remote_new(impl.this.core, NULL, 0);
+ pw_remote_add_listener(impl.monitor_remote, &impl.monitor_listener, &monitor_remote_events, &impl);
- impl.policy_remote = pw_remote_new(impl.core, NULL, 0);
- pw_remote_add_listener(impl.policy_remote, &impl.policy_listener, &remote_events, &impl);
+ impl.policy_remote = pw_remote_new(impl.this.core, NULL, 0);
+ pw_remote_add_listener(impl.policy_remote, &impl.policy_listener, &policy_remote_events, &impl);
- pw_module_load(impl.core, "libpipewire-module-client-device", NULL, NULL);
- pw_module_load(impl.core, "libpipewire-module-adapter", NULL, NULL);
- pw_module_load(impl.core, "libpipewire-module-metadata", NULL, NULL);
- pw_module_load(impl.core, "libpipewire-module-session-manager", NULL, NULL);
+ pw_module_load(impl.this.core, "libpipewire-module-client-device", NULL, NULL);
+ pw_module_load(impl.this.core, "libpipewire-module-adapter", NULL, NULL);
+ pw_module_load(impl.this.core, "libpipewire-module-metadata", NULL, NULL);
+ pw_module_load(impl.this.core, "libpipewire-module-session-manager", NULL, NULL);
- sm_monitor_start(impl.monitor_remote);
-// sm_policy_start(impl.policy_remote);
- sm_policy_ep_start(impl.policy_remote);
+ pw_map_init(&impl.globals, 64, 64);
+ spa_hook_list_init(&impl.hooks);
if ((res = pw_remote_connect(impl.monitor_remote)) < 0)
return res;
if ((res = pw_remote_connect(impl.policy_remote)) < 0)
return res;
- pw_main_loop_run(impl.loop);
+ pw_main_loop_run(impl.this.loop);
- pw_core_destroy(impl.core);
- pw_main_loop_destroy(impl.loop);
+ pw_core_destroy(impl.this.core);
+ pw_main_loop_destroy(impl.this.loop);
return 0;
}
diff --git a/src/examples/media-session/media-session.h b/src/examples/media-session/media-session.h
new file mode 100644
index 00000000..1001f43a
--- /dev/null
+++ b/src/examples/media-session/media-session.h
@@ -0,0 +1,173 @@
+/* PipeWire
+ *
+ * Copyright © 2019 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 SM_MEDIA_SESSION_H
+#define SM_MEDIA_SESSION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct sm_media_session;
+
+struct sm_object {
+ uint32_t id;
+ uint32_t type;
+
+ struct sm_media_session *session;
+
+#define SM_OBJECT_CHANGE_MASK_PROPERTIES (1<<0)
+#define SM_OBJECT_CHANGE_MASK_BIND (1<<1)
+ uint32_t mask; /**< monitored info */
+ uint32_t avail; /**< available info */
+ struct pw_properties *props; /**< global properties */
+
+ struct pw_proxy *proxy;
+ struct spa_hook proxy_listener;
+ struct spa_hook object_listener;
+ pw_destroy_t destroy;
+
+ struct spa_list data;
+};
+
+/** get user data with \a id and \a size to an object */
+void *sm_object_add_data(struct sm_object *obj, const char *id, size_t size);
+void *sm_object_get_data(struct sm_object *obj, const char *id);
+int sm_object_remove_data(struct sm_object *obj, const char *id);
+
+struct sm_client {
+ struct sm_object obj;
+
+#define SM_CLIENT_CHANGE_MASK_INFO (1<<0)
+#define SM_CLIENT_CHANGE_MASK_PERMISSIONS (1<<1)
+ uint32_t mask; /**< monitored info */
+ uint32_t avail; /**< available info */
+ uint32_t changed; /**< changed since last update */
+ struct pw_client_info *info;
+};
+
+struct sm_node {
+ struct sm_object obj;
+
+#define SM_NODE_CHANGE_MASK_INFO (1<<0)
+#define SM_NODE_CHANGE_MASK_PORTS (1<<1)
+ uint32_t mask; /**< monitored info */
+ uint32_t avail; /**< available info */
+ uint32_t changed; /**< changed since last update */
+ struct pw_node_info *info;
+ struct spa_list port_list;
+};
+
+struct sm_port {
+ struct sm_object obj;
+
+ enum pw_direction direction;
+ struct sm_node *node;
+ struct spa_list link; /**< link in node port_list */
+
+#define SM_PORT_CHANGE_MASK_INFO (1<<0)
+ uint32_t mask; /**< monitored info */
+ uint32_t avail; /**< available info */
+ uint32_t changed; /**< changed since last update */
+ struct pw_port_info *info;
+};
+
+struct sm_endpoint {
+ struct sm_object obj;
+
+ int32_t priority;
+
+#define SM_ENDPOINT_CHANGE_MASK_INFO (1<<0)
+#define SM_ENDPOINT_CHANGE_MASK_STREAMS (1<<1)
+ uint32_t mask; /**< monitored info */
+ uint32_t avail; /**< available info */
+ uint32_t changed; /**< changed since last update */
+ struct pw_endpoint_info *info;
+ struct spa_list stream_list;
+};
+
+struct sm_endpoint_stream {
+ struct sm_object obj;
+
+ int32_t priority;
+
+ struct sm_endpoint *endpoint;
+ struct spa_list link; /**< link in endpoint stream_list */
+
+#define SM_STREAM_CHANGE_MASK_INFO (1<<0)
+ uint32_t mask; /**< monitored info */
+ uint32_t avail; /**< available info */
+ uint32_t changed; /**< changed since last update */
+ struct pw_endpoint_stream_info *info;
+};
+
+struct sm_endpoint_link {
+ struct sm_object obj;
+
+ struct spa_list link;
+
+ uint32_t mask; /**< monitored info */
+ uint32_t avail; /**< available info */
+ uint32_t changed; /**< changed since last update */
+ struct pw_endpoint_link_info *info;
+};
+
+struct sm_media_session_events {
+#define SM_VERSION_MEDIA_SESSION_EVENTS 0
+ uint32_t version;
+
+ void (*update) (void *data, struct sm_object *object);
+ void (*remove) (void *data, struct sm_object *object);
+
+ void (*rescan) (void *data, int seq);
+};
+
+struct sm_media_session {
+ struct pw_main_loop *loop;
+ struct pw_core *core;
+
+ struct pw_session_info info;
+};
+
+int sm_media_session_add_listener(struct sm_media_session *sess, struct spa_hook *listener,
+ const struct sm_media_session_events *events, void *data);
+
+struct sm_object *sm_media_session_find_object(struct sm_media_session *sess, uint32_t id);
+
+int sm_media_session_schedule_rescan(struct sm_media_session *sess);
+
+struct pw_proxy *sm_media_session_export(struct sm_media_session *sess,
+ uint32_t type, struct pw_properties *properties,
+ void *object, size_t user_data_size);
+
+struct pw_proxy *sm_media_session_create_object(struct sm_media_session *sess,
+ const char *factory_name, uint32_t type, uint32_t version,
+ const struct spa_dict *props, size_t user_data_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/examples/media-session/monitor.c b/src/examples/media-session/monitor.c
index 44f0995e..3e3a4905 100644
--- a/src/examples/media-session/monitor.c
+++ b/src/examples/media-session/monitor.c
@@ -43,11 +43,13 @@
#include <dbus/dbus.h>
+#include "media-session.h"
+
#define NAME "media-session"
#define DEFAULT_IDLE_SECONDS 3
-void * sm_stream_monitor_start(struct pw_remote *remote, uint32_t session_id);
+void * sm_stream_monitor_start(struct sm_media_session *sess);
struct impl;
@@ -65,11 +67,7 @@ struct monitor {
struct impl {
struct timespec now;
- struct pw_core *core;
- struct pw_remote *remote;
- struct spa_hook remote_listener;
-
- struct pw_core_proxy *core_proxy;
+ struct sm_media_session *session;
struct monitor bluez5_monitor;
struct monitor alsa_monitor;
@@ -77,10 +75,6 @@ struct impl {
struct sm_metadata *metadata;
- struct pw_client_session_proxy *client_session;
- struct spa_hook client_session_listener;
- struct pw_session_info client_session_info;
-
struct spa_dbus *dbus;
struct spa_dbus_connection *dbus_connection;
DBusConnection *conn;
@@ -89,11 +83,6 @@ struct impl {
struct spa_source *jack_timeout;
struct pw_proxy *jack_device;
-
- struct pw_registry_proxy *registry_proxy;
- struct spa_hook registry_listener;
-
-
};
struct alsa_object;
@@ -106,65 +95,12 @@ static int setup_alsa_endpoint(struct alsa_object *obj);
#include "bluez-monitor.c"
#include "metadata.c"
-static int client_session_set_id(void *object, uint32_t id)
-{
- struct impl *impl = object;
-
- pw_log_debug("got sesssion id:%d", id);
- impl->client_session_info.id = id;
-
- pw_client_session_proxy_update(impl->client_session,
- PW_CLIENT_SESSION_UPDATE_INFO,
- 0, NULL,
- &impl->client_session_info);
-
- bluez5_start_monitor(impl, &impl->bluez5_monitor);
- alsa_start_monitor(impl, &impl->alsa_monitor);
- alsa_start_midi_bridge(impl);
- alsa_start_jack_device(impl);
- v4l2_start_monitor(impl, &impl->v4l2_monitor);
- sm_stream_monitor_start(impl->remote, id);
- return 0;
-}
-
-static int client_session_set_param(void *object, uint32_t id, uint32_t flags,
- const struct spa_pod *param)
-{
- struct impl *impl = object;
- pw_proxy_error((struct pw_proxy*)impl->client_session,
- -ENOTSUP, "Session:SetParam not supported");
- return -ENOTSUP;
-}
-
-static int client_session_link_set_param(void *object, uint32_t link_id, uint32_t id, uint32_t flags,
- const struct spa_pod *param)
-{
- struct impl *impl = object;
- pw_proxy_error((struct pw_proxy*)impl->client_session,
- -ENOTSUP, "Session:LinkSetParam not supported");
- return -ENOTSUP;
-}
-
-static int client_session_link_request_state(void *object, uint32_t link_id, uint32_t state)
-{
- return -ENOTSUP;
-}
-
-
-static const struct pw_client_session_proxy_events client_session_events = {
- PW_VERSION_CLIENT_SESSION_PROXY_METHODS,
- .set_id = client_session_set_id,
- .set_param = client_session_set_param,
- .link_set_param = client_session_link_set_param,
- .link_request_state = client_session_link_request_state,
-};
-
static void start_services(struct impl *impl)
{
const struct spa_support *support;
uint32_t n_support;
- support = pw_core_get_support(impl->core, &n_support);
+ support = pw_core_get_support(impl->session->core, &n_support);
impl->dbus = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DBus);
if (impl->dbus)
@@ -176,58 +112,21 @@ static void start_services(struct impl *impl)
else
pw_log_debug("got dbus connection %p", impl->conn);
- pw_remote_export(impl->remote,
+ sm_media_session_export(impl->session,
PW_TYPE_INTERFACE_Metadata,
NULL,
impl->metadata,
0);
- impl->client_session = pw_core_proxy_create_object(impl->core_proxy,
- "client-session",
- PW_TYPE_INTERFACE_ClientSession,
- PW_VERSION_CLIENT_SESSION_PROXY,
- NULL, 0);
- impl->client_session_info.version = PW_VERSION_SESSION_INFO;
-
- pw_client_session_proxy_add_listener(impl->client_session,
- &impl->client_session_listener,
- &client_session_events,
- impl);
-
-}
-
-static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remote_state state, const char *error)
-{
- struct impl *impl = _data;
-
- switch (state) {
- case PW_REMOTE_STATE_ERROR:
- pw_log_error(NAME" %p: remote error: %s", impl, error);
- break;
-
- case PW_REMOTE_STATE_CONNECTED:
- pw_log_info(NAME" %p: connected", impl);
- impl->core_proxy = pw_remote_get_core_proxy(impl->remote);
- start_services(impl);
- break;
-
- case PW_REMOTE_STATE_UNCONNECTED:
- pw_log_info(NAME" %p: disconnected", impl);
- impl->core_proxy = NULL;
- break;
-
- default:
- printf("remote state: \"%s\"\n", pw_remote_state_as_string(state));
- break;
- }
+ bluez5_start_monitor(impl, &impl->bluez5_monitor);
+ alsa_start_monitor(impl, &impl->alsa_monitor);
+ alsa_start_midi_bridge(impl);
+ alsa_start_jack_device(impl);
+ v4l2_start_monitor(impl, &impl->v4l2_monitor);
+ sm_stream_monitor_start(impl->session);
}
-static const struct pw_remote_events remote_events = {
- PW_VERSION_REMOTE_EVENTS,
- .state_changed = on_state_changed,
-};
-
-int sm_monitor_start(struct pw_remote *remote)
+int sm_monitor_start(struct sm_media_session *sess)
{
struct impl *impl;
@@ -235,14 +134,13 @@ int sm_monitor_start(struct pw_remote *remote)
if (impl == NULL)
return -errno;
- impl->core = pw_remote_get_core(remote);
- impl->remote = remote;
+ impl->session = sess;
clock_gettime(CLOCK_MONOTONIC, &impl->now);
impl->metadata = sm_metadata_new(NULL);
- pw_remote_add_listener(impl->remote, &impl->remote_listener, &remote_events, impl);
+ start_services(impl);
return 0;
}
diff --git a/src/examples/media-session/policy-ep.c b/src/examples/media-session/policy-ep.c
index cc3d4407..d1194f3f 100644
--- a/src/examples/media-session/policy-ep.c
+++ b/src/examples/media-session/policy-ep.c
@@ -40,6 +40,8 @@
#include "pipewire/private.h"
#include "extensions/session-manager.h"
+#include "media-session.h"
+
#define NAME "policy-ep"
#define DEFAULT_CHANNELS 2
@@ -47,72 +49,32 @@
#define DEFAULT_IDLE_SECONDS 3
-struct impl;
-
struct impl {
struct timespec now;
- struct pw_core *core;
- struct pw_remote *remote;
- struct spa_hook remote_listener;
-
- struct pw_core_proxy *core_proxy;
- struct spa_hook core_listener;
-
- struct pw_registry_proxy *registry_proxy;
- struct spa_hook registry_listener;
+ struct sm_media_session *session;
+ struct spa_hook listener;
- struct pw_map globals;
+ struct pw_core *core;
- struct spa_list client_list;
struct spa_list endpoint_list;
- struct spa_list session_list;
int seq;
};
-struct object {
- struct impl *impl;
- uint32_t id;
- uint32_t type;
- struct pw_proxy *proxy;
- struct spa_hook listener;
-};
-
-struct client {
- struct object obj;
-
- struct spa_list l;
-
- struct spa_hook listener;
- struct pw_client_info *info;
-};
-
-struct session {
- struct object obj;
-
- struct spa_list l;
-
- struct spa_hook listener;
- struct pw_session_info *info;
-};
-
struct endpoint {
- struct object obj;
+ struct sm_endpoint *obj;
- struct spa_list l;
+ uint32_t id;
+ struct impl *impl;
- struct spa_hook listener;
- struct pw_endpoint_info *info;
+ struct spa_list link; /**< link in impl endpoint_list */
+ enum pw_direction direction;
struct endpoint *peer;
- struct session *session;
uint32_t client_id;
int32_t priority;
- struct spa_list stream_list;
-
- enum pw_direction direction;
#define ENDPOINT_TYPE_UNKNOWN 0
#define ENDPOINT_TYPE_STREAM 1
#define ENDPOINT_TYPE_DEVICE 2
@@ -130,161 +92,46 @@ struct endpoint {
};
struct stream {
- struct object obj;
-
- struct spa_list l;
- enum pw_direction direction;
- struct pw_endpoint_stream_info *info;
- struct endpoint *endpoint;
-#define STREAM_FLAG_NONE 0
-#define STREAM_FLAG_DSP (1<<0)
-#define STREAM_FLAG_SKIP (1<<1)
- uint32_t flags;
-
- struct spa_hook listener;
-};
-
-struct link {
- struct object obj;
- struct stream *out;
- struct stream *in;
-};
-
-static void add_object(struct impl *impl, struct object *obj)
-{
- size_t size = pw_map_get_size(&impl->globals);
- while (obj->id > size)
- pw_map_insert_at(&impl->globals, size++, NULL);
- pw_map_insert_at(&impl->globals, obj->id, obj);
-}
-
-static void remove_object(struct impl *impl, struct object *obj)
-{
- pw_map_insert_at(&impl->globals, obj->id, NULL);
-}
-
-static void *find_object(struct impl *impl, uint32_t id)
-{
- void *obj;
- if ((obj = pw_map_lookup(&impl->globals, id)) != NULL)
- return obj;
- return NULL;
-}
-
-static void schedule_rescan(struct impl *impl)
-{
- if (impl->core_proxy)
- impl->seq = pw_core_proxy_sync(impl->core_proxy, 0, impl->seq);
-}
-
-static void endpoint_event_info(void *object, const struct pw_endpoint_info *update)
-{
- struct endpoint *e = object;
- struct impl *impl = e->obj.impl;
- struct pw_endpoint_info *info = e->info;
- const char *str;
-
- pw_log_debug(NAME" %p: info for endpoint %d type %d", impl, e->obj.id, e->type);
+ struct sm_endpoint_stream *obj;
- if (info == NULL && update) {
- info = e->info = calloc(1, sizeof(*info));
- info->id = update->id;
- info->name = update->name ? strdup(update->name) : NULL;
- info->media_class = update->media_class ? strdup(update->media_class) : NULL;
- info->direction = update->direction;
- info->flags = update->flags;
- }
- info->change_mask = update->change_mask;
- if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_SESSION) {
- info->session_id = update->session_id;
- e->session = find_object(impl, info->session_id);
- }
- if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) {
- if (info->props)
- pw_properties_free ((struct pw_properties *)info->props);
- info->props = (struct spa_dict *) pw_properties_new_dict (update->props);
- if ((str = spa_dict_lookup(info->props, PW_KEY_PRIORITY_SESSION)) != NULL)
- e->priority = pw_properties_parse_int(str);
- }
- e->enabled = true;
-}
-
-static void endpoint_event_param(void *object, int seq,
- uint32_t id, uint32_t index, uint32_t next,
- const struct spa_pod *param)
-{
- struct endpoint *e = object;
- struct impl *impl = e->obj.impl;
- pw_log_debug(NAME" %p: param for endpoint %d, %d", impl, e->obj.id, id);
-}
-
-static const struct pw_endpoint_proxy_events endpoint_events = {
- PW_VERSION_ENDPOINT_PROXY_EVENTS,
- .info = endpoint_event_info,
- .param = endpoint_event_param,
-};
-
-static void endpoint_proxy_destroy(void *data)
-{
- struct endpoint *e = data;
- struct impl *impl = e->obj.impl;
- struct stream *s, *t;
-
- pw_log_debug(NAME " %p: proxy destroy endpoint %d", impl, e->obj.id);
-
- spa_list_remove(&e->l);
-
- spa_list_for_each_safe(s, t, &e->stream_list, l) {
- spa_list_remove(&s->l);
- s->endpoint = NULL;
- }
- free(e->media);
-}
+ uint32_t id;
+ struct impl *impl;
-static const struct pw_proxy_events endpoint_proxy_events = {
- PW_VERSION_PROXY_EVENTS,
- .destroy = endpoint_proxy_destroy,
+ struct endpoint *endpoint;
};
static int
-handle_endpoint(struct impl *impl, uint32_t id,
- uint32_t type, const struct spa_dict *props)
+handle_endpoint(struct impl *impl, struct sm_object *object)
{
const char *str, *media_class;
enum pw_direction direction;
- struct pw_proxy *p;
struct endpoint *ep;
uint32_t client_id = SPA_ID_INVALID;
- if (props) {
- if ((str = spa_dict_lookup(props, PW_KEY_CLIENT_ID)) != NULL)
+ if (sm_object_get_data(object, "policy-endpoint") != NULL)
+ return 0;
+
+ if (object->props) {
+ if ((str = pw_properties_get(object->props, PW_KEY_CLIENT_ID)) != NULL)
client_id = atoi(str);
}
- p = pw_registry_proxy_bind(impl->registry_proxy,
- id, type, PW_VERSION_ENDPOINT_PROXY,
- sizeof(struct endpoint));
-
- ep = pw_proxy_get_user_data(p);
- ep->obj.impl = impl;
- ep->obj.id = id;
- ep->obj.type = type;
- ep->obj.proxy = p;
- ep->client_id = client_id;
- spa_list_init(&ep->stream_list);
- pw_proxy_add_listener(p, &ep->obj.listener, &endpoint_proxy_events, ep);
- pw_proxy_add_object_listener(p, &ep->listener, &endpoint_events, ep);
- add_object(impl, &ep->obj);
- spa_list_append(&impl->endpoint_list, &ep->l);
- ep->type = ENDPOINT_TYPE_UNKNOWN;
-
- media_class = props ? spa_dict_lookup(props, PW_KEY_MEDIA_CLASS) : NULL;
+ media_class = object->props ? pw_properties_get(object->props, PW_KEY_MEDIA_CLASS) : NULL;
pw_log_debug(NAME" %p: endpoint "PW_KEY_MEDIA_CLASS" %s", impl, media_class);
if (media_class == NULL)
return 0;
+ ep = sm_object_add_data(object, "policy-endpoint", sizeof(struct endpoint));
+ ep->obj = (struct sm_endpoint*)object;
+ ep->id = object->id;
+ ep->impl = impl;
+ ep->client_id = client_id;
+ ep->type = ENDPOINT_TYPE_UNKNOWN;
+ ep->enabled = true;
+ spa_list_append(&impl->endpoint_list, &ep->link);
+
if (strstr(media_class, "Stream/") == media_class) {
media_class += strlen("Stream/");
@@ -302,7 +149,7 @@ handle_endpoint(struct impl *impl, uint32_t id,
ep->direction = direction;
ep->type = ENDPOINT_TYPE_STREAM;
ep->media = strdup(media_class);
- pw_log_debug(NAME "%p: endpoint %d is stream %s", impl, id, ep->media);
+ pw_log_debug(NAME "%p: endpoint %d is stream %s", impl, object->id, ep->media);
}
else {
if (strstr(media_class, "Audio/") == media_class) {
@@ -324,267 +171,56 @@ handle_endpoint(struct impl *impl, uint32_t id,
ep->direction = direction;
ep->type = ENDPOINT_TYPE_DEVICE;
- pw_log_debug(NAME" %p: endpoint %d prio:%d", impl, id, ep->priority);
+ pw_log_debug(NAME" %p: endpoint %d prio:%d", impl, object->id, ep->priority);
}
return 1;
}
-static void stream_event_info(void *object, const struct pw_endpoint_stream_info *info)
-{
- struct stream *s = object;
- pw_log_debug(NAME" %p: info for stream %d", s->obj.impl, s->obj.id);
-}
-
-static void stream_event_param(void *object, int seq,
- uint32_t id, uint32_t index, uint32_t next,
- const struct spa_pod *param)
-{
- struct stream *s = object;
- struct endpoint *ep = s->endpoint;
- struct spa_audio_info_raw info = { 0, };
-
- pw_log_debug(NAME" %p: param for stream %d", s->obj.impl, s->obj.id);
-
- if (ep == NULL)
- return;
-
- if (id != SPA_PARAM_EnumFormat)
- return;
-
- if (spa_format_parse(param, &ep->media_type, &ep->media_subtype) < 0)
- return;
-
- if (ep->media_type != SPA_MEDIA_TYPE_audio ||
- ep->media_subtype != SPA_MEDIA_SUBTYPE_raw)
- return;
-
- spa_pod_fixate((struct spa_pod*)param);
-
- if (spa_format_audio_raw_parse(param, &info) < 0)
- return;
-
- if (info.channels > ep->format.channels)
- ep->format = info;
-}
-
-static const struct pw_endpoint_stream_proxy_events stream_events = {
- PW_VERSION_ENDPOINT_STREAM_PROXY_EVENTS,
- .info = stream_event_info,
- .param = stream_event_param,
-};
-
-static void stream_proxy_destroy(void *data)
-{
- struct stream *s = data;
-
- pw_log_debug(NAME " %p: proxy destroy stream %d", s->obj.impl, s->obj.id);
-
- if (s->endpoint) {
- spa_list_remove(&s->l);
- s->endpoint = NULL;
- }
-}
-
-static const struct pw_proxy_events stream_proxy_events = {
- PW_VERSION_PROXY_EVENTS,
- .destroy = stream_proxy_destroy,
-};
-
static int
-handle_stream(struct impl *impl, uint32_t id, uint32_t type,
- const struct spa_dict *props)
+handle_stream(struct impl *impl, struct sm_object *object)
{
+ struct sm_endpoint_stream *stream = (struct sm_endpoint_stream*)object;
struct stream *s;
- struct pw_proxy *p;
struct endpoint *ep;
- const char *str;
- uint32_t endpoint_id;
- if (props == NULL || (str = spa_dict_lookup(props, PW_KEY_ENDPOINT_ID)) == NULL)
- return -EINVAL;
-
- endpoint_id = atoi(str);
+ if (sm_object_get_data(object, "policy-endpoint") != NULL)
+ return 0;
- if ((ep = find_object(impl, endpoint_id)) == NULL)
- return -ESRCH;
+ if (stream->endpoint == NULL)
+ return 0;
- p = pw_registry_proxy_bind(impl->registry_proxy,
- id, type, PW_VERSION_ENDPOINT_STREAM_PROXY,
- sizeof(struct stream));
+ ep = sm_object_get_data(&stream->endpoint->obj, "policy-endpoint");
+ if (ep == NULL)
+ return 0;
- s = pw_proxy_get_user_data(p);
- s->obj.impl = impl;
- s->obj.id = id;
- s->obj.type = type;
- s->obj.proxy = p;
+ s = sm_object_add_data(object, "policy-endpoint", sizeof(struct stream));
+ s->obj = (struct sm_endpoint_stream*)object;
+ s->id = object->id;
+ s->impl = impl;
s->endpoint = ep;
- s->direction = ep->direction;
-
- pw_proxy_add_listener(p, &s->obj.listener, &stream_proxy_events, s);
- pw_proxy_add_object_listener(p, &s->listener, &stream_events, s);
- add_object(impl, &s->obj);
- spa_list_append(&ep->stream_list, &s->l);
-
- pw_log_debug(NAME" %p: new stream %d for endpoint %d type %d %08x", impl, id, endpoint_id,
- ep->type, s->flags);
-
- if (ep->type == ENDPOINT_TYPE_DEVICE) {
- pw_endpoint_stream_proxy_enum_params((struct pw_endpoint_stream_proxy*)p,
+ if (s->endpoint->type == ENDPOINT_TYPE_DEVICE) {
+ pw_endpoint_stream_proxy_enum_params((struct pw_endpoint_stream_proxy*)stream->obj.proxy,
0, SPA_PARAM_EnumFormat,
0, -1, NULL);
}
return 0;
}
-static void client_event_info(void *object, const struct pw_client_info *info)
-{
- struct client *c = object;
- uint32_t i;
-
- pw_log_debug(NAME" %p: info for client %d", c->obj.impl, c->obj.id);
- c->info = pw_client_info_update(c->info, info);
- for (i = 0; i < info->props->n_items; i++)
- pw_log_debug(NAME" %p: %s = %s", c,
- info->props->items[i].key,
- info->props->items[i].value);
-}
-
-static const struct pw_client_proxy_events client_events = {
- PW_VERSION_CLIENT_PROXY_EVENTS,
- .info = client_event_info,
-};
-
-static void client_proxy_destroy(void *data)
-{
- struct client *c = data;
-
- pw_log_debug(NAME " %p: proxy destroy client %d", c->obj.impl, c->obj.id);
-
- spa_list_remove(&c->l);
- if (c->info)
- pw_client_info_free(c->info);
-}
-
-static const struct pw_proxy_events client_proxy_events = {
- PW_VERSION_PROXY_EVENTS,
- .destroy = client_proxy_destroy,
-};
-
-static int
-handle_client(struct impl *impl, uint32_t id,
- uint32_t type, const struct spa_dict *props)
-{
- struct pw_proxy *p;
- struct client *client;
- struct pw_permission perms[2];
- const char *str;
-
- p = pw_registry_proxy_bind(impl->registry_proxy,
- id, type, PW_VERSION_CLIENT_PROXY,
- sizeof(struct client));
-
- client = pw_proxy_get_user_data(p);
- client->obj.impl = impl;
- client->obj.id = id;
- client->obj.type = type;
- client->obj.proxy = p;
-
- pw_proxy_add_listener(p, &client->obj.listener, &client_proxy_events, client);
- pw_proxy_add_object_listener(p, &client->listener, &client_events, client);
- add_object(impl, &client->obj);
- spa_list_append(&impl->client_list, &client->l);
-
- if (props == NULL)
- return 0;
-
- str = spa_dict_lookup(props, PW_KEY_ACCESS);
- if (str == NULL)
- return 0;
-
- if (strcmp(str, "restricted") == 0) {
- perms[0] = PW_PERMISSION_INIT(-1, PW_PERM_RWX);
- pw_client_proxy_update_permissions((struct pw_client_proxy*)p,
- 1, perms);
- }
- return 0;
-}
-
-static void session_event_info(void *object, const struct pw_session_info *info)
-{
- struct session *c = object;
- pw_log_debug(NAME" %p: info for session %d", c->obj.impl, c->obj.id);
-}
-
-static const struct pw_session_proxy_events session_events = {
- PW_VERSION_SESSION_PROXY_EVENTS,
- .info = session_event_info,
-};
-
-static void session_proxy_destroy(void *data)
-{
- struct session *c = data;
-
- pw_log_debug(NAME " %p: proxy destroy session %d", c->obj.impl, c->obj.id);
-
- spa_list_remove(&c->l);
-}
-
-static const struct pw_proxy_events session_proxy_events = {
- PW_VERSION_PROXY_EVENTS,
- .destroy = session_proxy_destroy,
-};
-
-static int
-handle_session(struct impl *impl, uint32_t id,
- uint32_t type, const struct spa_dict *props)
-{
- struct pw_proxy *p;
- struct session *session;
-
- p = pw_registry_proxy_bind(impl->registry_proxy,
- id, type, PW_VERSION_SESSION_PROXY,
- sizeof(struct session));
-
- session = pw_proxy_get_user_data(p);
- session->obj.impl = impl;
- session->obj.id = id;
- session->obj.type = type;
- session->obj.proxy = p;
-
- pw_proxy_add_listener(p, &session->obj.listener, &session_proxy_events, session);
- pw_proxy_add_object_listener(p, &session->listener, &session_events, session);
- add_object(impl, &session->obj);
- spa_list_append(&impl->session_list, &session->l);
-
- return 0;
-}
-
-static void
-registry_global(void *data,uint32_t id,
- uint32_t permissions, uint32_t type, uint32_t version,
- const struct spa_dict *props)
+static void session_update(void *data, struct sm_object *object)
{
struct impl *impl = data;
int res;
- pw_log_debug(NAME " %p: new global '%d' %d", impl, id, type);
-
- switch (type) {
- case PW_TYPE_INTERFACE_Client:
- res = handle_client(impl, id, type, props);
- break;
-
- case PW_TYPE_INTERFACE_Session:
- res = handle_session(impl, id, type, props);
- break;
+ pw_log_debug(NAME " %p: update global '%d'", impl, object->id);
+ switch (object->type) {
case PW_TYPE_INTERFACE_Endpoint:
- res = handle_endpoint(impl, id, type, props);
+ res = handle_endpoint(impl, object);
break;
case PW_TYPE_INTERFACE_EndpointStream:
- res = handle_stream(impl, id, type, props);
+ res = handle_stream(impl, object);
break;
default:
@@ -592,34 +228,32 @@ registry_global(void *data,uint32_t id,
break;
}
if (res < 0) {
- pw_log_warn(NAME" %p: can't handle global %d", impl, id);
+ pw_log_warn(NAME" %p: can't handle global %d", impl, object->id);
}
else
- schedule_rescan(impl);
+ sm_media_session_schedule_rescan(impl->session);
}
-static void
-registry_global_remove(void *data, uint32_t id)
+static void session_remove(void *data, struct sm_object *object)
{
struct impl *impl = data;
- struct object *obj;
+ pw_log_debug(NAME " %p: remove global '%d'", impl, object->id);
- pw_log_debug(NAME " %p: remove global '%d'", impl, id);
-
- if ((obj = find_object(impl, id)) == NULL)
- return;
+ switch (object->type) {
+ case PW_TYPE_INTERFACE_Endpoint:
+ {
+ struct endpoint *ep;
+ if ((ep = sm_object_get_data(object, "policy-endpoint")) != NULL)
+ spa_list_remove(&ep->link);
+ break;
+ }
+ default:
+ break;
+ }
- remove_object(impl, obj);
- schedule_rescan(impl);
+ sm_media_session_schedule_rescan(impl->session);
}
-static const struct pw_registry_proxy_events registry_events = {
- PW_VERSION_REGISTRY_PROXY_EVENTS,
- .global = registry_global,
- .global_remove = registry_global_remove,
-};
-
-
struct find_data {
struct impl *impl;
uint32_t path_id;
@@ -640,17 +274,17 @@ static int find_endpoint(void *data, struct endpoint *endpoint)
uint64_t plugged = 0;
pw_log_debug(NAME " %p: looking at endpoint '%d' enabled:%d busy:%d exclusive:%d",
- impl, endpoint->obj.id, endpoint->enabled, endpoint->busy, endpoint->exclusive);
+ impl, endpoint->id, endpoint->enabled, endpoint->busy, endpoint->exclusive);
if (!endpoint->enabled)
return 0;
- if (find->path_id != SPA_ID_INVALID && endpoint->obj.id != find->path_id)
+ if (find->path_id != SPA_ID_INVALID && endpoint->id != find->path_id)
return 0;
if (find->path_id == SPA_ID_INVALID) {
- if (endpoint->info == NULL ||
- (props = endpoint->info->props) == NULL)
+ if (endpoint->obj->info == NULL ||
+ (props = endpoint->obj->info->props) == NULL)
return 0;
if ((str = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS)) == NULL)
@@ -664,12 +298,12 @@ static int find_endpoint(void *data, struct endpoint *endpoint)
}
if ((find->exclusive && endpoint->busy) || endpoint->exclusive) {
- pw_log_debug(NAME " %p: endpoint '%d' in use", impl, endpoint->obj.id);
+ pw_log_debug(NAME " %p: endpoint '%d' in use", impl, endpoint->id);
return 0;
}
pw_log_debug(NAME " %p: found endpoint '%d' %"PRIu64" prio:%d", impl,
- endpoint->obj.id, plugged, priority);
+ endpoint->id, plugged, priority);
if (find->endpoint == NULL ||
priority > find->priority ||
@@ -684,53 +318,35 @@ static int find_endpoint(void *data, struct endpoint *endpoint)
static int link_endpoints(struct endpoint *endpoint, enum pw_direction direction, struct endpoint *peer, int max)
{
- struct impl *impl = peer->obj.impl;
- struct stream *s;
+ struct impl *impl = peer->impl;
+ struct pw_properties *props;
- pw_log_debug(NAME " %p: link endpoints %d %d %d", impl, max, endpoint->obj.id, peer->obj.id);
-
- if (endpoint->session == NULL) {
- pw_log_debug(NAME " %p: endpoint has no session", impl);
- return -EINVAL;
- }
+ pw_log_debug(NAME " %p: link endpoints %d %d %d", impl, max, endpoint->id, peer->id);
- spa_list_for_each(s, &endpoint->stream_list, l) {
- struct pw_properties *props;
+ props = pw_properties_new(NULL, NULL);
+ if (endpoint->direction == PW_DIRECTION_OUTPUT) {
+ pw_properties_setf(props, PW_KEY_LINK_OUTPUT_NODE, "%d", endpoint->id);
+ pw_properties_setf(props, PW_KEY_LINK_OUTPUT_PORT, "%d", -1);
+ pw_properties_setf(props, PW_KEY_LINK_INPUT_NODE, "%d", peer->id);
+ pw_properties_setf(props, PW_KEY_LINK_INPUT_PORT, "%d", -1);
+ pw_log_debug(NAME " %p: endpoint %d -> endpoint %d", impl,
+ endpoint->id, peer->id);
- pw_log_debug(NAME " %p: stream %p: %d %d", impl, s, s->direction, s->flags);
-
- if (s->direction == direction)
- continue;
- if (s->flags & STREAM_FLAG_SKIP)
- continue;
-
- if (max-- == 0)
- return 0;
-
- props = pw_properties_new(NULL, NULL);
- if (s->direction == PW_DIRECTION_OUTPUT) {
- pw_properties_setf(props, PW_KEY_LINK_OUTPUT_NODE, "%d", endpoint->obj.id);
- pw_properties_setf(props, PW_KEY_LINK_OUTPUT_PORT, "%d", s->obj.id);
- pw_properties_setf(props, PW_KEY_LINK_INPUT_NODE, "%d", peer->obj.id);
- pw_properties_setf(props, PW_KEY_LINK_INPUT_PORT, "%d", -1);
- pw_log_debug(NAME " %p: stream %d:%d -> endpoint %d", impl,
- endpoint->obj.id, s->obj.id, peer->obj.id);
+ }
+ else {
+ pw_properties_setf(props, PW_KEY_LINK_OUTPUT_NODE, "%d", peer->id);
+ pw_properties_setf(props, PW_KEY_LINK_OUTPUT_PORT, "%d", -1);
+ pw_properties_setf(props, PW_KEY_LINK_INPUT_NODE, "%d", endpoint->id);
+ pw_properties_setf(props, PW_KEY_LINK_INPUT_PORT, "%d", -1);
+ pw_log_debug(NAME " %p: endpoint %d -> endpoint %d", impl,
+ peer->id, endpoint->id);
+ }
- }
- else {
- pw_properties_setf(props, PW_KEY_LINK_OUTPUT_NODE, "%d", peer->obj.id);
- pw_properties_setf(props, PW_KEY_LINK_OUTPUT_PORT, "%d", -1);
- pw_properties_setf(props, PW_KEY_LINK_INPUT_NODE, "%d", endpoint->obj.id);
- pw_properties_setf(props, PW_KEY_LINK_INPUT_PORT, "%d", s->obj.id);
- pw_log_debug(NAME " %p: endpoint %d -> stream %d:%d", impl,
- peer->obj.id, endpoint->obj.id, s->obj.id);
- }
+ pw_endpoint_proxy_create_link((struct pw_endpoint_proxy*)endpoint->obj->obj.proxy,
+ &props->dict);
- pw_endpoint_proxy_create_link((struct pw_endpoint_proxy*)endpoint->obj.proxy,
- &props->dict);
+ pw_properties_free(props);
- pw_properties_free(props);
- }
endpoint->peer = peer;
peer->peer = endpoint;
@@ -750,27 +366,27 @@ static int rescan_endpoint(struct impl *impl, struct endpoint *ep)
if (ep->type == ENDPOINT_TYPE_DEVICE)
return 0;
- if (ep->info == NULL || ep->info->props == NULL) {
- pw_log_debug(NAME " %p: endpoint %d has no properties", impl, ep->obj.id);
+ if (ep->obj->info == NULL || ep->obj->info->props == NULL) {
+ pw_log_debug(NAME " %p: endpoint %d has no properties", impl, ep->id);
return 0;
}
if (ep->peer != NULL)
return 0;
- info = ep->info;
+ info = ep->obj->info;
props = info->props;
str = spa_dict_lookup(props, PW_KEY_ENDPOINT_AUTOCONNECT);
if (str == NULL || !pw_properties_parse_bool(str)) {
- pw_log_debug(NAME" %p: endpoint %d does not need autoconnect", impl, ep->obj.id);
+ pw_log_debug(NAME" %p: endpoint %d does not need autoconnect", impl, ep->id);
return 0;
}
if ((media = spa_dict_lookup(props, PW_KEY_MEDIA_TYPE)) == NULL)
media = ep->media;
if (media == NULL) {
- pw_log_debug(NAME" %p: endpoint %d has unknown media", impl, ep->obj.id);
+ pw_log_debug(NAME" %p: endpoint %d has unknown media", impl, ep->id);
return 0;
}
@@ -778,14 +394,14 @@ static int rescan_endpoint(struct impl *impl, struct endpoint *ep)
if ((category = spa_dict_lookup(props, PW_KEY_MEDIA_CATEGORY)) == NULL) {
pw_log_debug(NAME" %p: endpoint %d find category",
- impl, ep->obj.id);
+ impl, ep->id);
if (ep->direction == PW_DIRECTION_INPUT) {
category = "Capture";
} else if (ep->direction == PW_DIRECTION_OUTPUT) {
category = "Playback";
} else {
pw_log_warn(NAME" %p: endpoint %d can't determine category",
- impl, ep->obj.id);
+ impl, ep->id);
return -EINVAL;
}
}
@@ -821,7 +437,7 @@ static int rescan_endpoint(struct impl *impl, struct endpoint *ep)
find.media_class = "Audio/Source";
else {
pw_log_debug(NAME" %p: endpoint %d unhandled category %s",
- impl, ep->obj.id, category);
+ impl, ep->id, category);
return -EINVAL;
}
}
@@ -830,13 +446,13 @@ static int rescan_endpoint(struct impl *impl, struct endpoint *ep)
find.media_class = "Video/Source";
else {
pw_log_debug(NAME" %p: endpoint %d unhandled category %s",
- impl, ep->obj.id, category);
+ impl, ep->id, category);
return -EINVAL;
}
}
else {
pw_log_debug(NAME" %p: endpoint %d unhandled media %s",
- impl, ep->obj.id, media);
+ impl, ep->id, media);
return -EINVAL;
}
@@ -846,7 +462,7 @@ static int rescan_endpoint(struct impl *impl, struct endpoint *ep)
direction = PW_DIRECTION_INPUT;
else {
pw_log_debug(NAME" %p: endpoint %d unhandled category %s",
- impl, ep->obj.id, category);
+ impl, ep->id, category);
return -EINVAL;
}
@@ -862,46 +478,49 @@ static int rescan_endpoint(struct impl *impl, struct endpoint *ep)
find.impl = impl;
find.exclusive = exclusive;
- spa_list_for_each(peer, &impl->endpoint_list, l)
+ spa_list_for_each(peer, &impl->endpoint_list, link)
find_endpoint(&find, peer);
if (find.endpoint == NULL && find.path_id != SPA_ID_INVALID) {
- pw_log_debug(NAME " %p: no endpoint found for %d, try endpoint", impl, ep->obj.id);
+ struct sm_object *obj;
+ pw_log_debug(NAME " %p: no endpoint found for %d, try endpoint", impl, ep->id);
- if ((peer = find_object(impl, find.path_id)) != NULL) {
- if (peer->obj.type == PW_TYPE_INTERFACE_Endpoint)
+ if ((obj = sm_media_session_find_object(impl->session, find.path_id)) != NULL) {
+ if (obj->type == PW_TYPE_INTERFACE_Endpoint) {
+ peer = sm_object_get_data(obj, "policy-endpoint");
goto do_link;
+ }
}
else {
str = spa_dict_lookup(props, PW_KEY_NODE_DONT_RECONNECT);
if (str != NULL && pw_properties_parse_bool(str)) {
- pw_registry_proxy_destroy(impl->registry_proxy, ep->obj.id);
+// pw_registry_proxy_destroy(impl->registry_proxy, ep->id);
return -ENOENT;
}
}
}
if (find.endpoint == NULL) {
- struct client *client;
+ struct sm_object *obj;
- pw_log_warn(NAME " %p: no endpoint found for %d", impl, ep->obj.id);
+ pw_log_warn(NAME " %p: no endpoint found for %d", impl, ep->id);
- client = find_object(impl, ep->client_id);
- if (client && client->obj.type == PW_TYPE_INTERFACE_Client) {
- pw_client_proxy_error((struct pw_client_proxy*)client->obj.proxy,
- ep->obj.id, -ENOENT, "no endpoint available");
+ obj = sm_media_session_find_object(impl->session, ep->client_id);
+ if (obj && obj->type == PW_TYPE_INTERFACE_Client) {
+ pw_client_proxy_error((struct pw_client_proxy*)obj->proxy,
+ ep->id, -ENOENT, "no endpoint available");
}
return -ENOENT;
}
peer = find.endpoint;
if (exclusive && peer->busy) {
- pw_log_warn(NAME" %p: endpoint %d busy, can't get exclusive access", impl, peer->obj.id);
+ pw_log_warn(NAME" %p: endpoint %d busy, can't get exclusive access", impl, peer->id);
return -EBUSY;
}
peer->exclusive = exclusive;
- pw_log_debug(NAME" %p: linking to endpoint '%d'", impl, peer->obj.id);
+ pw_log_debug(NAME" %p: linking to endpoint '%d'", impl, peer->id);
peer->busy = true;
@@ -911,71 +530,26 @@ do_link:
return 1;
}
-static void do_rescan(struct impl *impl)
+static void session_rescan(void *data, int seq)
{
+ struct impl *impl = data;
struct endpoint *ep;
clock_gettime(CLOCK_MONOTONIC, &impl->now);
- pw_log_debug("media-session %p: do rescan", impl);
+ pw_log_debug(NAME" %p: rescan", impl);
- spa_list_for_each(ep, &impl->endpoint_list, l)
+ spa_list_for_each(ep, &impl->endpoint_list, link)
rescan_endpoint(impl, ep);
}
-static void core_done(void *data, uint32_t id, int seq)
-{
- struct impl *impl = data;
- pw_log_debug("media-session %p: sync %u %d/%d", impl, id, seq, impl->seq);
- if (impl->seq == seq)
- do_rescan(impl);
-}
-
-static const struct pw_core_proxy_events core_events = {
- PW_VERSION_CORE_EVENTS,
- .done = core_done
+static const struct sm_media_session_events session_events = {
+ SM_VERSION_MEDIA_SESSION_EVENTS,
+ .update = session_update,
+ .remove = session_remove,
+ .rescan = session_rescan,
};
-static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remote_state state, const char *error)
-{
- struct impl *impl = _data;
-
- switch (state) {
- case PW_REMOTE_STATE_ERROR:
- pw_log_error(NAME" %p: remote error: %s", impl, error);
- break;
-
- case PW_REMOTE_STATE_CONNECTED:
- pw_log_info(NAME" %p: connected", impl);
- impl->core_proxy = pw_remote_get_core_proxy(impl->remote);
- pw_core_proxy_add_listener(impl->core_proxy,
- &impl->core_listener,
- &core_events, impl);
- impl->registry_proxy = pw_core_proxy_get_registry(impl->core_proxy,
- PW_VERSION_REGISTRY_PROXY, 0);
- pw_registry_proxy_add_listener(impl->registry_proxy,
- &impl->registry_listener,
- &registry_events, impl);
- schedule_rescan(impl);
- break;
-
- case PW_REMOTE_STATE_UNCONNECTED:
- pw_log_info(NAME" %p: disconnected", impl);
- impl->core_proxy = NULL;
- impl->registry_proxy = NULL;
- break;
-
- default:
- printf("remote state: \"%s\"\n", pw_remote_state_as_string(state));
- break;
- }
-}
-
-static const struct pw_remote_events remote_events = {
- PW_VERSION_REMOTE_EVENTS,
- .state_changed = on_state_changed,
-};
-
-int sm_policy_ep_start(struct pw_remote *remote)
+int sm_policy_ep_start(struct sm_media_session *session)
{
struct impl *impl;
@@ -983,16 +557,12 @@ int sm_policy_ep_start(struct pw_remote *remote)
if (impl == NULL)
return -errno;
- impl->core = pw_remote_get_core(remote);
- impl->remote = remote;
-
- pw_map_init(&impl->globals, 64, 64);
+ impl->session = session;
+ impl->core = session->core;
- spa_list_init(&impl->client_list);
- spa_list_init(&impl->session_list);
spa_list_init(&impl->endpoint_list);
- pw_remote_add_listener(impl->remote, &impl->remote_listener, &remote_events, impl);
+ sm_media_session_add_listener(impl->session, &impl->listener, &session_events, impl);
return 0;
}
diff --git a/src/examples/media-session/stream-monitor.c b/src/examples/media-session/stream-monitor.c
index 190a8e9b..13d7e6bf 100644
--- a/src/examples/media-session/stream-monitor.c
+++ b/src/examples/media-session/stream-monitor.c
@@ -39,6 +39,7 @@
#include "pipewire/pipewire.h"
#include "pipewire/private.h"
#include "extensions/session-manager.h"
+#include "media-session.h"
#define NAME "stream-monitor"
@@ -48,76 +49,31 @@
struct client_endpoint;
struct impl {
- struct timespec now;
-
- struct pw_core *core;
- struct pw_remote *remote;
- struct spa_hook remote_listener;
-
- uint32_t session_id;
-
- struct pw_core_proxy *core_proxy;
- struct spa_hook core_listener;
-
- struct pw_registry_proxy *registry_proxy;
- struct spa_hook registry_listener;
-
- struct pw_map globals;
+ struct sm_media_session *session;
+ struct spa_hook listener;
- struct spa_list client_list;
- struct spa_list node_list;
int seq;
};
-struct object {
- struct impl *impl;
- uint32_t id;
- uint32_t type;
- struct pw_proxy *proxy;
- struct spa_hook listener;
-};
-
struct node {
- struct object obj;
+ struct sm_node *obj;
- struct spa_list l;
- struct client_endpoint *endpoint;
+ struct impl *impl;
+ struct spa_hook proxy_listener;
struct spa_hook listener;
- struct pw_node_info *info;
-
- struct spa_list port_list;
+ uint32_t id;
enum pw_direction direction;
-#define NODE_TYPE_UNKNOWN 0
-#define NODE_TYPE_STREAM 1
- uint32_t type;
char *media;
+ struct client_endpoint *endpoint;
+
uint32_t media_type;
uint32_t media_subtype;
struct spa_audio_info_raw format;
};
-struct endpoint {
- struct object obj;
-};
-
-struct port {
- struct object obj;
-
- struct spa_list l;
- enum pw_direction direction;
- struct pw_port_info *info;
- struct node *node;
-#define PORT_FLAG_NONE 0
-#define PORT_FLAG_DSP (1<<0)
-#define PORT_FLAG_SKIP (1<<1)
- uint32_t flags;
-
- struct spa_hook listener;
-};
-
struct stream {
struct pw_properties *props;
struct pw_endpoint_stream_info info;
@@ -138,29 +94,9 @@ struct client_endpoint {
struct pw_endpoint_info info;
struct stream stream;
+ uint32_t pending_config;
};
-static void add_object(struct impl *impl, struct object *obj)
-{
- size_t size = pw_map_get_size(&impl->globals);
- while (obj->id > size)
- pw_map_insert_at(&impl->globals, size++, NULL);
- pw_map_insert_at(&impl->globals, obj->id, obj);
-}
-
-static void remove_object(struct impl *impl, struct object *obj)
-{
- pw_map_insert_at(&impl->globals, obj->id, NULL);
-}
-
-static void *find_object(struct impl *impl, uint32_t id)
-{
- void *obj;
- if ((obj = pw_map_lookup(&impl->globals, id)) != NULL)
- return obj;
- return NULL;
-}
-
static int client_endpoint_set_id(void *object, uint32_t id)
{
struct client_endpoint *endpoint = object;
@@ -199,7 +135,7 @@ static int client_endpoint_create_link(void *object, const struct spa_dict *prop
struct client_endpoint *endpoint = object;
struct impl *impl = endpoint->impl;
const char *str;
- struct endpoint *ep;
+ struct sm_object *obj;
struct node *node = endpoint->node;
struct pw_properties *p;
int res;
@@ -214,14 +150,25 @@ static int client_endpoint_create_link(void *object, const struct spa_dict *prop
return -errno;
if (endpoint->info.direction == PW_DIRECTION_OUTPUT) {
- pw_properties_setf(p, PW_KEY_LINK_OUTPUT_NODE, "%d", endpoint->node->info->id);
+ pw_properties_setf(p, PW_KEY_LINK_OUTPUT_NODE, "%d", endpoint->node->id);
pw_properties_setf(p, PW_KEY_LINK_OUTPUT_PORT, "-1");
str = spa_dict_lookup(props, PW_KEY_LINK_INPUT_NODE);
} else {
- pw_properties_setf(p, PW_KEY_LINK_INPUT_NODE, "%d", endpoint->node->info->id);
+ pw_properties_setf(p, PW_KEY_LINK_INPUT_NODE, "%d", endpoint->node->id);
pw_properties_setf(p, PW_KEY_LINK_INPUT_PORT, "-1");
str = spa_dict_lookup(props, PW_KEY_LINK_OUTPUT_NODE);
}
+ if (str == NULL) {
+ pw_log_warn(NAME" %p: no target endpoint given", impl);
+ res = -EINVAL;
+ goto exit;
+ }
+ obj = sm_media_session_find_object(impl->session, atoi(str));
+ if (obj == NULL || obj->type != PW_TYPE_INTERFACE_Endpoint) {
+ pw_log_warn(NAME" %p: could not find object %s (%p)", impl, str, obj);
+ res = -EINVAL;
+ goto exit;
+ }
if (!endpoint->stream.active) {
char buf[1024];
@@ -242,25 +189,15 @@ static int client_endpoint_create_link(void *object, const struct spa_dict *prop
if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG))
spa_debug_pod(2, NULL, param);
- pw_node_proxy_set_param((struct pw_node_proxy*)node->obj.proxy,
+ pw_node_proxy_set_param((struct pw_node_proxy*)node->obj->obj.proxy,
SPA_PARAM_PortConfig, 0, param);
- endpoint->stream.active = true;
- }
-
- str = spa_dict_lookup(props, PW_KEY_LINK_INPUT_NODE);
- if (str == NULL) {
- res = -EINVAL;
- goto exit;
- }
+ endpoint->pending_config = pw_proxy_sync(node->obj->obj.proxy, 0);
- ep = find_object(impl, atoi(str));
- if (ep == NULL) {
- res = -EINVAL;
- goto exit;
+ endpoint->stream.active = true;
}
- pw_endpoint_proxy_create_link((struct pw_endpoint_proxy*)ep->obj.proxy, &p->dict);
+ pw_endpoint_proxy_create_link((struct pw_endpoint_proxy*)obj->proxy, &p->dict);
res = 0;
@@ -281,19 +218,19 @@ static const struct pw_client_endpoint_proxy_events client_endpoint_events = {
static struct client_endpoint *make_endpoint(struct node *node)
{
- struct impl *impl = node->obj.impl;
+ struct impl *impl = node->impl;
struct pw_properties *props;
struct client_endpoint *endpoint;
struct stream *s;
struct pw_proxy *proxy;
const char *str, *media_class = NULL, *name = NULL;
- struct spa_dict *dict = node->info->props;
props = pw_properties_new(NULL, NULL);
if (props == NULL)
return NULL;
- if (node->info && node->info->props) {
+ if (node->obj->info && node->obj->info->props) {
+ struct spa_dict *dict = node->obj->info->props;
if ((media_class = spa_dict_lookup(dict, PW_KEY_MEDIA_CLASS)) != NULL)
pw_properties_set(props, PW_KEY_MEDIA_CLASS, media_class);
if ((name = spa_dict_lookup(dict, PW_KEY_MEDIA_NAME)) != NULL)
@@ -302,7 +239,7 @@ static struct client_endpoint *make_endpoint(struct node *node)
pw_properties_set(props, PW_KEY_ENDPOINT_AUTOCONNECT, str);
}
- proxy = pw_core_proxy_create_object(impl->core_proxy,
+ proxy = sm_media_session_create_object(impl->session,
"client-endpoint",
PW_TYPE_INTERFACE_ClientEndpoint,
PW_VERSION_CLIENT_ENDPOINT_PROXY,
@@ -318,9 +255,9 @@ static struct client_endpoint *make_endpoint(struct node *node)
endpoint->props = props;
endpoint->client_endpoint = (struct pw_client_endpoint_proxy *) proxy;
endpoint->info.version = PW_VERSION_ENDPOINT_INFO;
- endpoint->info.name = (char*)pw_properties_get(endpoint->props, PW_KEY_ENDPOINT_NAME);
- endpoint->info.media_class = (char*)spa_dict_lookup(node->info->props, PW_KEY_MEDIA_CLASS);
- endpoint->info.session_id = impl->session_id;
+ endpoint->info.name = (char*)pw_properties_get(props, PW_KEY_ENDPOINT_NAME);
+ endpoint->info.media_class = (char*)pw_properties_get(props, PW_KEY_MEDIA_CLASS);
+ endpoint->info.session_id = impl->session->info.id;
endpoint->info.direction = node->direction;
endpoint->info.flags = 0;
endpoint->info.change_mask =
@@ -337,7 +274,7 @@ static struct client_endpoint *make_endpoint(struct node *node)
s = &endpoint->stream;
s->props = pw_properties_new(NULL, NULL);
- if ((str = spa_dict_lookup(dict, PW_KEY_MEDIA_CLASS)) != NULL)
+ if ((str = pw_properties_get(props, PW_KEY_MEDIA_CLASS)) != NULL)
pw_properties_set(s->props, PW_KEY_MEDIA_CLASS, str);
if (node->direction == PW_DIRECTION_OUTPUT)
pw_properties_set(s->props, PW_KEY_STREAM_NAME, "Playback");
@@ -351,7 +288,7 @@ static struct client_endpoint *make_endpoint(struct node *node)
s->info.change_mask = PW_ENDPOINT_STREAM_CHANGE_MASK_PROPS;
s->info.props = &s->props->dict;
- pw_log_debug("stream %d", node->obj.id);
+ pw_log_debug("stream %d", node->id);
pw_client_endpoint_proxy_stream_update(endpoint->client_endpoint,
s->info.id,
PW_CLIENT_ENDPOINT_STREAM_UPDATE_INFO,
@@ -365,24 +302,15 @@ static void destroy_endpoint(struct client_endpoint *endpoint)
pw_proxy_destroy((struct pw_proxy*)endpoint->client_endpoint);
}
-static void node_event_info(void *object, const struct pw_node_info *info)
-{
- struct node *n = object;
- struct impl *impl = n->obj.impl;
-
- pw_log_debug(NAME" %p: info for node %d type %d", impl, n->obj.id, n->type);
- n->info = pw_node_info_update(n->info, info);
-}
-
static void node_event_param(void *object, int seq,
uint32_t id, uint32_t index, uint32_t next,
const struct spa_pod *param)
{
struct node *n = object;
- struct impl *impl = n->obj.impl;
+ struct impl *impl = n->impl;
struct spa_audio_info_raw info = { 0, };
- pw_log_debug(NAME" %p: param for node %d, %d", impl, n->obj.id, id);
+ pw_log_debug(NAME" %p: param for node %d, %d", impl, n->id, id);
if (id != SPA_PARAM_EnumFormat)
goto error;
@@ -418,47 +346,60 @@ static void node_event_param(void *object, int seq,
static const struct pw_node_proxy_events node_events = {
PW_VERSION_NODE_PROXY_EVENTS,
- .info = node_event_info,
.param = node_event_param,
};
static void node_proxy_destroy(void *data)
{
struct node *n = data;
- struct impl *impl = n->obj.impl;
- struct port *p, *t;
+ struct impl *impl = n->impl;
- pw_log_debug(NAME " %p: proxy destroy node %d", impl, n->obj.id);
+ pw_log_debug(NAME " %p: proxy destroy node %d", impl, n->id);
- spa_list_remove(&n->l);
-
- spa_list_for_each_safe(p, t, &n->port_list, l) {
- spa_list_remove(&p->l);
- p->node = NULL;
- }
- if (n->info)
- pw_node_info_free(n->info);
if (n->endpoint)
destroy_endpoint(n->endpoint);
-
free(n->media);
}
+static void node_proxy_done(void *data, int seq)
+{
+ struct node *n = data;
+ struct impl *impl = n->impl;
+ struct client_endpoint *endpoint = n->endpoint;
+
+ if (endpoint == NULL)
+ return;
+ if (endpoint->pending_config != 0) {
+ pw_log_debug(NAME" %p: config complete", impl);
+ endpoint->pending_config = 0;
+ }
+}
+
+static void node_proxy_error(void *data, int seq, int res, const char *message)
+{
+ struct node *n = data;
+ struct impl *impl = n->impl;
+ pw_log_error(NAME " %p: proxy seq:%d got error %d: %s", impl, seq, res, message);
+}
+
static const struct pw_proxy_events node_proxy_events = {
PW_VERSION_PROXY_EVENTS,
.destroy = node_proxy_destroy,
+ .done = node_proxy_done,
+ .error = node_proxy_error,
};
static int
-handle_node(struct impl *impl, uint32_t id,
- uint32_t type, const struct spa_dict *props)
+handle_node(struct impl *impl, struct sm_object *obj)
{
const char *media_class;
enum pw_direction direction;
- struct pw_proxy *p;
struct node *node;
- media_class = props ? spa_dict_lookup(props, PW_KEY_MEDIA_CLASS) : NULL;
+ if (sm_object_get_data(obj, "stream-monitor") != NULL)
+ return 0;
+
+ media_class = obj->props ? pw_properties_get(obj->props, PW_KEY_MEDIA_CLASS) : NULL;
pw_log_debug(NAME" %p: node "PW_KEY_MEDIA_CLASS" %s", impl, media_class);
@@ -481,188 +422,23 @@ handle_node(struct impl *impl, uint32_t id,
else
return 0;
- p = pw_registry_proxy_bind(impl->registry_proxy,
- id, type, PW_VERSION_NODE_PROXY,
- sizeof(struct node));
-
- node = pw_proxy_get_user_data(p);
- node->obj.impl = impl;
- node->obj.id = id;
- node->obj.type = type;
- node->obj.proxy = p;
- spa_list_init(&node->port_list);
- pw_proxy_add_listener(p, &node->obj.listener, &node_proxy_events, node);
- pw_proxy_add_object_listener(p, &node->listener, &node_events, node);
- add_object(impl, &node->obj);
- spa_list_append(&impl->node_list, &node->l);
- node->type = NODE_TYPE_UNKNOWN;
-
+ node = sm_object_add_data(obj, "stream-monitor", sizeof(struct node));
+ node->obj = (struct sm_node*)obj;
+ node->impl = impl;
+ node->id = obj->id;
node->direction = direction;
- node->type = NODE_TYPE_STREAM;
node->media = strdup(media_class);
- pw_log_debug(NAME "%p: node %d is stream %s", impl, id, node->media);
+ pw_log_debug(NAME "%p: node %d is stream %s", impl, node->id, node->media);
- pw_node_proxy_enum_params((struct pw_node_proxy*)p,
+ pw_proxy_add_listener(obj->proxy, &node->proxy_listener, &node_proxy_events, node);
+ pw_proxy_add_object_listener(obj->proxy, &node->listener, &node_events, node);
+
+ pw_node_proxy_enum_params((struct pw_node_proxy*)obj->proxy,
0, SPA_PARAM_EnumFormat,
0, -1, NULL);
return 1;
}
-static void port_event_info(void *object, const struct pw_port_info *info)
-{
- struct port *p = object;
- pw_log_debug(NAME" %p: info for port %d", p->obj.impl, p->obj.id);
- p->info = pw_port_info_update(p->info, info);
-}
-
-static const struct pw_port_proxy_events port_events = {
- PW_VERSION_PORT_PROXY_EVENTS,
- .info = port_event_info,
-};
-
-static void port_proxy_destroy(void *data)
-{
- struct port *p = data;
-
- pw_log_debug(NAME " %p: proxy destroy port %d", p->obj.impl, p->obj.id);
-
- if (p->node) {
- spa_list_remove(&p->l);
- p->node = NULL;
- }
- if (p->info)
- pw_port_info_free(p->info);
-}
-
-static const struct pw_proxy_events port_proxy_events = {
- PW_VERSION_PROXY_EVENTS,
- .destroy = port_proxy_destroy,
-};
-
-static int
-handle_port(struct impl *impl, uint32_t id, uint32_t type,
- const struct spa_dict *props)
-{
- struct port *port;
- struct pw_proxy *p;
- struct node *node;
- const char *str;
- uint32_t node_id;
-
- if (props == NULL || (str = spa_dict_lookup(props, PW_KEY_NODE_ID)) == NULL)
- return -EINVAL;
-
- node_id = atoi(str);
-
- if ((node = find_object(impl, node_id)) == NULL)
- return 0;
-
- if (props == NULL || (str = spa_dict_lookup(props, PW_KEY_PORT_DIRECTION)) == NULL)
- return -EINVAL;
-
- p = pw_registry_proxy_bind(impl->registry_proxy,
- id, type, PW_VERSION_PORT_PROXY,
- sizeof(struct port));
-
- port = pw_proxy_get_user_data(p);
- port->obj.impl = impl;
- port->obj.id = id;
- port->obj.type = type;
- port->obj.proxy = p;
- port->node = node;
- port->direction = strcmp(str, "out") ? PW_DIRECTION_OUTPUT : PW_DIRECTION_INPUT;
-
- if (props != NULL && (str = spa_dict_lookup(props, PW_KEY_FORMAT_DSP)) != NULL)
- port->flags |= PORT_FLAG_DSP;
-
- pw_proxy_add_listener(p, &port->obj.listener, &port_proxy_events, port);
- pw_proxy_add_object_listener(p, &port->listener, &port_events, port);
- add_object(impl, &port->obj);
-
- spa_list_append(&node->port_list, &port->l);
-
- pw_log_debug(NAME" %p: new port %d for node %d type %d %08x", impl, id, node_id,
- node->type, port->flags);
-
- return 0;
-}
-
-static int
-handle_endpoint(struct impl *impl, uint32_t id, uint32_t type,
- const struct spa_dict *props)
-{
- struct endpoint *ep;
- struct pw_proxy *p;
-
- p = pw_registry_proxy_bind(impl->registry_proxy,
- id, type, PW_VERSION_ENDPOINT_PROXY,
- sizeof(struct endpoint));
-
- ep = pw_proxy_get_user_data(p);
- ep->obj.impl = impl;
- ep->obj.id = id;
- ep->obj.type = type;
- ep->obj.proxy = p;
- add_object(impl, &ep->obj);
-
- pw_log_debug(NAME" %p: new endpoint %d", impl, id);
-
- return 0;
-}
-
-static void
-registry_global(void *data,uint32_t id,
- uint32_t permissions, uint32_t type, uint32_t version,
- const struct spa_dict *props)
-{
- struct impl *impl = data;
- int res;
-
- pw_log_debug(NAME " %p: new global '%d' %d", impl, id, type);
-
- switch (type) {
- case PW_TYPE_INTERFACE_Node:
- res = handle_node(impl, id, type, props);
- break;
-
- case PW_TYPE_INTERFACE_Port:
- res = handle_port(impl, id, type, props);
- break;
-
- case PW_TYPE_INTERFACE_Endpoint:
- res = handle_endpoint(impl, id, type, props);
- break;
-
- default:
- res = 0;
- break;
- }
- if (res < 0) {
- pw_log_warn(NAME" %p: can't handle global %d: %s", impl, id, spa_strerror(res));
- }
-}
-
-static void
-registry_global_remove(void *data, uint32_t id)
-{
- struct impl *impl = data;
- struct object *obj;
-
- pw_log_debug(NAME " %p: remove global '%d'", impl, id);
-
- if ((obj = find_object(impl, id)) == NULL)
- return;
-
- remove_object(impl, obj);
-}
-
-static const struct pw_registry_proxy_events registry_events = {
- PW_VERSION_REGISTRY_PROXY_EVENTS,
- .global = registry_global,
- .global_remove = registry_global_remove,
-};
-
-
#if 0
static void stream_set_volume(struct impl *impl, struct node *node, float volume, bool mute)
{
@@ -723,7 +499,39 @@ static void rescan_session(struct impl *impl, struct session *sess)
}
#endif
-void * sm_stream_monitor_start(struct pw_remote *remote, int session_id)
+static void session_update(void *data, struct sm_object *object)
+{
+ struct impl *impl = data;
+ int res;
+
+ pw_log_debug(NAME " %p: update object '%d' %d", impl, object->id, object->type);
+
+ switch (object->type) {
+ case PW_TYPE_INTERFACE_Node:
+ res = handle_node(impl, object);
+ break;
+
+ default:
+ res = 0;
+ break;
+ }
+ if (res < 0) {
+ pw_log_warn(NAME" %p: can't handle global %d: %s", impl,
+ object->id, spa_strerror(res));
+ }
+}
+
+static void session_remove(void *data, struct sm_object *object)
+{
+}
+
+static const struct sm_media_session_events session_events = {
+ SM_VERSION_MEDIA_SESSION_EVENTS,
+ .update = session_update,
+ .remove = session_remove,
+};
+
+void * sm_stream_monitor_start(struct sm_media_session *session)
{
struct impl *impl;
@@ -731,26 +539,14 @@ void * sm_stream_monitor_start(struct pw_remote *remote, int session_id)
if (impl == NULL)
return NULL;
- impl->core = pw_remote_get_core(remote);
- impl->remote = remote;
- impl->session_id = session_id;
-
- pw_map_init(&impl->globals, 64, 64);
-
- spa_list_init(&impl->client_list);
- spa_list_init(&impl->node_list);
-
- impl->core_proxy = pw_remote_get_core_proxy(impl->remote);
- impl->registry_proxy = pw_core_proxy_get_registry(impl->core_proxy,
- PW_VERSION_REGISTRY_PROXY, 0);
- pw_registry_proxy_add_listener(impl->registry_proxy,
- &impl->registry_listener,
- &registry_events, impl);
+ impl->session = session;
+ sm_media_session_add_listener(session, &impl->listener, &session_events, impl);
return impl;
}
int sm_stream_monitor_stop(struct impl *impl)
{
+ spa_hook_remove(&impl->listener);
return 0;
}
diff --git a/src/examples/media-session/v4l2-monitor.c b/src/examples/media-session/v4l2-monitor.c
index 020ee979..e34c0367 100644
--- a/src/examples/media-session/v4l2-monitor.c
+++ b/src/examples/media-session/v4l2-monitor.c
@@ -132,7 +132,7 @@ static struct v4l2_node *v4l2_create_node(struct v4l2_object *obj, uint32_t id,
node->monitor = monitor;
node->object = obj;
node->id = id;
- node->proxy = pw_core_proxy_create_object(impl->core_proxy,
+ node->proxy = sm_media_session_create_object(impl->session,
"spa-node-factory",
PW_TYPE_INTERFACE_Node,
PW_VERSION_NODE_PROXY,
@@ -252,7 +252,7 @@ static struct v4l2_object *v4l2_create_object(struct monitor *monitor, uint32_t
const struct spa_device_object_info *info)
{
struct impl *impl = monitor->impl;
- struct pw_core *core = impl->core;
+ struct pw_core *core = impl->session->core;
struct v4l2_object *obj;
struct spa_handle *handle;
int res;
@@ -292,7 +292,7 @@ static struct v4l2_object *v4l2_create_object(struct monitor *monitor, uint32_t
obj->props = pw_properties_new_dict(info->props);
v4l2_update_device_props(obj);
- obj->proxy = pw_remote_export(impl->remote,
+ obj->proxy = sm_media_session_export(impl->session,
info->type, pw_properties_copy(obj->props), obj->device, 0);
if (obj->proxy == NULL) {
res = -errno;
@@ -356,7 +356,7 @@ static const struct spa_device_events v4l2_udev_callbacks =
static int v4l2_start_monitor(struct impl *impl, struct monitor *monitor)
{
struct spa_handle *handle;
- struct pw_core *core = impl->core;
+ struct pw_core *core = impl->session->core;
int res;
void *iface;