diff --git a/src/examples/media-session/alsa-endpoint.c b/src/examples/media-session/alsa-endpoint.c index 5cd0a6521..275a25a97 100644 --- a/src/examples/media-session/alsa-endpoint.c +++ b/src/examples/media-session/alsa-endpoint.c @@ -62,6 +62,7 @@ struct endpoint { struct spa_hook listener; struct pw_client_endpoint_proxy *client_endpoint; + struct spa_hook proxy_listener; struct spa_hook client_endpoint_listener; struct pw_endpoint_info info; @@ -79,6 +80,7 @@ struct endpoint { struct stream { struct spa_list link; + struct endpoint *endpoint; struct pw_properties *props; struct pw_endpoint_stream_info info; @@ -89,17 +91,15 @@ struct stream { }; struct node { - struct spa_list link; - struct impl *impl; struct sm_node *node; + struct device *device; + struct endpoint *endpoint; }; struct device { - struct spa_list link; - struct impl *impl; uint32_t id; struct sm_device *device; @@ -113,13 +113,6 @@ struct impl { struct spa_hook listener; }; -static int client_endpoint_set_id(void *object, uint32_t id) -{ - struct endpoint *endpoint = object; - endpoint->info.id = id; - return 0; -} - static int client_endpoint_set_session_id(void *object, uint32_t id) { struct endpoint *endpoint = object; @@ -228,7 +221,6 @@ exit: static const struct pw_client_endpoint_proxy_events client_endpoint_events = { PW_VERSION_CLIENT_ENDPOINT_PROXY_EVENTS, - .set_id = client_endpoint_set_id, .set_session_id = client_endpoint_set_session_id, .set_param = client_endpoint_set_param, .stream_set_param = client_endpoint_stream_set_param, @@ -245,6 +237,8 @@ static struct stream *endpoint_add_stream(struct endpoint *endpoint) return NULL; s->props = pw_properties_new(NULL, NULL); + s->endpoint = endpoint; + if ((str = pw_properties_get(endpoint->props, PW_KEY_MEDIA_CLASS)) != NULL) pw_properties_set(s->props, PW_KEY_MEDIA_CLASS, str); if ((str = pw_properties_get(endpoint->props, PW_KEY_PRIORITY_SESSION)) != NULL) @@ -279,6 +273,23 @@ static struct stream *endpoint_add_stream(struct endpoint *endpoint) return s; } +static void destroy_stream(struct stream *stream) +{ + struct endpoint *endpoint = stream->endpoint; + + pw_client_endpoint_proxy_stream_update(endpoint->client_endpoint, + stream->info.id, + PW_CLIENT_ENDPOINT_STREAM_UPDATE_DESTROYED, + 0, NULL, + &stream->info); + + spa_list_remove(&stream->link); + endpoint->info.n_streams--; + + pw_properties_free(stream->props); + free(stream); +} + static void update_params(void *data) { uint32_t n_params; @@ -309,7 +320,7 @@ static void update_params(void *data) &endpoint->info); } -static struct endpoint *make_endpoint(struct node *node, struct endpoint *monitor); +static struct endpoint *create_endpoint(struct node *node, struct endpoint *monitor); static void object_update(void *data) { @@ -371,7 +382,7 @@ static void complete_endpoint(void *data) struct endpoint *monitor; /* make monitor for sinks */ - monitor = make_endpoint(endpoint->node, endpoint); + monitor = create_endpoint(endpoint->node, endpoint); if (monitor == NULL) return; @@ -382,42 +393,85 @@ static void complete_endpoint(void *data) sm_object_add_listener(&endpoint->node->node->obj, &endpoint->listener, &object_events, endpoint); } -static struct endpoint *make_endpoint(struct node *node, struct endpoint *monitor) +static void proxy_destroy(void *data) +{ + struct endpoint *endpoint = data; + struct stream *s; + + spa_list_consume(s, &endpoint->stream_list, link) + destroy_stream(s); + + pw_properties_free(endpoint->props); + spa_list_remove(&endpoint->link); +} + +static void proxy_bound(void *data, uint32_t id) +{ + struct endpoint *endpoint = data; + endpoint->info.id = id; +} + +static const struct pw_proxy_events proxy_events = { + PW_VERSION_PROXY_EVENTS, + .destroy = proxy_destroy, + .bound = proxy_bound, +}; + +static struct endpoint *create_endpoint(struct node *node, struct endpoint *monitor) { struct impl *impl = node->impl; + struct device *device = node->device; struct pw_properties *props; struct endpoint *endpoint; struct pw_proxy *proxy; const char *str, *media_class = NULL, *name = NULL; uint32_t subscribe[4], n_subscribe = 0; struct pw_properties *pr = node->node->obj.props; + enum pw_direction direction; + + if (pr == NULL) { + errno = EINVAL; + return NULL; + } + + if ((media_class = pw_properties_get(pr, PW_KEY_MEDIA_CLASS)) == NULL) { + errno = EINVAL; + return NULL; + } props = pw_properties_new(NULL, NULL); if (props == NULL) return NULL; - if (pr) { - if ((media_class = pw_properties_get(pr, PW_KEY_MEDIA_CLASS)) != NULL) { - if (monitor != NULL) { - pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Source"); - } else { - pw_properties_set(props, PW_KEY_MEDIA_CLASS, media_class); - } - } - if ((str = pw_properties_get(pr, PW_KEY_PRIORITY_SESSION)) != NULL) - pw_properties_set(props, PW_KEY_PRIORITY_SESSION, str); - if ((name = pw_properties_get(pr, PW_KEY_NODE_DESCRIPTION)) != NULL) { - if (monitor != NULL) { - pw_properties_setf(props, PW_KEY_ENDPOINT_NAME, "Monitor of %s", monitor->info.name); - pw_properties_setf(props, PW_KEY_ENDPOINT_MONITOR, "%d", monitor->info.id); - } else { - pw_properties_set(props, PW_KEY_ENDPOINT_NAME, name); - } - } - if ((str = pw_properties_get(pr, PW_KEY_DEVICE_ICON_NAME)) != NULL) - pw_properties_set(props, PW_KEY_ENDPOINT_ICON_NAME, str); + if (strstr(media_class, "Source") != NULL) { + direction = PW_DIRECTION_OUTPUT; + } else if (strstr(media_class, "Sink") != NULL) { + direction = PW_DIRECTION_INPUT; + } else { + errno = EINVAL; + return NULL; } + if (monitor != NULL) { + pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Source"); + direction = PW_DIRECTION_OUTPUT; + } else { + pw_properties_set(props, PW_KEY_MEDIA_CLASS, media_class); + } + + if ((str = pw_properties_get(pr, PW_KEY_PRIORITY_SESSION)) != NULL) + pw_properties_set(props, PW_KEY_PRIORITY_SESSION, str); + if ((name = pw_properties_get(pr, PW_KEY_NODE_DESCRIPTION)) != NULL) { + if (monitor != NULL) { + pw_properties_setf(props, PW_KEY_ENDPOINT_NAME, "Monitor of %s", monitor->info.name); + pw_properties_setf(props, PW_KEY_ENDPOINT_MONITOR, "%d", monitor->info.id); + } else { + pw_properties_set(props, PW_KEY_ENDPOINT_NAME, name); + } + } + if ((str = pw_properties_get(pr, PW_KEY_DEVICE_ICON_NAME)) != NULL) + pw_properties_set(props, PW_KEY_ENDPOINT_ICON_NAME, str); + proxy = sm_media_session_create_object(impl->session, "client-endpoint", PW_TYPE_INTERFACE_ClientEndpoint, @@ -429,6 +483,7 @@ static struct endpoint *make_endpoint(struct node *node, struct endpoint *monito } endpoint = pw_proxy_get_user_data(proxy); + endpoint->impl = impl; endpoint->node = node; endpoint->monitor = monitor; endpoint->props = props; @@ -437,7 +492,7 @@ static struct endpoint *make_endpoint(struct node *node, struct endpoint *monito endpoint->info.name = (char*)pw_properties_get(endpoint->props, PW_KEY_ENDPOINT_NAME); endpoint->info.media_class = (char*)pw_properties_get(endpoint->props, PW_KEY_MEDIA_CLASS); endpoint->info.session_id = impl->session->session->obj.id; - endpoint->info.direction = monitor != NULL ? PW_DIRECTION_OUTPUT : PW_DIRECTION_INPUT; + endpoint->info.direction = direction; endpoint->info.flags = 0; endpoint->info.change_mask = PW_ENDPOINT_CHANGE_MASK_STREAMS | @@ -453,6 +508,9 @@ static struct endpoint *make_endpoint(struct node *node, struct endpoint *monito spa_list_init(&endpoint->stream_list); pw_log_debug(NAME" %p: new endpoint %p for alsa node %p", impl, endpoint, node); + pw_proxy_add_listener(proxy, + &endpoint->proxy_listener, + &proxy_events, endpoint); pw_client_endpoint_proxy_add_listener(endpoint->client_endpoint, &endpoint->client_endpoint_listener, @@ -467,12 +525,19 @@ static struct endpoint *make_endpoint(struct node *node, struct endpoint *monito pw_node_proxy_subscribe_params((struct pw_node_proxy*)node->node->obj.proxy, subscribe, n_subscribe); + spa_list_append(&device->endpoint_list, &endpoint->link); + if (monitor == NULL) sm_media_session_sync(impl->session, complete_endpoint, endpoint); return endpoint; } +static void destroy_endpoint(struct endpoint *endpoint) +{ + pw_proxy_destroy((struct pw_proxy*)endpoint->client_endpoint); +} + /** fallback, one stream for each node */ static int setup_alsa_fallback_endpoint(struct device *device) { @@ -488,9 +553,10 @@ static int setup_alsa_fallback_endpoint(struct device *device) pw_log_debug(NAME" %p: device %p has node %p", impl, d, n); node = sm_object_add_data(&n->obj, SESSION_KEY, sizeof(struct node)); + node->device = device; node->node = n; node->impl = impl; - node->endpoint = make_endpoint(node, NULL); + node->endpoint = create_endpoint(node, NULL); if (node->endpoint == NULL) return -errno; } @@ -550,7 +616,7 @@ exit: return res; } -static int setup_alsa_endpoint(struct device *device) +static int activate_device(struct device *device) { int res; @@ -560,6 +626,14 @@ static int setup_alsa_endpoint(struct device *device) return res; } +static int deactivate_device(struct device *device) +{ + struct endpoint *e; + spa_list_consume(e, &device->endpoint_list, link) + destroy_endpoint(e); + return 0; +} + static void device_update(void *data) { struct device *device = data; @@ -567,11 +641,13 @@ static void device_update(void *data) pw_log_debug(NAME" %p: device %p %08x %08x", impl, device, device->device->obj.avail, device->device->obj.changed); - if (!(device->device->obj.avail & SM_DEVICE_CHANGE_MASK_INFO)) + + if (!SPA_FLAG_IS_SET(device->device->obj.avail, + SM_DEVICE_CHANGE_MASK_INFO | SM_DEVICE_CHANGE_MASK_PARAMS)) return; if (device->device->obj.changed & SM_DEVICE_CHANGE_MASK_PARAMS) { - setup_alsa_endpoint(device); + activate_device(device); } } @@ -603,6 +679,7 @@ handle_device(struct impl *impl, struct sm_object *obj) device->impl = impl; device->id = obj->id; device->device = (struct sm_device*)obj; + spa_list_init(&device->endpoint_list); pw_log_debug(NAME" %p: found alsa device %d media_class %s", impl, obj->id, media_class); sm_object_add_listener(obj, &device->listener, &device_events, device); @@ -610,6 +687,12 @@ handle_device(struct impl *impl, struct sm_object *obj) return 0; } +static void destroy_device(struct device *device) +{ + deactivate_device(device); + spa_hook_remove(&device->listener); +} + static void session_create(void *data, struct sm_object *object) { struct impl *impl = data; @@ -634,7 +717,12 @@ static void session_remove(void *data, struct sm_object *object) { switch (object->type) { case PW_TYPE_INTERFACE_Device: + { + struct device *device; + if ((device = sm_object_get_data(object, SESSION_KEY)) != NULL) + destroy_device(device); break; + } default: break; } diff --git a/src/examples/media-session/alsa-monitor.c b/src/examples/media-session/alsa-monitor.c index 1cb8d9194..3ba423700 100644 --- a/src/examples/media-session/alsa-monitor.c +++ b/src/examples/media-session/alsa-monitor.c @@ -55,7 +55,7 @@ struct node { struct impl *impl; enum pw_direction direction; - struct device *object; + struct device *device; struct spa_list link; uint32_t id; @@ -77,14 +77,19 @@ struct device { int seq; int priority; + int profile; + struct pw_properties *props; struct spa_handle *handle; - struct pw_proxy *proxy; struct spa_device *device; struct spa_hook device_listener; + struct sm_device *sdevice; + struct spa_hook listener; + unsigned int first:1; + unsigned int appeared:1; struct spa_list node_list; }; @@ -107,18 +112,18 @@ struct impl { #undef NAME #define NAME "alsa-monitor" -static struct node *alsa_find_node(struct device *obj, uint32_t id) +static struct node *alsa_find_node(struct device *device, uint32_t id) { struct node *node; - spa_list_for_each(node, &obj->node_list, link) { + spa_list_for_each(node, &device->node_list, link) { if (node->id == id) return node; } return NULL; } -static void alsa_update_node(struct device *obj, struct node *node, +static void alsa_update_node(struct device *device, struct node *node, const struct spa_device_object_info *info) { pw_log_debug("update node %u", node->id); @@ -129,11 +134,11 @@ static void alsa_update_node(struct device *obj, struct node *node, pw_properties_update(node->props, info->props); } -static struct node *alsa_create_node(struct device *obj, uint32_t id, +static struct node *alsa_create_node(struct device *device, uint32_t id, const struct spa_device_object_info *info) { struct node *node; - struct impl *impl = obj->impl; + struct impl *impl = device->impl; int res; const char *dev, *subdev, *stream; int priority; @@ -152,8 +157,7 @@ static struct node *alsa_create_node(struct device *obj, uint32_t id, node->props = pw_properties_new_dict(info->props); - if (obj->device_id != 0) - pw_properties_setf(node->props, PW_KEY_DEVICE_ID, "%d", obj->device_id); + pw_properties_setf(node->props, PW_KEY_DEVICE_ID, "%d", device->device_id); pw_properties_set(node->props, "factory.name", info->factory_name); @@ -169,13 +173,13 @@ static struct node *alsa_create_node(struct device *obj, uint32_t id, else node->direction = PW_DIRECTION_INPUT; - if (obj->first) { + if (device->first) { if (atol(dev) != 0) - obj->priority -= 256; - obj->first = false; + device->priority -= 256; + device->first = false; } - priority = obj->priority; + priority = device->priority; if (!strcmp(stream, "capture")) priority += 1000; priority -= atol(dev) * 16; @@ -194,7 +198,7 @@ static struct node *alsa_create_node(struct device *obj, uint32_t id, } if (pw_properties_get(node->props, SPA_KEY_NODE_NAME) == NULL) { const char *devname; - if ((devname = pw_properties_get(obj->props, SPA_KEY_DEVICE_NAME)) == NULL) + if ((devname = pw_properties_get(device->props, SPA_KEY_DEVICE_NAME)) == NULL) devname = "unknown"; pw_properties_setf(node->props, SPA_KEY_NODE_NAME, "%s.%s.%s.%s", devname, stream, dev, subdev); @@ -202,7 +206,7 @@ static struct node *alsa_create_node(struct device *obj, uint32_t id, if (pw_properties_get(node->props, PW_KEY_NODE_DESCRIPTION) == NULL) { const char *desc, *name = NULL; - if ((desc = pw_properties_get(obj->props, SPA_KEY_DEVICE_DESCRIPTION)) == NULL) + if ((desc = pw_properties_get(device->props, SPA_KEY_DEVICE_DESCRIPTION)) == NULL) desc = "unknown"; name = pw_properties_get(node->props, SPA_KEY_API_ALSA_PCM_NAME); @@ -224,17 +228,16 @@ static struct node *alsa_create_node(struct device *obj, uint32_t id, } node->impl = impl; - node->object = obj; + node->device = device; node->id = id; node->snode = sm_media_session_create_node(impl->session, "adapter", - &node->props->dict, - 0); + &node->props->dict); if (node->snode == NULL) { res = -errno; goto clean_node; } - spa_list_append(&obj->node_list, &node->link); + spa_list_append(&device->node_list, &node->link); return node; @@ -246,7 +249,7 @@ exit: return NULL; } -static void alsa_remove_node(struct device *obj, struct node *node) +static void alsa_remove_node(struct device *device, struct node *node) { pw_log_debug("remove node %u", node->id); spa_list_remove(&node->link); @@ -256,36 +259,32 @@ static void alsa_remove_node(struct device *obj, struct node *node) static void alsa_device_info(void *data, const struct spa_device_info *info) { - struct device *obj = data; - const char *str; + struct device *device = data; if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG)) spa_debug_dict(0, info->props); - pw_properties_update(obj->props, info->props); - - if ((str = pw_properties_get(obj->props, PW_KEY_DEVICE_ID)) != NULL) - obj->device_id = pw_properties_parse_int(str); + pw_properties_update(device->props, info->props); } static void alsa_device_object_info(void *data, uint32_t id, const struct spa_device_object_info *info) { - struct device *obj = data; + struct device *device = data; struct node *node; - node = alsa_find_node(obj, id); + node = alsa_find_node(device, id); if (info == NULL) { if (node == NULL) { - pw_log_warn("object %p: unknown node %u", obj, id); + pw_log_warn("device %p: unknown node %u", device, id); return; } - alsa_remove_node(obj, node); + alsa_remove_node(device, node); } else if (node == NULL) { - alsa_create_node(obj, id, info); + alsa_create_node(device, id, info); } else { - alsa_update_node(obj, node, info); + alsa_update_node(device, node, info); } } @@ -297,11 +296,11 @@ static const struct spa_device_events alsa_device_events = { static struct device *alsa_find_device(struct impl *impl, uint32_t id) { - struct device *obj; + struct device *device; - spa_list_for_each(obj, &impl->device_list, link) { - if (obj->id == id) - return obj; + spa_list_for_each(device, &impl->device_list, link) { + if (device->id == id) + return device; } return NULL; } @@ -412,11 +411,17 @@ static void set_profile(struct device *device, int index) { char buf[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); - spa_device_set_param(device->device, - SPA_PARAM_Profile, 0, - spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_ParamProfile, SPA_PARAM_Profile, - SPA_PARAM_PROFILE_index, SPA_POD_Int(index))); + + pw_log_debug("%p: set profile %d", device, device->device_id); + + device->profile = index; + if (device->device_id != 0) { + spa_device_set_param(device->device, + SPA_PARAM_Profile, 0, + spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamProfile, SPA_PARAM_Profile, + SPA_PARAM_PROFILE_index, SPA_POD_Int(index))); + } } static void remove_jack_timeout(struct impl *impl) @@ -459,8 +464,6 @@ static void reserve_acquired(void *data, struct rd_device *d) remove_jack_timeout(impl); set_jack_profile(impl, 0); set_profile(device, 1); - -// setup_alsa_endpoint(device); } static void sync_complete_done(void *data, int seq) @@ -496,10 +499,10 @@ static void reserve_release(void *data, struct rd_device *d, int forced) set_profile(device, 0); if (device->seq == 0) - pw_proxy_add_listener(device->proxy, + pw_proxy_add_listener(device->sdevice->obj.proxy, &device->sync_listener, &sync_complete_release, device); - device->seq = pw_proxy_sync(device->proxy, 0); + device->seq = pw_proxy_sync(device->sdevice->obj.proxy, 0); } static const struct rd_device_callbacks reserve_callbacks = { @@ -507,6 +510,32 @@ static const struct rd_device_callbacks reserve_callbacks = { .release = reserve_release, }; + +static void device_update(void *data) +{ + struct device *device = data; + + pw_log_debug("device %p appeared %d %d", device, device->appeared, device->profile); + + if (device->appeared) + return; + + device->device_id = device->sdevice->obj.id; + device->appeared = true; + + spa_device_add_listener(device->device, + &device->device_listener, + &alsa_device_events, device); + + set_profile(device, device->profile); + +} + +static const struct sm_object_events device_events = { + SM_VERSION_OBJECT_EVENTS, + .update = device_update, +}; + static struct device *alsa_create_device(struct impl *impl, uint32_t id, const struct spa_device_object_info *info) { @@ -552,15 +581,18 @@ static struct device *alsa_create_device(struct impl *impl, uint32_t id, device->priority = 1000; update_device_props(device); - device->proxy = sm_media_session_export(impl->session, - info->type, + device->sdevice = sm_media_session_export_device(impl->session, pw_properties_copy(device->props), - device->device, 0); - if (device->proxy == NULL) { + device->device); + if (device->sdevice == NULL) { res = -errno; goto clean_device; } + sm_object_add_listener(&device->sdevice->obj, + &device->listener, + &device_events, device); + if ((card = spa_dict_lookup(info->props, SPA_KEY_API_ALSA_CARD)) != NULL) { const char *reserve; @@ -586,10 +618,6 @@ static struct device *alsa_create_device(struct impl *impl, uint32_t id, device->first = true; spa_list_init(&device->node_list); - - spa_device_add_listener(device->device, - &device->device_listener, &alsa_device_events, device); - spa_list_append(&impl->device_list, &device->link); return device; @@ -603,37 +631,39 @@ exit: return NULL; } -static void alsa_remove_device(struct impl *impl, struct device *obj) +static void alsa_remove_device(struct impl *impl, struct device *device) { - pw_log_debug("remove device %u", obj->id); - spa_list_remove(&obj->link); - spa_hook_remove(&obj->device_listener); - if (obj->seq != 0) - spa_hook_remove(&obj->sync_listener); - if (obj->reserve) - rd_device_destroy(obj->reserve); - pw_proxy_destroy(obj->proxy); - pw_unload_spa_handle(obj->handle); - free(obj); + pw_log_debug("remove device %u", device->id); + spa_list_remove(&device->link); + spa_hook_remove(&device->listener); + spa_hook_remove(&device->device_listener); + if (device->seq != 0) + spa_hook_remove(&device->sync_listener); + if (device->reserve) + rd_device_destroy(device->reserve); + if (device->sdevice) + sm_object_destroy(&device->sdevice->obj); + pw_unload_spa_handle(device->handle); + free(device); } static void alsa_udev_object_info(void *data, uint32_t id, const struct spa_device_object_info *info) { struct impl *impl = data; - struct device *obj; + struct device *device; - obj = alsa_find_device(impl, id); + device = alsa_find_device(impl, id); if (info == NULL) { - if (obj == NULL) + if (device == NULL) return; - alsa_remove_device(impl, obj); - } else if (obj == NULL) { - if ((obj = alsa_create_device(impl, id, info)) == NULL) + alsa_remove_device(impl, device); + } else if (device == NULL) { + if ((device = alsa_create_device(impl, id, info)) == NULL) return; } else { - alsa_update_device(impl, obj, info); + alsa_update_device(impl, device, info); } } @@ -663,6 +693,8 @@ static int alsa_start_jack_device(struct impl *impl) if (impl->jack_device == NULL) res = -errno; + pw_properties_free(props); + return res; } diff --git a/src/examples/media-session/media-session.c b/src/examples/media-session/media-session.c index f55f8340f..c4a0de3e3 100644 --- a/src/examples/media-session/media-session.c +++ b/src/examples/media-session/media-session.c @@ -109,6 +109,7 @@ struct impl { struct spa_hook_list hooks; struct pw_client_session_proxy *client_session; + struct spa_hook client_session_proxy_listener; struct spa_hook client_session_listener; struct spa_list endpoint_link_list; /** list of struct endpoint_link */ @@ -143,6 +144,15 @@ struct link { struct spa_list link; /**< link in struct endpoint_link link_list */ }; +struct object_info { + uint32_t type; + uint32_t version; + const void *events; + size_t size; + int (*init) (void *object); + void (*destroy) (void *object); +}; + static void add_object(struct impl *impl, struct sm_object *obj) { size_t size = pw_map_get_size(&impl->globals); @@ -291,6 +301,15 @@ static void client_destroy(void *object) pw_client_info_free(client->info); } +static const struct object_info client_info = { + .type = PW_TYPE_INTERFACE_Client, + .version = PW_VERSION_CLIENT_PROXY, + .events = &client_events, + .size = sizeof(struct sm_client), + .init = NULL, + .destroy = client_destroy, +}; + /** * Device */ @@ -335,6 +354,14 @@ static const struct pw_device_proxy_events device_events = { .param = device_event_param, }; +static int device_init(void *object) +{ + struct sm_device *device = object; + spa_list_init(&device->node_list); + spa_list_init(&device->param_list); + return 0; +} + static void device_destroy(void *object) { struct sm_device *device = object; @@ -351,6 +378,23 @@ static void device_destroy(void *object) pw_device_info_free(device->info); } +static const struct object_info device_info = { + .type = PW_TYPE_INTERFACE_Device, + .version = PW_VERSION_DEVICE_PROXY, + .events = &device_events, + .size = sizeof(struct sm_device), + .init = device_init, + .destroy = device_destroy, +}; + +static const struct object_info spa_device_info = { + .type = SPA_TYPE_INTERFACE_Device, + .version = SPA_VERSION_DEVICE, + .size = sizeof(struct sm_device), + .init = device_init, + .destroy = device_destroy, +}; + /** * Node */ @@ -363,12 +407,6 @@ static void node_event_info(void *object, const struct pw_node_info *info) pw_log_debug(NAME" %p: node %d info", impl, node->obj.id); node->info = pw_node_info_update(node->info, info); - if (node->obj.id == SPA_ID_INVALID) { - node->obj.id = info->id; - pw_log_debug(NAME" %p: node %d added", impl, node->obj.id); - add_object(impl, &node->obj); - } - node->obj.avail |= SM_NODE_CHANGE_MASK_INFO; node->obj.changed |= SM_NODE_CHANGE_MASK_INFO; @@ -428,6 +466,28 @@ static const struct pw_node_proxy_events node_events = { .param = node_event_param, }; +static int node_init(void *object) +{ + struct sm_node *node = object; + struct impl *impl = SPA_CONTAINER_OF(node->obj.session, struct impl, this); + struct pw_properties *props = node->obj.props; + const char *str; + + spa_list_init(&node->port_list); + spa_list_init(&node->param_list); + + if (props) { + if ((str = pw_properties_get(props, PW_KEY_DEVICE_ID)) != NULL) + node->device = find_object(impl, atoi(str)); + pw_log_debug(NAME" %p: node %d parent device %s", impl, node->obj.id, str); + if (node->device) { + spa_list_append(&node->device->node_list, &node->link); + node->device->obj.changed |= SM_DEVICE_CHANGE_MASK_NODES; + } + } + return 0; +} + static void node_destroy(void *object) { struct sm_node *node = object; @@ -448,6 +508,15 @@ static void node_destroy(void *object) pw_node_info_free(node->info); } +static const struct object_info node_info = { + .type = PW_TYPE_INTERFACE_Node, + .version = PW_VERSION_NODE_PROXY, + .events = &node_events, + .size = sizeof(struct sm_node), + .init = node_init, + .destroy = node_destroy, +}; + /** * Port */ @@ -469,6 +538,30 @@ static const struct pw_port_proxy_events port_events = { .info = port_event_info, }; +static int port_init(void *object) +{ + struct sm_port *port = object; + struct impl *impl = SPA_CONTAINER_OF(port->obj.session, struct impl, this); + struct pw_properties *props = port->obj.props; + const char *str; + + if (props) { + if ((str = pw_properties_get(props, PW_KEY_PORT_DIRECTION)) != NULL) + port->direction = strcmp(str, "out") == 0 ? + PW_DIRECTION_OUTPUT : PW_DIRECTION_INPUT; + if ((str = pw_properties_get(props, PW_KEY_NODE_ID)) != NULL) + port->node = find_object(impl, atoi(str)); + + pw_log_debug(NAME" %p: port %d parent node %s direction:%d", impl, + port->obj.id, str, port->direction); + if (port->node) { + spa_list_append(&port->node->port_list, &port->link); + port->node->obj.changed |= SM_NODE_CHANGE_MASK_PORTS; + } + } + return 0; +} + static void port_destroy(void *object) { struct sm_port *port = object; @@ -480,6 +573,15 @@ static void port_destroy(void *object) } } +static const struct object_info port_info = { + .type = PW_TYPE_INTERFACE_Port, + .version = PW_VERSION_PORT_PROXY, + .events = &port_events, + .size = sizeof(struct sm_port), + .init = port_init, + .destroy = port_destroy, +}; + /** * Session */ @@ -512,6 +614,18 @@ static const struct pw_session_proxy_events session_events = { .info = session_event_info, }; +static int session_init(void *object) +{ + struct sm_session *sess = object; + struct impl *impl = SPA_CONTAINER_OF(sess->obj.session, struct impl, this); + + if (sess->obj.id == impl->session_id) + impl->this.session = sess; + + spa_list_init(&sess->endpoint_list); + return 0; +} + static void session_destroy(void *object) { struct sm_session *sess = object; @@ -527,6 +641,15 @@ static void session_destroy(void *object) } } +static const struct object_info session_info = { + .type = PW_TYPE_INTERFACE_Session, + .version = PW_VERSION_SESSION_PROXY, + .events = &session_events, + .size = sizeof(struct sm_session), + .init = session_init, + .destroy = session_destroy, +}; + /** * Endpoint */ @@ -568,6 +691,28 @@ static const struct pw_endpoint_proxy_events endpoint_events = { .info = endpoint_event_info, }; +static int endpoint_init(void *object) +{ + struct sm_endpoint *endpoint = object; + struct impl *impl = SPA_CONTAINER_OF(endpoint->obj.session, struct impl, this); + struct pw_properties *props = endpoint->obj.props; + const char *str; + + if (props) { + if ((str = pw_properties_get(props, PW_KEY_SESSION_ID)) != NULL) + endpoint->session = find_object(impl, atoi(str)); + pw_log_debug(NAME" %p: endpoint %d parent session %s", impl, + endpoint->obj.id, str); + if (endpoint->session) { + spa_list_append(&endpoint->session->endpoint_list, &endpoint->link); + endpoint->session->obj.changed |= SM_SESSION_CHANGE_MASK_ENDPOINTS; + } + } + spa_list_init(&endpoint->stream_list); + + return 0; +} + static void endpoint_destroy(void *object) { struct sm_endpoint *endpoint = object; @@ -589,6 +734,16 @@ static void endpoint_destroy(void *object) } } +static const struct object_info endpoint_info = { + .type = PW_TYPE_INTERFACE_Endpoint, + .version = PW_VERSION_ENDPOINT_PROXY, + .events = &endpoint_events, + .size = sizeof(struct sm_endpoint), + .init = endpoint_init, + .destroy = endpoint_destroy, +}; + + /** * Endpoint Stream */ @@ -617,6 +772,28 @@ static const struct pw_endpoint_stream_proxy_events endpoint_stream_events = { .info = endpoint_stream_event_info, }; +static int endpoint_stream_init(void *object) +{ + struct sm_endpoint_stream *stream = object; + struct impl *impl = SPA_CONTAINER_OF(stream->obj.session, struct impl, this); + struct pw_properties *props = stream->obj.props; + const char *str; + + if (props) { + if ((str = pw_properties_get(props, PW_KEY_ENDPOINT_ID)) != NULL) + stream->endpoint = find_object(impl, atoi(str)); + pw_log_debug(NAME" %p: stream %d parent endpoint %s", impl, + stream->obj.id, str); + if (stream->endpoint) { + spa_list_append(&stream->endpoint->stream_list, &stream->link); + stream->endpoint->obj.changed |= SM_ENDPOINT_CHANGE_MASK_STREAMS; + } + } + spa_list_init(&stream->link_list); + + return 0; +} + static void endpoint_stream_destroy(void *object) { struct sm_endpoint_stream *stream = object; @@ -630,6 +807,16 @@ static void endpoint_stream_destroy(void *object) spa_list_remove(&stream->link); } } + +static const struct object_info endpoint_stream_info = { + .type = PW_TYPE_INTERFACE_EndpointStream, + .version = PW_VERSION_ENDPOINT_STREAM_PROXY, + .events = &endpoint_stream_events, + .size = sizeof(struct sm_endpoint_stream), + .init = endpoint_stream_init, + .destroy = endpoint_stream_destroy, +}; + /** * Endpoint Link */ @@ -679,6 +866,15 @@ static void endpoint_link_destroy(void *object) } } +static const struct object_info endpoint_link_info = { + .type = PW_TYPE_INTERFACE_EndpointLink, + .version = PW_VERSION_ENDPOINT_STREAM_PROXY, + .events = &endpoint_link_events, + .size = sizeof(struct sm_endpoint_link), + .init = NULL, + .destroy = endpoint_link_destroy, +}; + /** * Proxy */ @@ -705,210 +901,177 @@ static void done_proxy(void *data, int seq) obj->changed = 0; } +static void bound_proxy(void *data, uint32_t id) +{ + struct sm_object *obj = data; + struct impl *impl = SPA_CONTAINER_OF(obj->session, struct impl, this); + + pw_log_debug("bound %p proxy %p id:%d", obj, obj->proxy, id); + + if (obj->id == SPA_ID_INVALID) { + obj->id = id; + pw_log_debug("bound %p proxy %p id:%d", obj, obj->proxy, id); + add_object(impl, obj); + sm_media_session_emit_create(impl, obj); + } +} + static const struct pw_proxy_events proxy_events = { PW_VERSION_PROXY_EVENTS, .destroy = destroy_proxy, .done = done_proxy, + .bound = bound_proxy, }; -static void -init_object(struct impl *impl, struct sm_object *obj, uint32_t id, +static const struct object_info *get_object_info(struct impl *impl, uint32_t type) +{ + const struct object_info *info; + switch (type) { + case PW_TYPE_INTERFACE_Client: + info = &client_info; + break; + case SPA_TYPE_INTERFACE_Device: + info = &spa_device_info; + break; + case PW_TYPE_INTERFACE_Device: + info = &device_info; + break; + case PW_TYPE_INTERFACE_Node: + info = &node_info; + break; + case PW_TYPE_INTERFACE_Port: + info = &port_info; + break; + case PW_TYPE_INTERFACE_Session: + info = &session_info; + break; + case PW_TYPE_INTERFACE_Endpoint: + info = &endpoint_info; + break; + case PW_TYPE_INTERFACE_EndpointStream: + info = &endpoint_stream_info; + break; + case PW_TYPE_INTERFACE_EndpointLink: + info = &endpoint_link_info; + break; + default: + info = NULL; + break; + } + return info; +} + +static struct sm_object *init_object(struct impl *impl, const struct object_info *info, + struct pw_proxy *proxy, uint32_t id, + const struct spa_dict *props) +{ + struct sm_object *obj; + + obj = pw_proxy_get_user_data(proxy); + obj->session = &impl->this; + obj->id = id; + obj->type = info->type; + obj->props = props ? pw_properties_new_dict(props) : pw_properties_new(NULL, NULL); + obj->proxy = proxy; + obj->destroy = info->destroy; + obj->mask |= SM_OBJECT_CHANGE_MASK_PROPERTIES | SM_OBJECT_CHANGE_MASK_BIND; + obj->avail |= obj->mask; + spa_hook_list_init(&obj->hooks); + spa_list_init(&obj->data); + + pw_proxy_add_listener(obj->proxy, &obj->proxy_listener, &proxy_events, obj); + if (info->events != NULL) + pw_proxy_add_object_listener(obj->proxy, &obj->object_listener, info->events, obj); + SPA_FLAG_UPDATE(obj->mask, SM_OBJECT_CHANGE_MASK_LISTENER, info->events != NULL); + + if (info->init) + info->init(obj); + + if (id != SPA_ID_INVALID) { + add_object(impl, obj); + sm_media_session_emit_create(impl, obj); + } + return obj; +} + +static struct sm_object * +create_object(struct impl *impl, struct pw_proxy *proxy, + const struct spa_dict *props) +{ + uint32_t type; + const struct object_info *info; + struct sm_object *obj; + + type = pw_proxy_get_type(proxy, NULL); + + info = get_object_info(impl, type); + if (info == NULL) { + pw_log_error(NAME" %p: unknown object type %d", impl, type); + errno = ENOTSUP; + return NULL; + } + obj = init_object(impl, info, proxy, SPA_ID_INVALID, props); + + pw_log_debug(NAME" %p: created new object %p proxy %p", impl, obj, obj->proxy); + + return obj; +} + +static struct sm_object * +bind_object(struct impl *impl, const struct object_info *info, uint32_t id, uint32_t permissions, uint32_t type, uint32_t version, const struct spa_dict *props) { int res; - const void *events; - uint32_t client_version; - pw_destroy_t destroy; - size_t user_data_size; - const char *str; struct pw_proxy *proxy; + struct sm_object *obj; - proxy = obj ? obj->proxy : NULL; - - pw_log_debug(NAME " %p: init '%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_Device: - events = &device_events; - client_version = PW_VERSION_DEVICE_PROXY; - destroy = (pw_destroy_t) device_destroy; - user_data_size = sizeof(struct sm_device); - 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_Session: - events = &session_events; - client_version = PW_VERSION_SESSION_PROXY; - destroy = (pw_destroy_t) session_destroy; - user_data_size = sizeof(struct sm_session); - 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; - - case PW_TYPE_INTERFACE_EndpointLink: - events = &endpoint_link_events; - client_version = PW_VERSION_ENDPOINT_LINK_PROXY; - destroy = (pw_destroy_t) endpoint_link_destroy; - user_data_size = sizeof(struct sm_endpoint_link); - break; - - default: - return; - } - + proxy = pw_registry_proxy_bind(impl->registry_proxy, + id, type, info->version, info->size); if (proxy == NULL) { - proxy = pw_registry_proxy_bind(impl->registry_proxy, - id, type, client_version, user_data_size); - if (proxy == NULL) { - res = -errno; - goto error; - } + res = -errno; + goto error; } - if (obj == NULL) - 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_hook_list_init(&obj->hooks); - spa_list_init(&obj->data); - if (id != SPA_ID_INVALID) - add_object(impl, obj); + obj = init_object(impl, info, proxy, id, props); - pw_proxy_add_listener(proxy, &obj->proxy_listener, &proxy_events, obj); + pw_log_debug(NAME" %p: bound new object %p proxy %p id:%d", impl, obj, obj->proxy, obj->id); - switch (type) { - case PW_TYPE_INTERFACE_Device: - { - struct sm_device *device = (struct sm_device*) obj; - spa_list_init(&device->node_list); - spa_list_init(&device->param_list); - break; - } - - case PW_TYPE_INTERFACE_Node: - { - struct sm_node *node = (struct sm_node*) obj; - spa_list_init(&node->port_list); - spa_list_init(&node->param_list); - - if (props) { - if ((str = spa_dict_lookup(props, PW_KEY_DEVICE_ID)) != NULL) - node->device = find_object(impl, atoi(str)); - pw_log_debug(NAME" %p: node %d parent device %s", impl, id, str); - if (node->device) { - spa_list_append(&node->device->node_list, &node->link); - node->device->obj.changed |= SM_DEVICE_CHANGE_MASK_NODES; - } - } - 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") == 0 ? - 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 direction:%d", impl, id, str, - port->direction); - if (port->node) { - spa_list_append(&port->node->port_list, &port->link); - port->node->obj.changed |= SM_NODE_CHANGE_MASK_PORTS; - } - } - break; - } - case PW_TYPE_INTERFACE_Session: - { - struct sm_session *sess = (struct sm_session*) obj; - if (id == impl->session_id) - impl->this.session = sess; - spa_list_init(&sess->endpoint_list); - break; - } - case PW_TYPE_INTERFACE_Endpoint: - { - struct sm_endpoint *endpoint = (struct sm_endpoint*) obj; - if (props) { - if ((str = spa_dict_lookup(props, PW_KEY_SESSION_ID)) != NULL) - endpoint->session = find_object(impl, atoi(str)); - pw_log_debug(NAME" %p: endpoint %d parent session %s", impl, id, str); - if (endpoint->session) - spa_list_append(&endpoint->session->endpoint_list, &endpoint->link); - } - 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->obj.changed |= SM_ENDPOINT_CHANGE_MASK_STREAMS; - } - } - spa_list_init(&stream->link_list); - break; - } - default: - break; - } - - pw_log_debug(NAME" %p: created new object %p id:%d", impl, obj, obj->id); - sm_media_session_emit_create(impl, obj); - pw_proxy_add_object_listener(proxy, &obj->object_listener, events, obj); - - return; + return obj; error: pw_log_warn(NAME" %p: can't handle global %d: %s", impl, id, spa_strerror(res)); + errno = -res; + return NULL; +} + +static int +update_object(struct impl *impl, const struct object_info *info, + struct sm_object *obj, uint32_t id, + uint32_t permissions, uint32_t type, uint32_t version, + const struct spa_dict *props) +{ + pw_properties_update(obj->props, props); + + if (obj->type == type) + return 0; + + spa_hook_remove(&obj->proxy_listener); + if (SPA_FLAG_IS_SET(obj->mask, SM_OBJECT_CHANGE_MASK_LISTENER)) + spa_hook_remove(&obj->object_listener); + + obj->proxy = pw_registry_proxy_bind(impl->registry_proxy, + id, info->type, info->version, 0); + obj->type = type; + + pw_proxy_add_listener(obj->proxy, &obj->proxy_listener, &proxy_events, obj); + if (info->events) + pw_proxy_add_object_listener(obj->proxy, &obj->object_listener, info->events, obj); + + SPA_FLAG_UPDATE(obj->mask, SM_OBJECT_CHANGE_MASK_LISTENER, info->events != NULL); + + sm_media_session_emit_create(impl, obj); + + return 0; } static void @@ -918,14 +1081,22 @@ registry_global(void *data, uint32_t id, { struct impl *impl = data; struct sm_object *obj; + const struct object_info *info; - pw_log_debug(NAME " %p: new global '%d' %d", impl, id, type); + pw_log_debug(NAME " %p: new global '%d' %s/%d", impl, id, + spa_debug_type_find_name(pw_type_info(), type), version); + + info = get_object_info(impl, type); + if (info == NULL) + return; obj = find_object(impl, id); if (obj == NULL) { - init_object(impl, obj, id, permissions, type, version, props); + bind_object(impl, info, id, permissions, type, version, props); } else { - pw_log_debug(NAME " %p: our object %d appeared", impl, id); + pw_log_debug(NAME " %p: our object %d appeared %d/%d", + impl, id, obj->type, type); + update_object(impl, info, obj, id, permissions, type, version, props); } } @@ -1049,6 +1220,23 @@ struct pw_proxy *sm_media_session_export(struct sm_media_session *sess, properties, object, user_data_size); } +struct sm_device *sm_media_session_export_device(struct sm_media_session *sess, + struct pw_properties *properties, struct spa_device *object) +{ + struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this); + struct sm_device *device; + struct pw_proxy *proxy; + + pw_log_debug(NAME " %p: device %p", impl, object); + + proxy = pw_remote_export(impl->monitor_remote, SPA_TYPE_INTERFACE_Device, + properties, object, sizeof(struct sm_device)); + + device = (struct sm_device *) create_object(impl, proxy, &properties->dict); + + return device; +} + 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) @@ -1059,8 +1247,7 @@ struct pw_proxy *sm_media_session_create_object(struct sm_media_session *sess, } struct sm_node *sm_media_session_create_node(struct sm_media_session *sess, - const char *factory_name, const struct spa_dict *props, - size_t user_data_size) + const char *factory_name, const struct spa_dict *props) { struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this); struct sm_node *node; @@ -1073,13 +1260,9 @@ struct sm_node *sm_media_session_create_node(struct sm_media_session *sess, PW_TYPE_INTERFACE_Node, PW_VERSION_NODE_PROXY, props, - sizeof(struct sm_node) + user_data_size); + sizeof(struct sm_node)); - node = pw_proxy_get_user_data(proxy); - node->obj.proxy = proxy; - init_object(impl, &node->obj, SPA_ID_INVALID, - PW_PERM_RWX, PW_TYPE_INTERFACE_Node, - PW_VERSION_NODE_PROXY, props); + node = (struct sm_node *)create_object(impl, proxy, props); return node; } @@ -1278,35 +1461,6 @@ int sm_media_session_create_links(struct sm_media_session *sess, /** * Session implementation */ -static int client_session_set_id(void *object, uint32_t id) -{ - struct impl *impl = object; - struct pw_session_info info; - - impl->session_id = id; - - spa_zero(info); - info.version = PW_VERSION_SESSION_INFO; - info.id = id; - - pw_log_debug("got sesssion id:%d", id); - - pw_client_session_proxy_update(impl->client_session, - PW_CLIENT_SESSION_UPDATE_INFO, - 0, NULL, - &info); - - /* start monitors */ - sm_metadata_start(&impl->this); - sm_alsa_midi_start(&impl->this); - sm_bluez5_monitor_start(&impl->this); - sm_alsa_monitor_start(&impl->this); - sm_alsa_endpoint_start(&impl->this); - sm_v4l2_monitor_start(&impl->this); - sm_stream_monitor_start(&impl->this); - return 0; -} - static int client_session_set_param(void *object, uint32_t id, uint32_t flags, const struct spa_pod *param) { @@ -1332,12 +1486,44 @@ static int client_session_link_request_state(void *object, uint32_t link_id, uin 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 client_session_proxy_bound(void *data, uint32_t id) +{ + struct impl *impl = data; + struct pw_session_info info; + + impl->session_id = id; + + spa_zero(info); + info.version = PW_VERSION_SESSION_INFO; + info.id = id; + + pw_log_debug("got sesssion id:%d", id); + + pw_client_session_proxy_update(impl->client_session, + PW_CLIENT_SESSION_UPDATE_INFO, + 0, NULL, + &info); + + /* start monitors */ + sm_metadata_start(&impl->this); + sm_alsa_midi_start(&impl->this); + sm_bluez5_monitor_start(&impl->this); + sm_alsa_monitor_start(&impl->this); + sm_alsa_endpoint_start(&impl->this); + sm_v4l2_monitor_start(&impl->this); + sm_stream_monitor_start(&impl->this); +} + +static const struct pw_proxy_events client_session_proxy_events = { + PW_VERSION_PROXY_EVENTS, + .bound = client_session_proxy_bound, +}; + static int start_session(struct impl *impl) { impl->client_session = pw_core_proxy_create_object(impl->monitor_core, @@ -1346,10 +1532,13 @@ static int start_session(struct impl *impl) PW_VERSION_CLIENT_SESSION_PROXY, NULL, 0); + pw_proxy_add_listener((struct pw_proxy*)impl->client_session, + &impl->client_session_proxy_listener, + &client_session_proxy_events, impl); + pw_client_session_proxy_add_listener(impl->client_session, &impl->client_session_listener, - &client_session_events, - impl); + &client_session_events, impl); return 0; } diff --git a/src/examples/media-session/media-session.h b/src/examples/media-session/media-session.h index 84de60782..67c560461 100644 --- a/src/examples/media-session/media-session.h +++ b/src/examples/media-session/media-session.h @@ -47,8 +47,9 @@ struct sm_object { struct spa_list link; struct sm_media_session *session; -#define SM_OBJECT_CHANGE_MASK_PROPERTIES (1<<0) -#define SM_OBJECT_CHANGE_MASK_BIND (1<<1) +#define SM_OBJECT_CHANGE_MASK_LISTENER (1<<1) +#define SM_OBJECT_CHANGE_MASK_PROPERTIES (1<<2) +#define SM_OBJECT_CHANGE_MASK_BIND (1<<3) #define SM_OBJECT_CHANGE_MASK_LAST (1<<8) uint32_t mask; /**< monitored info */ uint32_t avail; /**< available info */ @@ -135,7 +136,8 @@ struct sm_port { struct sm_session { struct sm_object obj; -#define SM_SESSION_CHANGE_MASK_INFO (SM_OBJECT_CHANGE_MASK_LAST<<0) +#define SM_SESSION_CHANGE_MASK_INFO (SM_OBJECT_CHANGE_MASK_LAST<<0) +#define SM_SESSION_CHANGE_MASK_ENDPOINTS (SM_OBJECT_CHANGE_MASK_LAST<<1) struct pw_session_info *info; struct spa_list endpoint_list; }; @@ -217,13 +219,15 @@ 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 sm_device *sm_media_session_export_device(struct sm_media_session *sess, + struct pw_properties *properties, struct spa_device *device); + 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 sm_node *sm_media_session_create_node(struct sm_media_session *sess, - const char *factory_name, const struct spa_dict *props, - size_t user_data_size); + const char *factory_name, const struct spa_dict *props); int sm_media_session_create_links(struct sm_media_session *sess, const struct spa_dict *dict); diff --git a/src/examples/media-session/stream-monitor.c b/src/examples/media-session/stream-monitor.c index 01a5a1718..4ce118bd7 100644 --- a/src/examples/media-session/stream-monitor.c +++ b/src/examples/media-session/stream-monitor.c @@ -52,18 +52,14 @@ struct endpoint; struct impl { struct sm_media_session *session; struct spa_hook listener; - - int seq; }; struct node { struct sm_node *obj; + struct spa_hook listener; struct impl *impl; - struct spa_hook proxy_listener; - struct spa_hook listener; - uint32_t id; enum pw_direction direction; char *media; @@ -74,6 +70,9 @@ struct node { }; struct stream { + struct endpoint *endpoint; + struct spa_list link; + struct pw_properties *props; struct pw_endpoint_stream_info info; @@ -83,8 +82,6 @@ struct stream { }; struct endpoint { - struct spa_list link; - struct impl *impl; struct pw_properties *props; @@ -92,21 +89,14 @@ struct endpoint { struct pw_client_endpoint_proxy *client_endpoint; struct spa_hook client_endpoint_listener; + struct spa_hook proxy_listener; struct pw_endpoint_info info; struct spa_param_info params[5]; - struct stream stream; - uint32_t pending_config; + struct spa_list stream_list; }; -static int client_endpoint_set_id(void *object, uint32_t id) -{ - struct endpoint *endpoint = object; - endpoint->info.id = id; - return 0; -} - static int client_endpoint_set_session_id(void *object, uint32_t id) { struct endpoint *endpoint = object; @@ -133,8 +123,9 @@ static int client_endpoint_stream_set_param(void *object, uint32_t stream_id, return -ENOTSUP; } -static int stream_set_active(struct endpoint *endpoint, struct stream *stream, bool active) +static int stream_set_active(struct stream *stream, bool active) { + struct endpoint *endpoint = stream->endpoint; struct node *node = endpoint->node; char buf[1024]; struct spa_pod_builder b = { 0, }; @@ -171,6 +162,7 @@ static int client_endpoint_create_link(void *object, const struct spa_dict *prop struct endpoint *endpoint = object; struct impl *impl = endpoint->impl; struct pw_properties *p; + struct stream *stream; int res; pw_log_debug("create link"); @@ -178,7 +170,12 @@ static int client_endpoint_create_link(void *object, const struct spa_dict *prop if (props == NULL) return -EINVAL; - stream_set_active(endpoint, &endpoint->stream, true); + if (spa_list_is_empty(&endpoint->stream_list)) + return -EIO; + + /* FIXME take first stream */ + stream = spa_list_first(&endpoint->stream_list, struct stream, link); + stream_set_active(stream, true); p = pw_properties_new_dict(props); if (p == NULL) @@ -221,7 +218,6 @@ exit: static const struct pw_client_endpoint_proxy_events client_endpoint_events = { PW_VERSION_CLIENT_ENDPOINT_PROXY_EVENTS, - .set_id = client_endpoint_set_id, .set_session_id = client_endpoint_set_session_id, .set_param = client_endpoint_set_param, .stream_set_param = client_endpoint_stream_set_param, @@ -235,9 +231,13 @@ static struct stream *endpoint_add_stream(struct endpoint *endpoint) struct node *node = endpoint->node; const char *str; - s = &endpoint->stream; + s = calloc(1, sizeof(*s)); + if (s == NULL) + return NULL; + s->endpoint = endpoint; s->props = pw_properties_new(NULL, 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) @@ -251,6 +251,7 @@ static struct stream *endpoint_add_stream(struct endpoint *endpoint) s->info.name = (char*)pw_properties_get(s->props, PW_KEY_ENDPOINT_STREAM_NAME); s->info.change_mask = PW_ENDPOINT_STREAM_CHANGE_MASK_PROPS; s->info.props = &s->props->dict; + spa_list_append(&endpoint->stream_list, &s->link); pw_log_debug("stream %d", node->id); pw_client_endpoint_proxy_stream_update(endpoint->client_endpoint, @@ -261,6 +262,21 @@ static struct stream *endpoint_add_stream(struct endpoint *endpoint) return s; } +static void destroy_stream(struct stream *stream) +{ + struct endpoint *endpoint = stream->endpoint; + + pw_client_endpoint_proxy_stream_update(endpoint->client_endpoint, + stream->info.id, + PW_CLIENT_ENDPOINT_STREAM_UPDATE_DESTROYED, + 0, NULL, + &stream->info); + + pw_properties_free(stream->props); + spa_list_remove(&stream->link); + free(stream); +} + static void complete_endpoint(void *data) { struct endpoint *endpoint = data; @@ -335,7 +351,30 @@ static void update_params(void *data) &endpoint->info); } -static struct endpoint *make_endpoint(struct node *node) +static void proxy_destroy(void *data) +{ + struct endpoint *endpoint = data; + struct stream *s; + + spa_list_consume(s, &endpoint->stream_list, link) + destroy_stream(s); + + pw_properties_free(endpoint->props); +} + +static void proxy_bound(void *data, uint32_t id) +{ + struct endpoint *endpoint = data; + endpoint->info.id = id; +} + +static const struct pw_proxy_events proxy_events = { + PW_VERSION_PROXY_EVENTS, + .destroy = proxy_destroy, + .bound = proxy_bound, +}; + +static struct endpoint *create_endpoint(struct node *node) { struct impl *impl = node->impl; struct pw_properties *props; @@ -396,6 +435,11 @@ static struct endpoint *make_endpoint(struct node *node) endpoint->params[1] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE); endpoint->info.params = endpoint->params; endpoint->info.n_params = 2; + spa_list_init(&endpoint->stream_list); + + pw_proxy_add_listener(proxy, + &endpoint->proxy_listener, + &proxy_events, endpoint); pw_client_endpoint_proxy_add_listener(endpoint->client_endpoint, &endpoint->client_endpoint_listener, @@ -429,7 +473,7 @@ static void object_update(void *data) if (node->endpoint == NULL && node->obj->obj.avail & SM_OBJECT_CHANGE_MASK_PROPERTIES) - node->endpoint = make_endpoint(node); + node->endpoint = create_endpoint(node); if (node->obj->obj.changed & SM_NODE_CHANGE_MASK_PARAMS) update_params(node->endpoint); @@ -484,6 +528,14 @@ handle_node(struct impl *impl, struct sm_object *obj) return 1; } +static void destroy_node(struct node *node) +{ + if (node->endpoint) + destroy_endpoint(node->endpoint); + free(node->media); + spa_hook_remove(&node->listener); +} + static void session_create(void *data, struct sm_object *object) { struct impl *impl = data; @@ -510,11 +562,8 @@ static void session_remove(void *data, struct sm_object *object) case PW_TYPE_INTERFACE_Node: { struct node *node; - if ((node = sm_object_get_data(object, SESSION_KEY)) != NULL) { - if (node->endpoint) - destroy_endpoint(node->endpoint); - free(node->media); - } + if ((node = sm_object_get_data(object, SESSION_KEY)) != NULL) + destroy_node(node); break; } default: diff --git a/src/extensions/session-manager/impl-interfaces.h b/src/extensions/session-manager/impl-interfaces.h index 3b77f4a13..59ca03cef 100644 --- a/src/extensions/session-manager/impl-interfaces.h +++ b/src/extensions/session-manager/impl-interfaces.h @@ -39,35 +39,16 @@ extern "C" { #define PW_VERSION_CLIENT_ENDPOINT_PROXY 0 struct pw_client_endpoint_proxy { struct spa_interface iface; }; -#define PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_ID 0 -#define PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_SESSION_ID 1 -#define PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_PARAM 2 -#define PW_CLIENT_ENDPOINT_PROXY_EVENT_STREAM_SET_PARAM 3 -#define PW_CLIENT_ENDPOINT_PROXY_EVENT_CREATE_LINK 4 -#define PW_CLIENT_ENDPOINT_PROXY_EVENT_NUM 5 +#define PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_SESSION_ID 0 +#define PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_PARAM 1 +#define PW_CLIENT_ENDPOINT_PROXY_EVENT_STREAM_SET_PARAM 2 +#define PW_CLIENT_ENDPOINT_PROXY_EVENT_CREATE_LINK 3 +#define PW_CLIENT_ENDPOINT_PROXY_EVENT_NUM 4 struct pw_client_endpoint_proxy_events { #define PW_VERSION_CLIENT_ENDPOINT_PROXY_EVENTS 0 uint32_t version; /**< version of this structure */ - /** - * Sets the id of the \a endpoint. - * - * On endpoint implementations, this is called by the server to notify - * the implementation of the assigned global id of the endpoint. The - * implementation is obliged to set this id in the - * #struct pw_endpoint_info \a id field. The implementation should also - * not emit the info() event before this method is called. - * - * \param endpoint a #pw_endpoint - * \param id the global id assigned to this endpoint - * - * \return 0 on success - * -EINVAL when the id has already been set - * -ENOTSUP on the server-side endpoint implementation - */ - int (*set_id) (void *object, uint32_t id); - /** * Sets the session id of the \a endpoint. * @@ -190,34 +171,15 @@ struct pw_client_endpoint_proxy_methods { #define PW_VERSION_CLIENT_SESSION_PROXY 0 struct pw_client_session_proxy { struct spa_interface iface; }; -#define PW_CLIENT_SESSION_PROXY_EVENT_SET_ID 0 -#define PW_CLIENT_SESSION_PROXY_EVENT_SET_PARAM 1 -#define PW_CLIENT_SESSION_PROXY_EVENT_LINK_SET_PARAM 2 -#define PW_CLIENT_SESSION_PROXY_EVENT_LINK_REQUEST_STATE 3 -#define PW_CLIENT_SESSION_PROXY_EVENT_NUM 4 +#define PW_CLIENT_SESSION_PROXY_EVENT_SET_PARAM 0 +#define PW_CLIENT_SESSION_PROXY_EVENT_LINK_SET_PARAM 1 +#define PW_CLIENT_SESSION_PROXY_EVENT_LINK_REQUEST_STATE 2 +#define PW_CLIENT_SESSION_PROXY_EVENT_NUM 3 struct pw_client_session_proxy_events { #define PW_VERSION_CLIENT_SESSION_PROXY_EVENTS 0 uint32_t version; /**< version of this structure */ - /** - * Sets the id of the \a session. - * - * On session implementations, this is called by the server to notify - * the implementation of the assigned global id of the session. The - * implementation is obliged to set this id in the - * #struct pw_session_info \a id field. The implementation should also - * not emit the info() event before this method is called. - * - * \param session a #pw_session - * \param id the global id assigned to this session - * - * \return 0 on success - * -EINVAL when the id has already been set - * -ENOTSUP on the server-side session implementation - */ - int (*set_id) (void *object, uint32_t id); - /** * Set the configurable parameter in \a session. * diff --git a/src/modules/module-session-manager/endpoint.c b/src/modules/module-session-manager/endpoint.c index 1b98ea095..8eff33172 100644 --- a/src/modules/module-session-manager/endpoint.c +++ b/src/modules/module-session-manager/endpoint.c @@ -340,7 +340,6 @@ int endpoint_init(struct endpoint *this, this->info.props = &this->props->dict; pw_resource_bound_id(client_ep->resource, this->global->id); - pw_client_endpoint_resource_set_id(client_ep->resource, this->global->id); return pw_global_register(this->global); diff --git a/src/modules/module-session-manager/protocol-native.c b/src/modules/module-session-manager/protocol-native.c index 9ba0f5418..1f99217e8 100644 --- a/src/modules/module-session-manager/protocol-native.c +++ b/src/modules/module-session-manager/protocol-native.c @@ -308,20 +308,6 @@ do { \ * CLIENT ENDPOINT ***********************************************/ -static int client_endpoint_marshal_set_id (void *object, uint32_t id) -{ - struct pw_resource *resource = object; - struct spa_pod_builder *b; - - b = pw_protocol_native_begin_resource(resource, - PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_ID, NULL); - - spa_pod_builder_add_struct(b, - SPA_POD_Int(id)); - - return pw_protocol_native_end_resource(resource, b); -} - static int client_endpoint_marshal_set_session_id (void *object, uint32_t id) { struct pw_resource *resource = object; @@ -465,22 +451,6 @@ static int client_endpoint_marshal_stream_update(void *object, return pw_protocol_native_end_proxy(proxy, b); } -static int client_endpoint_demarshal_set_id(void *object, - const struct pw_protocol_native_message *msg) -{ - struct pw_proxy *proxy = object; - struct spa_pod_parser prs; - uint32_t id; - - spa_pod_parser_init(&prs, msg->data, msg->size); - if (spa_pod_parser_get_struct(&prs, - SPA_POD_Int(&id)) < 0) - return -EINVAL; - - return pw_proxy_notify(proxy, struct pw_client_endpoint_proxy_events, - set_id, 0, id); -} - static int client_endpoint_demarshal_set_session_id(void *object, const struct pw_protocol_native_message *msg) { @@ -633,7 +603,6 @@ static int client_endpoint_demarshal_stream_update(void *object, static const struct pw_client_endpoint_proxy_events pw_protocol_native_client_endpoint_event_marshal = { PW_VERSION_CLIENT_ENDPOINT_PROXY_EVENTS, - .set_id = client_endpoint_marshal_set_id, .set_session_id = client_endpoint_marshal_set_session_id, .set_param = client_endpoint_marshal_set_param, .stream_set_param = client_endpoint_marshal_stream_set_param, @@ -643,7 +612,6 @@ static const struct pw_client_endpoint_proxy_events pw_protocol_native_client_en static const struct pw_protocol_native_demarshal pw_protocol_native_client_endpoint_event_demarshal[PW_CLIENT_ENDPOINT_PROXY_EVENT_NUM] = { - [PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_ID] = { client_endpoint_demarshal_set_id, 0 }, [PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_SESSION_ID] = { client_endpoint_demarshal_set_session_id, 0 }, [PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_PARAM] = { client_endpoint_demarshal_set_param, 0 }, [PW_CLIENT_ENDPOINT_PROXY_EVENT_STREAM_SET_PARAM] = { client_endpoint_demarshal_stream_set_param, 0 }, @@ -681,20 +649,6 @@ static const struct pw_protocol_marshal pw_protocol_native_client_endpoint_marsh * CLIENT SESSION ***********************************************/ -static int client_session_marshal_set_id (void *object, uint32_t id) -{ - struct pw_resource *resource = object; - struct spa_pod_builder *b; - - b = pw_protocol_native_begin_resource(resource, - PW_CLIENT_SESSION_PROXY_EVENT_SET_ID, NULL); - - spa_pod_builder_add_struct(b, - SPA_POD_Int(id)); - - return pw_protocol_native_end_resource(resource, b); -} - static int client_session_marshal_set_param (void *object, uint32_t id, uint32_t flags, const struct spa_pod *param) @@ -826,22 +780,6 @@ static int client_session_marshal_link_update(void *object, return pw_protocol_native_end_proxy(proxy, b); } -static int client_session_demarshal_set_id(void *object, - const struct pw_protocol_native_message *msg) -{ - struct pw_proxy *proxy = object; - struct spa_pod_parser prs; - uint32_t id; - - spa_pod_parser_init(&prs, msg->data, msg->size); - if (spa_pod_parser_get_struct(&prs, - SPA_POD_Int(&id)) < 0) - return -EINVAL; - - return pw_proxy_notify(proxy, struct pw_client_session_proxy_events, - set_id, 0, id); -} - static int client_session_demarshal_set_param(void *object, const struct pw_protocol_native_message *msg) { @@ -979,7 +917,6 @@ static int client_session_demarshal_link_update(void *object, static const struct pw_client_session_proxy_events pw_protocol_native_client_session_event_marshal = { PW_VERSION_CLIENT_SESSION_PROXY_EVENTS, - .set_id = client_session_marshal_set_id, .set_param = client_session_marshal_set_param, .link_set_param = client_session_marshal_link_set_param, .link_request_state = client_session_marshal_link_request_state, @@ -988,7 +925,6 @@ static const struct pw_client_session_proxy_events pw_protocol_native_client_ses static const struct pw_protocol_native_demarshal pw_protocol_native_client_session_event_demarshal[PW_CLIENT_SESSION_PROXY_EVENT_NUM] = { - [PW_CLIENT_SESSION_PROXY_EVENT_SET_ID] = { client_session_demarshal_set_id, 0 }, [PW_CLIENT_SESSION_PROXY_EVENT_SET_PARAM] = { client_session_demarshal_set_param, 0 }, [PW_CLIENT_SESSION_PROXY_EVENT_LINK_SET_PARAM] = { client_session_demarshal_link_set_param, 0 }, [PW_CLIENT_SESSION_PROXY_EVENT_LINK_REQUEST_STATE] = { client_session_demarshal_link_request_state, 0 }, diff --git a/src/modules/module-session-manager/session.c b/src/modules/module-session-manager/session.c index f21726645..b655383e1 100644 --- a/src/modules/module-session-manager/session.c +++ b/src/modules/module-session-manager/session.c @@ -301,7 +301,6 @@ int session_init(struct session *this, this->info.props = &this->props->dict; pw_resource_bound_id(client_sess->resource, this->global->id); - pw_client_session_resource_set_id(client_sess->resource, this->global->id); return pw_global_register(this->global);