mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
Improve loop callbacks
Pass just one data item to the callbacks. Add properties to port. Add user data to link Handle autolink with multiple ports More work on jack support
This commit is contained in:
parent
cfd9967637
commit
9ad1f911b2
38 changed files with 1773 additions and 271 deletions
|
|
@ -90,7 +90,8 @@ static inline void spa_graph_scheduler_pull(struct spa_graph_scheduler *sched, s
|
||||||
pnode = pport->node;
|
pnode = pport->node;
|
||||||
debug("node %p peer %p io %d\n", node, pnode, pport->io->status);
|
debug("node %p peer %p io %d\n", node, pnode, pport->io->status);
|
||||||
if (pport->io->status == SPA_RESULT_NEED_BUFFER) {
|
if (pport->io->status == SPA_RESULT_NEED_BUFFER) {
|
||||||
spa_list_insert(ready.prev, &pnode->ready_link);
|
if (pnode->ready_link.next == NULL)
|
||||||
|
spa_list_append(&ready, &pnode->ready_link);
|
||||||
}
|
}
|
||||||
else if (pport->io->status == SPA_RESULT_OK && !(pnode->flags & SPA_GRAPH_NODE_FLAG_ASYNC))
|
else if (pport->io->status == SPA_RESULT_OK && !(pnode->flags & SPA_GRAPH_NODE_FLAG_ASYNC))
|
||||||
node->ready_in++;
|
node->ready_in++;
|
||||||
|
|
@ -111,7 +112,7 @@ static inline void spa_graph_scheduler_pull(struct spa_graph_scheduler *sched, s
|
||||||
n->ready_link.next = NULL;
|
n->ready_link.next = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug("node %p %d %d\n", node, node->ready_in, node->required_in);
|
debug("node %p ready_in:%d required_in:%d\n", node, node->ready_in, node->required_in);
|
||||||
|
|
||||||
if (node->required_in > 0 && node->ready_in == node->required_in) {
|
if (node->required_in > 0 && node->ready_in == node->required_in) {
|
||||||
node->state = node->callbacks->process_input(node->callbacks_data);
|
node->state = node->callbacks->process_input(node->callbacks_data);
|
||||||
|
|
@ -179,7 +180,8 @@ static inline void spa_graph_scheduler_push(struct spa_graph_scheduler *sched, s
|
||||||
pnode->ready_in, pnode->required_in);
|
pnode->ready_in, pnode->required_in);
|
||||||
|
|
||||||
if (pnode->required_in > 0 && pnode->ready_in == pnode->required_in)
|
if (pnode->required_in > 0 && pnode->ready_in == pnode->required_in)
|
||||||
spa_list_insert(ready.prev, &pnode->ready_link);
|
if (pnode->ready_link.next == NULL)
|
||||||
|
spa_list_append(&ready, &pnode->ready_link);
|
||||||
}
|
}
|
||||||
|
|
||||||
spa_graph_scheduler_chain(sched, &ready);
|
spa_graph_scheduler_chain(sched, &ready);
|
||||||
|
|
|
||||||
|
|
@ -148,19 +148,11 @@ struct spa_loop_control {
|
||||||
#define spa_loop_control_leave(l) (l)->leave(l)
|
#define spa_loop_control_leave(l) (l)->leave(l)
|
||||||
|
|
||||||
|
|
||||||
typedef void (*spa_source_io_func_t) (struct spa_loop_utils *utils,
|
typedef void (*spa_source_io_func_t) (void *data, int fd, enum spa_io mask);
|
||||||
struct spa_source *source,
|
typedef void (*spa_source_idle_func_t) (void *data);
|
||||||
int fd, enum spa_io mask, void *data);
|
typedef void (*spa_source_event_func_t) (void *data, uint64_t count);
|
||||||
typedef void (*spa_source_idle_func_t) (struct spa_loop_utils *utils,
|
typedef void (*spa_source_timer_func_t) (void *data, uint64_t expirations);
|
||||||
struct spa_source *source, void *data);
|
typedef void (*spa_source_signal_func_t) (void *data, int signal_number);
|
||||||
typedef void (*spa_source_event_func_t) (struct spa_loop_utils *utils,
|
|
||||||
struct spa_source *source,
|
|
||||||
uint64_t count, void *data);
|
|
||||||
typedef void (*spa_source_timer_func_t) (struct spa_loop_utils *utils,
|
|
||||||
struct spa_source *source, void *data);
|
|
||||||
typedef void (*spa_source_signal_func_t) (struct spa_loop_utils *utils,
|
|
||||||
struct spa_source *source,
|
|
||||||
int signal_number, void *data);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct spa_loop_utils:
|
* struct spa_loop_utils:
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,7 @@ loop_invoke(struct spa_loop *loop,
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wakeup_func(struct spa_loop_utils *utils, struct spa_source *source, uint64_t count, void *data)
|
static void wakeup_func(void *data, uint64_t count)
|
||||||
{
|
{
|
||||||
struct impl *impl = data;
|
struct impl *impl = data;
|
||||||
uint32_t index;
|
uint32_t index;
|
||||||
|
|
@ -357,7 +357,7 @@ static int loop_iterate(struct spa_loop_control *ctrl, int timeout)
|
||||||
static void source_io_func(struct spa_source *source)
|
static void source_io_func(struct spa_source *source)
|
||||||
{
|
{
|
||||||
struct source_impl *impl = SPA_CONTAINER_OF(source, struct source_impl, source);
|
struct source_impl *impl = SPA_CONTAINER_OF(source, struct source_impl, source);
|
||||||
impl->func.io(&impl->impl->utils, source, source->fd, source->rmask, source->data);
|
impl->func.io(source->data, source->fd, source->rmask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct spa_source *loop_add_io(struct spa_loop_utils *utils,
|
static struct spa_source *loop_add_io(struct spa_loop_utils *utils,
|
||||||
|
|
@ -398,7 +398,7 @@ static int loop_update_io(struct spa_source *source, enum spa_io mask)
|
||||||
static void source_idle_func(struct spa_source *source)
|
static void source_idle_func(struct spa_source *source)
|
||||||
{
|
{
|
||||||
struct source_impl *impl = SPA_CONTAINER_OF(source, struct source_impl, source);
|
struct source_impl *impl = SPA_CONTAINER_OF(source, struct source_impl, source);
|
||||||
impl->func.idle(&impl->impl->utils, source, source->data);
|
impl->func.idle(source->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct spa_source *loop_add_idle(struct spa_loop_utils *utils,
|
static struct spa_source *loop_add_idle(struct spa_loop_utils *utils,
|
||||||
|
|
@ -457,7 +457,7 @@ static void source_event_func(struct spa_source *source)
|
||||||
spa_log_warn(impl->impl->log, NAME " %p: failed to read event fd %d: %s",
|
spa_log_warn(impl->impl->log, NAME " %p: failed to read event fd %d: %s",
|
||||||
source, source->fd, strerror(errno));
|
source, source->fd, strerror(errno));
|
||||||
|
|
||||||
impl->func.event(&impl->impl->utils, source, count, source->data);
|
impl->func.event(source->data, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct spa_source *loop_add_event(struct spa_loop_utils *utils,
|
static struct spa_source *loop_add_event(struct spa_loop_utils *utils,
|
||||||
|
|
@ -499,13 +499,13 @@ static void loop_signal_event(struct spa_source *source)
|
||||||
static void source_timer_func(struct spa_source *source)
|
static void source_timer_func(struct spa_source *source)
|
||||||
{
|
{
|
||||||
struct source_impl *impl = SPA_CONTAINER_OF(source, struct source_impl, source);
|
struct source_impl *impl = SPA_CONTAINER_OF(source, struct source_impl, source);
|
||||||
uint64_t expires;
|
uint64_t expirations;
|
||||||
|
|
||||||
if (read(source->fd, &expires, sizeof(uint64_t)) != sizeof(uint64_t))
|
if (read(source->fd, &expirations, sizeof(uint64_t)) != sizeof(uint64_t))
|
||||||
spa_log_warn(impl->impl->log, NAME " %p: failed to read timer fd %d: %s",
|
spa_log_warn(impl->impl->log, NAME " %p: failed to read timer fd %d: %s",
|
||||||
source, source->fd, strerror(errno));
|
source, source->fd, strerror(errno));
|
||||||
|
|
||||||
impl->func.timer(&impl->impl->utils, source, source->data);
|
impl->func.timer(source->data, expirations);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct spa_source *loop_add_timer(struct spa_loop_utils *utils,
|
static struct spa_source *loop_add_timer(struct spa_loop_utils *utils,
|
||||||
|
|
@ -568,7 +568,7 @@ static void source_signal_func(struct spa_source *source)
|
||||||
spa_log_warn(impl->impl->log, NAME " %p: failed to read signal fd %d: %s",
|
spa_log_warn(impl->impl->log, NAME " %p: failed to read signal fd %d: %s",
|
||||||
source, source->fd, strerror(errno));
|
source, source->fd, strerror(errno));
|
||||||
|
|
||||||
impl->func.signal(&impl->impl->utils, source, impl->signal_number, source->data);
|
impl->func.signal(source->data, impl->signal_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct spa_source *loop_add_signal(struct spa_loop_utils *utils,
|
static struct spa_source *loop_add_signal(struct spa_loop_utils *utils,
|
||||||
|
|
|
||||||
|
|
@ -434,7 +434,7 @@ static void make_node(struct data *data)
|
||||||
data->node = pw_node_new(data->core, NULL, NULL, "SDL-sink", props, 0);
|
data->node = pw_node_new(data->core, NULL, NULL, "SDL-sink", props, 0);
|
||||||
pw_node_set_implementation(data->node, &impl_node, data);
|
pw_node_set_implementation(data->node, &impl_node, data);
|
||||||
|
|
||||||
data->port = pw_port_new(PW_DIRECTION_INPUT, 0, 0);
|
data->port = pw_port_new(PW_DIRECTION_INPUT, 0, NULL, 0);
|
||||||
pw_port_set_implementation(data->port, &impl_port, data);
|
pw_port_set_implementation(data->port, &impl_port, data);
|
||||||
pw_port_add(data->port, data->node);
|
pw_port_add(data->port, data->node);
|
||||||
pw_node_register(data->node);
|
pw_node_register(data->node);
|
||||||
|
|
|
||||||
|
|
@ -411,7 +411,7 @@ static void make_nodes(struct data *data)
|
||||||
data->node = pw_node_new(data->core, NULL, NULL, "SDL-sink", NULL, 0);
|
data->node = pw_node_new(data->core, NULL, NULL, "SDL-sink", NULL, 0);
|
||||||
pw_node_set_implementation(data->node, &impl_node, data);
|
pw_node_set_implementation(data->node, &impl_node, data);
|
||||||
|
|
||||||
data->port = pw_port_new(PW_DIRECTION_INPUT, 0, 0);
|
data->port = pw_port_new(PW_DIRECTION_INPUT, 0, NULL, 0);
|
||||||
pw_port_set_implementation(data->port, &impl_port, data);
|
pw_port_set_implementation(data->port, &impl_port, data);
|
||||||
pw_port_add(data->port, data->node);
|
pw_port_add(data->port, data->node);
|
||||||
pw_node_register(data->node);
|
pw_node_register(data->node);
|
||||||
|
|
@ -427,7 +427,8 @@ static void make_nodes(struct data *data)
|
||||||
data->port,
|
data->port,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL,
|
||||||
|
0);
|
||||||
pw_link_activate(data->link);
|
pw_link_activate(data->link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ struct data {
|
||||||
uint32_t seq;
|
uint32_t seq;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void on_timeout(struct spa_loop_utils *utils, struct spa_source *source, void *userdata)
|
static void on_timeout(void *userdata, uint64_t expirations)
|
||||||
{
|
{
|
||||||
struct data *data = userdata;
|
struct data *data = userdata;
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,8 @@ pipewire_module_protocol_native = shared_library('pipewire-module-protocol-nativ
|
||||||
if jack_dep.found()
|
if jack_dep.found()
|
||||||
pipewire_module_jack = shared_library('pipewire-module-jack',
|
pipewire_module_jack = shared_library('pipewire-module-jack',
|
||||||
[ 'module-jack.c',
|
[ 'module-jack.c',
|
||||||
'module-jack/shm.c' ],
|
'module-jack/shm.c',
|
||||||
|
'module-jack/jack-node.c' ],
|
||||||
c_args : pipewire_module_c_args,
|
c_args : pipewire_module_c_args,
|
||||||
include_directories : [configinc, spa_inc],
|
include_directories : [configinc, spa_inc],
|
||||||
link_with : spalib,
|
link_with : spalib,
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,13 @@ struct node_info {
|
||||||
struct pw_node *node;
|
struct pw_node *node;
|
||||||
struct spa_hook node_listener;
|
struct spa_hook node_listener;
|
||||||
|
|
||||||
|
struct spa_list links;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct link_data {
|
||||||
|
struct spa_list l;
|
||||||
|
|
||||||
|
struct node_info *node_info;
|
||||||
struct pw_link *link;
|
struct pw_link *link;
|
||||||
struct spa_hook link_listener;
|
struct spa_hook link_listener;
|
||||||
};
|
};
|
||||||
|
|
@ -62,11 +69,21 @@ static struct node_info *find_node_info(struct impl *impl, struct pw_node *node)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void link_data_free(struct link_data *data)
|
||||||
|
{
|
||||||
|
spa_list_remove(&data->l);
|
||||||
|
spa_hook_remove(&data->link_listener);
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
static void node_info_free(struct node_info *info)
|
static void node_info_free(struct node_info *info)
|
||||||
{
|
{
|
||||||
|
struct link_data *ld, *t;
|
||||||
|
|
||||||
spa_list_remove(&info->l);
|
spa_list_remove(&info->l);
|
||||||
spa_hook_remove(&info->node_listener);
|
spa_hook_remove(&info->node_listener);
|
||||||
spa_hook_remove(&info->link_listener);
|
spa_list_for_each_safe(ld, t, &info->links, l)
|
||||||
|
link_data_free(ld);
|
||||||
free(info);
|
free(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,8 +92,9 @@ static void try_link_port(struct pw_node *node, struct pw_port *port, struct nod
|
||||||
static void
|
static void
|
||||||
link_port_unlinked(void *data, struct pw_port *port)
|
link_port_unlinked(void *data, struct pw_port *port)
|
||||||
{
|
{
|
||||||
struct node_info *info = data;
|
struct link_data *ld = data;
|
||||||
struct pw_link *link = info->link;
|
struct node_info *info = ld->node_info;
|
||||||
|
struct pw_link *link = ld->link;
|
||||||
struct impl *impl = info->impl;
|
struct impl *impl = info->impl;
|
||||||
struct pw_port *input = pw_link_get_input(link);
|
struct pw_port *input = pw_link_get_input(link);
|
||||||
|
|
||||||
|
|
@ -89,8 +107,9 @@ link_port_unlinked(void *data, struct pw_port *port)
|
||||||
static void
|
static void
|
||||||
link_state_changed(void *data, enum pw_link_state old, enum pw_link_state state, const char *error)
|
link_state_changed(void *data, enum pw_link_state old, enum pw_link_state state, const char *error)
|
||||||
{
|
{
|
||||||
struct node_info *info = data;
|
struct link_data *ld = data;
|
||||||
struct pw_link *link = info->link;
|
struct node_info *info = ld->node_info;
|
||||||
|
struct pw_link *link = ld->link;
|
||||||
struct impl *impl = info->impl;
|
struct impl *impl = info->impl;
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
|
@ -114,13 +133,9 @@ link_state_changed(void *data, enum pw_link_state old, enum pw_link_state state,
|
||||||
static void
|
static void
|
||||||
link_destroy(void *data)
|
link_destroy(void *data)
|
||||||
{
|
{
|
||||||
struct node_info *info = data;
|
struct link_data *ld = data;
|
||||||
struct pw_link *link = info->link;
|
pw_log_debug("module %p: link %p destroyed", ld->node_info->impl, ld->link);
|
||||||
struct impl *impl = info->impl;
|
link_data_free(ld);
|
||||||
|
|
||||||
pw_log_debug("module %p: link %p destroyed", impl, link);
|
|
||||||
spa_hook_remove(&info->link_listener);
|
|
||||||
spa_list_init(&info->link_listener.link);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct pw_link_events link_events = {
|
static const struct pw_link_events link_events = {
|
||||||
|
|
@ -133,18 +148,15 @@ static const struct pw_link_events link_events = {
|
||||||
static void try_link_port(struct pw_node *node, struct pw_port *port, struct node_info *info)
|
static void try_link_port(struct pw_node *node, struct pw_port *port, struct node_info *info)
|
||||||
{
|
{
|
||||||
struct impl *impl = info->impl;
|
struct impl *impl = info->impl;
|
||||||
struct pw_properties *props;
|
const struct pw_properties *props;
|
||||||
const char *str;
|
const char *str;
|
||||||
uint32_t path_id;
|
uint32_t path_id;
|
||||||
char *error = NULL;
|
char *error = NULL;
|
||||||
struct pw_link *link;
|
struct pw_link *link;
|
||||||
struct pw_port *target;
|
struct pw_port *target;
|
||||||
|
struct link_data *ld;
|
||||||
|
|
||||||
props = pw_node_get_properties(node);
|
props = pw_node_get_properties(node);
|
||||||
if (props == NULL) {
|
|
||||||
pw_log_debug("module %p: node has no properties", impl);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
str = pw_properties_get(props, "pipewire.target.node");
|
str = pw_properties_get(props, "pipewire.target.node");
|
||||||
if (str != NULL)
|
if (str != NULL)
|
||||||
|
|
@ -170,13 +182,22 @@ static void try_link_port(struct pw_node *node, struct pw_port *port, struct nod
|
||||||
port = tmp;
|
port = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
link = pw_link_new(impl->core, pw_module_get_global(impl->module), port, target, NULL, NULL, &error);
|
link = pw_link_new(impl->core,
|
||||||
|
pw_module_get_global(impl->module),
|
||||||
|
port, target,
|
||||||
|
NULL, NULL,
|
||||||
|
&error,
|
||||||
|
sizeof(struct link_data));
|
||||||
if (link == NULL)
|
if (link == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
info->link = link;
|
ld = pw_link_get_user_data(link);
|
||||||
|
ld->link = link;
|
||||||
|
ld->node_info = info;
|
||||||
|
pw_link_add_listener(link, &ld->link_listener, &link_events, ld);
|
||||||
|
|
||||||
|
spa_list_append(&info->links, &ld->l);
|
||||||
|
|
||||||
pw_link_add_listener(link, &info->link_listener, &link_events, info);
|
|
||||||
pw_link_activate(link);
|
pw_link_activate(link);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
@ -242,11 +263,10 @@ core_global_added(void *data, struct pw_global *global)
|
||||||
ninfo = calloc(1, sizeof(struct node_info));
|
ninfo = calloc(1, sizeof(struct node_info));
|
||||||
ninfo->impl = impl;
|
ninfo->impl = impl;
|
||||||
ninfo->node = node;
|
ninfo->node = node;
|
||||||
|
spa_list_init(&ninfo->links);
|
||||||
|
|
||||||
spa_list_insert(impl->node_list.prev, &ninfo->l);
|
spa_list_append(&impl->node_list, &ninfo->l);
|
||||||
|
|
||||||
pw_node_add_listener(node, &ninfo->node_listener, &node_events, ninfo);
|
pw_node_add_listener(node, &ninfo->node_listener, &node_events, ninfo);
|
||||||
spa_list_init(&ninfo->link_listener.link);
|
|
||||||
|
|
||||||
pw_log_debug("module %p: node %p added", impl, node);
|
pw_log_debug("module %p: node %p added", impl, node);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -531,12 +531,12 @@ const struct pw_core_events core_events = {
|
||||||
.global_removed = core_global_removed,
|
.global_removed = core_global_removed,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void dispatch_cb(struct spa_loop_utils *utils, struct spa_source *source, void *userdata)
|
static void dispatch_cb(void *userdata)
|
||||||
{
|
{
|
||||||
struct impl *impl = userdata;
|
struct impl *impl = userdata;
|
||||||
|
|
||||||
if (dbus_connection_dispatch(impl->bus) == DBUS_DISPATCH_COMPLETE)
|
if (dbus_connection_dispatch(impl->bus) == DBUS_DISPATCH_COMPLETE)
|
||||||
pw_loop_enable_idle(pw_core_get_main_loop(impl->core), source, false);
|
pw_loop_enable_idle(pw_core_get_main_loop(impl->core), impl->dispatch_event, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *userdata)
|
static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *userdata)
|
||||||
|
|
@ -583,8 +583,7 @@ static inline unsigned int io_to_dbus(enum spa_io mask)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_io_event(struct spa_loop_utils *utils,
|
handle_io_event(void *userdata, int fd, enum spa_io mask)
|
||||||
struct spa_source *source, int fd, enum spa_io mask, void *userdata)
|
|
||||||
{
|
{
|
||||||
DBusWatch *watch = userdata;
|
DBusWatch *watch = userdata;
|
||||||
|
|
||||||
|
|
@ -630,20 +629,26 @@ static void toggle_watch(DBusWatch *watch, void *userdata)
|
||||||
|
|
||||||
pw_loop_update_io(pw_core_get_main_loop(impl->core), source, dbus_to_io(watch));
|
pw_loop_update_io(pw_core_get_main_loop(impl->core), source, dbus_to_io(watch));
|
||||||
}
|
}
|
||||||
|
struct timeout_data {
|
||||||
|
struct spa_source *source;
|
||||||
|
struct impl *impl;
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_timer_event(struct spa_loop_utils *utils, struct spa_source *source, void *userdata)
|
handle_timer_event(void *userdata, uint64_t expirations)
|
||||||
{
|
{
|
||||||
DBusTimeout *timeout = userdata;
|
DBusTimeout *timeout = userdata;
|
||||||
uint64_t t;
|
uint64_t t;
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
struct timeout_data *data = dbus_timeout_get_data(timeout);
|
||||||
|
struct impl *impl = data->impl;
|
||||||
|
|
||||||
if (dbus_timeout_get_enabled(timeout)) {
|
if (dbus_timeout_get_enabled(timeout)) {
|
||||||
t = dbus_timeout_get_interval(timeout) * SPA_NSEC_PER_MSEC;
|
t = dbus_timeout_get_interval(timeout) * SPA_NSEC_PER_MSEC;
|
||||||
ts.tv_sec = t / SPA_NSEC_PER_SEC;
|
ts.tv_sec = t / SPA_NSEC_PER_SEC;
|
||||||
ts.tv_nsec = t % SPA_NSEC_PER_SEC;
|
ts.tv_nsec = t % SPA_NSEC_PER_SEC;
|
||||||
spa_loop_utils_update_timer(utils, source, &ts, NULL, false);
|
pw_loop_update_timer(pw_core_get_main_loop(impl->core),
|
||||||
|
data->source, &ts, NULL, false);
|
||||||
dbus_timeout_handle(timeout);
|
dbus_timeout_handle(timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -651,40 +656,44 @@ handle_timer_event(struct spa_loop_utils *utils, struct spa_source *source, void
|
||||||
static dbus_bool_t add_timeout(DBusTimeout *timeout, void *userdata)
|
static dbus_bool_t add_timeout(DBusTimeout *timeout, void *userdata)
|
||||||
{
|
{
|
||||||
struct impl *impl = userdata;
|
struct impl *impl = userdata;
|
||||||
struct spa_source *source;
|
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
struct timeout_data *data;
|
||||||
uint64_t t;
|
uint64_t t;
|
||||||
|
|
||||||
if (!dbus_timeout_get_enabled(timeout))
|
if (!dbus_timeout_get_enabled(timeout))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
source = pw_loop_add_timer(pw_core_get_main_loop(impl->core), handle_timer_event, timeout);
|
data = calloc(1, sizeof(struct timeout_data));
|
||||||
|
data->impl = impl;
|
||||||
dbus_timeout_set_data(timeout, source, NULL);
|
data->source = pw_loop_add_timer(pw_core_get_main_loop(impl->core), handle_timer_event, timeout);
|
||||||
|
dbus_timeout_set_data(timeout, data, NULL);
|
||||||
|
|
||||||
t = dbus_timeout_get_interval(timeout) * SPA_NSEC_PER_MSEC;
|
t = dbus_timeout_get_interval(timeout) * SPA_NSEC_PER_MSEC;
|
||||||
ts.tv_sec = t / SPA_NSEC_PER_SEC;
|
ts.tv_sec = t / SPA_NSEC_PER_SEC;
|
||||||
ts.tv_nsec = t % SPA_NSEC_PER_SEC;
|
ts.tv_nsec = t % SPA_NSEC_PER_SEC;
|
||||||
pw_loop_update_timer(pw_core_get_main_loop(impl->core), source, &ts, NULL, false);
|
pw_loop_update_timer(pw_core_get_main_loop(impl->core), data->source, &ts, NULL, false);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_timeout(DBusTimeout *timeout, void *userdata)
|
static void remove_timeout(DBusTimeout *timeout, void *userdata)
|
||||||
{
|
{
|
||||||
struct impl *impl = userdata;
|
struct impl *impl = userdata;
|
||||||
struct spa_source *source;
|
struct timeout_data *data;
|
||||||
|
|
||||||
if ((source = dbus_timeout_get_data(timeout)))
|
if ((data = dbus_timeout_get_data(timeout))) {
|
||||||
pw_loop_destroy_source(pw_core_get_main_loop(impl->core), source);
|
pw_loop_destroy_source(pw_core_get_main_loop(impl->core), data->source);
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void toggle_timeout(DBusTimeout *timeout, void *userdata)
|
static void toggle_timeout(DBusTimeout *timeout, void *userdata)
|
||||||
{
|
{
|
||||||
struct impl *impl = userdata;
|
struct impl *impl = userdata;
|
||||||
struct spa_source *source;
|
struct timeout_data *data;
|
||||||
struct timespec ts, *tsp;
|
struct timespec ts, *tsp;
|
||||||
|
|
||||||
source = dbus_timeout_get_data(timeout);
|
data = dbus_timeout_get_data(timeout);
|
||||||
|
|
||||||
if (dbus_timeout_get_enabled(timeout)) {
|
if (dbus_timeout_get_enabled(timeout)) {
|
||||||
uint64_t t = dbus_timeout_get_interval(timeout) * SPA_NSEC_PER_MSEC;
|
uint64_t t = dbus_timeout_get_interval(timeout) * SPA_NSEC_PER_MSEC;
|
||||||
|
|
@ -694,7 +703,7 @@ static void toggle_timeout(DBusTimeout *timeout, void *userdata)
|
||||||
} else {
|
} else {
|
||||||
tsp = NULL;
|
tsp = NULL;
|
||||||
}
|
}
|
||||||
pw_loop_update_timer(pw_core_get_main_loop(impl->core), source, tsp, NULL, false);
|
pw_loop_update_timer(pw_core_get_main_loop(impl->core), data->source, tsp, NULL, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wakeup_main(void *userdata)
|
static void wakeup_main(void *userdata)
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,6 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <semaphore.h>
|
|
||||||
|
|
||||||
#include <jack/jack.h>
|
|
||||||
#include <jack/session.h>
|
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
|
@ -48,11 +44,8 @@
|
||||||
#include "pipewire/data-loop.h"
|
#include "pipewire/data-loop.h"
|
||||||
#include "pipewire/main-loop.h"
|
#include "pipewire/main-loop.h"
|
||||||
|
|
||||||
#include "modules/module-jack/defs.h"
|
#include "modules/module-jack/jack.h"
|
||||||
#include "modules/module-jack/shm.h"
|
#include "modules/module-jack/jack-node.h"
|
||||||
#include "modules/module-jack/shared.h"
|
|
||||||
#include "modules/module-jack/synchro.h"
|
|
||||||
#include "modules/module-jack/server.h"
|
|
||||||
|
|
||||||
#ifndef UNIX_PATH_MAX
|
#ifndef UNIX_PATH_MAX
|
||||||
#define UNIX_PATH_MAX 108
|
#define UNIX_PATH_MAX 108
|
||||||
|
|
@ -72,7 +65,6 @@ struct socket {
|
||||||
|
|
||||||
struct pw_loop *loop;
|
struct pw_loop *loop;
|
||||||
struct spa_source *source;
|
struct spa_source *source;
|
||||||
char *core_name;
|
|
||||||
struct spa_list link;
|
struct spa_list link;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -82,6 +74,8 @@ struct impl {
|
||||||
struct pw_module *module;
|
struct pw_module *module;
|
||||||
struct spa_list link;
|
struct spa_list link;
|
||||||
|
|
||||||
|
struct spa_source *timer;
|
||||||
|
|
||||||
struct pw_properties *properties;
|
struct pw_properties *properties;
|
||||||
|
|
||||||
struct spa_list socket_list;
|
struct spa_list socket_list;
|
||||||
|
|
@ -90,6 +84,8 @@ struct impl {
|
||||||
struct spa_loop_control_hooks hooks;
|
struct spa_loop_control_hooks hooks;
|
||||||
|
|
||||||
struct jack_server server;
|
struct jack_server server;
|
||||||
|
|
||||||
|
struct pw_link *sink_link;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct client {
|
struct client {
|
||||||
|
|
@ -101,6 +97,31 @@ struct client {
|
||||||
struct spa_source *source;
|
struct spa_source *source;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool init_socket_name(struct sockaddr_un *addr, const char *name, bool promiscuous, int which)
|
||||||
|
{
|
||||||
|
int name_size;
|
||||||
|
const char *runtime_dir;
|
||||||
|
|
||||||
|
runtime_dir = JACK_SOCKET_DIR;
|
||||||
|
|
||||||
|
addr->sun_family = AF_UNIX;
|
||||||
|
if (promiscuous) {
|
||||||
|
name_size = snprintf(addr->sun_path, sizeof(addr->sun_path),
|
||||||
|
"%s/jack_%s_%d", runtime_dir, name, which) + 1;
|
||||||
|
} else {
|
||||||
|
name_size = snprintf(addr->sun_path, sizeof(addr->sun_path),
|
||||||
|
"%s/jack_%s_%d_%d", runtime_dir, name, getuid(), which) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name_size > (int) sizeof(addr->sun_path)) {
|
||||||
|
pw_log_error("socket path \"%s/%s\" plus null terminator exceeds 108 bytes",
|
||||||
|
runtime_dir, name);
|
||||||
|
*addr->sun_path = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static int process_messages(struct client *client);
|
static int process_messages(struct client *client);
|
||||||
|
|
||||||
static void client_destroy(void *data)
|
static void client_destroy(void *data)
|
||||||
|
|
@ -116,6 +137,10 @@ static void client_destroy(void *data)
|
||||||
static int
|
static int
|
||||||
handle_register_port(struct client *client)
|
handle_register_port(struct client *client)
|
||||||
{
|
{
|
||||||
|
struct impl *impl = client->impl;
|
||||||
|
struct jack_server *server = &impl->server;
|
||||||
|
struct jack_graph_manager *mgr = server->graph_manager;
|
||||||
|
struct jack_connection_manager *conn;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int ref_num;
|
int ref_num;
|
||||||
char name[JACK_PORT_NAME_SIZE + 1];
|
char name[JACK_PORT_NAME_SIZE + 1];
|
||||||
|
|
@ -123,6 +148,8 @@ handle_register_port(struct client *client)
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
unsigned int buffer_size;
|
unsigned int buffer_size;
|
||||||
static jack_port_id_t port_index = 0;
|
static jack_port_id_t port_index = 0;
|
||||||
|
jack_port_type_id_t type_id;
|
||||||
|
struct jack_client *jc;
|
||||||
|
|
||||||
CheckSize(kRegisterPort_size);
|
CheckSize(kRegisterPort_size);
|
||||||
CheckRead(&ref_num, sizeof(int));
|
CheckRead(&ref_num, sizeof(int));
|
||||||
|
|
@ -131,10 +158,45 @@ handle_register_port(struct client *client)
|
||||||
CheckRead(&flags, sizeof(unsigned int));
|
CheckRead(&flags, sizeof(unsigned int));
|
||||||
CheckRead(&buffer_size, sizeof(unsigned int));
|
CheckRead(&buffer_size, sizeof(unsigned int));
|
||||||
|
|
||||||
pw_log_error("protocol-jack %p: kRegisterPort %d %s %s %u %u", client->impl,
|
pw_log_debug("protocol-jack %p: kRegisterPort %d %s %s %u %u", impl,
|
||||||
ref_num, name, port_type, flags, buffer_size);
|
ref_num, name, port_type, flags, buffer_size);
|
||||||
port_index++;
|
|
||||||
|
|
||||||
|
type_id = jack_port_get_type_id(port_type);
|
||||||
|
|
||||||
|
if (jack_graph_manager_find_port(mgr, name) != NO_PORT) {
|
||||||
|
pw_log_error("protocol-jack %p: port_name %s exists", impl, name);
|
||||||
|
result = -1;
|
||||||
|
goto reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
port_index = jack_graph_manager_allocate_port(mgr, ref_num, name, type_id, flags);
|
||||||
|
if (port_index == NO_PORT) {
|
||||||
|
pw_log_error("protocol-jack %p: failed to create port name %s", impl, name);
|
||||||
|
result = -1;
|
||||||
|
goto reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
jc = server->client_table[ref_num];
|
||||||
|
pw_jack_node_add_port(jc->node,
|
||||||
|
flags & JackPortIsInput ?
|
||||||
|
PW_DIRECTION_INPUT :
|
||||||
|
PW_DIRECTION_OUTPUT,
|
||||||
|
port_index);
|
||||||
|
|
||||||
|
conn = jack_graph_manager_next_start(mgr);
|
||||||
|
|
||||||
|
if (jack_connection_manager_add_port(conn, (flags & JackPortIsInput) ? true : false,
|
||||||
|
ref_num, port_index) < 0) {
|
||||||
|
pw_log_error("protocol-jack %p: failed to add port", impl);
|
||||||
|
jack_graph_manager_release_port(mgr, port_index);
|
||||||
|
result = -1;
|
||||||
|
goto reply_stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
reply_stop:
|
||||||
|
jack_graph_manager_next_stop(mgr);
|
||||||
|
|
||||||
|
reply:
|
||||||
CheckWrite(&result, sizeof(int));
|
CheckWrite(&result, sizeof(int));
|
||||||
CheckWrite(&port_index, sizeof(jack_port_id_t));
|
CheckWrite(&port_index, sizeof(jack_port_id_t));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -143,6 +205,10 @@ handle_register_port(struct client *client)
|
||||||
static int
|
static int
|
||||||
handle_activate_client(struct client *client)
|
handle_activate_client(struct client *client)
|
||||||
{
|
{
|
||||||
|
struct impl *impl = client->impl;
|
||||||
|
struct jack_server *server = &impl->server;
|
||||||
|
struct jack_graph_manager *mgr = server->graph_manager;
|
||||||
|
struct jack_connection_manager *conn;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int ref_num;
|
int ref_num;
|
||||||
int is_real_time;
|
int is_real_time;
|
||||||
|
|
@ -151,9 +217,16 @@ handle_activate_client(struct client *client)
|
||||||
CheckRead(&ref_num, sizeof(int));
|
CheckRead(&ref_num, sizeof(int));
|
||||||
CheckRead(&is_real_time, sizeof(int));
|
CheckRead(&is_real_time, sizeof(int));
|
||||||
|
|
||||||
pw_log_error("protocol-jack %p: kActivateClient %d %d", client->impl,
|
pw_log_debug("protocol-jack %p: kActivateClient %d %d", client->impl,
|
||||||
ref_num, is_real_time);
|
ref_num, is_real_time);
|
||||||
|
|
||||||
|
conn = jack_graph_manager_next_start(mgr);
|
||||||
|
|
||||||
|
jack_connection_manager_direct_connect(conn, server->freewheel_ref_num, ref_num);
|
||||||
|
jack_connection_manager_direct_connect(conn, ref_num, server->freewheel_ref_num);
|
||||||
|
|
||||||
|
jack_graph_manager_next_stop(mgr);
|
||||||
|
|
||||||
CheckWrite(&result, sizeof(int));
|
CheckWrite(&result, sizeof(int));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -161,15 +234,31 @@ handle_activate_client(struct client *client)
|
||||||
static int
|
static int
|
||||||
handle_deactivate_client(struct client *client)
|
handle_deactivate_client(struct client *client)
|
||||||
{
|
{
|
||||||
|
struct impl *impl = client->impl;
|
||||||
|
struct jack_server *server = &impl->server;
|
||||||
|
struct jack_graph_manager *mgr = server->graph_manager;
|
||||||
|
struct jack_connection_manager *conn;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int ref_num;
|
int ref_num, fw_ref;
|
||||||
|
|
||||||
CheckSize(kDeactivateClient_size);
|
CheckSize(kDeactivateClient_size);
|
||||||
CheckRead(&ref_num, sizeof(int));
|
CheckRead(&ref_num, sizeof(int));
|
||||||
|
|
||||||
pw_log_error("protocol-jack %p: kDeactivateClient %d", client->impl,
|
pw_log_debug("protocol-jack %p: kDeactivateClient %d", client->impl,
|
||||||
ref_num);
|
ref_num);
|
||||||
|
|
||||||
|
fw_ref = server->freewheel_ref_num;
|
||||||
|
|
||||||
|
conn = jack_graph_manager_next_start(mgr);
|
||||||
|
|
||||||
|
if (jack_connection_manager_is_direct_connection(conn, fw_ref, ref_num))
|
||||||
|
jack_connection_manager_direct_disconnect(conn, fw_ref, ref_num);
|
||||||
|
|
||||||
|
if (jack_connection_manager_is_direct_connection(conn, ref_num, fw_ref))
|
||||||
|
jack_connection_manager_direct_disconnect(conn, ref_num, fw_ref);
|
||||||
|
|
||||||
|
jack_graph_manager_next_stop(mgr);
|
||||||
|
|
||||||
CheckWrite(&result, sizeof(int));
|
CheckWrite(&result, sizeof(int));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -192,7 +281,7 @@ handle_client_check(struct client *client)
|
||||||
CheckRead(&UUID, sizeof(int));
|
CheckRead(&UUID, sizeof(int));
|
||||||
CheckRead(&open, sizeof(int));
|
CheckRead(&open, sizeof(int));
|
||||||
|
|
||||||
pw_log_error("protocol-jack %p: kClientCheck %s %d %d %d %d", client->impl,
|
pw_log_debug("protocol-jack %p: kClientCheck %s %d %d %d %d", client->impl,
|
||||||
name, protocol, options, UUID, open);
|
name, protocol, options, UUID, open);
|
||||||
|
|
||||||
status = 0;
|
status = 0;
|
||||||
|
|
@ -215,16 +304,74 @@ handle_client_check(struct client *client)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
notify_client(struct jack_client *client, int ref_num, const char *name, int notify,
|
||||||
|
int sync, const char* message, int value1, int value2)
|
||||||
|
{
|
||||||
|
int size, result = 0;
|
||||||
|
char _name[JACK_CLIENT_NAME_SIZE+1];
|
||||||
|
char _message[JACK_MESSAGE_SIZE+1];
|
||||||
|
|
||||||
|
if (client->fd == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
snprintf(_name, sizeof(_name), "%s", name);
|
||||||
|
snprintf(_message, sizeof(_message), "%s", message);
|
||||||
|
|
||||||
|
size = sizeof(int) + sizeof(_name) + 5 * sizeof(int) + sizeof(_message);
|
||||||
|
CheckWrite(&size, sizeof(int));
|
||||||
|
CheckWrite(_name, sizeof(_name));
|
||||||
|
CheckWrite(&ref_num, sizeof(int));
|
||||||
|
CheckWrite(¬ify, sizeof(int));
|
||||||
|
CheckWrite(&value1, sizeof(int));
|
||||||
|
CheckWrite(&value2, sizeof(int));
|
||||||
|
CheckWrite(&sync, sizeof(int));
|
||||||
|
CheckWrite(_message, sizeof(_message));
|
||||||
|
|
||||||
|
if (sync)
|
||||||
|
CheckRead(&result, sizeof(int));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
notify_add_client(struct impl *impl, struct jack_client *client, const char *name, int ref_num)
|
||||||
|
{
|
||||||
|
struct jack_server *server = &impl->server;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < CLIENT_NUM; i++) {
|
||||||
|
struct jack_client *c = server->client_table[i];
|
||||||
|
const char *n;
|
||||||
|
|
||||||
|
if (c == NULL || c == client)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
n = c->control->name;
|
||||||
|
if (notify_client(c, ref_num, name, jack_notify_AddClient, false, "", 0, 0) < 0) {
|
||||||
|
pw_log_warn("module-jack %p: can't notify client", impl);
|
||||||
|
}
|
||||||
|
if (notify_client(client, i, n, jack_notify_AddClient, true, "", 0, 0) < 0) {
|
||||||
|
pw_log_error("module-jack %p: can't notify client", impl);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
handle_client_open(struct client *client)
|
handle_client_open(struct client *client)
|
||||||
{
|
{
|
||||||
struct impl *impl = client->impl;
|
struct impl *impl = client->impl;
|
||||||
struct jack_server *server = &impl->server;
|
struct jack_server *server = &impl->server;
|
||||||
|
struct jack_graph_manager *mgr = server->graph_manager;
|
||||||
|
struct jack_connection_manager *conn;
|
||||||
int PID, UUID;
|
int PID, UUID;
|
||||||
char name[JACK_CLIENT_NAME_SIZE+1];
|
char name[JACK_CLIENT_NAME_SIZE+1];
|
||||||
int result, ref_num, shared_engine, shared_client, shared_graph;
|
int result = -1, ref_num, shared_engine, shared_client, shared_graph;
|
||||||
struct jack_client *jc;
|
struct jack_client *jc;
|
||||||
const struct ucred *ucred;
|
const struct ucred *ucred;
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
|
||||||
CheckSize(kClientOpen_size);
|
CheckSize(kClientOpen_size);
|
||||||
CheckRead(&PID, sizeof(int));
|
CheckRead(&PID, sizeof(int));
|
||||||
|
|
@ -233,7 +380,7 @@ handle_client_open(struct client *client)
|
||||||
|
|
||||||
ref_num = jack_server_allocate_ref_num(server);
|
ref_num = jack_server_allocate_ref_num(server);
|
||||||
if (ref_num == -1) {
|
if (ref_num == -1) {
|
||||||
result = -1;
|
pw_log_error("module-jack %p: can't allocated ref_num", impl);
|
||||||
goto reply;
|
goto reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -247,7 +394,20 @@ handle_client_open(struct client *client)
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
server->promiscuous) < 0) {
|
server->promiscuous) < 0) {
|
||||||
result = -1;
|
pw_log_error("module-jack %p: can't init synchro", impl);
|
||||||
|
goto reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((jc->fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||||
|
pw_log_error("module-jack %p: can't create socket %s", impl, strerror(errno));
|
||||||
|
goto reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!init_socket_name(&addr, name, server->promiscuous, 0))
|
||||||
|
goto reply;
|
||||||
|
|
||||||
|
if (connect(jc->fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||||
|
pw_log_error("module-jack %p: can't connect socket %s", impl, strerror(errno));
|
||||||
goto reply;
|
goto reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -255,17 +415,31 @@ handle_client_open(struct client *client)
|
||||||
|
|
||||||
jc->control = jack_client_control_alloc(name, ucred ? ucred->pid : 0, ref_num, -1);
|
jc->control = jack_client_control_alloc(name, ucred ? ucred->pid : 0, ref_num, -1);
|
||||||
if (jc->control == NULL) {
|
if (jc->control == NULL) {
|
||||||
result = -1;
|
pw_log_error("module-jack %p: can't create control", impl);
|
||||||
goto reply;
|
goto reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
server->client_table[ref_num] = jc;
|
server->client_table[ref_num] = jc;
|
||||||
|
pw_log_debug("module-jack %p: Added client %d \"%s\"", impl, ref_num, name);
|
||||||
|
|
||||||
|
conn = jack_graph_manager_next_start(mgr);
|
||||||
|
jack_connection_manager_init_ref_num(conn, ref_num);
|
||||||
|
jack_graph_manager_next_stop(mgr);
|
||||||
|
|
||||||
|
jc->node = pw_jack_node_new(impl->core, pw_module_get_global(impl->module),
|
||||||
|
server, ref_num, NULL);
|
||||||
|
|
||||||
|
if (notify_add_client(impl, jc, name, ref_num) < 0) {
|
||||||
|
pw_log_error("module-jack %p: can't notify add_client", impl);
|
||||||
|
goto reply;
|
||||||
|
}
|
||||||
|
|
||||||
result = 0;
|
|
||||||
shared_engine = impl->server.engine_control->info.index;
|
shared_engine = impl->server.engine_control->info.index;
|
||||||
shared_client = jc->control->info.index;
|
shared_client = jc->control->info.index;
|
||||||
shared_graph = impl->server.graph_manager->info.index;
|
shared_graph = impl->server.graph_manager->info.index;
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
|
||||||
reply:
|
reply:
|
||||||
CheckWrite(&result, sizeof(int));
|
CheckWrite(&result, sizeof(int));
|
||||||
CheckWrite(&shared_engine, sizeof(int));
|
CheckWrite(&shared_engine, sizeof(int));
|
||||||
|
|
@ -290,16 +464,123 @@ handle_client_close(struct client *client)
|
||||||
static int
|
static int
|
||||||
handle_connect_name_ports(struct client *client)
|
handle_connect_name_ports(struct client *client)
|
||||||
{
|
{
|
||||||
|
struct impl *impl = client->impl;
|
||||||
|
struct jack_server *server = &impl->server;
|
||||||
|
struct jack_graph_manager *mgr = server->graph_manager;
|
||||||
|
struct jack_connection_manager *conn;
|
||||||
|
struct jack_client *jc;
|
||||||
int ref_num;
|
int ref_num;
|
||||||
char src[REAL_JACK_PORT_NAME_SIZE+1];
|
char src[REAL_JACK_PORT_NAME_SIZE+1];
|
||||||
char dst[REAL_JACK_PORT_NAME_SIZE+1];
|
char dst[REAL_JACK_PORT_NAME_SIZE+1];
|
||||||
int result = 0;
|
int result = -1, in_ref, out_ref;
|
||||||
|
jack_port_id_t src_id, dst_id;
|
||||||
|
struct jack_port *src_port, *dst_port;
|
||||||
|
struct pw_port *out_port, *in_port;
|
||||||
|
struct pw_link *link;
|
||||||
|
|
||||||
CheckSize(kConnectNamePorts_size);
|
CheckSize(kConnectNamePorts_size);
|
||||||
CheckRead(&ref_num, sizeof(int));
|
CheckRead(&ref_num, sizeof(int));
|
||||||
CheckRead(src, sizeof(src));
|
CheckRead(src, sizeof(src));
|
||||||
CheckRead(dst, sizeof(dst));
|
CheckRead(dst, sizeof(dst));
|
||||||
|
|
||||||
|
src_id = jack_graph_manager_find_port(mgr, src);
|
||||||
|
if (src_id == NO_PORT) {
|
||||||
|
pw_log_error("protocol-jack %p: port_name %s does not exist", impl, src);
|
||||||
|
goto reply;
|
||||||
|
}
|
||||||
|
dst_id = jack_graph_manager_find_port(mgr, dst);
|
||||||
|
if (dst_id == NO_PORT) {
|
||||||
|
pw_log_error("protocol-jack %p: port_name %s does not exist", impl, dst);
|
||||||
|
goto reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
pw_log_debug("protocol-jack %p: kConnectNamePort %d %s %s %u %u", impl,
|
||||||
|
ref_num, src, dst, src_id, dst_id);
|
||||||
|
|
||||||
|
src_port = jack_graph_manager_get_port(mgr, src_id);
|
||||||
|
dst_port = jack_graph_manager_get_port(mgr, dst_id);
|
||||||
|
|
||||||
|
if (((src_port->flags & JackPortIsOutput) == 0) ||
|
||||||
|
((dst_port->flags & JackPortIsInput) == 0)) {
|
||||||
|
pw_log_error("protocol-jack %p: ports are not input and output", impl);
|
||||||
|
goto reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!src_port->in_use || !dst_port->in_use) {
|
||||||
|
pw_log_error("protocol-jack %p: ports are not in use", impl);
|
||||||
|
goto reply;
|
||||||
|
}
|
||||||
|
if (src_port->type_id != dst_port->type_id) {
|
||||||
|
pw_log_error("protocol-jack %p: ports are not of the same type", impl);
|
||||||
|
goto reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn = jack_graph_manager_next_start(mgr);
|
||||||
|
|
||||||
|
out_ref = jack_connection_manager_get_output_refnum(conn, src_id);
|
||||||
|
if (out_ref == -1) {
|
||||||
|
pw_log_error("protocol-jack %p: unknown port_id %d", impl, src_id);
|
||||||
|
goto reply_stop;
|
||||||
|
}
|
||||||
|
if ((jc = server->client_table[out_ref]) == NULL) {
|
||||||
|
pw_log_error("protocol-jack %p: unknown client %d", impl, out_ref);
|
||||||
|
goto reply_stop;
|
||||||
|
}
|
||||||
|
if (!jc->control->active) {
|
||||||
|
pw_log_error("protocol-jack %p: can't connect ports of inactive client", impl);
|
||||||
|
goto reply_stop;
|
||||||
|
}
|
||||||
|
out_port = pw_jack_node_find_port(jc->node, PW_DIRECTION_OUTPUT, src_id);
|
||||||
|
|
||||||
|
in_ref = jack_connection_manager_get_input_refnum(conn, dst_id);
|
||||||
|
if (in_ref == -1) {
|
||||||
|
pw_log_error("protocol-jack %p: unknown port_id %d", impl, dst_id);
|
||||||
|
goto reply_stop;
|
||||||
|
}
|
||||||
|
if ((jc = server->client_table[in_ref]) == NULL) {
|
||||||
|
pw_log_error("protocol-jack %p: unknown client %d", impl, in_ref);
|
||||||
|
goto reply_stop;
|
||||||
|
}
|
||||||
|
if (!jc->control->active) {
|
||||||
|
pw_log_error("protocol-jack %p: can't connect ports of inactive client", impl);
|
||||||
|
goto reply_stop;
|
||||||
|
}
|
||||||
|
in_port = pw_jack_node_find_port(jc->node, PW_DIRECTION_INPUT, dst_id);
|
||||||
|
|
||||||
|
if (jack_connection_manager_is_connected(conn, src_id, dst_id)) {
|
||||||
|
pw_log_error("protocol-jack %p: ports are already connected", impl);
|
||||||
|
goto reply_stop;
|
||||||
|
}
|
||||||
|
if (jack_connection_manager_connect(conn, src_id, dst_id) < 0) {
|
||||||
|
pw_log_error("protocol-jack %p: connection table is full", impl);
|
||||||
|
goto reply_stop;
|
||||||
|
}
|
||||||
|
if (jack_connection_manager_connect(conn, dst_id, src_id) < 0) {
|
||||||
|
pw_log_error("protocol-jack %p: connection table is full", impl);
|
||||||
|
goto reply_stop;
|
||||||
|
}
|
||||||
|
if (jack_connection_manager_is_loop_path(conn, src_id, dst_id) < 0)
|
||||||
|
jack_connection_manager_inc_feedback_connection(conn, src_id, dst_id);
|
||||||
|
else
|
||||||
|
jack_connection_manager_inc_direct_connection(conn, src_id, dst_id);
|
||||||
|
|
||||||
|
pw_log_debug("%p %p", out_port, in_port);
|
||||||
|
|
||||||
|
link = pw_link_new(impl->core,
|
||||||
|
pw_module_get_global(impl->module),
|
||||||
|
out_port,
|
||||||
|
in_port,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
pw_link_activate(link);
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
reply_stop:
|
||||||
|
jack_graph_manager_next_stop(mgr);
|
||||||
|
|
||||||
|
reply:
|
||||||
CheckWrite(&result, sizeof(int));
|
CheckWrite(&result, sizeof(int));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -417,8 +698,7 @@ client_busy_changed(void *data, bool busy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
connection_data(struct spa_loop_utils *utils,
|
connection_data(void *data, int fd, enum spa_io mask)
|
||||||
struct spa_source *source, int fd, enum spa_io mask, void *data)
|
|
||||||
{
|
{
|
||||||
struct client *client = data;
|
struct client *client = data;
|
||||||
|
|
||||||
|
|
@ -473,7 +753,7 @@ static struct client *client_new(struct impl *impl, int fd)
|
||||||
|
|
||||||
pw_client_add_listener(client, &this->client_listener, &client_events, this);
|
pw_client_add_listener(client, &this->client_listener, &client_events, this);
|
||||||
|
|
||||||
pw_log_error("module-jack %p: added new client", impl);
|
pw_log_debug("module-jack %p: added new client", impl);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
|
|
@ -484,9 +764,10 @@ static struct client *client_new(struct impl *impl, int fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
make_int_client(struct impl *impl, struct pw_node *node)
|
make_audio_client(struct impl *impl)
|
||||||
{
|
{
|
||||||
struct jack_server *server = &impl->server;
|
struct jack_server *server = &impl->server;
|
||||||
|
struct jack_graph_manager *mgr = server->graph_manager;
|
||||||
struct jack_connection_manager *conn;
|
struct jack_connection_manager *conn;
|
||||||
int ref_num;
|
int ref_num;
|
||||||
struct jack_client *jc;
|
struct jack_client *jc;
|
||||||
|
|
@ -507,7 +788,6 @@ make_int_client(struct impl *impl, struct pw_node *node)
|
||||||
|
|
||||||
jc = calloc(1,sizeof(struct jack_client));
|
jc = calloc(1,sizeof(struct jack_client));
|
||||||
jc->ref_num = ref_num;
|
jc->ref_num = ref_num;
|
||||||
jc->node = node;
|
|
||||||
jc->control = jack_client_control_alloc("system", -1, ref_num, -1);
|
jc->control = jack_client_control_alloc("system", -1, ref_num, -1);
|
||||||
jc->control->active = true;
|
jc->control->active = true;
|
||||||
|
|
||||||
|
|
@ -515,26 +795,89 @@ make_int_client(struct impl *impl, struct pw_node *node)
|
||||||
|
|
||||||
impl->server.engine_control->driver_num++;
|
impl->server.engine_control->driver_num++;
|
||||||
|
|
||||||
conn = jack_graph_manager_next_start(server->graph_manager);
|
conn = jack_graph_manager_next_start(mgr);
|
||||||
|
|
||||||
jack_connection_manager_init_ref_num(conn, ref_num);
|
jack_connection_manager_init_ref_num(conn, ref_num);
|
||||||
|
jack_connection_manager_direct_connect(conn, ref_num, ref_num);
|
||||||
|
|
||||||
port_id = jack_graph_manager_allocate_port(server->graph_manager,
|
port_id = jack_graph_manager_allocate_port(mgr,
|
||||||
ref_num, "system:playback_1", 2,
|
ref_num, "system:playback_1", 0,
|
||||||
JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal);
|
JackPortIsInput |
|
||||||
|
JackPortIsPhysical |
|
||||||
|
JackPortIsTerminal);
|
||||||
jack_connection_manager_add_port(conn, true, ref_num, port_id);
|
jack_connection_manager_add_port(conn, true, ref_num, port_id);
|
||||||
|
|
||||||
jack_graph_manager_next_stop(server->graph_manager);
|
port_id = jack_graph_manager_allocate_port(mgr,
|
||||||
|
ref_num, "system:playback_2", 0,
|
||||||
|
JackPortIsInput |
|
||||||
|
JackPortIsPhysical |
|
||||||
|
JackPortIsTerminal);
|
||||||
|
jack_connection_manager_add_port(conn, true, ref_num, port_id);
|
||||||
|
|
||||||
|
jack_graph_manager_next_stop(mgr);
|
||||||
|
|
||||||
|
server->audio_ref_num = ref_num;
|
||||||
|
|
||||||
|
server->audio_node = pw_jack_node_new(impl->core, pw_module_get_global(impl->module),
|
||||||
|
server, ref_num, NULL);
|
||||||
|
server->audio_node_node = pw_jack_node_get_node(server->audio_node);
|
||||||
|
jc->node = server->audio_node;
|
||||||
|
|
||||||
|
pw_log_debug("module-jack %p: Added audio driver %d", impl, ref_num);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
make_freewheel_client(struct impl *impl)
|
||||||
|
{
|
||||||
|
struct jack_server *server = &impl->server;
|
||||||
|
struct jack_graph_manager *mgr = server->graph_manager;
|
||||||
|
struct jack_connection_manager *conn;
|
||||||
|
int ref_num;
|
||||||
|
struct jack_client *jc;
|
||||||
|
|
||||||
|
ref_num = jack_server_allocate_ref_num(server);
|
||||||
|
if (ref_num == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (jack_synchro_init(&server->synchro_table[ref_num],
|
||||||
|
"freewheel",
|
||||||
|
server->engine_control->server_name,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
server->promiscuous) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
jc = calloc(1,sizeof(struct jack_client));
|
||||||
|
jc->ref_num = ref_num;
|
||||||
|
jc->control = jack_client_control_alloc("freewheel", -1, ref_num, -1);
|
||||||
|
jc->control->active = true;
|
||||||
|
|
||||||
|
server->client_table[ref_num] = jc;
|
||||||
|
|
||||||
|
impl->server.engine_control->driver_num++;
|
||||||
|
|
||||||
|
conn = jack_graph_manager_next_start(mgr);
|
||||||
|
|
||||||
|
jack_connection_manager_init_ref_num(conn, ref_num);
|
||||||
|
jack_connection_manager_direct_connect(conn, ref_num, ref_num);
|
||||||
|
|
||||||
|
jack_graph_manager_next_stop(mgr);
|
||||||
|
|
||||||
|
server->freewheel_ref_num = ref_num;
|
||||||
|
pw_log_debug("module-jack %p: Added freewheel driver %d", impl, ref_num);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool on_global(void *data, struct pw_global *global)
|
static bool on_global(void *data, struct pw_global *global)
|
||||||
|
|
||||||
{
|
{
|
||||||
struct impl *impl = data;
|
struct impl *impl = data;
|
||||||
struct pw_node *node;
|
struct pw_node *node, *n;
|
||||||
struct pw_properties *properties;
|
const struct pw_properties *properties;
|
||||||
const char *str;
|
const char *str;
|
||||||
|
|
||||||
if (pw_global_get_type(global) != impl->t->node)
|
if (pw_global_get_type(global) != impl->t->node)
|
||||||
|
|
@ -549,16 +892,78 @@ static bool on_global(void *data, struct pw_global *global)
|
||||||
if (strcmp(str, "Audio/Sink") != 0)
|
if (strcmp(str, "Audio/Sink") != 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
make_int_client(impl, node);
|
n = pw_jack_node_get_node(impl->server.audio_node);
|
||||||
return true;
|
|
||||||
|
impl->sink_link = pw_link_new(impl->core, pw_module_get_global(impl->module),
|
||||||
|
pw_node_get_free_port(n, PW_DIRECTION_OUTPUT),
|
||||||
|
pw_node_get_free_port(node, PW_DIRECTION_INPUT),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
pw_link_inc_idle(impl->sink_link);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void on_timeout(void *data, uint64_t expirations)
|
||||||
|
{
|
||||||
|
struct impl *impl = data;
|
||||||
|
struct jack_server *server = &impl->server;
|
||||||
|
struct jack_graph_manager *mgr = server->graph_manager;
|
||||||
|
struct jack_connection_manager *conn;
|
||||||
|
struct jack_client *client;
|
||||||
|
int activation;
|
||||||
|
|
||||||
|
client = server->client_table[server->freewheel_ref_num];
|
||||||
|
|
||||||
|
conn = jack_graph_manager_try_switch(mgr);
|
||||||
|
|
||||||
|
jack_connection_manager_reset(conn, mgr->client_timing);
|
||||||
|
|
||||||
|
activation = jack_connection_manager_get_activation(conn, server->freewheel_ref_num);
|
||||||
|
if (activation == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pw_log_trace("resume %d", activation);
|
||||||
|
jack_connection_manager_resume_ref_num(conn,
|
||||||
|
client->control,
|
||||||
|
server->synchro_table,
|
||||||
|
mgr->client_timing);
|
||||||
|
|
||||||
|
if (server->engine_control->sync_mode) {
|
||||||
|
pw_log_trace("suspend");
|
||||||
|
jack_connection_manager_suspend_ref_num(conn,
|
||||||
|
client->control,
|
||||||
|
server->synchro_table,
|
||||||
|
mgr->client_timing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static bool init_nodes(struct impl *impl)
|
static bool init_nodes(struct impl *impl)
|
||||||
{
|
{
|
||||||
struct pw_core *core = impl->core;
|
struct pw_core *core = impl->core;
|
||||||
|
#if 0
|
||||||
|
struct timespec timeout, interval;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
make_audio_client(impl);
|
||||||
|
make_freewheel_client(impl);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
timeout.tv_sec = 0;
|
||||||
|
timeout.tv_nsec = 1;
|
||||||
|
interval.tv_sec = 0;
|
||||||
|
interval.tv_nsec = 10 * SPA_NSEC_PER_MSEC;
|
||||||
|
|
||||||
|
impl->timer = pw_loop_add_timer(pw_core_get_main_loop(impl->core), on_timeout, impl);
|
||||||
|
pw_loop_update_timer(pw_core_get_main_loop(impl->core), impl->timer, &timeout, &interval, false);
|
||||||
|
#endif
|
||||||
|
|
||||||
pw_core_for_each_global(core, on_global, impl);
|
pw_core_for_each_global(core, on_global, impl);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -586,36 +991,8 @@ static void destroy_socket(struct socket *s)
|
||||||
free(s);
|
free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool init_socket_name(struct socket *s, const char *name, bool promiscuous, int which)
|
|
||||||
{
|
|
||||||
int name_size;
|
|
||||||
const char *runtime_dir;
|
|
||||||
|
|
||||||
runtime_dir = JACK_SOCKET_DIR;
|
|
||||||
|
|
||||||
s->addr.sun_family = AF_UNIX;
|
|
||||||
if (promiscuous) {
|
|
||||||
name_size = snprintf(s->addr.sun_path, sizeof(s->addr.sun_path),
|
|
||||||
"%s/jack_%s_%d", runtime_dir, name, which) + 1;
|
|
||||||
} else {
|
|
||||||
name_size = snprintf(s->addr.sun_path, sizeof(s->addr.sun_path),
|
|
||||||
"%s/jack_%s_%d_%d", runtime_dir, name, getuid(), which) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->core_name = (s->addr.sun_path + name_size - 1) - strlen(name);
|
|
||||||
|
|
||||||
if (name_size > (int) sizeof(s->addr.sun_path)) {
|
|
||||||
pw_log_error("socket path \"%s/%s\" plus null terminator exceeds 108 bytes",
|
|
||||||
runtime_dir, name);
|
|
||||||
*s->addr.sun_path = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
socket_data(struct spa_loop_utils *utils,
|
socket_data(void *data, int fd, enum spa_io mask)
|
||||||
struct spa_source *source, int fd, enum spa_io mask, void *data)
|
|
||||||
{
|
{
|
||||||
struct impl *impl = data;
|
struct impl *impl = data;
|
||||||
struct client *client;
|
struct client *client;
|
||||||
|
|
@ -682,6 +1059,8 @@ static int init_server(struct impl *impl, const char *name, bool promiscuous)
|
||||||
|
|
||||||
jack_cleanup_shm();
|
jack_cleanup_shm();
|
||||||
|
|
||||||
|
server->promiscuous = promiscuous;
|
||||||
|
|
||||||
/* graph manager */
|
/* graph manager */
|
||||||
server->graph_manager = jack_graph_manager_alloc(2048);
|
server->graph_manager = jack_graph_manager_alloc(2048);
|
||||||
|
|
||||||
|
|
@ -696,7 +1075,7 @@ static int init_server(struct impl *impl, const char *name, bool promiscuous)
|
||||||
|
|
||||||
s = create_socket();
|
s = create_socket();
|
||||||
|
|
||||||
if (!init_socket_name(s, name, promiscuous, 0))
|
if (!init_socket_name(&s->addr, name, promiscuous, 0))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!add_socket(impl, s))
|
if (!add_socket(impl, s))
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#define JACK_PORT_NAME_SIZE 256
|
#define JACK_PORT_NAME_SIZE 256
|
||||||
#define JACK_PORT_TYPE_SIZE 32
|
#define JACK_PORT_TYPE_SIZE 32
|
||||||
#define JACK_PROTOCOL_VERSION 8
|
#define JACK_PROTOCOL_VERSION 8
|
||||||
|
#define JACK_MESSAGE_SIZE 256
|
||||||
|
|
||||||
#define PORT_NUM_MAX 4096
|
#define PORT_NUM_MAX 4096
|
||||||
#define PORT_NUM_FOR_CLIENT 2048
|
#define PORT_NUM_FOR_CLIENT 2048
|
||||||
|
|
@ -60,8 +61,6 @@
|
||||||
#define EMPTY 0xFFFD
|
#define EMPTY 0xFFFD
|
||||||
#define FREE 0xFFFC
|
#define FREE 0xFFFC
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
JACK_TIMER_SYSTEM_CLOCK,
|
JACK_TIMER_SYSTEM_CLOCK,
|
||||||
JACK_TIMER_HPET,
|
JACK_TIMER_HPET,
|
||||||
|
|
|
||||||
508
src/modules/module-jack/jack-node.c
Normal file
508
src/modules/module-jack/jack-node.c
Normal file
|
|
@ -0,0 +1,508 @@
|
||||||
|
/* PipeWire
|
||||||
|
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/eventfd.h>
|
||||||
|
|
||||||
|
#include <spa/node.h>
|
||||||
|
#include <spa/hook.h>
|
||||||
|
#include <spa/format-builder.h>
|
||||||
|
#include <spa/lib/format.h>
|
||||||
|
#include <spa/audio/format-utils.h>
|
||||||
|
|
||||||
|
#include "pipewire/pipewire.h"
|
||||||
|
#include "pipewire/core.h"
|
||||||
|
#include "pipewire/private.h"
|
||||||
|
|
||||||
|
#include "jack.h"
|
||||||
|
#include "jack-node.h"
|
||||||
|
|
||||||
|
#define NAME "jack-node"
|
||||||
|
|
||||||
|
/** \cond */
|
||||||
|
|
||||||
|
struct type {
|
||||||
|
uint32_t format;
|
||||||
|
struct spa_type_data data;
|
||||||
|
struct spa_type_media_type media_type;
|
||||||
|
struct spa_type_media_subtype media_subtype;
|
||||||
|
struct spa_type_format_audio format_audio;
|
||||||
|
struct spa_type_audio_format audio_format;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pw_jack_node {
|
||||||
|
struct pw_core *core;
|
||||||
|
struct pw_node *node;
|
||||||
|
|
||||||
|
struct spa_hook_list listener_list;
|
||||||
|
|
||||||
|
struct jack_server *server;
|
||||||
|
struct type type;
|
||||||
|
int ref_num;
|
||||||
|
struct pw_port *otherport;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void init_type(struct type *type, struct spa_type_map *map)
|
||||||
|
{
|
||||||
|
type->format = spa_type_map_get_id(map, SPA_TYPE__Format);
|
||||||
|
spa_type_data_map(map, &type->data);
|
||||||
|
spa_type_media_type_map(map, &type->media_type);
|
||||||
|
spa_type_media_subtype_map(map, &type->media_subtype);
|
||||||
|
spa_type_format_audio_map(map, &type->format_audio);
|
||||||
|
spa_type_audio_format_map(map, &type->audio_format);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct buffer {
|
||||||
|
struct spa_list link;
|
||||||
|
struct spa_buffer *outbuf;
|
||||||
|
void *ptr;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct port_data {
|
||||||
|
struct pw_jack_node *node;
|
||||||
|
|
||||||
|
int jack_port_id;
|
||||||
|
struct jack_port *port;
|
||||||
|
|
||||||
|
struct spa_port_info info;
|
||||||
|
|
||||||
|
struct spa_port_io *io;
|
||||||
|
|
||||||
|
struct buffer buffers[64];
|
||||||
|
uint32_t n_buffers;
|
||||||
|
struct spa_list empty;
|
||||||
|
|
||||||
|
uint8_t buffer[1024];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \endcond */
|
||||||
|
|
||||||
|
static int node_get_props(void *data, struct spa_props **props)
|
||||||
|
{
|
||||||
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int node_set_props(void *data, const struct spa_props *props)
|
||||||
|
{
|
||||||
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int node_send_command(void *data,
|
||||||
|
const struct spa_command *command)
|
||||||
|
{
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pw_port* node_add_port(void *data,
|
||||||
|
enum pw_direction direction,
|
||||||
|
uint32_t port_id)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct buffer *buffer_dequeue(struct pw_jack_node *this, struct port_data *pd)
|
||||||
|
{
|
||||||
|
struct buffer *b;
|
||||||
|
|
||||||
|
if (spa_list_is_empty(&pd->empty))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
b = spa_list_first(&pd->empty, struct buffer, link);
|
||||||
|
spa_list_remove(&b->link);
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void recycle_buffer(struct pw_jack_node *this, struct port_data *pd, uint32_t id)
|
||||||
|
{
|
||||||
|
struct buffer *b = &pd->buffers[id];
|
||||||
|
pw_log_trace("recycle buffer %d", id);
|
||||||
|
spa_list_append(&pd->empty, &b->link);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int node_process_input(void *data)
|
||||||
|
{
|
||||||
|
struct pw_jack_node *this = data;
|
||||||
|
struct spa_graph_node *node = &this->node->rt.node;
|
||||||
|
struct spa_graph_port *p;
|
||||||
|
struct buffer *out;
|
||||||
|
struct port_data *opd = pw_port_get_user_data(this->otherport);
|
||||||
|
struct spa_port_io *out_io = opd->io;
|
||||||
|
|
||||||
|
pw_log_trace("process input");
|
||||||
|
if (out_io->status == SPA_RESULT_HAVE_BUFFER)
|
||||||
|
return SPA_RESULT_HAVE_BUFFER;
|
||||||
|
|
||||||
|
out = buffer_dequeue(this, opd);
|
||||||
|
if (out == NULL)
|
||||||
|
return SPA_RESULT_OUT_OF_BUFFERS;
|
||||||
|
|
||||||
|
spa_list_for_each(p, &node->ports[SPA_DIRECTION_INPUT], link) {
|
||||||
|
struct pw_port *port = p->callbacks_data;
|
||||||
|
struct port_data *ipd = pw_port_get_user_data(port);
|
||||||
|
struct spa_port_io *in_io = ipd->io;
|
||||||
|
|
||||||
|
in_io->status = SPA_RESULT_NEED_BUFFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_io->buffer_id = out->outbuf->id;
|
||||||
|
out_io->status = SPA_RESULT_HAVE_BUFFER;
|
||||||
|
|
||||||
|
return SPA_RESULT_HAVE_BUFFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int node_process_output(void *data)
|
||||||
|
{
|
||||||
|
struct pw_jack_node *this = data;
|
||||||
|
struct spa_graph_node *node = &this->node->rt.node;
|
||||||
|
struct spa_graph_port *p;
|
||||||
|
|
||||||
|
pw_log_trace(NAME "%p: process output", this);
|
||||||
|
|
||||||
|
spa_list_for_each(p, &node->ports[SPA_DIRECTION_OUTPUT], link) {
|
||||||
|
struct pw_port *port = p->callbacks_data;
|
||||||
|
struct port_data *opd = pw_port_get_user_data(port);
|
||||||
|
struct spa_port_io *out_io = opd->io;
|
||||||
|
|
||||||
|
if (out_io->status == SPA_RESULT_HAVE_BUFFER)
|
||||||
|
return SPA_RESULT_HAVE_BUFFER;
|
||||||
|
|
||||||
|
if (out_io->buffer_id != SPA_ID_INVALID) {
|
||||||
|
recycle_buffer(this, opd, out_io->buffer_id);
|
||||||
|
out_io->buffer_id = SPA_ID_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spa_list_for_each(p, &node->ports[SPA_DIRECTION_INPUT], link) {
|
||||||
|
struct pw_port *port = p->callbacks_data;
|
||||||
|
struct port_data *ipd = pw_port_get_user_data(port);
|
||||||
|
struct spa_port_io *in_io = ipd->io;
|
||||||
|
|
||||||
|
in_io->status = SPA_RESULT_NEED_BUFFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
spa_hook_list_call(&this->listener_list, struct pw_jack_node_events, process);
|
||||||
|
|
||||||
|
return SPA_RESULT_NEED_BUFFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pw_node_implementation node_impl = {
|
||||||
|
PW_VERSION_NODE_IMPLEMENTATION,
|
||||||
|
.get_props = node_get_props,
|
||||||
|
.set_props = node_set_props,
|
||||||
|
.send_command = node_send_command,
|
||||||
|
.add_port = node_add_port,
|
||||||
|
.process_input = node_process_input,
|
||||||
|
.process_output = node_process_output,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int port_set_io(void *data, struct spa_port_io *io)
|
||||||
|
{
|
||||||
|
struct port_data *pd = data;
|
||||||
|
pd->io = io;
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PROP(f,key,type,...) \
|
||||||
|
SPA_POD_PROP (f,key,0,type,1,__VA_ARGS__)
|
||||||
|
|
||||||
|
static int port_enum_formats(void *data,
|
||||||
|
struct spa_format **format,
|
||||||
|
const struct spa_format *filter,
|
||||||
|
int32_t index)
|
||||||
|
{
|
||||||
|
struct port_data *pd = data;
|
||||||
|
struct type *t = &pd->node->type;
|
||||||
|
struct spa_pod_builder b = { NULL, };
|
||||||
|
struct spa_pod_frame f[2];
|
||||||
|
|
||||||
|
if (index > 0)
|
||||||
|
return SPA_RESULT_ENUM_END;
|
||||||
|
|
||||||
|
spa_pod_builder_init(&b, pd->buffer, sizeof(pd->buffer));
|
||||||
|
|
||||||
|
if (pd->port) {
|
||||||
|
if (pd->port->type_id == 0) {
|
||||||
|
spa_pod_builder_format(&b, &f[0], t->format,
|
||||||
|
t->media_type.audio, t->media_subtype.raw,
|
||||||
|
PROP(&f[1], t->format_audio.format, SPA_POD_TYPE_ID, t->audio_format.F32),
|
||||||
|
PROP(&f[1], t->format_audio.rate, SPA_POD_TYPE_INT, 44100),
|
||||||
|
PROP(&f[1], t->format_audio.channels, SPA_POD_TYPE_INT, 1));
|
||||||
|
}
|
||||||
|
else if (pd->port->type_id == 1) {
|
||||||
|
return SPA_RESULT_ENUM_END;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return SPA_RESULT_ENUM_END;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
spa_pod_builder_format(&b, &f[0], t->format,
|
||||||
|
t->media_type.audio, t->media_subtype.raw,
|
||||||
|
PROP(&f[1], t->format_audio.format, SPA_POD_TYPE_ID, t->audio_format.S16),
|
||||||
|
PROP(&f[1], t->format_audio.rate, SPA_POD_TYPE_INT, 44100),
|
||||||
|
PROP(&f[1], t->format_audio.channels, SPA_POD_TYPE_INT, 2));
|
||||||
|
}
|
||||||
|
*format = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_format);
|
||||||
|
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int port_set_format(void *data, uint32_t flags, const struct spa_format *format)
|
||||||
|
{
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int port_get_format(void *data, const struct spa_format **format)
|
||||||
|
{
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int port_get_info(void *data, const struct spa_port_info **info)
|
||||||
|
{
|
||||||
|
struct port_data *pd = data;
|
||||||
|
|
||||||
|
pd->info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS | SPA_PORT_INFO_FLAG_LIVE;
|
||||||
|
pd->info.rate = 44100;
|
||||||
|
*info = &pd->info;
|
||||||
|
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int port_enum_params(void *data, uint32_t index, struct spa_param **param)
|
||||||
|
{
|
||||||
|
return SPA_RESULT_ENUM_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int port_set_param(void *data, struct spa_param *param)
|
||||||
|
{
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int port_use_buffers(void *data, struct spa_buffer **buffers, uint32_t n_buffers)
|
||||||
|
{
|
||||||
|
struct port_data *pd = data;
|
||||||
|
struct type *t = &pd->node->type;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < n_buffers; i++) {
|
||||||
|
struct buffer *b;
|
||||||
|
struct spa_data *d = buffers[i]->datas;
|
||||||
|
|
||||||
|
b = &pd->buffers[i];
|
||||||
|
b->outbuf = buffers[i];
|
||||||
|
if ((d[0].type == t->data.MemPtr ||
|
||||||
|
d[0].type == t->data.MemFd ||
|
||||||
|
d[0].type == t->data.DmaBuf) && d[0].data != NULL) {
|
||||||
|
b->ptr = d[0].data;
|
||||||
|
b->size = d[0].maxsize;
|
||||||
|
} else {
|
||||||
|
pw_log_error(NAME " %p: invalid memory on buffer %p", pd, buffers[i]);
|
||||||
|
return SPA_RESULT_ERROR;
|
||||||
|
}
|
||||||
|
spa_list_append(&pd->empty, &b->link);
|
||||||
|
}
|
||||||
|
pd->n_buffers = n_buffers;
|
||||||
|
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int port_alloc_buffers(void *data,
|
||||||
|
struct spa_param **params, uint32_t n_params,
|
||||||
|
struct spa_buffer **buffers, uint32_t *n_buffers)
|
||||||
|
{
|
||||||
|
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int port_reuse_buffer(void *data, uint32_t buffer_id)
|
||||||
|
{
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int port_send_command(void *data, struct spa_command *command)
|
||||||
|
{
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pw_port_implementation port_impl = {
|
||||||
|
PW_VERSION_PORT_IMPLEMENTATION,
|
||||||
|
.set_io = port_set_io,
|
||||||
|
.enum_formats = port_enum_formats,
|
||||||
|
.set_format = port_set_format,
|
||||||
|
.get_format = port_get_format,
|
||||||
|
.get_info = port_get_info,
|
||||||
|
.enum_params = port_enum_params,
|
||||||
|
.set_param = port_set_param,
|
||||||
|
.use_buffers = port_use_buffers,
|
||||||
|
.alloc_buffers = port_alloc_buffers,
|
||||||
|
.reuse_buffer = port_reuse_buffer,
|
||||||
|
.send_command = port_send_command,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct pw_port *make_port(struct pw_jack_node *node, enum pw_direction direction,
|
||||||
|
int port_id, int jack_port_id, struct jack_port *jp, bool autoconnect)
|
||||||
|
{
|
||||||
|
struct pw_port *port;
|
||||||
|
struct port_data *pd;
|
||||||
|
struct pw_properties *properties = NULL;
|
||||||
|
|
||||||
|
if (autoconnect)
|
||||||
|
properties = pw_properties_new("pipewire.autoconnect", "1", NULL);
|
||||||
|
|
||||||
|
port = pw_port_new(direction, port_id, properties, sizeof(struct port_data));
|
||||||
|
pd = pw_port_get_user_data(port);
|
||||||
|
pd->node = node;
|
||||||
|
pd->jack_port_id = jack_port_id;
|
||||||
|
pd->port = jp;
|
||||||
|
spa_list_init(&pd->empty);
|
||||||
|
pw_port_set_implementation(port, &port_impl, pd);
|
||||||
|
pw_port_add(port, node->node);
|
||||||
|
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pw_jack_node *pw_jack_node_new(struct pw_core *core,
|
||||||
|
struct pw_global *parent,
|
||||||
|
struct jack_server *server,
|
||||||
|
int ref_num,
|
||||||
|
struct pw_properties *properties)
|
||||||
|
{
|
||||||
|
struct pw_jack_node *this;
|
||||||
|
struct pw_node *node;
|
||||||
|
struct jack_client *client = server->client_table[ref_num];
|
||||||
|
struct jack_graph_manager *mgr = server->graph_manager;
|
||||||
|
struct jack_connection_manager *conn;
|
||||||
|
int i;
|
||||||
|
jack_int_t *p;
|
||||||
|
bool make_input = false, make_output = false;
|
||||||
|
|
||||||
|
node = pw_node_new(core, NULL, parent, client->control->name,
|
||||||
|
properties, sizeof(struct pw_jack_node));
|
||||||
|
if (node == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
this = pw_node_get_user_data(node);
|
||||||
|
pw_log_debug("jack-node %p: new", this);
|
||||||
|
|
||||||
|
this->node = node;
|
||||||
|
this->core = core;
|
||||||
|
spa_hook_list_init(&this->listener_list);
|
||||||
|
this->server = server;
|
||||||
|
this->ref_num = ref_num;
|
||||||
|
init_type(&this->type, pw_core_get_type(core)->map);
|
||||||
|
|
||||||
|
pw_node_set_implementation(node, &node_impl, this);
|
||||||
|
|
||||||
|
conn = jack_graph_manager_next_start(mgr);
|
||||||
|
|
||||||
|
p = GET_ITEMS_FIXED_ARRAY1(conn->input_port[ref_num]);
|
||||||
|
for (i = 0; i < PORT_NUM_FOR_CLIENT && p[i] != EMPTY; i++) {
|
||||||
|
struct jack_port *jp = jack_graph_manager_get_port(mgr, p[i]);
|
||||||
|
|
||||||
|
if (jp->flags & JackPortIsPhysical)
|
||||||
|
make_output = true;
|
||||||
|
|
||||||
|
make_port(this, PW_DIRECTION_INPUT, i, p[i], jp, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
p = GET_ITEMS_FIXED_ARRAY(conn->output_port[ref_num]);
|
||||||
|
for (i = 0; i < PORT_NUM_FOR_CLIENT && p[i] != EMPTY; i++) {
|
||||||
|
struct jack_port *jp = jack_graph_manager_get_port(mgr, p[i]);
|
||||||
|
|
||||||
|
if (jp->flags & JackPortIsPhysical)
|
||||||
|
make_input = true;
|
||||||
|
|
||||||
|
make_port(this, PW_DIRECTION_OUTPUT, i, p[i], jp, false);
|
||||||
|
}
|
||||||
|
jack_graph_manager_next_stop(mgr);
|
||||||
|
|
||||||
|
if (make_output)
|
||||||
|
this->otherport = make_port(this, PW_DIRECTION_OUTPUT, 0, -1, NULL, true);
|
||||||
|
if (make_input)
|
||||||
|
this->otherport = make_port(this, PW_DIRECTION_INPUT, 0, -1, NULL, true);
|
||||||
|
|
||||||
|
pw_node_register(node);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pw_jack_node_destroy(struct pw_jack_node *node)
|
||||||
|
{
|
||||||
|
pw_log_debug("jack-node %p: destroy", node);
|
||||||
|
pw_node_destroy(node->node);
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pw_node *pw_jack_node_get_node(struct pw_jack_node *node)
|
||||||
|
{
|
||||||
|
return node->node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pw_jack_node_add_listener(struct pw_jack_node *node,
|
||||||
|
struct spa_hook *listener,
|
||||||
|
const struct pw_jack_node_events *events,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
spa_hook_list_append(&node->listener_list, listener, events, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct find_data {
|
||||||
|
jack_port_id_t port_id;
|
||||||
|
struct pw_port *result;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool find_port(void *data, struct pw_port *port)
|
||||||
|
{
|
||||||
|
struct find_data *d = data;
|
||||||
|
struct port_data *pd = pw_port_get_user_data(port);
|
||||||
|
|
||||||
|
if (pd->jack_port_id == d->port_id) {
|
||||||
|
d->result = port;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pw_port *pw_jack_node_add_port(struct pw_jack_node *node,
|
||||||
|
enum pw_direction direction,
|
||||||
|
jack_port_id_t port_id)
|
||||||
|
{
|
||||||
|
struct jack_server *server = node->server;
|
||||||
|
struct jack_graph_manager *mgr = server->graph_manager;
|
||||||
|
struct jack_port *jp = jack_graph_manager_get_port(mgr, port_id);
|
||||||
|
return make_port(node, direction, port_id, port_id, jp, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pw_port *pw_jack_node_find_port(struct pw_jack_node *node,
|
||||||
|
enum pw_direction direction,
|
||||||
|
jack_port_id_t port_id)
|
||||||
|
{
|
||||||
|
struct find_data data = { port_id, };
|
||||||
|
if (!pw_node_for_each_port(node->node, direction, find_port, &data))
|
||||||
|
return data.result;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
73
src/modules/module-jack/jack-node.h
Normal file
73
src/modules/module-jack/jack-node.h
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
/* PipeWire
|
||||||
|
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PIPEWIRE_JACK_NODE_H__
|
||||||
|
#define __PIPEWIRE_JACK_NODE_H__
|
||||||
|
|
||||||
|
#include <pipewire/node.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** \class pw_jack_node
|
||||||
|
*
|
||||||
|
* PipeWire jack node interface
|
||||||
|
*/
|
||||||
|
struct pw_jack_node;
|
||||||
|
|
||||||
|
struct pw_jack_node_events {
|
||||||
|
#define PW_VERSION_JACK_NODE_EVENTS 0
|
||||||
|
uint32_t version;
|
||||||
|
|
||||||
|
void (*destroy) (void *data);
|
||||||
|
|
||||||
|
void (*process) (void *data);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct pw_jack_node *
|
||||||
|
pw_jack_node_new(struct pw_core *core,
|
||||||
|
struct pw_global *parent,
|
||||||
|
struct jack_server *server,
|
||||||
|
int ref_num,
|
||||||
|
struct pw_properties *properties);
|
||||||
|
|
||||||
|
void
|
||||||
|
pw_jack_node_destroy(struct pw_jack_node *node);
|
||||||
|
|
||||||
|
struct pw_node *pw_jack_node_get_node(struct pw_jack_node *node);
|
||||||
|
|
||||||
|
void pw_jack_node_add_listener(struct pw_jack_node *node,
|
||||||
|
struct spa_hook *listener,
|
||||||
|
const struct pw_jack_node_events *events,
|
||||||
|
void *data);
|
||||||
|
|
||||||
|
struct pw_port *pw_jack_node_add_port(struct pw_jack_node *node,
|
||||||
|
enum pw_direction direction,
|
||||||
|
jack_port_id_t port_id);
|
||||||
|
|
||||||
|
struct pw_port *pw_jack_node_find_port(struct pw_jack_node *node,
|
||||||
|
enum pw_direction direction, jack_port_id_t port_id);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __PIPEWIRE_JACK_NODE_H__ */
|
||||||
28
src/modules/module-jack/jack.h
Normal file
28
src/modules/module-jack/jack.h
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* PipeWire
|
||||||
|
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <jack/jack.h>
|
||||||
|
#include <jack/session.h>
|
||||||
|
|
||||||
|
#include "modules/module-jack/defs.h"
|
||||||
|
#include "modules/module-jack/synchro.h"
|
||||||
|
#include "modules/module-jack/shm.h"
|
||||||
|
#include "modules/module-jack/shared.h"
|
||||||
|
#include "modules/module-jack/port.h"
|
||||||
|
#include "modules/module-jack/server.h"
|
||||||
28
src/modules/module-jack/port.h
Normal file
28
src/modules/module-jack/port.h
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* PipeWire
|
||||||
|
* Copyright (C) 2017 Wim Taymans <wim.taymans@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline jack_port_type_id_t
|
||||||
|
jack_port_get_type_id(const char *type)
|
||||||
|
{
|
||||||
|
if (strcmp(type, JACK_DEFAULT_AUDIO_TYPE) == 0)
|
||||||
|
return 0;
|
||||||
|
else if (strcmp(type, JACK_DEFAULT_MIDI_TYPE) == 0)
|
||||||
|
return 1;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
@ -21,7 +21,8 @@ struct jack_client {
|
||||||
int ref_num;
|
int ref_num;
|
||||||
struct client *owner;
|
struct client *owner;
|
||||||
struct jack_client_control *control;
|
struct jack_client_control *control;
|
||||||
struct pw_node *node;
|
struct pw_jack_node *node;
|
||||||
|
int fd; /* notify fd */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct jack_server {
|
struct jack_server {
|
||||||
|
|
@ -34,6 +35,13 @@ struct jack_server {
|
||||||
|
|
||||||
struct jack_client* client_table[CLIENT_NUM];
|
struct jack_client* client_table[CLIENT_NUM];
|
||||||
struct jack_synchro synchro_table[CLIENT_NUM];
|
struct jack_synchro synchro_table[CLIENT_NUM];
|
||||||
|
|
||||||
|
int audio_ref_num;
|
||||||
|
int freewheel_ref_num;
|
||||||
|
|
||||||
|
struct pw_jack_node *audio_node;
|
||||||
|
struct pw_node *audio_node_node;
|
||||||
|
int audio_used;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,64 @@ static inline void jack_port_init(struct jack_port *port, int ref_num,
|
||||||
port->tied = NO_PORT;
|
port->tied = NO_PORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void jack_port_release(struct jack_port *port) {
|
||||||
|
port->in_use = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRE_PACKED_STRUCTURE
|
||||||
|
struct jack_client_control {
|
||||||
|
jack_shm_info_t info;
|
||||||
|
char name[JACK_CLIENT_NAME_SIZE+1];
|
||||||
|
bool callback[jack_notify_max];
|
||||||
|
volatile jack_transport_state_t transport_state;
|
||||||
|
volatile bool transport_sync;
|
||||||
|
volatile bool transport_timebase;
|
||||||
|
int ref_num;
|
||||||
|
int PID;
|
||||||
|
bool active;
|
||||||
|
|
||||||
|
int session_ID;
|
||||||
|
char session_command[JACK_SESSION_COMMAND_SIZE];
|
||||||
|
jack_session_flags_t session_flags;
|
||||||
|
} POST_PACKED_STRUCTURE;
|
||||||
|
|
||||||
|
static inline struct jack_client_control *
|
||||||
|
jack_client_control_alloc(const char* name, int pid, int ref_num, int uuid)
|
||||||
|
{
|
||||||
|
struct jack_client_control *ctrl;
|
||||||
|
jack_shm_info_t info;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
size = sizeof(struct jack_client_control);
|
||||||
|
if (jack_shm_alloc(size, &info, segment_num++) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ctrl = (struct jack_client_control *)jack_shm_addr(&info);
|
||||||
|
ctrl->info = info;
|
||||||
|
|
||||||
|
strcpy(ctrl->name, name);
|
||||||
|
for (int i = 0; i < jack_notify_max; i++)
|
||||||
|
ctrl->callback[i] = false;
|
||||||
|
|
||||||
|
// Always activated
|
||||||
|
ctrl->callback[jack_notify_AddClient] = true;
|
||||||
|
ctrl->callback[jack_notify_RemoveClient] = true;
|
||||||
|
ctrl->callback[jack_notify_ActivateClient] = true;
|
||||||
|
ctrl->callback[jack_notify_LatencyCallback] = true;
|
||||||
|
// So that driver synchro are correctly setup in "flush" or "normal" mode
|
||||||
|
ctrl->callback[jack_notify_StartFreewheelCallback] = true;
|
||||||
|
ctrl->callback[jack_notify_StopFreewheelCallback] = true;
|
||||||
|
ctrl->ref_num = ref_num;
|
||||||
|
ctrl->PID = pid;
|
||||||
|
ctrl->transport_state = JackTransportStopped;
|
||||||
|
ctrl->transport_sync = false;
|
||||||
|
ctrl->transport_timebase = false;
|
||||||
|
ctrl->active = false;
|
||||||
|
ctrl->session_ID = uuid;
|
||||||
|
|
||||||
|
return ctrl;
|
||||||
|
}
|
||||||
|
|
||||||
#define MAKE_FIXED_ARRAY(size) \
|
#define MAKE_FIXED_ARRAY(size) \
|
||||||
PRE_PACKED_STRUCTURE \
|
PRE_PACKED_STRUCTURE \
|
||||||
struct { \
|
struct { \
|
||||||
|
|
@ -105,24 +163,41 @@ struct { \
|
||||||
uint32_t counter; \
|
uint32_t counter; \
|
||||||
} POST_PACKED_STRUCTURE
|
} POST_PACKED_STRUCTURE
|
||||||
|
|
||||||
#define INIT_FIXED_ARRAY(arr) ({ \
|
#define INIT_FIXED_ARRAY(arr) ({ \
|
||||||
int i; \
|
int _i; \
|
||||||
for (i = 0; i < SPA_N_ELEMENTS(arr.table); i++) \
|
for (_i = 0; _i < SPA_N_ELEMENTS(arr.table); _i++) \
|
||||||
arr.table[i] = EMPTY; \
|
arr.table[_i] = EMPTY; \
|
||||||
arr.counter = 0; \
|
arr.counter = 0; \
|
||||||
|
})
|
||||||
|
#define GET_ITEMS_FIXED_ARRAY(arr) ({ \
|
||||||
|
arr.table; \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define ADD_FIXED_ARRAY(arr,item) ({ \
|
#define ADD_FIXED_ARRAY(arr,item) ({ \
|
||||||
int i,ret = -1; \
|
int _ret = -1; \
|
||||||
for (i = 0; i < SPA_N_ELEMENTS(arr.table); i++) { \
|
if (arr.counter < SPA_N_ELEMENTS(arr.table)) { \
|
||||||
if (arr.table[i] == EMPTY) { \
|
_ret = arr.counter++; \
|
||||||
arr.table[i] = item; \
|
arr.table[_ret] = item; \
|
||||||
arr.counter++; \
|
} \
|
||||||
ret = 0; \
|
_ret; \
|
||||||
|
})
|
||||||
|
#define GET_FIXED_ARRAY(arr,item) ({ \
|
||||||
|
int _i,_ret = -1; \
|
||||||
|
for (_i = 0; _i < arr.counter; _i++) { \
|
||||||
|
if (arr.table[_i] == item) { \
|
||||||
|
_ret = _i; \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
ret; \
|
_ret; \
|
||||||
|
})
|
||||||
|
#define REMOVE_FIXED_ARRAY(arr,item) ({ \
|
||||||
|
int _ret = GET_FIXED_ARRAY(arr,item); \
|
||||||
|
if (_ret >= 0) { \
|
||||||
|
arr.counter--; \
|
||||||
|
arr.table[_ret] = arr.table[arr.counter]; \
|
||||||
|
arr.table[arr.counter] = EMPTY; \
|
||||||
|
} \
|
||||||
|
_ret; \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define MAKE_FIXED_ARRAY1(size) \
|
#define MAKE_FIXED_ARRAY1(size) \
|
||||||
|
|
@ -136,8 +211,9 @@ struct { \
|
||||||
INIT_FIXED_ARRAY(arr.array); \
|
INIT_FIXED_ARRAY(arr.array); \
|
||||||
arr.used = false; \
|
arr.used = false; \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define ADD_FIXED_ARRAY1(arr,item) ADD_FIXED_ARRAY(arr.array,item)
|
#define ADD_FIXED_ARRAY1(arr,item) ADD_FIXED_ARRAY(arr.array,item)
|
||||||
|
#define GET_FIXED_ARRAY1(arr,item) GET_FIXED_ARRAY(arr.array,item)
|
||||||
|
#define GET_ITEMS_FIXED_ARRAY1(arr) GET_ITEMS_FIXED_ARRAY(arr.array)
|
||||||
|
|
||||||
#define MAKE_FIXED_MATRIX(size) \
|
#define MAKE_FIXED_MATRIX(size) \
|
||||||
PRE_PACKED_STRUCTURE \
|
PRE_PACKED_STRUCTURE \
|
||||||
|
|
@ -152,6 +228,21 @@ struct { \
|
||||||
mat.table[i][idx] = 0; \
|
mat.table[i][idx] = 0; \
|
||||||
} \
|
} \
|
||||||
})
|
})
|
||||||
|
#define GET_ITEMS_FIXED_MATRIX(mat,idx1) ({ \
|
||||||
|
mat.table[idx1]; \
|
||||||
|
})
|
||||||
|
#define INC_FIXED_MATRIX(mat,idx1,idx2) ({ \
|
||||||
|
++mat.table[idx1][idx2]; \
|
||||||
|
})
|
||||||
|
#define DEC_FIXED_MATRIX(mat,idx1,idx2) ({ \
|
||||||
|
--mat.table[idx1][idx2]; \
|
||||||
|
})
|
||||||
|
#define GET_FIXED_MATRIX(mat,idx1,idx2) ({ \
|
||||||
|
mat.table[idx1][idx2]; \
|
||||||
|
})
|
||||||
|
#define CLEAR_FIXED_MATRIX(mat,idx1,idx2) ({ \
|
||||||
|
mat.table[idx1][idx2] = 0; \
|
||||||
|
})
|
||||||
|
|
||||||
PRE_PACKED_STRUCTURE
|
PRE_PACKED_STRUCTURE
|
||||||
struct jack_activation_count {
|
struct jack_activation_count {
|
||||||
|
|
@ -162,6 +253,33 @@ struct jack_activation_count {
|
||||||
static inline void jack_activation_count_set_value(struct jack_activation_count *cnt, int32_t val) {
|
static inline void jack_activation_count_set_value(struct jack_activation_count *cnt, int32_t val) {
|
||||||
cnt->value = val;
|
cnt->value = val;
|
||||||
}
|
}
|
||||||
|
static inline int32_t jack_activation_count_get_value(struct jack_activation_count *cnt) {
|
||||||
|
return cnt->value;
|
||||||
|
}
|
||||||
|
static inline int32_t jack_activation_count_get_count(struct jack_activation_count *cnt) {
|
||||||
|
return cnt->count;
|
||||||
|
}
|
||||||
|
static inline void jack_activation_count_reset(struct jack_activation_count *cnt) {
|
||||||
|
cnt->value = cnt->count;
|
||||||
|
}
|
||||||
|
static inline void jack_activation_count_inc_value(struct jack_activation_count *cnt) {
|
||||||
|
cnt->count++;
|
||||||
|
}
|
||||||
|
static inline void jack_activation_count_dec_value(struct jack_activation_count *cnt) {
|
||||||
|
cnt->count--;
|
||||||
|
}
|
||||||
|
static inline bool jack_activation_count_signal(struct jack_activation_count *cnt,
|
||||||
|
struct jack_synchro *synchro)
|
||||||
|
{
|
||||||
|
bool res = true;
|
||||||
|
|
||||||
|
if (cnt->value == 0)
|
||||||
|
res = jack_synchro_signal(synchro);
|
||||||
|
else if (__atomic_sub_fetch(&cnt->value, 1, __ATOMIC_SEQ_CST) == 0)
|
||||||
|
res = jack_synchro_signal(synchro);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
#define MAKE_LOOP_FEEDBACK(size) \
|
#define MAKE_LOOP_FEEDBACK(size) \
|
||||||
PRE_PACKED_STRUCTURE \
|
PRE_PACKED_STRUCTURE \
|
||||||
|
|
@ -177,6 +295,62 @@ struct { \
|
||||||
arr.table[i][2] = 0; \
|
arr.table[i][2] = 0; \
|
||||||
} \
|
} \
|
||||||
})
|
})
|
||||||
|
#define ADD_LOOP_FEEDBACK(arr,ref1,ref2) ({ \
|
||||||
|
int i,res = false; \
|
||||||
|
for (i = 0; i < SPA_N_ELEMENTS(arr.table); i++) { \
|
||||||
|
if (arr.table[i][0] == EMPTY) { \
|
||||||
|
arr.table[i][0] = ref1; \
|
||||||
|
arr.table[i][1] = ref2; \
|
||||||
|
arr.table[i][2] = 1; \
|
||||||
|
res = true; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
res; \
|
||||||
|
})
|
||||||
|
#define DEL_LOOP_FEEDBACK(arr,ref1,ref2) ({ \
|
||||||
|
int i,res = false; \
|
||||||
|
for (i = 0; i < SPA_N_ELEMENTS(arr.table); i++) { \
|
||||||
|
if (arr.table[i][0] == ref1 && \
|
||||||
|
arr.table[i][1] == ref2) { \
|
||||||
|
arr.table[i][0] = EMPTY; \
|
||||||
|
arr.table[i][1] = EMPTY; \
|
||||||
|
arr.table[i][2] = 0; \
|
||||||
|
res = true; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
res; \
|
||||||
|
})
|
||||||
|
#define GET_LOOP_FEEDBACK(arr,ref1,ref2) ({ \
|
||||||
|
int i,res = 1; \
|
||||||
|
for (i = 0; i < SPA_N_ELEMENTS(arr.table); i++) { \
|
||||||
|
if (arr.table[i][0] == ref1 && \
|
||||||
|
arr.table[i][1] == ref2) { \
|
||||||
|
res = i; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
res; \
|
||||||
|
})
|
||||||
|
#define INC_LOOP_FEEDBACK(arr,ref1,ref2) ({ \
|
||||||
|
int res = true, idx = GET_LOOP_FEEDBACK(arr,ref1,ref2); \
|
||||||
|
if (idx >= 0) \
|
||||||
|
arr.table[idx][2]++; \
|
||||||
|
else \
|
||||||
|
res = ADD_LOOP_FEEDBACK(arr,ref1,ref2); \
|
||||||
|
res; \
|
||||||
|
})
|
||||||
|
#define DEC_LOOP_FEEDBACK(arr,idx) ({ \
|
||||||
|
int res = true, idx = GET_LOOP_FEEDBACK(arr,ref1,ref2); \
|
||||||
|
if (idx >= 0) { \
|
||||||
|
if (--arr.table[idx][2] == 0) \
|
||||||
|
res = DEL_LOOP_FEEDBACK(arr,ref1,ref2); \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
res = false; \
|
||||||
|
res; \
|
||||||
|
})
|
||||||
|
|
||||||
PRE_PACKED_STRUCTURE
|
PRE_PACKED_STRUCTURE
|
||||||
struct jack_connection_manager {
|
struct jack_connection_manager {
|
||||||
|
|
@ -194,7 +368,8 @@ jack_connection_manager_init_ref_num(struct jack_connection_manager *conn, int r
|
||||||
INIT_FIXED_ARRAY1(conn->input_port[ref_num]);
|
INIT_FIXED_ARRAY1(conn->input_port[ref_num]);
|
||||||
INIT_FIXED_ARRAY(conn->output_port[ref_num]);
|
INIT_FIXED_ARRAY(conn->output_port[ref_num]);
|
||||||
INIT_FIXED_MATRIX(conn->connection_ref, ref_num);
|
INIT_FIXED_MATRIX(conn->connection_ref, ref_num);
|
||||||
jack_activation_count_set_value (&conn->input_counter[ref_num], 0);
|
conn->input_counter[ref_num].count = 0;
|
||||||
|
jack_activation_count_set_value(&conn->input_counter[ref_num], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
|
@ -210,14 +385,185 @@ jack_connection_manager_init(struct jack_connection_manager *conn)
|
||||||
jack_connection_manager_init_ref_num(conn, i);
|
jack_connection_manager_init_ref_num(conn, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
jack_connection_manager_reset(struct jack_connection_manager *conn,
|
||||||
|
struct jack_client_timing *timing)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < CLIENT_NUM; i++) {
|
||||||
|
jack_activation_count_reset(&conn->input_counter[i]);
|
||||||
|
timing[i].status = NotTriggered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
jack_connection_manager_add_port(struct jack_connection_manager *conn, bool input,
|
jack_connection_manager_add_port(struct jack_connection_manager *conn, bool input,
|
||||||
int ref_num, jack_port_id_t port_id)
|
int ref_num, jack_port_id_t port_id)
|
||||||
{
|
{
|
||||||
if (input)
|
if (input) {
|
||||||
return ADD_FIXED_ARRAY1(conn->input_port[ref_num], port_id);
|
return ADD_FIXED_ARRAY1(conn->input_port[ref_num], port_id);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
return ADD_FIXED_ARRAY(conn->output_port[ref_num], port_id);
|
return ADD_FIXED_ARRAY(conn->output_port[ref_num], port_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
jack_connection_manager_get_output_refnum(struct jack_connection_manager *conn,
|
||||||
|
jack_port_id_t port_index)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < CLIENT_NUM; i++) {
|
||||||
|
if (GET_FIXED_ARRAY(conn->output_port[i], port_index) != -1)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
jack_connection_manager_get_input_refnum(struct jack_connection_manager *conn,
|
||||||
|
jack_port_id_t port_index)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < CLIENT_NUM; i++) {
|
||||||
|
if (GET_FIXED_ARRAY1(conn->input_port[i], port_index) != -1)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
jack_connection_manager_is_connected(struct jack_connection_manager *conn,
|
||||||
|
jack_port_id_t src_id, jack_port_id_t dst_id)
|
||||||
|
{
|
||||||
|
return GET_FIXED_ARRAY(conn->connection[src_id], dst_id) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
jack_connection_manager_connect(struct jack_connection_manager *conn,
|
||||||
|
jack_port_id_t src_id, jack_port_id_t dst_id)
|
||||||
|
{
|
||||||
|
return ADD_FIXED_ARRAY(conn->connection[src_id], dst_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
jack_connection_manager_disconnect(struct jack_connection_manager *conn,
|
||||||
|
jack_port_id_t src_id, jack_port_id_t dst_id)
|
||||||
|
{
|
||||||
|
return REMOVE_FIXED_ARRAY(conn->connection[src_id], dst_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
jack_connection_manager_is_loop_path(struct jack_connection_manager *conn,
|
||||||
|
jack_port_id_t src_id, jack_port_id_t dst_id)
|
||||||
|
{
|
||||||
|
/* FIXME */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
jack_connection_manager_direct_connect(struct jack_connection_manager *conn,
|
||||||
|
int ref1, int ref2)
|
||||||
|
{
|
||||||
|
if (INC_FIXED_MATRIX(conn->connection_ref, ref1, ref2) == 1)
|
||||||
|
jack_activation_count_inc_value(&conn->input_counter[ref2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
jack_connection_manager_is_direct_connection(struct jack_connection_manager *conn,
|
||||||
|
int ref1, int ref2)
|
||||||
|
{
|
||||||
|
return GET_FIXED_MATRIX(conn->connection_ref, ref1, ref2) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
jack_connection_manager_direct_disconnect(struct jack_connection_manager *conn,
|
||||||
|
int ref1, int ref2)
|
||||||
|
{
|
||||||
|
if (DEC_FIXED_MATRIX(conn->connection_ref, ref1, ref2) == 0)
|
||||||
|
jack_activation_count_dec_value(&conn->input_counter[ref2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
jack_connection_manager_inc_feedback_connection(struct jack_connection_manager *conn,
|
||||||
|
jack_port_id_t src_id, jack_port_id_t dst_id)
|
||||||
|
{
|
||||||
|
int ref1 = jack_connection_manager_get_output_refnum(conn, src_id);
|
||||||
|
int ref2 = jack_connection_manager_get_input_refnum(conn, dst_id);
|
||||||
|
|
||||||
|
if (ref1 != ref2)
|
||||||
|
jack_connection_manager_direct_connect(conn, ref2, ref1);
|
||||||
|
|
||||||
|
return INC_LOOP_FEEDBACK(conn->loop_feedback, ref1, ref2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
jack_connection_manager_inc_direct_connection(struct jack_connection_manager *conn,
|
||||||
|
jack_port_id_t src_id, jack_port_id_t dst_id)
|
||||||
|
{
|
||||||
|
int ref1 = jack_connection_manager_get_output_refnum(conn, src_id);
|
||||||
|
int ref2 = jack_connection_manager_get_input_refnum(conn, dst_id);
|
||||||
|
|
||||||
|
jack_connection_manager_direct_connect(conn, ref1, ref2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
jack_connection_manager_dec_direct_connection(struct jack_connection_manager *conn,
|
||||||
|
jack_port_id_t src_id, jack_port_id_t dst_id)
|
||||||
|
{
|
||||||
|
int ref1 = jack_connection_manager_get_output_refnum(conn, src_id);
|
||||||
|
int ref2 = jack_connection_manager_get_input_refnum(conn, dst_id);
|
||||||
|
|
||||||
|
jack_connection_manager_direct_disconnect(conn, ref1, ref2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
jack_connection_manager_get_activation(struct jack_connection_manager *conn, int ref_num)
|
||||||
|
{
|
||||||
|
return jack_activation_count_get_value(&conn->input_counter[ref_num]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
jack_connection_manager_suspend_ref_num(struct jack_connection_manager *conn,
|
||||||
|
struct jack_client_control *control,
|
||||||
|
struct jack_synchro *synchro,
|
||||||
|
struct jack_client_timing *timing)
|
||||||
|
{
|
||||||
|
int res = 0, ref_num = control->ref_num;
|
||||||
|
jack_time_t current_date = 0;
|
||||||
|
|
||||||
|
if (jack_synchro_wait(&synchro[ref_num])) {
|
||||||
|
timing[ref_num].status = Finished;
|
||||||
|
timing[ref_num].awake_at = current_date;
|
||||||
|
}
|
||||||
|
return res ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
jack_connection_manager_resume_ref_num(struct jack_connection_manager *conn,
|
||||||
|
struct jack_client_control *control,
|
||||||
|
struct jack_synchro *synchro,
|
||||||
|
struct jack_client_timing *timing)
|
||||||
|
{
|
||||||
|
int i, res = 0, ref_num = control->ref_num;
|
||||||
|
const jack_int_t* output_ref = GET_ITEMS_FIXED_MATRIX(conn->connection_ref, ref_num);
|
||||||
|
jack_time_t current_date = 0;
|
||||||
|
|
||||||
|
timing[ref_num].status = Finished;
|
||||||
|
timing[ref_num].finished_at = current_date;
|
||||||
|
|
||||||
|
for (i = 0; i < CLIENT_NUM; i++) {
|
||||||
|
if (output_ref[i] <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
timing[i].status = Triggered;
|
||||||
|
timing[i].signaled_at = current_date;
|
||||||
|
|
||||||
|
if (!jack_activation_count_signal(&conn->input_counter[i], &synchro[i]))
|
||||||
|
res = -1;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRE_PACKED_STRUCTURE
|
PRE_PACKED_STRUCTURE
|
||||||
|
|
@ -286,6 +632,8 @@ jack_graph_manager_alloc(int port_max)
|
||||||
|
|
||||||
mgr = (struct jack_graph_manager *)jack_shm_addr(&info);
|
mgr = (struct jack_graph_manager *)jack_shm_addr(&info);
|
||||||
mgr->info = info;
|
mgr->info = info;
|
||||||
|
Counter(mgr->state.counter) = 0;
|
||||||
|
mgr->state.call_write_counter = 0;
|
||||||
|
|
||||||
jack_connection_manager_init(&mgr->state.state[0]);
|
jack_connection_manager_init(&mgr->state.state[0]);
|
||||||
jack_connection_manager_init(&mgr->state.state[1]);
|
jack_connection_manager_init(&mgr->state.state[1]);
|
||||||
|
|
@ -313,6 +661,31 @@ jack_graph_manager_allocate_port(struct jack_graph_manager *mgr,
|
||||||
return NO_PORT;
|
return NO_PORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
jack_graph_manager_release_port(struct jack_graph_manager *mgr, jack_port_id_t port_id)
|
||||||
|
{
|
||||||
|
jack_port_release(&mgr->port_array[port_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct jack_port *
|
||||||
|
jack_graph_manager_get_port(struct jack_graph_manager *mgr, jack_port_id_t port_index)
|
||||||
|
{
|
||||||
|
if (port_index > 0 && port_index < mgr->port_max)
|
||||||
|
return &mgr->port_array[port_index];
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline jack_port_id_t
|
||||||
|
jack_graph_manager_find_port(struct jack_graph_manager *mgr, const char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < mgr->port_max; i++) {
|
||||||
|
struct jack_port *port = &mgr->port_array[i];
|
||||||
|
if (port->in_use && strcmp(port->name, name) == 0)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return NO_PORT;
|
||||||
|
}
|
||||||
|
|
||||||
static inline struct jack_connection_manager *
|
static inline struct jack_connection_manager *
|
||||||
jack_graph_manager_next_start(struct jack_graph_manager *manager)
|
jack_graph_manager_next_start(struct jack_graph_manager *manager)
|
||||||
|
|
@ -370,6 +743,38 @@ jack_graph_manager_next_stop(struct jack_graph_manager *manager)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
jack_graph_manager_is_pending_change(struct jack_graph_manager *manager)
|
||||||
|
{
|
||||||
|
return CurIndex(manager->state.counter) != NextIndex(manager->state.counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct jack_connection_manager *
|
||||||
|
jack_graph_manager_get_current(struct jack_graph_manager *manager)
|
||||||
|
{
|
||||||
|
return &manager->state.state[CurArrayIndex(manager->state.counter)];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct jack_connection_manager *
|
||||||
|
jack_graph_manager_try_switch(struct jack_graph_manager *manager)
|
||||||
|
{
|
||||||
|
struct jack_atomic_counter old_val;
|
||||||
|
struct jack_atomic_counter new_val;
|
||||||
|
do {
|
||||||
|
old_val = manager->state.counter;
|
||||||
|
new_val = old_val;
|
||||||
|
CurIndex(new_val) = NextIndex(new_val);
|
||||||
|
}
|
||||||
|
while (!__atomic_compare_exchange_n((uint32_t*)&manager->state.counter,
|
||||||
|
(uint32_t*)&Counter(old_val),
|
||||||
|
Counter(new_val),
|
||||||
|
false,
|
||||||
|
__ATOMIC_SEQ_CST,
|
||||||
|
__ATOMIC_SEQ_CST));
|
||||||
|
|
||||||
|
return &manager->state.state[CurArrayIndex(manager->state.counter)];
|
||||||
|
}
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TransportCommandNone = 0,
|
TransportCommandNone = 0,
|
||||||
TransportCommandStart = 1,
|
TransportCommandStart = 1,
|
||||||
|
|
@ -515,7 +920,7 @@ jack_engine_control_alloc(const char* name)
|
||||||
|
|
||||||
ctrl->buffer_size = 512;
|
ctrl->buffer_size = 512;
|
||||||
ctrl->sample_rate = 48000;
|
ctrl->sample_rate = 48000;
|
||||||
ctrl->sync_mode = false;
|
ctrl->sync_mode = true;
|
||||||
ctrl->temporary = false;
|
ctrl->temporary = false;
|
||||||
ctrl->period_usecs = 1000000.f / ctrl->sample_rate * ctrl->buffer_size;
|
ctrl->period_usecs = 1000000.f / ctrl->sample_rate * ctrl->buffer_size;
|
||||||
ctrl->timeout_usecs = 0;
|
ctrl->timeout_usecs = 0;
|
||||||
|
|
@ -545,57 +950,3 @@ jack_engine_control_alloc(const char* name)
|
||||||
|
|
||||||
return ctrl;
|
return ctrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRE_PACKED_STRUCTURE
|
|
||||||
struct jack_client_control {
|
|
||||||
jack_shm_info_t info;
|
|
||||||
char name[JACK_CLIENT_NAME_SIZE+1];
|
|
||||||
bool callback[jack_notify_max];
|
|
||||||
volatile jack_transport_state_t transport_state;
|
|
||||||
volatile bool transport_sync;
|
|
||||||
volatile bool transport_timebase;
|
|
||||||
int ref_num;
|
|
||||||
int PID;
|
|
||||||
bool active;
|
|
||||||
|
|
||||||
int session_ID;
|
|
||||||
char session_command[JACK_SESSION_COMMAND_SIZE];
|
|
||||||
jack_session_flags_t session_flags;
|
|
||||||
} POST_PACKED_STRUCTURE;
|
|
||||||
|
|
||||||
static inline struct jack_client_control *
|
|
||||||
jack_client_control_alloc(const char* name, int pid, int ref_num, int uuid)
|
|
||||||
{
|
|
||||||
struct jack_client_control *ctrl;
|
|
||||||
jack_shm_info_t info;
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
size = sizeof(struct jack_client_control);
|
|
||||||
if (jack_shm_alloc(size, &info, segment_num++) < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ctrl = (struct jack_client_control *)jack_shm_addr(&info);
|
|
||||||
ctrl->info = info;
|
|
||||||
|
|
||||||
strcpy(ctrl->name, name);
|
|
||||||
for (int i = 0; i < jack_notify_max; i++)
|
|
||||||
ctrl->callback[i] = false;
|
|
||||||
|
|
||||||
// Always activated
|
|
||||||
ctrl->callback[jack_notify_AddClient] = true;
|
|
||||||
ctrl->callback[jack_notify_RemoveClient] = true;
|
|
||||||
ctrl->callback[jack_notify_ActivateClient] = true;
|
|
||||||
ctrl->callback[jack_notify_LatencyCallback] = true;
|
|
||||||
// So that driver synchro are correctly setup in "flush" or "normal" mode
|
|
||||||
ctrl->callback[jack_notify_StartFreewheelCallback] = true;
|
|
||||||
ctrl->callback[jack_notify_StopFreewheelCallback] = true;
|
|
||||||
ctrl->ref_num = ref_num;
|
|
||||||
ctrl->PID = pid;
|
|
||||||
ctrl->transport_state = JackTransportStopped;
|
|
||||||
ctrl->transport_sync = false;
|
|
||||||
ctrl->transport_timebase = false;
|
|
||||||
ctrl->active = false;
|
|
||||||
ctrl->session_ID = uuid;
|
|
||||||
|
|
||||||
return ctrl;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
* Boston, MA 02110-1301, USA.
|
* Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <semaphore.h>
|
||||||
|
|
||||||
struct jack_synchro {
|
struct jack_synchro {
|
||||||
char name[SYNC_MAX_NAME_SIZE];
|
char name[SYNC_MAX_NAME_SIZE];
|
||||||
bool flush;
|
bool flush;
|
||||||
|
|
@ -46,3 +48,29 @@ jack_synchro_init(struct jack_synchro *synchro,
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
jack_synchro_signal(struct jack_synchro *synchro)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
if (synchro->flush)
|
||||||
|
return true;
|
||||||
|
if ((res = sem_post(synchro->semaphore)) < 0)
|
||||||
|
pw_log_error("semaphore %s post err = %s", synchro->name, strerror(errno));
|
||||||
|
|
||||||
|
return res == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
jack_synchro_wait(struct jack_synchro *synchro)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
while ((res = sem_wait(synchro->semaphore)) < 0) {
|
||||||
|
if (errno != EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pw_log_error("semaphore %s wait err = %s", synchro->name, strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return res == 0;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ static bool on_global(void *data, struct pw_global *global)
|
||||||
{
|
{
|
||||||
struct impl *impl = data;
|
struct impl *impl = data;
|
||||||
struct pw_node *n, *node;
|
struct pw_node *n, *node;
|
||||||
struct pw_properties *properties;
|
const struct pw_properties *properties;
|
||||||
const char *str;
|
const char *str;
|
||||||
char *error;
|
char *error;
|
||||||
struct pw_port *ip, *op;
|
struct pw_port *ip, *op;
|
||||||
|
|
@ -160,7 +160,7 @@ static bool on_global(void *data, struct pw_global *global)
|
||||||
if (op == NULL)
|
if (op == NULL)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
link = pw_link_new(impl->core, pw_module_get_global(impl->module), op, ip, NULL, NULL, &error);
|
link = pw_link_new(impl->core, pw_module_get_global(impl->module), op, ip, NULL, NULL, &error, 0);
|
||||||
pw_link_inc_idle(link);
|
pw_link_inc_idle(link);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -190,8 +190,7 @@ client_busy_changed(void *data, bool busy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
connection_data(struct spa_loop_utils *utils,
|
connection_data(void *data, int fd, enum spa_io mask)
|
||||||
struct spa_source *source, int fd, enum spa_io mask, void *data)
|
|
||||||
{
|
{
|
||||||
struct client_data *this = data;
|
struct client_data *this = data;
|
||||||
struct pw_client *client = this->client;
|
struct pw_client *client = this->client;
|
||||||
|
|
@ -343,8 +342,7 @@ static bool lock_socket(struct listener *l)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
socket_data(struct spa_loop_utils *utils,
|
socket_data(void *data, int fd, enum spa_io mask)
|
||||||
struct spa_source *source, int fd, enum spa_io mask, void *data)
|
|
||||||
{
|
{
|
||||||
struct listener *l = data;
|
struct listener *l = data;
|
||||||
struct pw_client *client;
|
struct pw_client *client;
|
||||||
|
|
@ -454,8 +452,7 @@ static int impl_connect(struct pw_protocol_connection *conn)
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_remote_data(struct spa_loop_utils *utils,
|
on_remote_data(void *data, int fd, enum spa_io mask)
|
||||||
struct spa_source *source, int fd, enum spa_io mask, void *data)
|
|
||||||
{
|
{
|
||||||
struct connection *impl = data;
|
struct connection *impl = data;
|
||||||
struct pw_remote *this = impl->this.remote;
|
struct pw_remote *this = impl->this.remote;
|
||||||
|
|
@ -523,8 +520,7 @@ on_remote_data(struct spa_loop_utils *utils,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void do_flush_event(struct spa_loop_utils *utils, struct spa_source *source,
|
static void do_flush_event(void *data, uint64_t count)
|
||||||
uint64_t count, void *data)
|
|
||||||
{
|
{
|
||||||
struct connection *impl = data;
|
struct connection *impl = data;
|
||||||
impl->flush_signaled = false;
|
impl->flush_signaled = false;
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ static void node_info_free(struct node_info *info)
|
||||||
free(info);
|
free(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void idle_timeout(struct spa_loop_utils *utils, struct spa_source *source, void *data)
|
static void idle_timeout(void *data, uint64_t expirations)
|
||||||
{
|
{
|
||||||
struct node_info *info = data;
|
struct node_info *info = data;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,7 @@ static void add_item(struct pw_spa_monitor *this, struct spa_monitor_item *item)
|
||||||
}
|
}
|
||||||
if ((res = spa_handle_get_interface(handle, t->spa_clock, &clock_iface)) < 0) {
|
if ((res = spa_handle_get_interface(handle, t->spa_clock, &clock_iface)) < 0) {
|
||||||
pw_log_info("no CLOCK interface: %d", res);
|
pw_log_info("no CLOCK interface: %d", res);
|
||||||
|
clock_iface = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ make_port(struct impl *impl, enum pw_direction direction, uint32_t port_id)
|
||||||
struct pw_port *port;
|
struct pw_port *port;
|
||||||
struct port *p;
|
struct port *p;
|
||||||
|
|
||||||
port = pw_port_new(direction, port_id, sizeof(struct port));
|
port = pw_port_new(direction, port_id, NULL, sizeof(struct port));
|
||||||
if (port == NULL)
|
if (port == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -320,6 +320,13 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *pro
|
||||||
if (this == NULL)
|
if (this == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (properties == NULL)
|
||||||
|
properties = pw_properties_new(NULL, NULL);
|
||||||
|
if (properties == NULL)
|
||||||
|
goto no_mem;
|
||||||
|
|
||||||
|
this->properties = properties;
|
||||||
|
|
||||||
this->data_loop_impl = pw_data_loop_new(properties);
|
this->data_loop_impl = pw_data_loop_new(properties);
|
||||||
if (this->data_loop_impl == NULL)
|
if (this->data_loop_impl == NULL)
|
||||||
goto no_data_loop;
|
goto no_data_loop;
|
||||||
|
|
@ -355,23 +362,21 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *pro
|
||||||
spa_list_init(&this->link_list);
|
spa_list_init(&this->link_list);
|
||||||
spa_hook_list_init(&this->listener_list);
|
spa_hook_list_init(&this->listener_list);
|
||||||
|
|
||||||
|
if ((name = pw_properties_get(properties, "pipewire.core.name")) == NULL) {
|
||||||
|
pw_properties_setf(properties,
|
||||||
|
"pipewire.core.name", "pipewire-%s-%d",
|
||||||
|
pw_get_user_name(), getpid());
|
||||||
|
name = pw_properties_get(properties, "pipewire.core.name");
|
||||||
|
}
|
||||||
|
|
||||||
this->info.change_mask = 0;
|
this->info.change_mask = 0;
|
||||||
this->info.user_name = pw_get_user_name();
|
this->info.user_name = pw_get_user_name();
|
||||||
this->info.host_name = pw_get_host_name();
|
this->info.host_name = pw_get_host_name();
|
||||||
this->info.version = SPA_STRINGIFY(PW_VERSION_CORE);
|
this->info.version = SPA_STRINGIFY(PW_VERSION_CORE);
|
||||||
srandom(time(NULL));
|
srandom(time(NULL));
|
||||||
this->info.cookie = random();
|
this->info.cookie = random();
|
||||||
this->info.props = this->properties ? &this->properties->dict : NULL;
|
this->info.props = &properties->dict;
|
||||||
|
this->info.name = name;
|
||||||
if (properties == NULL)
|
|
||||||
properties = pw_properties_new(NULL, NULL);
|
|
||||||
if ((name = pw_properties_get(properties, "pipewire.core.name")) == NULL) {
|
|
||||||
pw_properties_setf(properties,
|
|
||||||
"pipewire.core.name", "pipewire-%s-%d",
|
|
||||||
pw_get_user_name(), getpid());
|
|
||||||
}
|
|
||||||
this->info.name = pw_properties_get(properties, "pipewire.core.name");
|
|
||||||
this->properties = properties;
|
|
||||||
|
|
||||||
this->global = pw_core_add_global(this,
|
this->global = pw_core_add_global(this,
|
||||||
NULL,
|
NULL,
|
||||||
|
|
@ -382,6 +387,7 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *pro
|
||||||
this);
|
this);
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
|
no_mem:
|
||||||
no_data_loop:
|
no_data_loop:
|
||||||
free(this);
|
free(this);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -472,26 +478,19 @@ const struct pw_properties *pw_core_get_properties(struct pw_core *core)
|
||||||
void pw_core_update_properties(struct pw_core *core, const struct spa_dict *dict)
|
void pw_core_update_properties(struct pw_core *core, const struct spa_dict *dict)
|
||||||
{
|
{
|
||||||
struct pw_resource *resource;
|
struct pw_resource *resource;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
if (core->properties == NULL) {
|
for (i = 0; i < dict->n_items; i++)
|
||||||
if (dict)
|
pw_properties_set(core->properties, dict->items[i].key, dict->items[i].value);
|
||||||
core->properties = pw_properties_new_dict(dict);
|
|
||||||
} else if (dict != &core->properties->dict) {
|
|
||||||
uint32_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < dict->n_items; i++)
|
|
||||||
pw_properties_set(core->properties,
|
|
||||||
dict->items[i].key, dict->items[i].value);
|
|
||||||
}
|
|
||||||
|
|
||||||
core->info.change_mask = PW_CORE_CHANGE_MASK_PROPS;
|
core->info.change_mask = PW_CORE_CHANGE_MASK_PROPS;
|
||||||
core->info.props = core->properties ? &core->properties->dict : NULL;
|
core->info.props = &core->properties->dict;
|
||||||
|
|
||||||
spa_hook_list_call(&core->listener_list, struct pw_core_events, info_changed, &core->info);
|
spa_hook_list_call(&core->listener_list, struct pw_core_events, info_changed, &core->info);
|
||||||
|
|
||||||
spa_list_for_each(resource, &core->resource_list, link) {
|
spa_list_for_each(resource, &core->resource_list, link)
|
||||||
pw_core_resource_info(resource, &core->info);
|
pw_core_resource_info(resource, &core->info);
|
||||||
}
|
|
||||||
core->info.change_mask = 0;
|
core->info.change_mask = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -545,6 +544,9 @@ struct pw_port *pw_core_find_port(struct pw_core *core,
|
||||||
if (n->global == NULL)
|
if (n->global == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (other_port->node == n)
|
||||||
|
continue;
|
||||||
|
|
||||||
pw_log_debug("node id \"%d\"", n->global->id);
|
pw_log_debug("node id \"%d\"", n->global->id);
|
||||||
|
|
||||||
if (have_id) {
|
if (have_id) {
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ static void *do_loop(void *user_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void do_stop(struct spa_loop_utils *utils, struct spa_source *source, uint64_t count, void *data)
|
static void do_stop(void *data, uint64_t count)
|
||||||
{
|
{
|
||||||
struct pw_data_loop *this = data;
|
struct pw_data_loop *this = data;
|
||||||
this->running = false;
|
this->running = false;
|
||||||
|
|
|
||||||
|
|
@ -187,16 +187,16 @@ struct pw_node_info *pw_node_info_update(struct pw_node_info *info,
|
||||||
}
|
}
|
||||||
info->change_mask = update->change_mask;
|
info->change_mask = update->change_mask;
|
||||||
|
|
||||||
if (update->change_mask & (1 << 0)) {
|
if (update->change_mask & PW_NODE_CHANGE_MASK_NAME) {
|
||||||
if (info->name)
|
if (info->name)
|
||||||
free((void *) info->name);
|
free((void *) info->name);
|
||||||
info->name = update->name ? strdup(update->name) : NULL;
|
info->name = update->name ? strdup(update->name) : NULL;
|
||||||
}
|
}
|
||||||
if (update->change_mask & (1 << 1)) {
|
if (update->change_mask & PW_NODE_CHANGE_MASK_INPUT_PORTS) {
|
||||||
info->max_input_ports = update->max_input_ports;
|
info->max_input_ports = update->max_input_ports;
|
||||||
info->n_input_ports = update->n_input_ports;
|
info->n_input_ports = update->n_input_ports;
|
||||||
}
|
}
|
||||||
if (update->change_mask & (1 << 2)) {
|
if (update->change_mask & PW_NODE_CHANGE_MASK_INPUT_FORMATS) {
|
||||||
for (i = 0; i < info->n_input_formats; i++)
|
for (i = 0; i < info->n_input_formats; i++)
|
||||||
free(info->input_formats[i]);
|
free(info->input_formats[i]);
|
||||||
info->n_input_formats = update->n_input_formats;
|
info->n_input_formats = update->n_input_formats;
|
||||||
|
|
@ -212,11 +212,11 @@ struct pw_node_info *pw_node_info_update(struct pw_node_info *info,
|
||||||
info->input_formats[i] = spa_format_copy(update->input_formats[i]);
|
info->input_formats[i] = spa_format_copy(update->input_formats[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (update->change_mask & (1 << 3)) {
|
if (update->change_mask & PW_NODE_CHANGE_MASK_OUTPUT_PORTS) {
|
||||||
info->max_output_ports = update->max_output_ports;
|
info->max_output_ports = update->max_output_ports;
|
||||||
info->n_output_ports = update->n_output_ports;
|
info->n_output_ports = update->n_output_ports;
|
||||||
}
|
}
|
||||||
if (update->change_mask & (1 << 4)) {
|
if (update->change_mask & PW_NODE_CHANGE_MASK_OUTPUT_FORMATS) {
|
||||||
for (i = 0; i < info->n_output_formats; i++)
|
for (i = 0; i < info->n_output_formats; i++)
|
||||||
free(info->output_formats[i]);
|
free(info->output_formats[i]);
|
||||||
info->n_output_formats = update->n_output_formats;
|
info->n_output_formats = update->n_output_formats;
|
||||||
|
|
@ -233,13 +233,13 @@ struct pw_node_info *pw_node_info_update(struct pw_node_info *info,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update->change_mask & (1 << 5)) {
|
if (update->change_mask & PW_NODE_CHANGE_MASK_STATE) {
|
||||||
info->state = update->state;
|
info->state = update->state;
|
||||||
if (info->error)
|
if (info->error)
|
||||||
free((void *) info->error);
|
free((void *) info->error);
|
||||||
info->error = update->error ? strdup(update->error) : NULL;
|
info->error = update->error ? strdup(update->error) : NULL;
|
||||||
}
|
}
|
||||||
if (update->change_mask & (1 << 6)) {
|
if (update->change_mask & PW_NODE_CHANGE_MASK_PROPS) {
|
||||||
if (info->props)
|
if (info->props)
|
||||||
pw_spa_dict_destroy(info->props);
|
pw_spa_dict_destroy(info->props);
|
||||||
info->props = pw_spa_dict_copy(update->props);
|
info->props = pw_spa_dict_copy(update->props);
|
||||||
|
|
|
||||||
|
|
@ -132,8 +132,15 @@ void pw_client_info_free(struct pw_client_info *info);
|
||||||
|
|
||||||
/** The node information. Extra information can be added in later versions \memberof pw_introspect */
|
/** The node information. Extra information can be added in later versions \memberof pw_introspect */
|
||||||
struct pw_node_info {
|
struct pw_node_info {
|
||||||
|
#define PW_NODE_CHANGE_MASK_NAME (1 << 0)
|
||||||
|
#define PW_NODE_CHANGE_MASK_INPUT_PORTS (1 << 1)
|
||||||
|
#define PW_NODE_CHANGE_MASK_INPUT_FORMATS (1 << 2)
|
||||||
|
#define PW_NODE_CHANGE_MASK_OUTPUT_PORTS (1 << 3)
|
||||||
|
#define PW_NODE_CHANGE_MASK_OUTPUT_FORMATS (1 << 4)
|
||||||
|
#define PW_NODE_CHANGE_MASK_STATE (1 << 5)
|
||||||
|
#define PW_NODE_CHANGE_MASK_PROPS (1 << 6)
|
||||||
uint64_t change_mask; /**< bitfield of changed fields since last call */
|
uint64_t change_mask; /**< bitfield of changed fields since last call */
|
||||||
const char *name; /**< name the node, suitable for display */
|
const char *name; /**< name the node, suitable for display */
|
||||||
uint32_t max_input_ports; /**< maximum number of inputs */
|
uint32_t max_input_ports; /**< maximum number of inputs */
|
||||||
uint32_t n_input_ports; /**< number of inputs */
|
uint32_t n_input_ports; /**< number of inputs */
|
||||||
uint32_t n_input_formats; /**< number of input formats */
|
uint32_t n_input_formats; /**< number of input formats */
|
||||||
|
|
|
||||||
|
|
@ -1021,7 +1021,8 @@ struct pw_link *pw_link_new(struct pw_core *core,
|
||||||
struct pw_port *input,
|
struct pw_port *input,
|
||||||
struct spa_format *format_filter,
|
struct spa_format *format_filter,
|
||||||
struct pw_properties *properties,
|
struct pw_properties *properties,
|
||||||
char **error)
|
char **error,
|
||||||
|
size_t user_data_size)
|
||||||
{
|
{
|
||||||
struct impl *impl;
|
struct impl *impl;
|
||||||
struct pw_link *this;
|
struct pw_link *this;
|
||||||
|
|
@ -1033,13 +1034,16 @@ struct pw_link *pw_link_new(struct pw_core *core,
|
||||||
if (pw_link_find(output, input))
|
if (pw_link_find(output, input))
|
||||||
goto link_exists;
|
goto link_exists;
|
||||||
|
|
||||||
impl = calloc(1, sizeof(struct impl));
|
impl = calloc(1, sizeof(struct impl) + user_data_size);
|
||||||
if (impl == NULL)
|
if (impl == NULL)
|
||||||
goto no_mem;
|
goto no_mem;
|
||||||
|
|
||||||
this = &impl->this;
|
this = &impl->this;
|
||||||
pw_log_debug("link %p: new", this);
|
pw_log_debug("link %p: new", this);
|
||||||
|
|
||||||
|
if (user_data_size > 0)
|
||||||
|
this->user_data = SPA_MEMBER(impl, sizeof(struct impl), void);
|
||||||
|
|
||||||
impl->work = pw_work_queue_new(core->main_loop);
|
impl->work = pw_work_queue_new(core->main_loop);
|
||||||
|
|
||||||
this->core = core;
|
this->core = core;
|
||||||
|
|
@ -1157,6 +1161,7 @@ void pw_link_add_listener(struct pw_link *link,
|
||||||
const struct pw_link_events *events,
|
const struct pw_link_events *events,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
|
pw_log_debug("link %p: add listener %p", link, listener);
|
||||||
spa_hook_list_append(&link->listener_list, listener, events, data);
|
spa_hook_list_append(&link->listener_list, listener, events, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1176,6 +1181,11 @@ struct pw_core *pw_link_get_core(struct pw_link *link)
|
||||||
return link->core;
|
return link->core;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *pw_link_get_user_data(struct pw_link *link)
|
||||||
|
{
|
||||||
|
return link->user_data;
|
||||||
|
}
|
||||||
|
|
||||||
const struct pw_link_info *pw_link_get_info(struct pw_link *link)
|
const struct pw_link_info *pw_link_get_info(struct pw_link *link)
|
||||||
{
|
{
|
||||||
return &link->info;
|
return &link->info;
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,8 @@ pw_link_new(struct pw_core *core, /**< the core object */
|
||||||
struct pw_port *input, /**< an input port */
|
struct pw_port *input, /**< an input port */
|
||||||
struct spa_format *format_filter, /**< an optional format filter */
|
struct spa_format *format_filter, /**< an optional format filter */
|
||||||
struct pw_properties *properties /**< extra properties */,
|
struct pw_properties *properties /**< extra properties */,
|
||||||
char **error /**< error string when result is NULL */);
|
char **error, /**< error string when result is NULL */
|
||||||
|
size_t user_data_size /**< extra user data size */);
|
||||||
|
|
||||||
/** Destroy a link \memberof pw_link */
|
/** Destroy a link \memberof pw_link */
|
||||||
void pw_link_destroy(struct pw_link *link);
|
void pw_link_destroy(struct pw_link *link);
|
||||||
|
|
@ -84,6 +85,8 @@ void pw_link_add_listener(struct pw_link *link,
|
||||||
|
|
||||||
struct pw_core *pw_link_get_core(struct pw_link *link);
|
struct pw_core *pw_link_get_core(struct pw_link *link);
|
||||||
|
|
||||||
|
void *pw_link_get_user_data(struct pw_link *link);
|
||||||
|
|
||||||
const struct pw_link_info *pw_link_get_info(struct pw_link *link);
|
const struct pw_link_info *pw_link_get_info(struct pw_link *link);
|
||||||
|
|
||||||
/** Get the global of the link */
|
/** Get the global of the link */
|
||||||
|
|
|
||||||
|
|
@ -447,11 +447,30 @@ struct pw_global *pw_node_get_global(struct pw_node *node)
|
||||||
return node->global;
|
return node->global;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct pw_properties *pw_node_get_properties(struct pw_node *node)
|
const struct pw_properties *pw_node_get_properties(struct pw_node *node)
|
||||||
{
|
{
|
||||||
return node->properties;
|
return node->properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pw_node_update_properties(struct pw_node *node, const struct spa_dict *dict)
|
||||||
|
{
|
||||||
|
struct pw_resource *resource;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < dict->n_items; i++)
|
||||||
|
pw_properties_set(node->properties, dict->items[i].key, dict->items[i].value);
|
||||||
|
|
||||||
|
node->info.props = &node->properties->dict;
|
||||||
|
|
||||||
|
node->info.change_mask = PW_NODE_CHANGE_MASK_PROPS;
|
||||||
|
spa_hook_list_call(&node->listener_list, struct pw_node_events, info_changed, &node->info);
|
||||||
|
|
||||||
|
spa_list_for_each(resource, &node->resource_list, link)
|
||||||
|
pw_node_resource_info(resource, &node->info);
|
||||||
|
|
||||||
|
node->info.change_mask = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void pw_node_set_implementation(struct pw_node *node,
|
void pw_node_set_implementation(struct pw_node *node,
|
||||||
const struct pw_node_implementation *implementation,
|
const struct pw_node_implementation *implementation,
|
||||||
void *data)
|
void *data)
|
||||||
|
|
@ -759,7 +778,7 @@ void pw_node_update_state(struct pw_node *node, enum pw_node_state state, char *
|
||||||
spa_hook_list_call(&node->listener_list, struct pw_node_events, state_changed,
|
spa_hook_list_call(&node->listener_list, struct pw_node_events, state_changed,
|
||||||
old, state, error);
|
old, state, error);
|
||||||
|
|
||||||
node->info.change_mask |= 1 << 5;
|
node->info.change_mask |= PW_NODE_CHANGE_MASK_STATE;
|
||||||
spa_hook_list_call(&node->listener_list, struct pw_node_events, info_changed, &node->info);
|
spa_hook_list_call(&node->listener_list, struct pw_node_events, info_changed, &node->info);
|
||||||
|
|
||||||
spa_list_for_each(resource, &node->resource_list, link)
|
spa_list_for_each(resource, &node->resource_list, link)
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,9 @@ struct pw_resource *pw_node_get_owner(struct pw_node *node);
|
||||||
|
|
||||||
struct pw_global *pw_node_get_global(struct pw_node *node);
|
struct pw_global *pw_node_get_global(struct pw_node *node);
|
||||||
|
|
||||||
struct pw_properties *pw_node_get_properties(struct pw_node *node);
|
const struct pw_properties *pw_node_get_properties(struct pw_node *node);
|
||||||
|
|
||||||
|
void pw_node_update_properties(struct pw_node *node, const struct spa_dict *dict);
|
||||||
|
|
||||||
void pw_node_set_implementation(struct pw_node *node,
|
void pw_node_set_implementation(struct pw_node *node,
|
||||||
const struct pw_node_implementation *implementation,
|
const struct pw_node_implementation *implementation,
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,7 @@ static const struct spa_graph_port_callbacks schedule_mix_port = {
|
||||||
|
|
||||||
struct pw_port *pw_port_new(enum pw_direction direction,
|
struct pw_port *pw_port_new(enum pw_direction direction,
|
||||||
uint32_t port_id,
|
uint32_t port_id,
|
||||||
|
struct pw_properties *properties,
|
||||||
size_t user_data_size)
|
size_t user_data_size)
|
||||||
{
|
{
|
||||||
struct impl *impl;
|
struct impl *impl;
|
||||||
|
|
@ -153,8 +154,14 @@ struct pw_port *pw_port_new(enum pw_direction direction,
|
||||||
this = &impl->this;
|
this = &impl->this;
|
||||||
pw_log_debug("port %p: new", this);
|
pw_log_debug("port %p: new", this);
|
||||||
|
|
||||||
|
if (properties == NULL)
|
||||||
|
properties = pw_properties_new(NULL, NULL);
|
||||||
|
if (properties == NULL)
|
||||||
|
goto no_mem;
|
||||||
|
|
||||||
this->direction = direction;
|
this->direction = direction;
|
||||||
this->port_id = port_id;
|
this->port_id = port_id;
|
||||||
|
this->properties = properties;
|
||||||
this->state = PW_PORT_STATE_INIT;
|
this->state = PW_PORT_STATE_INIT;
|
||||||
this->io.status = SPA_RESULT_OK;
|
this->io.status = SPA_RESULT_OK;
|
||||||
this->io.buffer_id = SPA_ID_INVALID;
|
this->io.buffer_id = SPA_ID_INVALID;
|
||||||
|
|
@ -166,6 +173,8 @@ struct pw_port *pw_port_new(enum pw_direction direction,
|
||||||
|
|
||||||
spa_hook_list_init(&this->listener_list);
|
spa_hook_list_init(&this->listener_list);
|
||||||
|
|
||||||
|
spa_graph_port_set_callbacks(&this->rt.port, NULL, this);
|
||||||
|
|
||||||
spa_graph_port_init(&this->rt.port,
|
spa_graph_port_init(&this->rt.port,
|
||||||
this->direction,
|
this->direction,
|
||||||
this->port_id,
|
this->port_id,
|
||||||
|
|
@ -188,6 +197,10 @@ struct pw_port *pw_port_new(enum pw_direction direction,
|
||||||
&schedule_tee_port,
|
&schedule_tee_port,
|
||||||
this);
|
this);
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
|
no_mem:
|
||||||
|
free(impl);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum pw_direction pw_port_get_direction(struct pw_port *port)
|
enum pw_direction pw_port_get_direction(struct pw_port *port)
|
||||||
|
|
@ -200,6 +213,21 @@ uint32_t pw_port_get_id(struct pw_port *port)
|
||||||
return port->port_id;
|
return port->port_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const struct pw_properties *pw_port_get_properties(struct pw_port *port)
|
||||||
|
{
|
||||||
|
return port->properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pw_port_update_properties(struct pw_port *port, const struct spa_dict *dict)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < dict->n_items; i++)
|
||||||
|
pw_properties_set(port->properties, dict->items[i].key, dict->items[i].value);
|
||||||
|
|
||||||
|
spa_hook_list_call(&port->listener_list, struct pw_port_events,
|
||||||
|
properties_changed, port->properties);
|
||||||
|
}
|
||||||
|
|
||||||
struct pw_node *pw_port_get_node(struct pw_port *port)
|
struct pw_node *pw_port_get_node(struct pw_port *port)
|
||||||
{
|
{
|
||||||
return port->node;
|
return port->node;
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,8 @@ struct pw_port_events {
|
||||||
void (*destroy) (void *data);
|
void (*destroy) (void *data);
|
||||||
|
|
||||||
void (*state_changed) (void *data, enum pw_port_state state);
|
void (*state_changed) (void *data, enum pw_port_state state);
|
||||||
|
|
||||||
|
void (*properties_changed) (void *data, const struct pw_properties *properties);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Create a new port \memberof pw_port
|
/** Create a new port \memberof pw_port
|
||||||
|
|
@ -101,11 +103,16 @@ struct pw_port_events {
|
||||||
struct pw_port *
|
struct pw_port *
|
||||||
pw_port_new(enum pw_direction direction,
|
pw_port_new(enum pw_direction direction,
|
||||||
uint32_t port_id,
|
uint32_t port_id,
|
||||||
|
struct pw_properties *properties,
|
||||||
size_t user_data_size);
|
size_t user_data_size);
|
||||||
|
|
||||||
/** Get the port direction */
|
/** Get the port direction */
|
||||||
enum pw_direction pw_port_get_direction(struct pw_port *port);
|
enum pw_direction pw_port_get_direction(struct pw_port *port);
|
||||||
|
|
||||||
|
const struct pw_properties *pw_port_get_properties(struct pw_port *port);
|
||||||
|
|
||||||
|
void pw_port_update_properties(struct pw_port *port, const struct spa_dict *dict);
|
||||||
|
|
||||||
/** Get the port id */
|
/** Get the port id */
|
||||||
uint32_t pw_port_get_id(struct pw_port *port);
|
uint32_t pw_port_get_id(struct pw_port *port);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,8 @@ struct pw_link {
|
||||||
struct spa_graph_port out_port;
|
struct spa_graph_port out_port;
|
||||||
struct spa_graph_port in_port;
|
struct spa_graph_port in_port;
|
||||||
} rt;
|
} rt;
|
||||||
|
|
||||||
|
void *user_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pw_module {
|
struct pw_module {
|
||||||
|
|
@ -230,6 +232,7 @@ struct pw_port {
|
||||||
|
|
||||||
enum pw_direction direction; /**< port direction */
|
enum pw_direction direction; /**< port direction */
|
||||||
uint32_t port_id; /**< port id */
|
uint32_t port_id; /**< port id */
|
||||||
|
struct pw_properties *properties;
|
||||||
|
|
||||||
enum pw_port_state state; /**< state of the port */
|
enum pw_port_state state; /**< state of the port */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -445,8 +445,7 @@ static void handle_rtnode_message(struct pw_proxy *proxy, struct pw_client_node_
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_rtsocket_condition(struct spa_loop_utils *utils,
|
on_rtsocket_condition(void *user_data, int fd, enum spa_io mask)
|
||||||
struct spa_source *source, int fd, enum spa_io mask, void *user_data)
|
|
||||||
{
|
{
|
||||||
struct pw_proxy *proxy = user_data;
|
struct pw_proxy *proxy = user_data;
|
||||||
struct node_data *data = proxy->user_data;
|
struct node_data *data = proxy->user_data;
|
||||||
|
|
|
||||||
|
|
@ -444,7 +444,7 @@ static void do_node_init(struct pw_stream *stream)
|
||||||
add_async_complete(stream, 0, SPA_RESULT_OK);
|
add_async_complete(stream, 0, SPA_RESULT_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_timeout(struct spa_loop_utils *utils, struct spa_source *source, void *data)
|
static void on_timeout(void *data, uint64_t expirations)
|
||||||
{
|
{
|
||||||
struct pw_stream *stream = data;
|
struct pw_stream *stream = data;
|
||||||
add_request_clock_update(stream);
|
add_request_clock_update(stream);
|
||||||
|
|
@ -544,8 +544,7 @@ static void handle_rtnode_message(struct pw_stream *stream, struct pw_client_nod
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_rtsocket_condition(struct spa_loop_utils *utils,
|
on_rtsocket_condition(void *data, int fd, enum spa_io mask)
|
||||||
struct spa_source *source, int fd, enum spa_io mask, void *data)
|
|
||||||
{
|
{
|
||||||
struct pw_stream *stream = data;
|
struct pw_stream *stream = data;
|
||||||
struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
|
struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ static const struct spa_loop_control_hooks impl_hooks = {
|
||||||
after,
|
after,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void do_stop(struct spa_loop_utils *utils, struct spa_source *source, uint64_t count, void *data)
|
static void do_stop(void *data, uint64_t count)
|
||||||
{
|
{
|
||||||
struct pw_thread_loop *this = data;
|
struct pw_thread_loop *this = data;
|
||||||
this->running = false;
|
this->running = false;
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,7 @@ struct pw_work_queue {
|
||||||
};
|
};
|
||||||
/** \endcond */
|
/** \endcond */
|
||||||
|
|
||||||
static void process_work_queue(struct spa_loop_utils *utils, struct spa_source *source,
|
static void process_work_queue(void *data, uint64_t count)
|
||||||
uint64_t count, void *data)
|
|
||||||
{
|
{
|
||||||
struct pw_work_queue *this = data;
|
struct pw_work_queue *this = data;
|
||||||
struct work_item *item, *tmp;
|
struct work_item *item, *tmp;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue