diff --git a/src/examples/media-session/alsa-endpoint.c b/src/examples/media-session/alsa-endpoint.c index a6dcaaeee..94f37aad9 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 6d9b80f29..3362359a9 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 c755d1a4c..50ffbc942 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 5b7893bb1..b26f90eec 100644 --- a/src/examples/media-session/media-session.c +++ b/src/examples/media-session/media-session.c @@ -43,40 +43,651 @@ #include +#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 on_state_changed(void *_data, enum pw_remote_state old, enum pw_remote_state state, const char *error) +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(impl->loop); + 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, + ®istry_events, impl); + start_session(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 +696,42 @@ 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 monitor_remote_events = { PW_VERSION_REMOTE_EVENTS, - .state_changed = on_state_changed, + .state_changed = on_monitor_state_changed, +}; + +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(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(sess->loop); + break; + + default: + printf("remote state: \"%s\"\n", pw_remote_state_as_string(state)); + break; + } +} + +static const struct pw_remote_events policy_remote_events = { + PW_VERSION_REMOTE_EVENTS, + .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 000000000..1001f43a3 --- /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 44f0995ee..3e3a4905c 100644 --- a/src/examples/media-session/monitor.c +++ b/src/examples/media-session/monitor.c @@ -43,11 +43,13 @@ #include +#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); - + 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 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; - } -} - -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 cc3d44077..d1194f3fe 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 sm_media_session *session; + struct spa_hook listener; + 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 pw_map globals; - - 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 sm_endpoint_stream *obj; + + uint32_t id; + struct impl *impl; - 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); - - 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); -} - -static const struct pw_proxy_events endpoint_proxy_events = { - PW_VERSION_PROXY_EVENTS, - .destroy = endpoint_proxy_destroy, }; 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; + if (sm_object_get_data(object, "policy-endpoint") != NULL) + return 0; - endpoint_id = atoi(str); + if (stream->endpoint == NULL) + return 0; - if ((ep = find_object(impl, endpoint_id)) == NULL) - return -ESRCH; + ep = sm_object_get_data(&stream->endpoint->obj, "policy-endpoint"); + if (ep == NULL) + return 0; - p = pw_registry_proxy_bind(impl->registry_proxy, - id, type, PW_VERSION_ENDPOINT_STREAM_PROXY, - sizeof(struct stream)); - - 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); + 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; + } - if ((obj = find_object(impl, id)) == NULL) - return; - - 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); + pw_log_debug(NAME " %p: link endpoints %d %d %d", impl, max, endpoint->id, peer->id); - if (endpoint->session == NULL) { - pw_log_debug(NAME " %p: endpoint has no session", impl); - return -EINVAL; + 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); + + } + 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); } - spa_list_for_each(s, &endpoint->stream_list, l) { - struct pw_properties *props; + pw_endpoint_proxy_create_link((struct pw_endpoint_proxy*)endpoint->obj->obj.proxy, + &props->dict); - pw_log_debug(NAME " %p: stream %p: %d %d", impl, s, s->direction, s->flags); + pw_properties_free(props); - 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->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.proxy, - &props->dict); - - 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, - ®istry_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; + impl->session = session; + impl->core = session->core; - pw_map_init(&impl->globals, 64, 64); - - 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 190a8e9bf..13d7e6bf1 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 sm_media_session *session; + struct spa_hook listener; - 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 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->pending_config = pw_proxy_sync(node->obj->obj.proxy, 0); + endpoint->stream.active = true; } - str = spa_dict_lookup(props, PW_KEY_LINK_INPUT_NODE); - if (str == NULL) { - res = -EINVAL; - goto exit; - } - - ep = find_object(impl, atoi(str)); - if (ep == NULL) { - res = -EINVAL; - goto exit; - } - - 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, - ®istry_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 020ee9794..e34c0367e 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;