mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-04 13:30:12 -05:00
impl-node: run the remote driver node logic remotely
Don't signal the pipewire daemon to run the driver. We can transfer the complete driver state to the client and run everything there.
This commit is contained in:
parent
a46076b207
commit
b8fe832188
4 changed files with 39 additions and 85 deletions
|
|
@ -1080,8 +1080,6 @@ static void node_on_data_fd_events(struct spa_source *source)
|
||||||
if (SPA_LIKELY(source->rmask & SPA_IO_IN)) {
|
if (SPA_LIKELY(source->rmask & SPA_IO_IN)) {
|
||||||
uint64_t cmd;
|
uint64_t cmd;
|
||||||
struct pw_impl_node *node = impl->this.node;
|
struct pw_impl_node *node = impl->this.node;
|
||||||
struct pw_node_activation *a = node->rt.activation;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
if (SPA_UNLIKELY(spa_system_eventfd_read(impl->data_system,
|
if (SPA_UNLIKELY(spa_system_eventfd_read(impl->data_system,
|
||||||
impl->data_source.fd, &cmd) < 0))
|
impl->data_source.fd, &cmd) < 0))
|
||||||
|
|
@ -1090,9 +1088,15 @@ static void node_on_data_fd_events(struct spa_source *source)
|
||||||
pw_log_info("(%s-%u) client missed %"PRIu64" wakeups",
|
pw_log_info("(%s-%u) client missed %"PRIu64" wakeups",
|
||||||
node->name, node->info.id, cmd - 1);
|
node->name, node->info.id, cmd - 1);
|
||||||
|
|
||||||
status = a->state[0].status;
|
if (impl->resource && impl->resource->version < 5) {
|
||||||
spa_log_trace_fp(impl->log, "%p: got ready %d", impl, status);
|
struct pw_node_activation *a = node->rt.activation;
|
||||||
spa_node_call_ready(&impl->callbacks, status);
|
int status = a->state[0].status;
|
||||||
|
spa_log_trace_fp(impl->log, "%p: got ready %d", impl, status);
|
||||||
|
spa_node_call_ready(&impl->callbacks, status);
|
||||||
|
} else {
|
||||||
|
spa_log_trace_fp(impl->log, "%p: got complete", impl);
|
||||||
|
pw_context_driver_emit_complete(node->context, node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1202,16 +1206,14 @@ static void node_peer_added(void *data, struct pw_impl_node *peer)
|
||||||
struct impl *impl = data;
|
struct impl *impl = data;
|
||||||
struct pw_memblock *m;
|
struct pw_memblock *m;
|
||||||
|
|
||||||
if (peer == impl->this.node)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m = pw_mempool_import_block(impl->client->pool, peer->activation);
|
m = pw_mempool_import_block(impl->client->pool, peer->activation);
|
||||||
if (m == NULL) {
|
if (m == NULL) {
|
||||||
pw_log_debug("%p: can't ensure mem: %m", impl);
|
pw_log_warn("%p: can't ensure mem: %m", impl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pw_log_debug("%p: peer %p id:%u added mem_id:%u", &impl->this, peer,
|
|
||||||
peer->info.id, m->id);
|
pw_log_debug("%p: peer %p/%p id:%u added mem_id:%u", impl, peer,
|
||||||
|
impl->this.node, peer->info.id, m->id);
|
||||||
|
|
||||||
if (impl->resource == NULL)
|
if (impl->resource == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
@ -1229,17 +1231,15 @@ static void node_peer_removed(void *data, struct pw_impl_node *peer)
|
||||||
struct impl *impl = data;
|
struct impl *impl = data;
|
||||||
struct pw_memblock *m;
|
struct pw_memblock *m;
|
||||||
|
|
||||||
if (peer == impl->this.node)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m = pw_mempool_find_fd(impl->client->pool, peer->activation->fd);
|
m = pw_mempool_find_fd(impl->client->pool, peer->activation->fd);
|
||||||
if (m == NULL) {
|
if (m == NULL) {
|
||||||
pw_log_warn("%p: unknown peer %p fd:%d", impl, peer,
|
pw_log_warn("%p: unknown peer %p fd:%d", impl, peer,
|
||||||
peer->source.fd);
|
peer->source.fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pw_log_debug("%p: peer %p %u removed", impl, peer,
|
|
||||||
peer->info.id);
|
pw_log_debug("%p: peer %p/%p id:%u removed mem_id:%u", impl, peer,
|
||||||
|
impl->this.node, peer->info.id, m->id);
|
||||||
|
|
||||||
if (impl->resource != NULL) {
|
if (impl->resource != NULL) {
|
||||||
pw_client_node_resource_set_activation(impl->resource,
|
pw_client_node_resource_set_activation(impl->resource,
|
||||||
|
|
@ -1249,7 +1249,6 @@ static void node_peer_removed(void *data, struct pw_impl_node *peer)
|
||||||
0,
|
0,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pw_memblock_unref(m);
|
pw_memblock_unref(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1356,7 +1355,7 @@ static void node_free(void *data)
|
||||||
pw_resource_destroy(impl->resource);
|
pw_resource_destroy(impl->resource);
|
||||||
|
|
||||||
if (impl->activation)
|
if (impl->activation)
|
||||||
pw_memblock_unref(impl->activation);
|
pw_memblock_free(impl->activation);
|
||||||
|
|
||||||
pw_array_for_each(area, &impl->io_areas) {
|
pw_array_for_each(area, &impl->io_areas) {
|
||||||
if (*area)
|
if (*area)
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ struct mix {
|
||||||
|
|
||||||
struct node_data {
|
struct node_data {
|
||||||
struct pw_context *context;
|
struct pw_context *context;
|
||||||
|
struct spa_hook context_listener;
|
||||||
|
|
||||||
struct pw_loop *data_loop;
|
struct pw_loop *data_loop;
|
||||||
struct spa_system *data_system;
|
struct spa_system *data_system;
|
||||||
|
|
||||||
|
|
@ -1128,6 +1130,9 @@ static void client_node_removed(void *_data)
|
||||||
spa_hook_remove(&data->proxy_client_node_listener);
|
spa_hook_remove(&data->proxy_client_node_listener);
|
||||||
spa_hook_remove(&data->client_node_listener);
|
spa_hook_remove(&data->client_node_listener);
|
||||||
|
|
||||||
|
pw_context_driver_remove_listener(data->context,
|
||||||
|
&data->context_listener);
|
||||||
|
|
||||||
if (data->node) {
|
if (data->node) {
|
||||||
spa_hook_remove(&data->node_listener);
|
spa_hook_remove(&data->node_listener);
|
||||||
pw_impl_node_set_state(data->node, PW_NODE_STATE_SUSPENDED);
|
pw_impl_node_set_state(data->node, PW_NODE_STATE_SUSPENDED);
|
||||||
|
|
@ -1170,60 +1175,22 @@ static inline uint64_t get_time_ns(struct spa_system *system)
|
||||||
spa_system_clock_gettime(system, CLOCK_MONOTONIC, &ts);
|
spa_system_clock_gettime(system, CLOCK_MONOTONIC, &ts);
|
||||||
return SPA_TIMESPEC_TO_NSEC(&ts);
|
return SPA_TIMESPEC_TO_NSEC(&ts);
|
||||||
}
|
}
|
||||||
static int node_ready(void *d, int status)
|
|
||||||
|
static void context_complete(void *data, struct pw_impl_node *node)
|
||||||
{
|
{
|
||||||
struct node_data *data = d;
|
struct node_data *d = data;
|
||||||
struct pw_impl_node *node = data->node;
|
struct spa_system *data_system = d->data_system;
|
||||||
struct pw_node_activation *a = node->rt.activation;
|
|
||||||
struct spa_system *data_system = data->data_system;
|
|
||||||
struct pw_impl_port *p;
|
|
||||||
|
|
||||||
pw_log_trace_fp("node %p: ready driver:%d exported:%d status:%d", node,
|
if (node != d->node || !node->driving)
|
||||||
node->driver, node->exported, status);
|
return;
|
||||||
|
|
||||||
if (status & SPA_STATUS_HAVE_DATA) {
|
if (SPA_UNLIKELY(spa_system_eventfd_write(data_system, d->rtwritefd, 1) < 0))
|
||||||
spa_list_for_each(p, &node->rt.output_mix, rt.node_link)
|
|
||||||
spa_node_process_fast(p->mix);
|
|
||||||
}
|
|
||||||
|
|
||||||
a->state[0].status = status;
|
|
||||||
a->signal_time = get_time_ns(data_system);
|
|
||||||
|
|
||||||
if (SPA_UNLIKELY(spa_system_eventfd_write(data_system, data->rtwritefd, 1) < 0))
|
|
||||||
pw_log_warn("node %p: write failed %m", node);
|
pw_log_warn("node %p: write failed %m", node);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int node_reuse_buffer(void *data, uint32_t port_id, uint32_t buffer_id)
|
static const struct pw_context_driver_events context_events = {
|
||||||
{
|
PW_VERSION_CONTEXT_DRIVER_EVENTS,
|
||||||
return 0;
|
.complete = context_complete,
|
||||||
}
|
|
||||||
|
|
||||||
static int node_xrun(void *d, uint64_t trigger, uint64_t delay, struct spa_pod *info)
|
|
||||||
{
|
|
||||||
struct node_data *data = d;
|
|
||||||
struct pw_impl_node *node = data->node;
|
|
||||||
struct pw_node_activation *a = node->rt.activation;
|
|
||||||
|
|
||||||
a->xrun_count++;
|
|
||||||
a->xrun_time = trigger;
|
|
||||||
a->xrun_delay = delay;
|
|
||||||
a->max_delay = SPA_MAX(a->max_delay, delay);
|
|
||||||
|
|
||||||
pw_log_debug("node %p: XRun! count:%u time:%"PRIu64" delay:%"PRIu64" max:%"PRIu64,
|
|
||||||
node, a->xrun_count, trigger, delay, a->max_delay);
|
|
||||||
|
|
||||||
pw_context_driver_emit_xrun(data->context, node);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct spa_node_callbacks node_callbacks = {
|
|
||||||
SPA_VERSION_NODE_CALLBACKS,
|
|
||||||
.ready = node_ready,
|
|
||||||
.reuse_buffer = node_reuse_buffer,
|
|
||||||
.xrun = node_xrun
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct pw_proxy *node_export(struct pw_core *core, void *object, bool do_free,
|
static struct pw_proxy *node_export(struct pw_core *core, void *object, bool do_free,
|
||||||
|
|
@ -1274,13 +1241,16 @@ static struct pw_proxy *node_export(struct pw_core *core, void *object, bool do_
|
||||||
&data->proxy_client_node_listener,
|
&data->proxy_client_node_listener,
|
||||||
&proxy_client_node_events, data);
|
&proxy_client_node_events, data);
|
||||||
|
|
||||||
spa_node_set_callbacks(node->node, &node_callbacks, data);
|
|
||||||
pw_impl_node_add_listener(node, &data->node_listener, &node_events, data);
|
pw_impl_node_add_listener(node, &data->node_listener, &node_events, data);
|
||||||
|
|
||||||
pw_client_node_add_listener(data->client_node,
|
pw_client_node_add_listener(data->client_node,
|
||||||
&data->client_node_listener,
|
&data->client_node_listener,
|
||||||
&client_node_events,
|
&client_node_events,
|
||||||
data);
|
data);
|
||||||
|
pw_context_driver_add_listener(data->context,
|
||||||
|
&data->context_listener,
|
||||||
|
&context_events, data);
|
||||||
|
|
||||||
do_node_init(data);
|
do_node_init(data);
|
||||||
|
|
||||||
return client_node;
|
return client_node;
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
#define PW_TYPE_INTERFACE_ClientNode PW_TYPE_INFO_INTERFACE_BASE "ClientNode"
|
#define PW_TYPE_INTERFACE_ClientNode PW_TYPE_INFO_INTERFACE_BASE "ClientNode"
|
||||||
|
|
||||||
#define PW_VERSION_CLIENT_NODE 4
|
#define PW_VERSION_CLIENT_NODE 5
|
||||||
struct pw_client_node;
|
struct pw_client_node;
|
||||||
|
|
||||||
#define PW_EXTENSION_MODULE_CLIENT_NODE PIPEWIRE_MODULE_PREFIX "module-client-node"
|
#define PW_EXTENSION_MODULE_CLIENT_NODE PIPEWIRE_MODULE_PREFIX "module-client-node"
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,6 @@ struct impl {
|
||||||
|
|
||||||
unsigned int cache_params:1;
|
unsigned int cache_params:1;
|
||||||
unsigned int pending_play:1;
|
unsigned int pending_play:1;
|
||||||
|
|
||||||
uint64_t prev_signal_time;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define pw_node_resource(r,m,v,...) pw_resource_call(r,struct pw_node_events,m,v,__VA_ARGS__)
|
#define pw_node_resource(r,m,v,...) pw_resource_call(r,struct pw_node_events,m,v,__VA_ARGS__)
|
||||||
|
|
@ -903,8 +901,8 @@ int pw_impl_node_set_driver(struct pw_impl_node *node, struct pw_impl_node *driv
|
||||||
|
|
||||||
pw_impl_node_emit_driver_changed(node, old, driver);
|
pw_impl_node_emit_driver_changed(node, old, driver);
|
||||||
|
|
||||||
pw_impl_node_emit_peer_removed(old, node);
|
|
||||||
pw_impl_node_emit_peer_added(driver, node);
|
pw_impl_node_emit_peer_added(driver, node);
|
||||||
|
pw_impl_node_emit_peer_removed(old, node);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1245,6 +1243,7 @@ static inline int process_node(void *data)
|
||||||
} else {
|
} else {
|
||||||
/* calculate CPU time when finished */
|
/* calculate CPU time when finished */
|
||||||
calculate_stats(this, a);
|
calculate_stats(this, a);
|
||||||
|
pw_context_driver_emit_complete(this->context, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SPA_UNLIKELY(status & SPA_STATUS_DRAINED))
|
if (SPA_UNLIKELY(status & SPA_STATUS_DRAINED))
|
||||||
|
|
@ -1738,7 +1737,6 @@ static inline void update_position(struct pw_impl_node *node, int all_ready, uin
|
||||||
static int node_ready(void *data, int status)
|
static int node_ready(void *data, int status)
|
||||||
{
|
{
|
||||||
struct pw_impl_node *node = data, *reposition_node = NULL;
|
struct pw_impl_node *node = data, *reposition_node = NULL;
|
||||||
struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this);
|
|
||||||
struct pw_impl_node *driver = node->driver_node;
|
struct pw_impl_node *driver = node->driver_node;
|
||||||
struct pw_node_activation *a = node->rt.activation;
|
struct pw_node_activation *a = node->rt.activation;
|
||||||
struct spa_system *data_system = node->data_system;
|
struct spa_system *data_system = node->data_system;
|
||||||
|
|
@ -1773,18 +1771,6 @@ static int node_ready(void *data, int status)
|
||||||
state->pending, state->required);
|
state->pending, state->required);
|
||||||
check_states(node, nsec);
|
check_states(node, nsec);
|
||||||
pw_context_driver_emit_incomplete(node->context, node);
|
pw_context_driver_emit_incomplete(node->context, node);
|
||||||
} else {
|
|
||||||
uint64_t signal_time = a->signal_time;
|
|
||||||
/* old nodes set the TRIGGERED status on node_ready, patch this
|
|
||||||
* up here to avoid errors in pw-top */
|
|
||||||
a->status = PW_NODE_ACTIVATION_FINISHED;
|
|
||||||
a->signal_time = a->prev_signal_time;
|
|
||||||
a->prev_signal_time = impl->prev_signal_time;
|
|
||||||
|
|
||||||
pw_context_driver_emit_complete(node->context, node);
|
|
||||||
|
|
||||||
a->prev_signal_time = a->signal_time;
|
|
||||||
a->signal_time = signal_time;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This update is done too late, the driver should do this
|
/* This update is done too late, the driver should do this
|
||||||
|
|
@ -1841,7 +1827,6 @@ again:
|
||||||
* eventfd */
|
* eventfd */
|
||||||
if (!node->remote)
|
if (!node->remote)
|
||||||
a->signal_time = nsec;
|
a->signal_time = nsec;
|
||||||
impl->prev_signal_time = a->prev_signal_time;
|
|
||||||
a->prev_signal_time = a->signal_time;
|
a->prev_signal_time = a->signal_time;
|
||||||
|
|
||||||
a->sync_timeout = SPA_MIN(min_timeout, DEFAULT_SYNC_TIMEOUT);
|
a->sync_timeout = SPA_MIN(min_timeout, DEFAULT_SYNC_TIMEOUT);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue