pipewire/src/modules/spa/spa-node.c

220 lines
5.1 KiB
C
Raw Normal View History

/* PipeWire */
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
/* SPDX-License-Identifier: MIT */
2016-11-14 12:42:00 +01:00
#include "config.h"
2016-11-14 12:42:00 +01:00
#include <string.h>
#include <stdio.h>
#include <dlfcn.h>
#include <spa/node/node.h>
#include <spa/node/utils.h>
#include <spa/utils/cleanup.h>
#include <spa/utils/result.h>
#include <spa/param/props.h>
#include <spa/pod/iter.h>
#include <spa/debug/types.h>
2016-11-14 12:42:00 +01:00
#include "spa-node.h"
2017-05-23 19:15:33 +02:00
struct impl {
2019-12-11 12:41:45 +01:00
struct pw_impl_node *this;
enum pw_spa_node_flags flags;
2016-11-14 12:42:00 +01:00
2020-11-09 15:35:12 +01:00
struct spa_handle *handle;
struct spa_node *node; /**< handle to SPA node */
struct spa_hook node_listener;
int init_pending;
2017-10-17 16:57:26 +02:00
void *user_data;
unsigned int async_init:1;
};
static void spa_node_free(void *data)
{
struct impl *impl = data;
2019-12-11 12:41:45 +01:00
struct pw_impl_node *node = impl->this;
pw_log_debug("spa-node %p: free", node);
2018-05-17 17:30:30 +02:00
spa_hook_remove(&impl->node_listener);
2019-07-17 15:31:01 +02:00
if (impl->handle)
2019-05-29 17:53:25 +02:00
pw_unload_spa_handle(impl->handle);
}
static void complete_init(struct impl *impl)
{
2019-12-11 12:41:45 +01:00
struct pw_impl_node *this = impl->this;
impl->init_pending = SPA_ID_INVALID;
if (SPA_FLAG_IS_SET(impl->flags, PW_SPA_NODE_FLAG_ACTIVATE))
2019-12-11 12:41:45 +01:00
pw_impl_node_set_active(this, true);
if (!SPA_FLAG_IS_SET(impl->flags, PW_SPA_NODE_FLAG_NO_REGISTER))
2019-12-11 12:41:45 +01:00
pw_impl_node_register(this, NULL);
else
2019-12-11 12:41:45 +01:00
pw_impl_node_initialized(this);
}
static void spa_node_result(void *data, int seq, int res, uint32_t type, const void *result)
{
struct impl *impl = data;
2019-12-11 12:41:45 +01:00
struct pw_impl_node *node = impl->this;
if (seq == impl->init_pending) {
pw_log_debug("spa-node %p: init complete event %d %d", node, seq, res);
complete_init(impl);
}
}
2019-12-11 12:41:45 +01:00
static const struct pw_impl_node_events node_events = {
PW_VERSION_IMPL_NODE_EVENTS,
.free = spa_node_free,
.result = spa_node_result,
};
2019-12-11 12:41:45 +01:00
struct pw_impl_node *
pw_spa_node_new(struct pw_context *context,
enum pw_spa_node_flags flags,
struct spa_node *node,
struct spa_handle *handle,
struct pw_properties *properties,
size_t user_data_size)
{
2019-12-11 12:41:45 +01:00
struct pw_impl_node *this;
struct impl *impl;
int res;
this = pw_context_create_node(context, properties, sizeof(struct impl) + user_data_size);
2019-06-20 11:04:34 +02:00
if (this == NULL) {
res = -errno;
goto error_exit;
}
impl = pw_impl_node_get_user_data(this);
impl->this = this;
impl->node = node;
2019-06-20 11:04:34 +02:00
impl->handle = handle;
impl->flags = flags;
2017-10-17 16:57:26 +02:00
if (user_data_size > 0)
impl->user_data = SPA_PTROFF(impl, sizeof(struct impl), void);
2017-10-17 16:57:26 +02:00
2019-12-11 12:41:45 +01:00
pw_impl_node_add_listener(this, &impl->node_listener, &node_events, impl);
if ((res = pw_impl_node_set_implementation(this, impl->node)) < 0)
2019-06-20 11:04:34 +02:00
goto error_exit_clean_node;
if (flags & PW_SPA_NODE_FLAG_ASYNC) {
impl->init_pending = spa_node_sync(impl->node, res);
} else {
complete_init(impl);
}
return this;
2019-06-20 11:04:34 +02:00
error_exit_clean_node:
2019-12-11 12:41:45 +01:00
pw_impl_node_destroy(this);
2019-06-20 11:04:34 +02:00
handle = NULL;
error_exit:
if (handle)
pw_unload_spa_handle(handle);
2019-06-19 16:22:22 +02:00
errno = -res;
return NULL;
}
2019-12-11 12:41:45 +01:00
void *pw_spa_node_get_user_data(struct pw_impl_node *node)
2017-10-17 16:57:26 +02:00
{
struct impl *impl = pw_impl_node_get_user_data(node);
2017-10-17 16:57:26 +02:00
return impl->user_data;
}
struct match {
struct pw_properties *props;
int count;
};
#define MATCH_INIT(p) ((struct match){ .props = (p) })
static int execute_match(void *data, const char *location, const char *action,
const char *val, size_t len)
{
struct match *match = data;
if (spa_streq(action, "update-props")) {
match->count += pw_properties_update_string(match->props, val, len);
}
return 1;
}
2019-12-11 12:41:45 +01:00
struct pw_impl_node *pw_spa_node_load(struct pw_context *context,
const char *factory_name,
enum pw_spa_node_flags flags,
struct pw_properties *properties,
size_t user_data_size)
{
2019-12-11 12:41:45 +01:00
struct pw_impl_node *this;
2017-05-26 08:05:01 +02:00
struct spa_node *spa_node;
int res;
struct spa_handle *handle;
void *iface;
const struct pw_properties *p;
struct pw_loop *loop;
struct match match;
if (properties == NULL) {
properties = pw_properties_new(NULL, NULL);
if (properties == NULL)
return NULL;
}
p = pw_context_get_properties(context);
pw_properties_set(properties, "clock.quantum-limit",
pw_properties_get(p, "default.clock.quantum-limit"));
match = MATCH_INIT(properties);
pw_context_conf_section_match_rules(context, "node.rules",
&properties->dict, execute_match, &match);
loop = pw_context_acquire_loop(context, &properties->dict);
if (loop == NULL) {
res = -errno;
goto error_exit;
}
pw_properties_set(properties, PW_KEY_NODE_LOOP_NAME, loop->name);
pw_context_release_loop(context, loop);
handle = pw_context_load_spa_handle(context, factory_name, &properties->dict);
2019-06-19 16:22:22 +02:00
if (handle == NULL) {
res = -errno;
goto error_exit;
2019-06-19 16:22:22 +02:00
}
2018-04-09 10:06:17 +02:00
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Node, &iface)) < 0) {
pw_log_error("can't get node interface %d", res);
2019-06-20 11:04:34 +02:00
goto error_exit_unload;
2017-05-26 08:05:01 +02:00
}
2019-05-29 17:53:25 +02:00
if (SPA_RESULT_IS_ASYNC(res))
flags |= PW_SPA_NODE_FLAG_ASYNC;
2017-05-26 08:05:01 +02:00
spa_node = iface;
this = pw_spa_node_new(context, flags,
spa_node, handle, spa_steal_ptr(properties), user_data_size);
2019-06-19 16:22:22 +02:00
if (this == NULL) {
res = -errno;
goto error_exit_unload;
2019-06-19 16:22:22 +02:00
}
2017-05-26 08:05:01 +02:00
return this;
2019-06-20 11:04:34 +02:00
error_exit_unload:
2019-05-29 17:53:25 +02:00
pw_unload_spa_handle(handle);
error_exit:
pw_properties_free(properties);
2019-06-19 16:22:22 +02:00
errno = -res;
2017-05-26 08:05:01 +02:00
return NULL;
2016-11-14 12:42:00 +01:00
}