Add proxy destroy

Make the current destroy method on the core for proxies to remove the
server side resource.
Make a new destroy method on the registry to destroy globals.
Remove the destroy method on the client-node
media-session: monitor the dsp and device node states to manage the
session state
This commit is contained in:
Wim Taymans 2018-09-21 16:43:11 +02:00
parent ce4cfd78e7
commit 59f10ad453
10 changed files with 276 additions and 157 deletions

View file

@ -42,6 +42,8 @@
#define DEFAULT_CHANNELS 2
#define DEFAULT_SAMPLERATE 48000
#define DEFAULT_IDLE_SECONDS 3
#define MIN_QUANTUM_SIZE 64
#define MAX_QUANTUM_SIZE 1024
@ -86,6 +88,7 @@ struct node {
struct spa_list session_link;
struct session *session;
struct session *manager;
struct spa_list port_list;
enum pw_direction direction;
@ -126,7 +129,8 @@ struct session {
struct node *node;
struct node *dsp;
struct link *link;
struct pw_link_proxy *link;
struct spa_hook link_listener;
struct spa_list node_list;
@ -173,18 +177,152 @@ static void schedule_rescan(struct impl *impl)
static void remove_idle_timeout(struct session *sess)
{
struct impl *impl = sess->impl;
struct pw_loop *main_loop = pw_core_get_main_loop(impl->core);
if (sess->idle_timeout) {
pw_loop_destroy_source(pw_core_get_main_loop(impl->core), sess->idle_timeout);
pw_loop_destroy_source(main_loop, sess->idle_timeout);
sess->idle_timeout = NULL;
}
}
static void idle_timeout(void *data, uint64_t expirations)
{
struct session *sess = data;
struct impl *impl = sess->impl;
struct spa_command *cmd = &SPA_NODE_COMMAND_INIT(SPA_NODE_COMMAND_Suspend);
pw_log_debug(NAME " %p: session %d idle timeout", impl, sess->id);
remove_idle_timeout(sess);
pw_node_proxy_send_command((struct pw_node_proxy*)sess->node->obj.proxy, cmd);
if (sess->dsp)
pw_node_proxy_send_command((struct pw_node_proxy*)sess->dsp->obj.proxy, cmd);
}
static void add_idle_timeout(struct session *sess)
{
struct timespec value;
struct impl *impl = sess->impl;
struct pw_loop *main_loop = pw_core_get_main_loop(impl->core);
if (sess->idle_timeout == NULL)
sess->idle_timeout = pw_loop_add_timer(main_loop, idle_timeout, sess);
value.tv_sec = DEFAULT_IDLE_SECONDS;
value.tv_nsec = 0;
pw_loop_update_timer(main_loop, sess->idle_timeout, &value, NULL, false);
}
static int unlink_session_dsp(struct impl *impl, struct session *session)
{
pw_core_proxy_destroy(impl->core_proxy, (struct pw_proxy*)session->link);
session->link = NULL;
return 0;
}
static int on_node_idle(struct impl *impl, struct node *node)
{
struct session *sess = node->manager;
if (sess == NULL)
return 0;
switch (node->type) {
case NODE_TYPE_DSP:
pw_log_debug(NAME" %p: dsp idle for session %d", impl, sess->id);
if (sess->link)
unlink_session_dsp(impl, sess);
break;
case NODE_TYPE_DEVICE:
pw_log_debug(NAME" %p: device idle for session %d", impl, sess->id);
sess->busy = false;
sess->exclusive = false;
add_idle_timeout(sess);
break;
default:
break;
}
return 0;
}
static int link_session_dsp(struct impl *impl, struct session *session)
{
struct pw_properties *props;
pw_log_debug(NAME " %p: link session dsp '%d'", impl, session->id);
props = pw_properties_new(NULL, NULL);
// pw_properties_set(props, PW_LINK_PROP_PASSIVE, "true");
if (session->direction == PW_DIRECTION_OUTPUT) {
pw_properties_setf(props, PW_LINK_OUTPUT_NODE_ID, "%d", session->dsp->info->id);
pw_properties_setf(props, PW_LINK_OUTPUT_PORT_ID, "%d", -1);
pw_properties_setf(props, PW_LINK_INPUT_NODE_ID, "%d", session->node->info->id);
pw_properties_setf(props, PW_LINK_INPUT_PORT_ID, "%d", -1);
}
else {
pw_properties_setf(props, PW_LINK_OUTPUT_NODE_ID, "%d", session->node->info->id);
pw_properties_setf(props, PW_LINK_OUTPUT_PORT_ID, "%d", -1);
pw_properties_setf(props, PW_LINK_INPUT_NODE_ID, "%d", session->dsp->info->id);
pw_properties_setf(props, PW_LINK_INPUT_PORT_ID, "%d", -1);
}
session->link = pw_core_proxy_create_object(impl->core_proxy,
"link-factory",
PW_TYPE_INTERFACE_Link,
PW_VERSION_LINK,
&props->dict,
0);
return 0;
}
static int on_node_running(struct impl *impl, struct node *node)
{
struct session *sess = node->manager;
if (sess == NULL)
return 0;
switch (node->type) {
case NODE_TYPE_DSP:
pw_log_debug(NAME" %p: dsp running for session %d", impl, sess->id);
if (sess->link == NULL)
link_session_dsp(impl, sess);
break;
case NODE_TYPE_DEVICE:
pw_log_debug(NAME" %p: device running or session %d", impl, sess->id);
remove_idle_timeout(sess);
break;
default:
break;
}
return 0;
}
static void node_event_info(void *object, struct pw_node_info *info)
{
struct node *n = object;
pw_log_debug(NAME" %p: info for node %d", n->obj.impl, n->obj.id);
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);
switch (info->state) {
case PW_NODE_STATE_IDLE:
on_node_idle(impl, n);
break;
case PW_NODE_STATE_RUNNING:
on_node_running(impl, n);
break;
case PW_NODE_STATE_SUSPENDED:
break;
default:
break;
}
}
static const struct pw_node_proxy_events node_events = {
@ -299,6 +437,7 @@ handle_node(struct impl *impl, uint32_t id, uint32_t parent_id,
node->direction = direction;
node->type = NODE_TYPE_DEVICE;
node->manager = sess;
pw_log_debug(NAME" %p: new session for device node %d", impl, id);
}
@ -432,23 +571,9 @@ registry_global(void *data,uint32_t id, uint32_t parent_id,
schedule_rescan(impl);
}
static void
registry_global_remove(void *data, uint32_t id)
static void remove_session(struct impl *impl, struct session *sess)
{
struct impl *impl = data;
struct object *obj;
struct session *sess;
pw_log_debug(NAME " %p: remove global '%d'", impl, id);
if ((obj = find_object(impl, id)) == NULL)
return;
spa_list_for_each(sess, &impl->session_list, l) {
struct node *node = (struct node *)obj, *n, *t;
if (sess->node != node)
continue;
struct node *n, *t;
pw_log_debug(NAME " %p: remove session '%d'", impl, sess->id);
remove_idle_timeout(sess);
@ -459,15 +584,36 @@ registry_global_remove(void *data, uint32_t id)
}
if (sess->dsp) {
uint32_t id = ((struct object *)sess->dsp)->id;
pw_log_debug(NAME " %p: destroy dsp '%d'", impl, id);
pw_core_proxy_destroy(impl->core_proxy, id);
pw_log_debug(NAME " %p: destroy dsp", impl);
pw_core_proxy_destroy(impl->core_proxy, sess->dsp->obj.proxy);
}
spa_list_remove(&sess->l);
free(sess);
}
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;
switch (obj->type) {
case PW_TYPE_INTERFACE_Node:
{
struct node *node = (struct node*) obj;
if (node->manager)
remove_session(impl, node->manager);
break;
}
default:
break;
}
remove_object(impl, obj);
schedule_rescan(impl);
}
@ -479,39 +625,6 @@ static const struct pw_registry_proxy_events registry_events = {
};
static int link_session_dsp(struct session *session)
{
struct impl *impl = session->impl;
struct pw_properties *props;
pw_log_debug(NAME " %p: link session dsp '%d'", impl, session->id);
props = pw_properties_new(NULL, NULL);
pw_properties_set(props, PW_LINK_PROP_PASSIVE, "true");
if (session->direction == PW_DIRECTION_OUTPUT) {
pw_properties_setf(props, PW_LINK_OUTPUT_NODE_ID, "%d", session->dsp->info->id);
pw_properties_setf(props, PW_LINK_OUTPUT_PORT_ID, "%d", -1);
pw_properties_setf(props, PW_LINK_INPUT_NODE_ID, "%d", session->node->info->id);
pw_properties_setf(props, PW_LINK_INPUT_PORT_ID, "%d", -1);
}
else {
pw_properties_setf(props, PW_LINK_OUTPUT_NODE_ID, "%d", session->node->info->id);
pw_properties_setf(props, PW_LINK_OUTPUT_PORT_ID, "%d", -1);
pw_properties_setf(props, PW_LINK_INPUT_NODE_ID, "%d", session->dsp->info->id);
pw_properties_setf(props, PW_LINK_INPUT_PORT_ID, "%d", -1);
}
session->link = pw_core_proxy_create_object(impl->core_proxy,
"link-factory",
PW_TYPE_INTERFACE_Link,
PW_VERSION_LINK,
&props->dict,
0);
return 0;
}
struct find_data {
struct impl *impl;
uint32_t path_id;
@ -618,7 +731,6 @@ static int rescan_node(struct impl *impl, struct node *node)
struct pw_node_info *info;
struct node *peer;
enum pw_direction direction;
int res;
if (node->type == NODE_TYPE_DSP || node->type == NODE_TYPE_DEVICE)
return 0;
@ -722,10 +834,6 @@ static int rescan_node(struct impl *impl, struct node *node)
session->exclusive = exclusive;
}
else {
if (session->link == NULL) {
if ((res = link_session_dsp(session)) < 0)
return res;
}
peer = session->dsp;
}
@ -734,7 +842,6 @@ static int rescan_node(struct impl *impl, struct node *node)
session->busy = true;
node->session = session;
spa_list_append(&session->node_list, &node->session_link);
remove_idle_timeout(session);
link_nodes(peer, direction, node);
@ -756,6 +863,7 @@ static void dsp_node_event_info(void *object, struct pw_node_info *info)
dsp->direction = s->direction;
dsp->type = NODE_TYPE_DSP;
dsp->manager = s;
}
static const struct pw_node_proxy_events dsp_node_events = {
@ -763,36 +871,8 @@ static const struct pw_node_proxy_events dsp_node_events = {
.info = dsp_node_event_info,
};
static void idle_timeout(void *data, uint64_t expirations)
{
struct session *sess = data;
struct impl *impl = sess->impl;
struct spa_command *cmd = &SPA_NODE_COMMAND_INIT(SPA_NODE_COMMAND_Suspend);
pw_log_debug(NAME " %p: session %d idle timeout", impl, sess->id);
remove_idle_timeout(sess);
pw_node_proxy_send_command((struct pw_node_proxy*)sess->node->obj.proxy, cmd);
if (sess->dsp)
pw_node_proxy_send_command((struct pw_node_proxy*)sess->dsp->obj.proxy, cmd);
}
static void rescan_session(struct impl *impl, struct session *sess)
{
if (spa_list_is_empty(&sess->node_list) && sess->busy) {
struct pw_loop *main_loop = pw_core_get_main_loop(impl->core);
struct timespec value;
pw_log_debug(NAME "%p: session %d became idle", impl, sess->id);
sess->exclusive = false;
sess->busy = false;
sess->idle_timeout = pw_loop_add_timer(main_loop, idle_timeout, sess);
value.tv_sec = 3;
value.tv_nsec = 0;
pw_loop_update_timer(main_loop, sess->idle_timeout, &value, NULL, false);
}
if (sess->need_dsp && sess->dsp == NULL && !sess->dsp_pending) {
struct pw_properties *props;
struct node *node = sess->node;

View file

@ -58,8 +58,7 @@ struct pw_client_node_position {
#define PW_CLIENT_NODE_PROXY_METHOD_PORT_UPDATE 2
#define PW_CLIENT_NODE_PROXY_METHOD_SET_ACTIVE 3
#define PW_CLIENT_NODE_PROXY_METHOD_EVENT 4
#define PW_CLIENT_NODE_PROXY_METHOD_DESTROY 5
#define PW_CLIENT_NODE_PROXY_METHOD_NUM 6
#define PW_CLIENT_NODE_PROXY_METHOD_NUM 5
/** \ref pw_client_node methods */
struct pw_client_node_proxy_methods {
@ -120,10 +119,6 @@ struct pw_client_node_proxy_methods {
* \param event the event to send
*/
void (*event) (void *object, struct spa_event *event);
/**
* Destroy the client_node
*/
void (*destroy) (void *object);
};
static inline void
@ -176,13 +171,6 @@ pw_client_node_proxy_event(struct pw_client_node_proxy *p, struct spa_event *eve
pw_proxy_do((struct pw_proxy*)p, struct pw_client_node_proxy_methods, event, event);
}
static inline void
pw_client_node_proxy_destroy(struct pw_client_node_proxy *p)
{
pw_proxy_do((struct pw_proxy*)p, struct pw_client_node_proxy_methods, destroy);
}
#define PW_CLIENT_NODE_PROXY_EVENT_ADD_MEM 0
#define PW_CLIENT_NODE_PROXY_EVENT_TRANSPORT 1
#define PW_CLIENT_NODE_PROXY_EVENT_SET_PARAM 2

View file

@ -1086,12 +1086,6 @@ static void client_node_event(void *data, struct spa_event *event)
this->callbacks->event(this->callbacks_data, event);
}
static void client_node_destroy(void *data)
{
struct impl *impl = data;
pw_client_node_destroy(&impl->this);
}
static struct pw_client_node_proxy_methods client_node_methods = {
PW_VERSION_CLIENT_NODE_PROXY_METHODS,
.done = client_node_done,
@ -1099,7 +1093,6 @@ static struct pw_client_node_proxy_methods client_node_methods = {
.port_update = client_node_port_update,
.set_active = client_node_set_active,
.event = client_node_event,
.destroy = client_node_destroy,
};
static void node_on_data_fd_events(struct spa_source *source)

View file

@ -153,18 +153,6 @@ static void client_node_marshal_event_method(void *object, struct spa_event *eve
pw_protocol_native_end_proxy(proxy, b);
}
static void client_node_marshal_destroy(void *object)
{
struct pw_proxy *proxy = object;
struct spa_pod_builder *b;
b = pw_protocol_native_begin_proxy(proxy, PW_CLIENT_NODE_PROXY_METHOD_DESTROY);
spa_pod_builder_add_struct(b);
pw_protocol_native_end_proxy(proxy, b);
}
static int client_node_demarshal_add_mem(void *object, void *data, size_t size)
{
struct pw_proxy *proxy = object;
@ -874,27 +862,13 @@ static int client_node_demarshal_event_method(void *object, void *data, size_t s
return 0;
}
static int client_node_demarshal_destroy(void *object, void *data, size_t size)
{
struct pw_resource *resource = object;
struct spa_pod_parser prs;
spa_pod_parser_init(&prs, data, size, 0);
if (spa_pod_parser_get(&prs, "[", NULL) < 0)
return -EINVAL;
pw_resource_do(resource, struct pw_client_node_proxy_methods, destroy, 0);
return 0;
}
static const struct pw_client_node_proxy_methods pw_protocol_native_client_node_method_marshal = {
PW_VERSION_CLIENT_NODE_PROXY_METHODS,
&client_node_marshal_done,
&client_node_marshal_update,
&client_node_marshal_port_update,
&client_node_marshal_set_active,
&client_node_marshal_event_method,
&client_node_marshal_destroy
&client_node_marshal_event_method
};
static const struct pw_protocol_native_demarshal pw_protocol_native_client_node_method_demarshal[] = {
@ -902,8 +876,7 @@ static const struct pw_protocol_native_demarshal pw_protocol_native_client_node_
{ &client_node_demarshal_update, 0 },
{ &client_node_demarshal_port_update, 0 },
{ &client_node_demarshal_set_active, 0 },
{ &client_node_demarshal_event_method, 0 },
{ &client_node_demarshal_destroy, 0 },
{ &client_node_demarshal_event_method, 0 }
};
static const struct pw_client_node_proxy_events pw_protocol_native_client_node_event_marshal = {

View file

@ -509,6 +509,22 @@ static int registry_demarshal_bind(void *object, void *data, size_t size)
return 0;
}
static int registry_demarshal_destroy(void *object, void *data, size_t size)
{
struct pw_resource *resource = object;
struct spa_pod_parser prs;
uint32_t id;
spa_pod_parser_init(&prs, data, size, 0);
if (spa_pod_parser_get(&prs,
"["
"i", &id, NULL) < 0)
return -EINVAL;
pw_resource_do(resource, struct pw_registry_proxy_methods, destroy, 0, id);
return 0;
}
static void module_marshal_info(void *object, struct pw_module_info *info)
{
struct pw_resource *resource = object;
@ -1127,6 +1143,17 @@ static void registry_marshal_bind(void *object, uint32_t id,
pw_protocol_native_end_proxy(proxy, b);
}
static void registry_marshal_destroy(void *object, uint32_t id)
{
struct pw_proxy *proxy = object;
struct spa_pod_builder *b;
b = pw_protocol_native_begin_proxy(proxy, PW_REGISTRY_PROXY_METHOD_DESTROY);
spa_pod_builder_add_struct(b,
"i", id);
pw_protocol_native_end_proxy(proxy, b);
}
static const struct pw_core_proxy_methods pw_protocol_native_core_method_marshal = {
PW_VERSION_CORE_PROXY_METHODS,
&core_marshal_hello,
@ -1177,10 +1204,12 @@ static const struct pw_protocol_marshal pw_protocol_native_core_marshal = {
static const struct pw_registry_proxy_methods pw_protocol_native_registry_method_marshal = {
PW_VERSION_REGISTRY_PROXY_METHODS,
&registry_marshal_bind,
&registry_marshal_destroy,
};
static const struct pw_protocol_native_demarshal pw_protocol_native_registry_method_demarshal[] = {
{ &registry_demarshal_bind, 0, },
{ &registry_demarshal_destroy, 0, },
};
static const struct pw_registry_proxy_events pw_protocol_native_registry_event_marshal = {

View file

@ -89,9 +89,38 @@ static void registry_bind(void *object, uint32_t id,
pw_core_resource_remove_id(client->core_resource, new_id);
}
static void registry_destroy(void *object, uint32_t id)
{
struct pw_resource *resource = object;
struct pw_client *client = resource->client;
struct pw_core *core = resource->core;
struct pw_global *global;
uint32_t permissions;
if ((global = pw_core_find_global(core, id)) == NULL)
goto no_id;
permissions = pw_global_get_permissions(global, client);
if (!PW_PERM_IS_X(permissions))
goto no_id;
pw_log_debug("global %p: destroy global id %d", global, id);
pw_global_destroy(global);
return;
no_id:
pw_log_debug("registry %p: no global with id %u to destroy", resource, id);
goto exit;
exit:
return;
}
static const struct pw_registry_proxy_methods registry_methods = {
PW_VERSION_REGISTRY_PROXY_METHODS,
.bind = registry_bind
.bind = registry_bind,
.destroy = registry_destroy
};
static void destroy_registry_resource(void *object)
@ -254,16 +283,24 @@ core_create_object(void *object,
static void core_destroy(void *object, uint32_t id)
{
struct pw_resource *resource = object;
struct pw_core *this = resource->core;
struct pw_global *global;
struct pw_client *client = resource->client;
struct pw_resource *r;
pw_log_debug("core %p: destroy %d from resource %p", resource->core, id, resource);
global = pw_core_find_global(this, id);
if (global == NULL)
if ((r = pw_client_find_resource(client, id)) == NULL)
goto no_resource;
pw_resource_destroy(r);
done:
return;
pw_global_destroy(global);
no_resource:
pw_log_error("can't find resouce %d", id);
pw_core_resource_error(client->core_resource,
resource->id, -EINVAL, "unknown resouce %d", id);
goto done;
}
static const struct pw_core_proxy_methods core_methods = {

View file

@ -259,9 +259,9 @@ void pw_global_destroy(struct pw_global *global)
{
struct pw_core *core = global->core;
pw_log_debug("global %p: destroy %u", global, global->id);
global_unregister(global);
pw_log_debug("global %p: destroy %u", global, global->id);
pw_global_events_destroy(global);
pw_map_remove(&core->globals, global->id);

View file

@ -172,11 +172,12 @@ struct pw_core_proxy_methods {
uint32_t version,
const struct spa_dict *props,
uint32_t new_id);
/**
* Destroy an object id
* Destroy an resource
*
* \param id the object id to destroy
* Destroy the server resource with the given proxy id.
*
* \param id the client proxy id to destroy
*/
void (*destroy) (void *object, uint32_t id);
};
@ -228,9 +229,9 @@ pw_core_proxy_create_object(struct pw_core_proxy *core,
}
static inline void
pw_core_proxy_destroy(struct pw_core_proxy *core, uint32_t id)
pw_core_proxy_destroy(struct pw_core_proxy *core, struct pw_proxy *proxy)
{
pw_proxy_do((struct pw_proxy*)core, struct pw_core_proxy_methods, destroy, id);
pw_proxy_do((struct pw_proxy*)core, struct pw_core_proxy_methods, destroy, pw_proxy_get_id(proxy));
}
#define PW_CORE_PROXY_EVENT_DONE 0
@ -336,7 +337,8 @@ pw_core_proxy_add_listener(struct pw_core_proxy *core,
* the access permissions on an object.
*/
#define PW_REGISTRY_PROXY_METHOD_BIND 0
#define PW_REGISTRY_PROXY_METHOD_NUM 1
#define PW_REGISTRY_PROXY_METHOD_DESTROY 1
#define PW_REGISTRY_PROXY_METHOD_NUM 2
/** Registry methods */
struct pw_registry_proxy_methods {
@ -355,6 +357,15 @@ struct pw_registry_proxy_methods {
* \param new_id the client proxy to use
*/
void (*bind) (void *object, uint32_t id, uint32_t type, uint32_t version, uint32_t new_id);
/**
* Attempt to destroy a global object
*
* Try to destroy the global object.
*
* \param id the global id to destroy
*/
void (*destroy) (void *object, uint32_t id);
};
/** Registry */
@ -369,6 +380,13 @@ pw_registry_proxy_bind(struct pw_registry_proxy *registry,
return p;
}
static inline void
pw_registry_proxy_destroy(struct pw_registry_proxy *registry, uint32_t id)
{
struct pw_proxy *reg = (struct pw_proxy*)registry;
pw_proxy_do(reg, struct pw_registry_proxy_methods, destroy, id);
}
#define PW_REGISTRY_PROXY_EVENT_GLOBAL 0
#define PW_REGISTRY_PROXY_EVENT_GLOBAL_REMOVE 1
#define PW_REGISTRY_PROXY_EVENT_NUM 2

View file

@ -1270,8 +1270,9 @@ static void do_node_init(struct pw_proxy *proxy)
static void node_destroy(void *data)
{
struct node_data *d = data;
struct pw_remote *remote = d->remote;
pw_log_debug("%p: destroy", d);
pw_client_node_proxy_destroy(d->node_proxy);
pw_core_proxy_destroy(remote->core_proxy, (struct pw_proxy *)d->node_proxy);
pw_proxy_destroy((struct pw_proxy *)d->node_proxy);
}

View file

@ -992,7 +992,7 @@ static bool do_destroy(struct data *data, const char *cmd, char *args, char **er
asprintf(error, "%s: unknown global %d", cmd, id);
return false;
}
pw_core_proxy_destroy(rd->core_proxy, id);
pw_registry_proxy_destroy(rd->registry_proxy, id);
return true;
}