media-session: improve cleanup of objects

Don't try to use the proxy destroy event to destroy the objects.
It is not called automatically anymore, only when we call
pw_proxy_destroy() ourselves.

Destroy the proxy objects when we destroy the session managed
object instead, either when the global is removed or when we
explicitly call _destroy()

Add an object free signal to clean up final resources after the
proxies have been destroyed, like closing libraries.

Track and destroy our link proxies.
This commit is contained in:
Wim Taymans 2020-06-04 17:41:01 +02:00
parent 47ae56df7d
commit ed31ca30cd
4 changed files with 104 additions and 80 deletions

View file

@ -42,6 +42,7 @@
#include <spa/monitor/device.h>
#include "pipewire/pipewire.h"
#include "pipewire/private.h"
#include "extensions/session-manager.h"
#include <dbus/dbus.h>
@ -54,6 +55,7 @@
#define sm_object_emit_update(s) sm_object_emit(s, update, 0)
#define sm_object_emit_destroy(s) sm_object_emit(s, destroy, 0)
#define sm_object_emit_free(s) sm_object_emit(s, free, 0)
#define sm_media_session_emit(s,m,v,...) spa_hook_list_call(&(s)->hooks, struct sm_media_session_events, m, v, ##__VA_ARGS__)
@ -237,17 +239,56 @@ int sm_object_remove_data(struct sm_object *obj, const char *id)
int sm_object_destroy(struct sm_object *obj)
{
pw_log_debug(NAME" %p: object %d", obj->session, obj->id);
if (obj->proxy) {
pw_proxy_destroy(obj->proxy);
if (obj->handle == obj->proxy)
obj->handle = NULL;
obj->proxy = NULL;
struct impl *impl = SPA_CONTAINER_OF(obj->session, struct impl, this);
struct data *d;
struct pw_proxy *p, *h;
p = obj->proxy;
h = obj->handle;
pw_log_debug(NAME" %p: object %d proxy:%p handle:%p", obj->session,
obj->id, p, h);
sm_object_emit_destroy(obj);
if (SPA_FLAG_IS_SET(obj->mask, SM_OBJECT_CHANGE_MASK_LISTENER)) {
SPA_FLAG_CLEAR(obj->mask, SM_OBJECT_CHANGE_MASK_LISTENER);
spa_hook_remove(&obj->object_listener);
}
if (obj->handle) {
pw_proxy_destroy(obj->handle);
obj->handle = NULL;
if (obj->id != SPA_ID_INVALID)
remove_object(impl, obj);
if (obj->destroy)
obj->destroy(obj);
if (p) {
pw_proxy_ref(p);
spa_hook_remove(&obj->proxy_listener);
}
if (h) {
pw_proxy_ref(h);
spa_hook_remove(&obj->handle_listener);
}
if (p)
pw_proxy_destroy(p);
if (h != p)
pw_proxy_destroy(h);
sm_object_emit_free(obj);
if (obj->props)
pw_properties_free(obj->props);
obj->props = NULL;
spa_list_consume(d, &obj->data, link) {
spa_list_remove(&d->link);
free(d);
}
if (p)
pw_proxy_unref(p);
if (h)
pw_proxy_unref(h);
return 0;
}
@ -911,46 +952,6 @@ static const struct object_info endpoint_link_info = {
/**
* Proxy
*/
static void
destroy_proxy(void *data)
{
struct sm_object *obj = data;
struct impl *impl = SPA_CONTAINER_OF(obj->session, struct impl, this);
struct data *d;
pw_log_debug("object %p: proxy:%p id:%d", obj, obj->proxy, obj->id);
if (SPA_FLAG_IS_SET(obj->mask, SM_OBJECT_CHANGE_MASK_LISTENER)) {
SPA_FLAG_CLEAR(obj->mask, SM_OBJECT_CHANGE_MASK_LISTENER);
spa_hook_remove(&obj->object_listener);
}
if (obj->id != SPA_ID_INVALID)
remove_object(impl, obj);
sm_object_emit_destroy(obj);
if (obj->destroy)
obj->destroy(obj);
if (obj->proxy) {
spa_hook_remove(&obj->proxy_listener);
obj->proxy = NULL;
}
if (obj->handle) {
spa_hook_remove(&obj->handle_listener);
obj->handle = NULL;
}
if (obj->props)
pw_properties_free(obj->props);
obj->props = NULL;
spa_list_consume(d, &obj->data, link) {
spa_list_remove(&d->link);
free(d);
}
}
static void done_proxy(void *data, int seq)
{
struct sm_object *obj = data;
@ -980,7 +981,6 @@ static void bound_proxy(void *data, uint32_t id)
static const struct pw_proxy_events proxy_events = {
PW_VERSION_PROXY_EVENTS,
.destroy = destroy_proxy,
.done = done_proxy,
.bound = bound_proxy,
};
@ -1074,7 +1074,8 @@ create_object(struct impl *impl, struct pw_proxy *proxy, struct pw_proxy *handle
}
obj = init_object(impl, info, proxy, handle, SPA_ID_INVALID, props);
pw_log_debug(NAME" %p: created new object %p proxy %p", impl, obj, obj->proxy);
pw_log_debug(NAME" %p: created new object %p proxy:%p handle:%p", impl,
obj, obj->proxy, obj->handle);
return obj;
}
@ -1271,7 +1272,7 @@ registry_global_remove(void *data, uint32_t id)
if ((obj = find_object(impl, id)) == NULL)
return;
remove_object(impl, obj);
sm_object_destroy(obj);
}
static const struct pw_registry_events registry_events = {
@ -1391,6 +1392,12 @@ static void check_endpoint_link(struct endpoint_link *link)
}
}
static void proxy_link_removed(void *data)
{
struct link *l = data;
pw_proxy_destroy(l->proxy);
}
static void proxy_link_destroy(void *data)
{
struct link *l = data;
@ -1404,6 +1411,7 @@ static void proxy_link_destroy(void *data)
static const struct pw_proxy_events proxy_link_events = {
PW_VERSION_PROXY_EVENTS,
.removed = proxy_link_removed,
.destroy = proxy_link_destroy
};
@ -1695,8 +1703,8 @@ static void session_shutdown(struct impl *impl)
pw_log_info(NAME" %p", impl);
spa_list_for_each(obj, &impl->global_list, link)
sm_media_session_emit_remove(impl, obj);
spa_list_consume(obj, &impl->global_list, link)
sm_object_destroy(obj);
sm_media_session_emit_destroy(impl);
@ -1887,6 +1895,7 @@ exit:
pw_map_clear(&impl.endpoint_links);
pw_map_clear(&impl.globals);
pw_properties_free(impl.this.props);
pw_deinit();