diff --git a/src/examples/export-sink.c b/src/examples/export-sink.c index a09fed5f9..7842be06d 100644 --- a/src/examples/export-sink.c +++ b/src/examples/export-sink.c @@ -458,8 +458,8 @@ static void make_node(struct data *data) data->node = pw_node_new(data->core, "SDL-sink", props, 0); data->impl_node = impl_node; pw_node_set_implementation(data->node, &data->impl_node); - pw_node_register(data->node, NULL, NULL); + pw_node_set_active(data->node, true); pw_remote_export(data->remote, data->node); } diff --git a/src/examples/export-source.c b/src/examples/export-source.c index 3840c55e9..5eada5ae9 100644 --- a/src/examples/export-source.c +++ b/src/examples/export-source.c @@ -355,6 +355,7 @@ static void make_node(struct data *data) pw_node_set_implementation(data->node, &data->impl_node); pw_node_register(data->node, NULL, NULL); + pw_node_set_active(data->node, true); pw_remote_export(data->remote, data->node); } diff --git a/src/examples/export-spa.c b/src/examples/export-spa.c index ed2e31365..4a0d99630 100644 --- a/src/examples/export-spa.c +++ b/src/examples/export-spa.c @@ -70,6 +70,8 @@ static int make_node(struct data *data) PW_VERSION_NODE, props, SPA_ID_INVALID); + pw_node_set_active(data->node, true); + pw_remote_export(data->remote, data->node); return 0; diff --git a/src/examples/video-play.c b/src/examples/video-play.c index bc520b672..8294db13f 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -149,10 +149,18 @@ on_stream_new_buffer(void *_data, uint32_t id) handle_events(data); } -static void on_stream_state_changed(void *data, enum pw_stream_state old, +static void on_stream_state_changed(void *_data, enum pw_stream_state old, enum pw_stream_state state, const char *error) { + struct data *data = _data; printf("stream state: \"%s\"\n", pw_stream_state_as_string(state)); + switch (state) { + case PW_STREAM_STATE_CONFIGURE: + pw_stream_set_active(data->stream, true); + break; + default: + break; + } } static struct { @@ -355,7 +363,7 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo pw_stream_connect(data->stream, PW_DIRECTION_INPUT, PW_STREAM_MODE_BUFFER, - data->path, PW_STREAM_FLAG_AUTOCONNECT, 1, formats); + data->path, PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE, 1, formats); break; } default: diff --git a/src/extensions/client-node.h b/src/extensions/client-node.h index b715efdb9..6c3a90af4 100644 --- a/src/extensions/client-node.h +++ b/src/extensions/client-node.h @@ -166,9 +166,10 @@ struct pw_client_node_buffer { #define PW_CLIENT_NODE_PROXY_METHOD_DONE 0 #define PW_CLIENT_NODE_PROXY_METHOD_UPDATE 1 #define PW_CLIENT_NODE_PROXY_METHOD_PORT_UPDATE 2 -#define PW_CLIENT_NODE_PROXY_METHOD_EVENT 3 -#define PW_CLIENT_NODE_PROXY_METHOD_DESTROY 4 -#define PW_CLIENT_NODE_PROXY_METHOD_NUM 5 +#define PW_CLIENT_NODE_PROXY_METHOD_SET_ACTIVE 3 +#define PW_CLIENT_NODE_PROXY_METHOD_EVENT 4 +#define PW_CLIENT_NODE_PROXY_METHOD_DESTROY 5 +#define PW_CLIENT_NODE_PROXY_METHOD_NUM 6 /** \ref pw_client_node methods */ struct pw_client_node_proxy_methods { @@ -225,6 +226,10 @@ struct pw_client_node_proxy_methods { uint32_t n_params, const struct spa_param **params, const struct spa_port_info *info); + /** + * Activate of deactivate the node + */ + void (*set_active) (void *object, bool active); /** * Send an event to the node * \param event the event to send @@ -278,6 +283,12 @@ pw_client_node_proxy_port_update(struct pw_client_node_proxy *p, info); } +static inline void +pw_client_node_proxy_set_active(struct pw_client_node_proxy *p, bool active) +{ + pw_proxy_do((struct pw_proxy*)p, struct pw_client_node_proxy_methods, set_active, active); +} + static inline void pw_client_node_proxy_event(struct pw_client_node_proxy *p, struct spa_event *event) { diff --git a/src/modules/module-client-node/client-node.c b/src/modules/module-client-node/client-node.c index 2c711aedb..958efd146 100644 --- a/src/modules/module-client-node/client-node.c +++ b/src/modules/module-client-node/client-node.c @@ -896,6 +896,12 @@ client_node_port_update(void *data, } } +static void client_node_set_active(void *data, bool active) +{ + struct impl *impl = data; + pw_node_set_active(impl->this.node, active); +} + static void client_node_event(void *data, struct spa_event *event) { struct impl *impl = data; @@ -914,6 +920,7 @@ static struct pw_client_node_proxy_methods client_node_methods = { .done = client_node_done, .update = client_node_update, .port_update = client_node_port_update, + .set_active = client_node_set_active, .event = client_node_event, .destroy = client_node_destroy, }; @@ -1164,7 +1171,7 @@ struct pw_client_node *pw_client_node_new(struct pw_resource *resource, pw_resource_get_client(this->resource), NULL, name, - true, + PW_SPA_NODE_FLAG_ASYNC, &impl->proxy.node, NULL, properties, 0); diff --git a/src/modules/module-client-node/protocol-native.c b/src/modules/module-client-node/protocol-native.c index db2d151c6..f8c90a45f 100644 --- a/src/modules/module-client-node/protocol-native.c +++ b/src/modules/module-client-node/protocol-native.c @@ -113,6 +113,18 @@ client_node_marshal_port_update(void *object, pw_protocol_native_end_proxy(proxy, b); } +static void client_node_marshal_set_active(void *object, bool active) +{ + struct pw_proxy *proxy = object; + struct spa_pod_builder *b; + + b = pw_protocol_native_begin_proxy(proxy, PW_CLIENT_NODE_PROXY_METHOD_SET_ACTIVE); + + spa_pod_builder_struct(b, "b", active); + + pw_protocol_native_end_proxy(proxy, b); +} + static void client_node_marshal_event_method(void *object, struct spa_event *event) { struct pw_proxy *proxy = object; @@ -749,6 +761,22 @@ static bool client_node_demarshal_port_update(void *object, void *data, size_t s return true; } +static bool client_node_demarshal_set_active(void *object, void *data, size_t size) +{ + struct pw_resource *resource = object; + struct spa_pod_parser prs; + bool active; + + spa_pod_parser_init(&prs, data, size, 0); + if (spa_pod_parser_get(&prs, + "[" + "b", &active, NULL) < 0) + return false; + + pw_resource_do(resource, struct pw_client_node_proxy_methods, set_active, active); + return true; +} + static bool client_node_demarshal_event_method(void *object, void *data, size_t size) { struct pw_resource *resource = object; @@ -783,6 +811,7 @@ static const struct pw_client_node_proxy_methods pw_protocol_native_client_node_ &client_node_marshal_done, &client_node_marshal_update, &client_node_marshal_port_update, + &client_node_marshal_set_active, &client_node_marshal_event_method, &client_node_marshal_destroy }; @@ -791,6 +820,7 @@ static const struct pw_protocol_native_demarshal pw_protocol_native_client_node_ { &client_node_demarshal_done, 0 }, { &client_node_demarshal_update, PW_PROTOCOL_NATIVE_REMAP }, { &client_node_demarshal_port_update, PW_PROTOCOL_NATIVE_REMAP }, + { &client_node_demarshal_set_active, 0 }, { &client_node_demarshal_event_method, PW_PROTOCOL_NATIVE_REMAP }, { &client_node_demarshal_destroy, 0 }, }; diff --git a/src/modules/module-mixer.c b/src/modules/module-mixer.c index 7a3210fb0..f62b0764b 100644 --- a/src/modules/module-mixer.c +++ b/src/modules/module-mixer.c @@ -94,7 +94,6 @@ static struct pw_node *make_node(struct impl *impl) int res; void *iface; struct spa_node *spa_node; - struct spa_clock *spa_clock; struct pw_node *node; const struct spa_support *support; uint32_t n_support; @@ -114,13 +113,8 @@ static struct pw_node *make_node(struct impl *impl) } spa_node = iface; - if ((res = spa_handle_get_interface(handle, impl->t->spa_clock, &iface)) < 0) { - iface = NULL; - } - spa_clock = iface; - node = pw_spa_node_new(impl->core, NULL, pw_module_get_global(impl->module), - "audiomixer", false, spa_node, spa_clock, NULL, 0); + "audiomixer", PW_SPA_NODE_FLAG_ACTIVATE, spa_node, handle, NULL, 0); return node; diff --git a/src/modules/spa/module-node-factory.c b/src/modules/spa/module-node-factory.c index a4865327f..fcae2e90d 100644 --- a/src/modules/spa/module-node-factory.c +++ b/src/modules/spa/module-node-factory.c @@ -67,6 +67,7 @@ static void *create_object(void *_data, lib, factory_name, name, + 0, properties, 0); if (node == NULL) goto no_mem; diff --git a/src/modules/spa/module-node.c b/src/modules/spa/module-node.c index cd3631ee4..8583134cc 100644 --- a/src/modules/spa/module-node.c +++ b/src/modules/spa/module-node.c @@ -65,6 +65,7 @@ bool pipewire__module_init(struct pw_module *module, const char *args) NULL, pw_module_get_global(module), argv[0], argv[1], argv[2], + PW_SPA_NODE_FLAG_ACTIVATE, props, 0); pw_free_strv(argv); diff --git a/src/modules/spa/spa-monitor.c b/src/modules/spa/spa-monitor.c index 408fe3713..84955e12e 100644 --- a/src/modules/spa/spa-monitor.c +++ b/src/modules/spa/spa-monitor.c @@ -64,7 +64,6 @@ static void add_item(struct pw_spa_monitor *this, struct spa_monitor_item *item) struct spa_handle *handle; struct monitor_item *mitem; void *node_iface; - void *clock_iface; struct pw_properties *props = NULL; const char *name, *id, *klass; struct spa_handle_factory *factory; @@ -114,17 +113,13 @@ static void add_item(struct pw_spa_monitor *this, struct spa_monitor_item *item) pw_log_error("can't get NODE interface: %d", res); return; } - if ((res = spa_handle_get_interface(handle, t->spa_clock, &clock_iface)) < 0) { - pw_log_info("no CLOCK interface: %d", res); - clock_iface = NULL; - } - mitem = calloc(1, sizeof(struct monitor_item)); mitem->id = strdup(id); mitem->handle = handle; mitem->node = pw_spa_node_new(impl->core, NULL, impl->parent, name, - false, node_iface, clock_iface, props, 0); + PW_SPA_NODE_FLAG_ACTIVATE, + node_iface, handle, props, 0); spa_list_append(&impl->item_list, &mitem->link); } diff --git a/src/modules/spa/spa-node.c b/src/modules/spa/spa-node.c index 198c7947e..b7b3c9eee 100644 --- a/src/modules/spa/spa-node.c +++ b/src/modules/spa/spa-node.c @@ -40,6 +40,7 @@ struct impl { struct pw_client *owner; struct pw_global *parent; + enum pw_spa_node_flags flags; bool async_init; void *hnd; @@ -72,7 +73,8 @@ static void complete_init(struct impl *impl) { struct pw_node *this = impl->this; pw_node_register(this, impl->owner, impl->parent); - pw_node_set_active(this, true); + if (impl->flags & PW_SPA_NODE_FLAG_ACTIVATE) + pw_node_set_active(this, true); } static void on_node_done(void *data, uint32_t seq, int res) @@ -98,32 +100,40 @@ pw_spa_node_new(struct pw_core *core, struct pw_client *owner, struct pw_global *parent, const char *name, - bool async, + enum pw_spa_node_flags flags, struct spa_node *node, - struct spa_clock *clock, + struct spa_handle *handle, struct pw_properties *properties, size_t user_data_size) { struct pw_node *this; struct impl *impl; + void *iface = NULL; + struct pw_type *t = pw_core_get_type(core); + int res; this = pw_node_new(core, name, properties, sizeof(struct impl) + user_data_size); if (this == NULL) return NULL; - this->clock = clock; + if (handle) { + if ((res = spa_handle_get_interface(handle, t->spa_clock, &iface)) < 0) + iface = NULL; + this->clock = iface; + } impl = this->user_data; impl->this = this; impl->owner = owner; impl->parent = parent; impl->node = node; - impl->async_init = async; + impl->flags = flags; + impl->async_init = flags & PW_SPA_NODE_FLAG_ASYNC; pw_node_add_listener(this, &impl->node_listener, &node_events, impl); pw_node_set_implementation(this, impl->node); - if (!async) + if (!impl->async_init) complete_init(impl); return this; @@ -198,13 +208,13 @@ struct pw_node *pw_spa_node_load(struct pw_core *core, const char *lib, const char *factory_name, const char *name, + enum pw_spa_node_flags flags, struct pw_properties *properties, size_t user_data_size) { struct pw_node *this; struct impl *impl; struct spa_node *spa_node; - struct spa_clock *spa_clock; int res; struct spa_handle *handle; void *hnd; @@ -214,7 +224,6 @@ struct pw_node *pw_spa_node_load(struct pw_core *core, void *iface; char *filename; const char *dir; - bool async; const struct spa_support *support; uint32_t n_support; struct pw_type *t = pw_core_get_type(core); @@ -251,7 +260,8 @@ struct pw_node *pw_spa_node_load(struct pw_core *core, pw_log_error("can't make factory instance: %d", res); goto init_failed; } - async = SPA_RESULT_IS_ASYNC(res); + if (SPA_RESULT_IS_ASYNC(res)) + flags |= PW_SPA_NODE_FLAG_ASYNC; if ((res = spa_handle_get_interface(handle, t->spa_node, &iface)) < 0) { pw_log_error("can't get node interface %d", res); @@ -259,19 +269,14 @@ struct pw_node *pw_spa_node_load(struct pw_core *core, } spa_node = iface; - if ((res = spa_handle_get_interface(handle, t->spa_clock, &iface)) < 0) { - iface = NULL; - } - spa_clock = iface; - if (properties != NULL) { if (setup_props(core, spa_node, properties) != SPA_RESULT_OK) { pw_log_debug("Unrecognized properties"); } } - this = pw_spa_node_new(core, owner, parent, name, async, - spa_node, spa_clock, properties, user_data_size); + this = pw_spa_node_new(core, owner, parent, name, flags, + spa_node, handle, properties, user_data_size); impl = this->user_data; impl->hnd = hnd; diff --git a/src/modules/spa/spa-node.h b/src/modules/spa/spa-node.h index 744e02f45..497ae82c9 100644 --- a/src/modules/spa/spa-node.h +++ b/src/modules/spa/spa-node.h @@ -30,14 +30,19 @@ extern "C" { #endif +enum pw_spa_node_flags { + PW_SPA_NODE_FLAG_ASYNC = (1 << 0), + PW_SPA_NODE_FLAG_ACTIVATE = (1 << 1), +}; + struct pw_node * pw_spa_node_new(struct pw_core *core, struct pw_client *owner, /**< optional owner */ struct pw_global *parent, /**< optional parent */ const char *name, - bool async, + enum pw_spa_node_flags flags, struct spa_node *node, - struct spa_clock *clock, + struct spa_handle *handle, struct pw_properties *properties, size_t user_data_size); @@ -48,6 +53,7 @@ pw_spa_node_load(struct pw_core *core, const char *lib, const char *factory_name, const char *name, + enum pw_spa_node_flags flags, struct pw_properties *properties, size_t user_data_size); diff --git a/src/pipewire/node.c b/src/pipewire/node.c index c369f004b..a1abf5dc6 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -858,6 +858,7 @@ bool pw_node_set_active(struct pw_node *node, bool active) if (old != active) { pw_log_debug("node %p: %s", node, active ? "activate" : "deactivate"); node->active = active; + spa_hook_list_call(&node->listener_list, struct pw_node_events, active_changed, active); if (active) node_activate(node); else diff --git a/src/pipewire/node.h b/src/pipewire/node.h index f4fe68790..5523cc843 100644 --- a/src/pipewire/node.h +++ b/src/pipewire/node.h @@ -66,6 +66,9 @@ struct pw_node_events { /** the node info changed */ void (*info_changed) (void *data, struct pw_node_info *info); + /** the node active state changed */ + void (*active_changed) (void *data, bool active); + /** a new state is requested on the node */ void (*state_request) (void *data, enum pw_node_state state); /** the state of the node changed */ diff --git a/src/pipewire/remote.c b/src/pipewire/remote.c index f968791cf..bd5d457b3 100644 --- a/src/pipewire/remote.c +++ b/src/pipewire/remote.c @@ -586,6 +586,8 @@ static void client_node_transport(void *object, uint32_t node_id, readfd, SPA_IO_ERR | SPA_IO_HUP, true, on_rtsocket_condition, proxy); + if (data->node->active) + pw_client_node_proxy_set_active(data->node_proxy, true); } static void add_port_update(struct pw_proxy *proxy, struct pw_port *port, uint32_t change_mask) @@ -1034,8 +1036,16 @@ static void do_node_init(struct pw_proxy *proxy) pw_client_node_proxy_done(data->node_proxy, 0, SPA_RESULT_OK); } +static void node_active_changed(void *data, bool active) +{ + struct node_data *d = data; + pw_log_debug("active %d", active); + pw_client_node_proxy_set_active(d->node_proxy, active); +} + static const struct pw_node_events node_events = { PW_VERSION_NODE_EVENTS, + .active_changed = node_active_changed, .need_input = node_need_input, .have_output = node_have_output, }; diff --git a/src/pipewire/remote.h b/src/pipewire/remote.h index c496a3f2c..05e6361d8 100644 --- a/src/pipewire/remote.h +++ b/src/pipewire/remote.h @@ -170,12 +170,12 @@ void pw_remote_add_listener(struct pw_remote *remote, void *data); /** Connect to a remote PipeWire \memberof pw_remote - * \return true on success. */ + * \return 0 on success, < 0 on error */ int pw_remote_connect(struct pw_remote *remote); /** Connect to a remote PipeWire on the given socket \memberof pw_remote * \param fd the connected socket to use - * \return true on success. */ + * \return 0 on success, < 0 on error */ int pw_remote_connect_fd(struct pw_remote *remote, int fd); /** Get the core proxy, can only be called when connected */ diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index 2e8fec01e..b61e4f312 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -77,6 +77,7 @@ struct stream { uint32_t pending_seq; enum pw_stream_mode mode; + enum pw_stream_flags flags; int rtwritefd; struct spa_source *rtsocket_source; @@ -459,6 +460,8 @@ static void do_node_init(struct pw_stream *stream) add_port_update(stream, PW_CLIENT_NODE_PORT_UPDATE_POSSIBLE_FORMATS | PW_CLIENT_NODE_PORT_UPDATE_INFO); add_async_complete(stream, 0, SPA_RESULT_OK); + if (!(impl->flags & PW_STREAM_FLAG_INACTIVE)) + pw_client_node_proxy_set_active(impl->node_proxy, true); } static void on_timeout(void *data, uint64_t expirations) @@ -945,6 +948,7 @@ pw_stream_connect(struct pw_stream *stream, direction == PW_DIRECTION_INPUT ? SPA_DIRECTION_INPUT : SPA_DIRECTION_OUTPUT; impl->port_id = 0; impl->mode = mode; + impl->flags = flags; set_possible_formats(stream, n_possible_formats, possible_formats); @@ -1021,6 +1025,12 @@ void pw_stream_disconnect(struct pw_stream *stream) } } +void pw_stream_set_active(struct pw_stream *stream, bool active) +{ + struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); + pw_client_node_proxy_set_active(impl->node_proxy, active); +} + bool pw_stream_get_time(struct pw_stream *stream, struct pw_time *time) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); diff --git a/src/pipewire/stream.h b/src/pipewire/stream.h index c413a61a5..519824ee3 100644 --- a/src/pipewire/stream.h +++ b/src/pipewire/stream.h @@ -209,11 +209,12 @@ const char * pw_stream_state_as_string(enum pw_stream_state state); /** \enum pw_stream_flags Extra flags that can be used in \ref pw_stream_connect() \memberof pw_stream */ enum pw_stream_flags { - PW_STREAM_FLAG_NONE = 0, /**< no flags */ - PW_STREAM_FLAG_AUTOCONNECT = (1 << 0), /**< try to automatically connect - * this stream */ - PW_STREAM_FLAG_CLOCK_UPDATE = (1 << 1), /**< request periodic clock updates for - * this stream */ + PW_STREAM_FLAG_NONE = 0, /**< no flags */ + PW_STREAM_FLAG_AUTOCONNECT = (1 << 0), /**< try to automatically connect + * this stream */ + PW_STREAM_FLAG_CLOCK_UPDATE = (1 << 1), /**< request periodic clock updates for + * this stream */ + PW_STREAM_FLAG_INACTIVE = (1 << 2), /**< start the stream inactive */ }; /** \enum pw_stream_mode The method for transfering data for a stream \memberof pw_stream */ @@ -293,6 +294,9 @@ pw_stream_finish_format(struct pw_stream *stream, /**< a \ref pw_stream */ struct spa_param **params, /**< an array of pointers to \ref spa_param */ uint32_t n_params /**< number of elements in \a params */); +/** Activate or deactivate the stream \memberof pw_stream */ +void pw_stream_set_active(struct pw_stream *stream, bool active); + /** Query the time on the stream \memberof pw_stream */ bool pw_stream_get_time(struct pw_stream *stream, struct pw_time *time);