mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
Work on unifying client and server
Remove context and extensions, make client API also use the core. Make a new pw_remote object that keeps connections with remote instances. Remove introspection API, it's just as easy to connect to the registry and get updates like that. Expand the protocol a little to make it useful for making listeners and connections. Move protocol specific connection to the module. Make some new convenience methods. Make a factory to create nodes from spa objects Add an example of a local pipeline displaying a v4l2 source.
This commit is contained in:
parent
2ece95ea48
commit
847cef83b6
65 changed files with 2634 additions and 2713 deletions
|
|
@ -1,888 +0,0 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "pipewire/client/pipewire.h"
|
||||
|
||||
#include "pipewire/client/context.h"
|
||||
#include "pipewire/client/extension.h"
|
||||
#include "pipewire/client/introspect.h"
|
||||
#include "pipewire/client/interfaces.h"
|
||||
#include "pipewire/client/connection.h"
|
||||
#include "pipewire/client/subscribe.h"
|
||||
|
||||
#include <spa/lib/debug.h>
|
||||
|
||||
/** \cond */
|
||||
struct context {
|
||||
struct pw_context this;
|
||||
|
||||
struct spa_support support[3];
|
||||
|
||||
bool no_proxy;
|
||||
|
||||
int fd;
|
||||
struct pw_connection *connection;
|
||||
struct spa_source *source;
|
||||
|
||||
bool disconnecting;
|
||||
struct pw_listener need_flush;
|
||||
struct spa_source *flush_event;
|
||||
};
|
||||
|
||||
struct proxy_data {
|
||||
void *info;
|
||||
};
|
||||
/** \endcond */
|
||||
|
||||
const char *pw_context_state_as_string(enum pw_context_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case PW_CONTEXT_STATE_ERROR:
|
||||
return "error";
|
||||
case PW_CONTEXT_STATE_UNCONNECTED:
|
||||
return "unconnected";
|
||||
case PW_CONTEXT_STATE_CONNECTING:
|
||||
return "connecting";
|
||||
case PW_CONTEXT_STATE_CONNECTED:
|
||||
return "connected";
|
||||
}
|
||||
return "invalid-state";
|
||||
}
|
||||
|
||||
static void
|
||||
context_set_state(struct pw_context *context, enum pw_context_state state, const char *fmt, ...)
|
||||
{
|
||||
if (context->state != state) {
|
||||
|
||||
if (context->error)
|
||||
free(context->error);
|
||||
|
||||
if (fmt) {
|
||||
va_list varargs;
|
||||
|
||||
va_start(varargs, fmt);
|
||||
if (vasprintf(&context->error, fmt, varargs) < 0) {
|
||||
pw_log_debug("context %p: error formating message: %m", context);
|
||||
context->error = NULL;
|
||||
}
|
||||
va_end(varargs);
|
||||
} else {
|
||||
context->error = NULL;
|
||||
}
|
||||
pw_log_debug("context %p: update state from %s -> %s (%s)", context,
|
||||
pw_context_state_as_string(context->state),
|
||||
pw_context_state_as_string(state), context->error);
|
||||
|
||||
context->state = state;
|
||||
pw_signal_emit(&context->state_changed, context);
|
||||
}
|
||||
}
|
||||
|
||||
static void core_event_info(void *object, struct pw_core_info *info)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_context *this = proxy->context;
|
||||
enum pw_subscription_event event;
|
||||
struct proxy_data *data = proxy->user_data;
|
||||
|
||||
pw_log_debug("got core info");
|
||||
|
||||
if (data->info == NULL)
|
||||
event = PW_SUBSCRIPTION_EVENT_NEW;
|
||||
else
|
||||
event = PW_SUBSCRIPTION_EVENT_CHANGE;
|
||||
|
||||
data->info = pw_core_info_update(data->info, info);
|
||||
|
||||
pw_signal_emit(&this->subscription, this, event, proxy->type, proxy->id);
|
||||
}
|
||||
|
||||
static void core_event_done(void *object, uint32_t seq)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_context *this = proxy->context;
|
||||
|
||||
if (seq == 0) {
|
||||
pw_core_do_sync(this->core_proxy, 1);
|
||||
} else if (seq == 1) {
|
||||
context_set_state(this, PW_CONTEXT_STATE_CONNECTED, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void core_event_error(void *object, uint32_t id, int res, const char *error, ...)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_context *this = proxy->context;
|
||||
context_set_state(this, PW_CONTEXT_STATE_ERROR, error);
|
||||
}
|
||||
|
||||
static void core_event_remove_id(void *object, uint32_t id)
|
||||
{
|
||||
struct pw_proxy *core_proxy = object;
|
||||
struct pw_context *this = core_proxy->context;
|
||||
struct pw_proxy *proxy;
|
||||
|
||||
proxy = pw_map_lookup(&this->objects, id);
|
||||
if (proxy) {
|
||||
pw_log_debug("context %p: object remove %u", this, id);
|
||||
pw_proxy_destroy(proxy);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
core_event_update_types(void *object, uint32_t first_id, uint32_t n_types, const char **types)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_context *this = proxy->context;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_types; i++, first_id++) {
|
||||
uint32_t this_id = spa_type_map_get_id(this->type.map, types[i]);
|
||||
if (!pw_map_insert_at(&this->types, first_id, PW_MAP_ID_TO_PTR(this_id)))
|
||||
pw_log_error("can't add type for client");
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pw_core_events core_events = {
|
||||
&core_event_update_types,
|
||||
&core_event_done,
|
||||
&core_event_error,
|
||||
&core_event_remove_id,
|
||||
&core_event_info,
|
||||
};
|
||||
|
||||
static void module_event_info(void *object, struct pw_module_info *info)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_context *this = proxy->context;
|
||||
enum pw_subscription_event event;
|
||||
struct proxy_data *data = proxy->user_data;
|
||||
|
||||
pw_log_debug("got module info");
|
||||
|
||||
if (data->info == NULL)
|
||||
event = PW_SUBSCRIPTION_EVENT_NEW;
|
||||
else
|
||||
event = PW_SUBSCRIPTION_EVENT_CHANGE;
|
||||
|
||||
data->info = pw_module_info_update(data->info, info);
|
||||
|
||||
pw_signal_emit(&this->subscription, this, event, proxy->type, proxy->id);
|
||||
}
|
||||
|
||||
static const struct pw_module_events module_events = {
|
||||
&module_event_info,
|
||||
};
|
||||
|
||||
static void node_event_info(void *object, struct pw_node_info *info)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_context *this = proxy->context;
|
||||
enum pw_subscription_event event;
|
||||
struct proxy_data *data = proxy->user_data;
|
||||
|
||||
pw_log_debug("got node info");
|
||||
|
||||
if (data->info == NULL)
|
||||
event = PW_SUBSCRIPTION_EVENT_NEW;
|
||||
else
|
||||
event = PW_SUBSCRIPTION_EVENT_CHANGE;
|
||||
|
||||
data->info = pw_node_info_update(data->info, info);
|
||||
|
||||
pw_signal_emit(&this->subscription, this, event, proxy->type, proxy->id);
|
||||
}
|
||||
|
||||
static const struct pw_node_events node_events = {
|
||||
&node_event_info
|
||||
};
|
||||
|
||||
static void client_event_info(void *object, struct pw_client_info *info)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_context *this = proxy->context;
|
||||
enum pw_subscription_event event;
|
||||
struct proxy_data *data = proxy->user_data;
|
||||
|
||||
pw_log_debug("got client info");
|
||||
|
||||
if (data->info == NULL)
|
||||
event = PW_SUBSCRIPTION_EVENT_NEW;
|
||||
else
|
||||
event = PW_SUBSCRIPTION_EVENT_CHANGE;
|
||||
|
||||
data->info = pw_client_info_update(data->info, info);
|
||||
|
||||
pw_signal_emit(&this->subscription, this, event, proxy->type, proxy->id);
|
||||
}
|
||||
|
||||
static const struct pw_client_events client_events = {
|
||||
&client_event_info
|
||||
};
|
||||
|
||||
static void link_event_info(void *object, struct pw_link_info *info)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_context *this = proxy->context;
|
||||
enum pw_subscription_event event;
|
||||
struct proxy_data *data = proxy->user_data;
|
||||
|
||||
pw_log_debug("got link info");
|
||||
|
||||
if (data->info == NULL)
|
||||
event = PW_SUBSCRIPTION_EVENT_NEW;
|
||||
else
|
||||
event = PW_SUBSCRIPTION_EVENT_CHANGE;
|
||||
|
||||
data->info = pw_link_info_update(data->info, info);
|
||||
|
||||
pw_signal_emit(&this->subscription, this, event, proxy->type, proxy->id);
|
||||
}
|
||||
|
||||
static const struct pw_link_events link_events = {
|
||||
&link_event_info
|
||||
};
|
||||
|
||||
static void
|
||||
destroy_proxy (void *data)
|
||||
{
|
||||
struct pw_proxy *proxy = data;
|
||||
struct proxy_data *user_data = proxy->user_data;
|
||||
|
||||
if (user_data->info == NULL)
|
||||
return;
|
||||
|
||||
if (proxy->type == proxy->context->type.core) {
|
||||
pw_core_info_free (user_data->info);
|
||||
} else if (proxy->type == proxy->context->type.node) {
|
||||
pw_node_info_free (user_data->info);
|
||||
} else if (proxy->type == proxy->context->type.module) {
|
||||
pw_module_info_free (user_data->info);
|
||||
} else if (proxy->type == proxy->context->type.client) {
|
||||
pw_client_info_free (user_data->info);
|
||||
} else if (proxy->type == proxy->context->type.link) {
|
||||
pw_link_info_free (user_data->info);
|
||||
}
|
||||
user_data->info = NULL;
|
||||
}
|
||||
|
||||
static void registry_event_global(void *object, uint32_t id, const char *type, uint32_t version)
|
||||
{
|
||||
struct pw_proxy *registry_proxy = object;
|
||||
struct pw_context *this = registry_proxy->context;
|
||||
struct context *impl = SPA_CONTAINER_OF(this, struct context, this);
|
||||
struct pw_proxy *proxy = NULL;
|
||||
uint32_t proxy_type, client_version;
|
||||
const void *implementation;
|
||||
|
||||
if (impl->no_proxy)
|
||||
return;
|
||||
|
||||
pw_log_debug("got global %u %s %u", id, type, version);
|
||||
|
||||
if (!strcmp(type, PIPEWIRE_TYPE__Node)) {
|
||||
proxy_type = this->type.node;
|
||||
implementation = &node_events;
|
||||
client_version = PW_VERSION_NODE;
|
||||
} else if (!strcmp(type, PIPEWIRE_TYPE__Module)) {
|
||||
proxy_type = this->type.module;
|
||||
implementation = &module_events;
|
||||
client_version = PW_VERSION_MODULE;
|
||||
} else if (!strcmp(type, PIPEWIRE_TYPE__Client)) {
|
||||
proxy_type = this->type.client;
|
||||
implementation = &client_events;
|
||||
client_version = PW_VERSION_CLIENT;
|
||||
} else if (!strcmp(type, PIPEWIRE_TYPE__Link)) {
|
||||
proxy_type = this->type.link;
|
||||
implementation = &link_events;
|
||||
client_version = PW_VERSION_LINK;
|
||||
} else
|
||||
return;
|
||||
|
||||
proxy = pw_proxy_new(this, SPA_ID_INVALID, proxy_type, sizeof(struct proxy_data));
|
||||
if (proxy == NULL)
|
||||
goto no_mem;
|
||||
|
||||
pw_proxy_set_implementation(proxy, this, client_version, implementation, destroy_proxy);
|
||||
|
||||
pw_registry_do_bind(registry_proxy, id, version, proxy->id);
|
||||
|
||||
return;
|
||||
|
||||
no_mem:
|
||||
pw_log_error("context %p: failed to create proxy", this);
|
||||
return;
|
||||
}
|
||||
|
||||
static void registry_event_global_remove(void *object, uint32_t id)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_context *this = proxy->context;
|
||||
|
||||
pw_log_debug("got global remove %u", id);
|
||||
|
||||
pw_signal_emit(&this->subscription, this, PW_SUBSCRIPTION_EVENT_REMOVE, SPA_ID_INVALID, id);
|
||||
}
|
||||
|
||||
static const struct pw_registry_events registry_events = {
|
||||
®istry_event_global,
|
||||
®istry_event_global_remove
|
||||
};
|
||||
|
||||
typedef bool(*demarshal_func_t) (void *object, void *data, size_t size);
|
||||
|
||||
static void do_flush_event(struct spa_loop_utils *utils, struct spa_source *source, void *data)
|
||||
{
|
||||
struct context *impl = data;
|
||||
if (impl->connection)
|
||||
if (!pw_connection_flush(impl->connection))
|
||||
pw_context_disconnect(&impl->this);
|
||||
}
|
||||
|
||||
static void on_need_flush(struct pw_listener *listener, struct pw_connection *connection)
|
||||
{
|
||||
struct context *impl = SPA_CONTAINER_OF(listener, struct context, need_flush);
|
||||
struct pw_context *this = &impl->this;
|
||||
pw_loop_signal_event(this->loop, impl->flush_event);
|
||||
}
|
||||
|
||||
static void
|
||||
on_context_data(struct spa_loop_utils *utils,
|
||||
struct spa_source *source, int fd, enum spa_io mask, void *data)
|
||||
{
|
||||
struct context *impl = data;
|
||||
struct pw_context *this = &impl->this;
|
||||
struct pw_connection *conn = impl->connection;
|
||||
|
||||
if (mask & (SPA_IO_ERR | SPA_IO_HUP)) {
|
||||
context_set_state(this, PW_CONTEXT_STATE_ERROR, "connection closed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mask & SPA_IO_IN) {
|
||||
uint8_t opcode;
|
||||
uint32_t id;
|
||||
uint32_t size;
|
||||
void *message;
|
||||
|
||||
while (!impl->disconnecting
|
||||
&& pw_connection_get_next(conn, &opcode, &id, &message, &size)) {
|
||||
struct pw_proxy *proxy;
|
||||
const demarshal_func_t *demarshal;
|
||||
|
||||
pw_log_trace("context %p: got message %d from %u", this, opcode, id);
|
||||
|
||||
proxy = pw_map_lookup(&this->objects, id);
|
||||
if (proxy == NULL) {
|
||||
pw_log_error("context %p: could not find proxy %u", this, id);
|
||||
continue;
|
||||
}
|
||||
if (opcode >= proxy->iface->n_events) {
|
||||
pw_log_error("context %p: invalid method %u for %u", this, opcode,
|
||||
id);
|
||||
continue;
|
||||
}
|
||||
|
||||
demarshal = proxy->iface->events;
|
||||
if (demarshal[opcode]) {
|
||||
if (!demarshal[opcode] (proxy, message, size))
|
||||
pw_log_error
|
||||
("context %p: invalid message received %u for %u", this,
|
||||
opcode, id);
|
||||
} else
|
||||
pw_log_error("context %p: function %d not implemented on %u", this,
|
||||
opcode, id);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct pw_context *pw_context_new(struct pw_loop *loop,
|
||||
const char *name, struct pw_properties *properties)
|
||||
{
|
||||
struct context *impl;
|
||||
struct pw_context *this;
|
||||
|
||||
impl = calloc(1, sizeof(struct context));
|
||||
if (impl == NULL)
|
||||
return NULL;
|
||||
|
||||
impl->fd = -1;
|
||||
|
||||
this = &impl->this;
|
||||
pw_log_debug("context %p: new", impl);
|
||||
|
||||
this->name = strdup(name);
|
||||
|
||||
if (properties == NULL)
|
||||
properties = pw_properties_new("application.name", name, NULL);
|
||||
if (properties == NULL)
|
||||
goto no_mem;
|
||||
|
||||
pw_fill_context_properties(properties);
|
||||
this->properties = properties;
|
||||
|
||||
this->loop = loop;
|
||||
|
||||
pw_type_init(&this->type);
|
||||
|
||||
spa_debug_set_type_map(this->type.map);
|
||||
|
||||
impl->support[0] = SPA_SUPPORT_INIT (SPA_TYPE__TypeMap, this->type.map);
|
||||
impl->support[1] = SPA_SUPPORT_INIT (SPA_TYPE_LOOP__MainLoop, this->loop->loop);
|
||||
impl->support[2] = SPA_SUPPORT_INIT (SPA_TYPE__Log, pw_log_get());
|
||||
this->support = impl->support;
|
||||
this->n_support = 3;
|
||||
|
||||
impl->flush_event = pw_loop_add_event(loop, do_flush_event, impl);
|
||||
|
||||
this->state = PW_CONTEXT_STATE_UNCONNECTED;
|
||||
|
||||
pw_map_init(&this->objects, 64, 32);
|
||||
pw_map_init(&this->types, 64, 32);
|
||||
|
||||
spa_list_init(&this->extension_list);
|
||||
spa_list_init(&this->stream_list);
|
||||
spa_list_init(&this->proxy_list);
|
||||
|
||||
pw_signal_init(&this->state_changed);
|
||||
pw_signal_init(&this->subscription);
|
||||
pw_signal_init(&this->destroy_signal);
|
||||
|
||||
pw_extension_load(this, "libpipewire-module-protocol-native", NULL);
|
||||
pw_extension_load(this, "libpipewire-module-client-node", NULL);
|
||||
|
||||
this->protocol = pw_protocol_get(PW_TYPE_PROTOCOL__Native);
|
||||
|
||||
return this;
|
||||
|
||||
no_mem:
|
||||
free(this->name);
|
||||
free(impl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pw_context_destroy(struct pw_context *context)
|
||||
{
|
||||
struct context *impl = SPA_CONTAINER_OF(context, struct context, this);
|
||||
struct pw_stream *stream, *t1;
|
||||
struct pw_proxy *proxy, *t2;
|
||||
struct pw_extension *ext, *t3;
|
||||
|
||||
pw_log_debug("context %p: destroy", context);
|
||||
pw_signal_emit(&context->destroy_signal, context);
|
||||
|
||||
pw_loop_destroy_source(impl->this.loop, impl->flush_event);
|
||||
|
||||
if (context->state != PW_CONTEXT_STATE_UNCONNECTED)
|
||||
pw_context_disconnect(context);
|
||||
|
||||
spa_list_for_each_safe(stream, t1, &context->stream_list, link)
|
||||
pw_stream_destroy(stream);
|
||||
spa_list_for_each_safe(proxy, t2, &context->proxy_list, link)
|
||||
pw_proxy_destroy(proxy);
|
||||
spa_list_for_each_safe(ext, t3, &context->extension_list, link)
|
||||
pw_extension_destroy(ext);
|
||||
|
||||
pw_map_clear(&context->objects);
|
||||
pw_map_clear(&context->types);
|
||||
|
||||
free(context->name);
|
||||
if (context->properties)
|
||||
pw_properties_free(context->properties);
|
||||
free(context->error);
|
||||
free(impl);
|
||||
}
|
||||
|
||||
bool pw_context_connect(struct pw_context *context, enum pw_context_flags flags)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
socklen_t size;
|
||||
const char *runtime_dir, *name = NULL;
|
||||
int name_size, fd;
|
||||
|
||||
if ((runtime_dir = getenv("XDG_RUNTIME_DIR")) == NULL) {
|
||||
context_set_state(context,
|
||||
PW_CONTEXT_STATE_ERROR,
|
||||
"connect failed: XDG_RUNTIME_DIR not set in the environment");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (name == NULL)
|
||||
name = getenv("PIPEWIRE_CORE");
|
||||
if (name == NULL)
|
||||
name = "pipewire-0";
|
||||
|
||||
if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0)
|
||||
return false;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_LOCAL;
|
||||
name_size = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", runtime_dir, name) + 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);
|
||||
goto error_close;
|
||||
};
|
||||
|
||||
size = offsetof(struct sockaddr_un, sun_path) + name_size;
|
||||
|
||||
if (connect(fd, (struct sockaddr *) &addr, size) < 0) {
|
||||
context_set_state(context,
|
||||
PW_CONTEXT_STATE_ERROR, "connect failed: %s", strerror(errno));
|
||||
goto error_close;
|
||||
}
|
||||
|
||||
return pw_context_connect_fd(context, flags, fd);
|
||||
|
||||
error_close:
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pw_context_connect_fd(struct pw_context *context, enum pw_context_flags flags, int fd)
|
||||
{
|
||||
struct context *impl = SPA_CONTAINER_OF(context, struct context, this);
|
||||
|
||||
context_set_state(context, PW_CONTEXT_STATE_CONNECTING, NULL);
|
||||
|
||||
impl->connection = pw_connection_new(fd);
|
||||
if (impl->connection == NULL)
|
||||
goto error_close;
|
||||
|
||||
context->protocol_private = impl->connection;
|
||||
|
||||
pw_signal_add(&impl->connection->need_flush, &impl->need_flush, on_need_flush);
|
||||
|
||||
impl->fd = fd;
|
||||
|
||||
impl->source = pw_loop_add_io(context->loop,
|
||||
fd,
|
||||
SPA_IO_IN | SPA_IO_HUP | SPA_IO_ERR,
|
||||
false, on_context_data, impl);
|
||||
|
||||
context->core_proxy = pw_proxy_new(context, 0, context->type.core, sizeof(struct proxy_data));
|
||||
if (context->core_proxy == NULL)
|
||||
goto no_proxy;
|
||||
|
||||
pw_proxy_set_implementation(context->core_proxy, context, PW_VERSION_CORE,
|
||||
&core_events, destroy_proxy);
|
||||
|
||||
pw_core_do_client_update(context->core_proxy, &context->properties->dict);
|
||||
|
||||
if (!(flags & PW_CONTEXT_FLAG_NO_REGISTRY)) {
|
||||
context->registry_proxy = pw_proxy_new(context,
|
||||
SPA_ID_INVALID, context->type.registry, 0);
|
||||
|
||||
if (context->registry_proxy == NULL)
|
||||
goto no_registry;
|
||||
|
||||
pw_proxy_set_implementation(context->registry_proxy, context, PW_VERSION_REGISTRY,
|
||||
®istry_events, NULL);
|
||||
|
||||
pw_core_do_get_registry(context->core_proxy, context->registry_proxy->id);
|
||||
}
|
||||
impl->no_proxy = ! !(flags & PW_CONTEXT_FLAG_NO_PROXY);
|
||||
|
||||
pw_core_do_sync(context->core_proxy, 0);
|
||||
|
||||
return true;
|
||||
|
||||
no_registry:
|
||||
pw_proxy_destroy(context->core_proxy);
|
||||
no_proxy:
|
||||
pw_loop_destroy_source(context->loop, impl->source);
|
||||
pw_connection_destroy(impl->connection);
|
||||
error_close:
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
void pw_context_disconnect(struct pw_context *context)
|
||||
{
|
||||
struct context *impl = SPA_CONTAINER_OF(context, struct context, this);
|
||||
|
||||
impl->disconnecting = true;
|
||||
|
||||
if (impl->source)
|
||||
pw_loop_destroy_source(context->loop, impl->source);
|
||||
impl->source = NULL;
|
||||
|
||||
if (context->registry_proxy)
|
||||
pw_proxy_destroy(context->registry_proxy);
|
||||
context->registry_proxy = NULL;
|
||||
|
||||
if (context->core_proxy)
|
||||
pw_proxy_destroy(context->core_proxy);
|
||||
context->core_proxy = NULL;
|
||||
|
||||
if (impl->connection)
|
||||
pw_connection_destroy(impl->connection);
|
||||
impl->connection = NULL;
|
||||
context->protocol_private = NULL;
|
||||
|
||||
if (impl->fd != -1)
|
||||
close(impl->fd);
|
||||
impl->fd = -1;
|
||||
|
||||
context_set_state(context, PW_CONTEXT_STATE_UNCONNECTED, NULL);
|
||||
}
|
||||
|
||||
/** Get core information
|
||||
*
|
||||
* \param context A \ref pw_context
|
||||
* \param cb the callback to call with the result
|
||||
* \param user_data user data passed to \a cb
|
||||
*
|
||||
* \memberof pw_introspect
|
||||
*/
|
||||
void pw_context_get_core_info(struct pw_context *context, pw_core_info_cb_t cb, void *user_data)
|
||||
{
|
||||
struct pw_proxy *proxy;
|
||||
|
||||
proxy = pw_map_lookup(&context->objects, 0);
|
||||
if (proxy == NULL) {
|
||||
cb(context, SPA_RESULT_INVALID_OBJECT_ID, NULL, user_data);
|
||||
} else if (proxy->type == context->type.core) {
|
||||
struct proxy_data *data = proxy->user_data;
|
||||
struct pw_core_info *info = data->info;
|
||||
if (info) {
|
||||
cb(context, SPA_RESULT_OK, info, user_data);
|
||||
info->change_mask = 0;
|
||||
}
|
||||
}
|
||||
cb(context, SPA_RESULT_ENUM_END, NULL, user_data);
|
||||
}
|
||||
|
||||
typedef void (*list_func_t) (struct pw_context *, int, void *, void *);
|
||||
|
||||
static void do_list(struct pw_context *context, uint32_t type, list_func_t cb, void *user_data)
|
||||
{
|
||||
union pw_map_item *item;
|
||||
|
||||
pw_array_for_each(item, &context->objects.items) {
|
||||
struct pw_proxy *proxy;
|
||||
struct proxy_data *data;
|
||||
|
||||
if (pw_map_item_is_free(item))
|
||||
continue;
|
||||
|
||||
proxy = item->data;
|
||||
if (proxy->type != type)
|
||||
continue;
|
||||
|
||||
data = proxy->user_data;
|
||||
if (data->info)
|
||||
cb(context, SPA_RESULT_OK, data->info, user_data);
|
||||
}
|
||||
cb(context, SPA_RESULT_ENUM_END, NULL, user_data);
|
||||
}
|
||||
|
||||
/** Get all module information
|
||||
*
|
||||
* \param context A \ref pw_context
|
||||
* \param cb the callback to call with the results
|
||||
* \param user_data user data passed to \a cb
|
||||
*
|
||||
* \a cb is called for each module
|
||||
*
|
||||
* \memberof pw_introspect
|
||||
*/
|
||||
void
|
||||
pw_context_list_module_info(struct pw_context *context, pw_module_info_cb_t cb, void *user_data)
|
||||
{
|
||||
do_list(context, context->type.module, (list_func_t) cb, user_data);
|
||||
}
|
||||
|
||||
/** Get module information
|
||||
*
|
||||
* \param context A \ref pw_context
|
||||
* \param id the client side id of the module to query
|
||||
* \param cb the callback to call with the results
|
||||
* \param user_data user data passed to \a cb
|
||||
*
|
||||
* \a cb is called for the module with \a id
|
||||
*
|
||||
* \memberof pw_introspect
|
||||
*/
|
||||
void
|
||||
pw_context_get_module_info_by_id(struct pw_context *context,
|
||||
uint32_t id, pw_module_info_cb_t cb, void *user_data)
|
||||
{
|
||||
struct pw_proxy *proxy;
|
||||
|
||||
proxy = pw_map_lookup(&context->objects, id);
|
||||
if (proxy == NULL) {
|
||||
cb(context, SPA_RESULT_INVALID_OBJECT_ID, NULL, user_data);
|
||||
} else if (proxy->type == context->type.module) {
|
||||
struct proxy_data *data = proxy->user_data;
|
||||
struct pw_module_info *info = data->info;
|
||||
if (info) {
|
||||
cb(context, SPA_RESULT_OK, info, user_data);
|
||||
info->change_mask = 0;
|
||||
}
|
||||
}
|
||||
cb(context, SPA_RESULT_ENUM_END, NULL, user_data);
|
||||
}
|
||||
|
||||
/** Get all client information
|
||||
*
|
||||
* \param context A \ref pw_context
|
||||
* \param cb the callback to call with the results
|
||||
* \param user_data user data passed to \a cb
|
||||
*
|
||||
* \a cb is called for each client
|
||||
*
|
||||
* \memberof pw_introspect
|
||||
*/
|
||||
void
|
||||
pw_context_list_client_info(struct pw_context *context, pw_client_info_cb_t cb, void *user_data)
|
||||
{
|
||||
do_list(context, context->type.client, (list_func_t) cb, user_data);
|
||||
}
|
||||
|
||||
/** Get client information
|
||||
*
|
||||
* \param context A \ref pw_context
|
||||
* \param id the client side id of the client to query
|
||||
* \param cb the callback to call with the results
|
||||
* \param user_data user data passed to \a cb
|
||||
*
|
||||
* \a cb is called for the client with \a id
|
||||
*
|
||||
* \memberof pw_introspect
|
||||
*/
|
||||
void
|
||||
pw_context_get_client_info_by_id(struct pw_context *context,
|
||||
uint32_t id, pw_client_info_cb_t cb, void *user_data)
|
||||
{
|
||||
struct pw_proxy *proxy;
|
||||
|
||||
proxy = pw_map_lookup(&context->objects, id);
|
||||
if (proxy == NULL) {
|
||||
cb(context, SPA_RESULT_INVALID_OBJECT_ID, NULL, user_data);
|
||||
} else if (proxy->type == context->type.client) {
|
||||
struct proxy_data *data = proxy->user_data;
|
||||
struct pw_client_info *info = data->info;
|
||||
if (info) {
|
||||
cb(context, SPA_RESULT_OK, info, user_data);
|
||||
info->change_mask = 0;
|
||||
}
|
||||
}
|
||||
cb(context, SPA_RESULT_ENUM_END, NULL, user_data);
|
||||
}
|
||||
|
||||
/** Get all node information
|
||||
*
|
||||
* \param context A \ref pw_context
|
||||
* \param cb the callback to call with the results
|
||||
* \param user_data user data passed to \a cb
|
||||
*
|
||||
* \a cb is called for each node
|
||||
*
|
||||
* \memberof pw_introspect
|
||||
*/
|
||||
void pw_context_list_node_info(struct pw_context *context, pw_node_info_cb_t cb, void *user_data)
|
||||
{
|
||||
do_list(context, context->type.node, (list_func_t) cb, user_data);
|
||||
}
|
||||
|
||||
/** Get node information
|
||||
*
|
||||
* \param context A \ref pw_context
|
||||
* \param id the client side id of the node to query
|
||||
* \param cb the callback to call with the results
|
||||
* \param user_data user data passed to \a cb
|
||||
*
|
||||
* \a cb is called for the node with \a id
|
||||
*
|
||||
* \memberof pw_introspect
|
||||
*/
|
||||
void
|
||||
pw_context_get_node_info_by_id(struct pw_context *context,
|
||||
uint32_t id, pw_node_info_cb_t cb, void *user_data)
|
||||
{
|
||||
struct pw_proxy *proxy;
|
||||
|
||||
proxy = pw_map_lookup(&context->objects, id);
|
||||
if (proxy == NULL) {
|
||||
cb(context, SPA_RESULT_INVALID_OBJECT_ID, NULL, user_data);
|
||||
} else if (proxy->type == context->type.node) {
|
||||
struct proxy_data *data = proxy->user_data;
|
||||
struct pw_node_info *info = data->info;
|
||||
if (info) {
|
||||
cb(context, SPA_RESULT_OK, info, user_data);
|
||||
info->change_mask = 0;
|
||||
}
|
||||
}
|
||||
cb(context, SPA_RESULT_ENUM_END, NULL, user_data);
|
||||
}
|
||||
|
||||
/** Get all link information
|
||||
*
|
||||
* \param context A \ref pw_context
|
||||
* \param cb the callback to call with the results
|
||||
* \param user_data user data passed to \a cb
|
||||
*
|
||||
* \a cb is called for each link
|
||||
*
|
||||
* \memberof pw_introspect
|
||||
*/
|
||||
void pw_context_list_link_info(struct pw_context *context, pw_link_info_cb_t cb, void *user_data)
|
||||
{
|
||||
do_list(context, context->type.link, (list_func_t) cb, user_data);
|
||||
}
|
||||
|
||||
/** Get link information
|
||||
*
|
||||
* \param context A \ref pw_context
|
||||
* \param id the client side id of the link to query
|
||||
* \param cb the callback to call with the results
|
||||
* \param user_data user data passed to \a cb
|
||||
*
|
||||
* \a cb is called for the link with \a id
|
||||
*
|
||||
* \memberof pw_introspect
|
||||
*/
|
||||
void
|
||||
pw_context_get_link_info_by_id(struct pw_context *context,
|
||||
uint32_t id, pw_link_info_cb_t cb, void *user_data)
|
||||
{
|
||||
struct pw_proxy *proxy;
|
||||
|
||||
proxy = pw_map_lookup(&context->objects, id);
|
||||
if (proxy == NULL) {
|
||||
cb(context, SPA_RESULT_INVALID_OBJECT_ID, NULL, user_data);
|
||||
} else if (proxy->type == context->type.link) {
|
||||
struct proxy_data *data = proxy->user_data;
|
||||
struct pw_link_info *info = data->info;
|
||||
if (info) {
|
||||
cb(context, SPA_RESULT_OK, info, user_data);
|
||||
info->change_mask = 0;
|
||||
}
|
||||
}
|
||||
cb(context, SPA_RESULT_ENUM_END, NULL, user_data);
|
||||
}
|
||||
|
|
@ -1,208 +0,0 @@
|
|||
/* 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_CONTEXT_H__
|
||||
#define __PIPEWIRE_CONTEXT_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \page page_client_api Client API
|
||||
*
|
||||
* \section sec_client_api_overview Overview
|
||||
*
|
||||
* The client side API allows you to connect to the PipeWire server and
|
||||
* perform actions on the PipeWire graph. This includes
|
||||
*
|
||||
* \li introspecting the objects on the server
|
||||
* \li Creating nodes
|
||||
* \li Linking nodes on their ports
|
||||
* \li providing media to the server for playback or consumption
|
||||
* \li retrieving media from the server
|
||||
*
|
||||
* \section sec_client_api_loop Event Loop Abstraction
|
||||
*
|
||||
* Most API is asynchronous and based around an event loop. Methods will
|
||||
* start an operation which will cause a state change of the \ref pw_context
|
||||
* object. Connect to the state_changed signal to be notified of these
|
||||
* state changes.
|
||||
*
|
||||
* The most convenient way to deal with the asynchronous calls is probably
|
||||
* with the thread loop (See \subpage page_thread_loop for more details).
|
||||
*
|
||||
* \subsection ssec_client_api_context_proxy Proxy
|
||||
*
|
||||
* Proxies are client side representations of server side resources. They
|
||||
* allow communication between client and server objects.
|
||||
*
|
||||
* The context maintains a list of all proxies, including a core proxy
|
||||
* object and a registry object.
|
||||
*
|
||||
* See also \subpage page_proxy
|
||||
*
|
||||
* \section sec_client_api_context Context
|
||||
*
|
||||
* \subsection ssec_context_create Create
|
||||
*
|
||||
* To create a new context use pw_context_new(). You will
|
||||
* need to pass a \ref pw_loop implementation to use as the event loop.
|
||||
*
|
||||
* A typical loop would be created with pw_thread_loop_new() but
|
||||
* other implementation are possible.
|
||||
*
|
||||
* You will also need to pass properties for the context. Use
|
||||
* pw_fill_context_properties() to get a default set of properties.
|
||||
*
|
||||
* After creating the context, you can track the state of the context
|
||||
* by listening for the state_changed signal.
|
||||
*
|
||||
* \subsection ssec_client_api_context_connect Connecting
|
||||
*
|
||||
* A context must be connected to a server before any operation can be
|
||||
* issued. Calling pw_context_connect() will initiate the connection
|
||||
* procedure.
|
||||
*
|
||||
* When connecting, the context will automatically create a registry
|
||||
* proxy to get notified of server objects. This behaviour can be disabled
|
||||
* by passing the \ref PW_CONTEXT_FLAG_NO_REGISTRY. You can create your
|
||||
* own registry later from the core_proxy member of the context.
|
||||
*
|
||||
* The context will automatically create proxies for all remote objects
|
||||
* and will bind to them. Use the subscription signal to reveive
|
||||
* notifications about objects. You can also disable this behaviour
|
||||
* with the \ref PW_CONTEXT_FLAG_NO_PROXY flag and manually bind to
|
||||
* the objects you are interested in.
|
||||
*
|
||||
* \subsection ssec_client_api_context_functions Streams
|
||||
*
|
||||
* Data exchange with the PipeWire server is done with the \ref pw_stream
|
||||
* object. \subpage page_streams
|
||||
*
|
||||
* \subsection ssec_client_api_context_disconnect Disconnect
|
||||
*
|
||||
* Use pw_context_disconnect() to disconnect from the server.
|
||||
*/
|
||||
|
||||
#include <pipewire/client/map.h>
|
||||
#include <pipewire/client/loop.h>
|
||||
#include <pipewire/client/properties.h>
|
||||
#include <pipewire/client/protocol.h>
|
||||
#include <pipewire/client/subscribe.h>
|
||||
#include <pipewire/client/proxy.h>
|
||||
#include <pipewire/client/type.h>
|
||||
|
||||
/** \enum pw_context_state The state of a \ref pw_context \memberof pw_context */
|
||||
enum pw_context_state {
|
||||
PW_CONTEXT_STATE_ERROR = -1, /**< context is in error */
|
||||
PW_CONTEXT_STATE_UNCONNECTED = 0, /**< not connected */
|
||||
PW_CONTEXT_STATE_CONNECTING = 1, /**< connecting to PipeWire daemon */
|
||||
PW_CONTEXT_STATE_CONNECTED = 2, /**< context is connected and ready */
|
||||
};
|
||||
|
||||
/** Convert a \ref pw_context_state to a readable string \memberof pw_context */
|
||||
const char *pw_context_state_as_string(enum pw_context_state state);
|
||||
|
||||
/** \enum pw_context_flags Extra flags passed to pw_context_connect() \memberof pw_context */
|
||||
enum pw_context_flags {
|
||||
PW_CONTEXT_FLAG_NONE = 0, /**< no flags */
|
||||
PW_CONTEXT_FLAG_NO_REGISTRY = (1 << 0), /**< don't create the registry object */
|
||||
PW_CONTEXT_FLAG_NO_PROXY = (1 << 1), /**< don't automatically create proxies for
|
||||
* server side objects */
|
||||
};
|
||||
|
||||
/** \class pw_context
|
||||
*
|
||||
* \brief Represents a connection with the PipeWire server
|
||||
*
|
||||
* a \ref pw_context is created and used to connect to the server.
|
||||
* A \ref pw_proxy for the core object will automatically be created
|
||||
* when connecting.
|
||||
*
|
||||
* See also \ref page_client_api
|
||||
*/
|
||||
struct pw_context {
|
||||
char *name; /**< the application name */
|
||||
struct pw_properties *properties; /**< extra properties */
|
||||
|
||||
struct pw_type type; /**< the type map */
|
||||
|
||||
struct pw_loop *loop; /**< the loop */
|
||||
|
||||
struct spa_support *support; /**< support for spa plugins */
|
||||
uint32_t n_support; /**< number of support items */
|
||||
|
||||
struct pw_proxy *core_proxy; /**< proxy for the core object */
|
||||
struct pw_proxy *registry_proxy; /**< proxy for the registry object. Can
|
||||
* be NULL when \ref PW_CONTEXT_FLAG_NO_PROXY
|
||||
* was specified */
|
||||
struct pw_map objects; /**< map of client side proxy objects
|
||||
* indexed with the client id */
|
||||
uint32_t n_types; /**< number of client types */
|
||||
struct pw_map types; /**< client types */
|
||||
|
||||
struct spa_list extension_list; /**< list of \ref pw_extension objects */
|
||||
struct spa_list stream_list; /**< list of \ref pw_stream objects */
|
||||
struct spa_list proxy_list; /**< list of \ref pw_proxy objects */
|
||||
|
||||
struct pw_protocol *protocol; /**< the protocol in use */
|
||||
void *protocol_private; /**< private data for the protocol */
|
||||
|
||||
enum pw_context_state state; /**< context state */
|
||||
char *error; /**< error string */
|
||||
/** Signal emited when the state changes */
|
||||
PW_SIGNAL(state_changed, (struct pw_listener *listener, struct pw_context *context));
|
||||
|
||||
/** Signal emited when a global is added/changed/removed */
|
||||
PW_SIGNAL(subscription, (struct pw_listener *listener,
|
||||
struct pw_context *context,
|
||||
enum pw_subscription_event event, uint32_t type, uint32_t id));
|
||||
|
||||
/** Signal emited when the context is destroyed */
|
||||
PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_context *context));
|
||||
};
|
||||
|
||||
/** Create a new unconnected context \memberof pw_context
|
||||
* \return a new unconnected context */
|
||||
struct pw_context *
|
||||
pw_context_new(struct pw_loop *loop, /**< a \ref pw_loop to use as event loop */
|
||||
const char *name, /**< an application name */
|
||||
struct pw_properties *properties /**< optional properties, ownership of
|
||||
* the properties is taken.*/ );
|
||||
|
||||
/** Destroy a context \memberof pw_context */
|
||||
void pw_context_destroy(struct pw_context *context);
|
||||
|
||||
/** Connect to the PipeWire daemon \memberof pw_context
|
||||
* \return true on success. */
|
||||
bool pw_context_connect(struct pw_context *context, enum pw_context_flags flags);
|
||||
|
||||
/** Connect to the PipeWire daemon on the given socket \memberof pw_context
|
||||
* \param fd the connected socket to use
|
||||
* \return true on success. */
|
||||
bool pw_context_connect_fd(struct pw_context *context, enum pw_context_flags flags, int fd);
|
||||
|
||||
/** Disconnect from the daemon. \memberof pw_context */
|
||||
void pw_context_disconnect(struct pw_context *context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __PIPEWIRE_CONTEXT_H__ */
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
/* PipeWire
|
||||
* Copyright (C) 2016 Axis Communications <dev-gstreamer@axis.com>
|
||||
* @author Linus Svensson <linus.svensson@axis.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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "pipewire/client/pipewire.h"
|
||||
#include "pipewire/client/interfaces.h"
|
||||
#include "pipewire/client/utils.h"
|
||||
#include "pipewire/client/extension.h"
|
||||
|
||||
/** \cond */
|
||||
struct impl {
|
||||
struct pw_extension this;
|
||||
void *hnd;
|
||||
};
|
||||
/** \endcond */
|
||||
|
||||
/** Load an extension \memberof pw_extension
|
||||
*
|
||||
* \param context a \ref pw_context
|
||||
* \param name name of the extension to load
|
||||
* \param args A string with arguments for the extension
|
||||
* \param[out] err Return location for an error string, or NULL
|
||||
* \return A \ref pw_extension if the extension could be loaded, or NULL on failure.
|
||||
*/
|
||||
struct pw_extension *pw_extension_load(struct pw_context *context,
|
||||
const char *name, const char *args)
|
||||
{
|
||||
struct pw_extension *this;
|
||||
struct impl *impl;
|
||||
void *hnd;
|
||||
char *filename = NULL;
|
||||
const char *module_dir;
|
||||
pw_extension_init_func_t init_func;
|
||||
|
||||
module_dir = getenv("PIPEWIRE_MODULE_DIR");
|
||||
if (module_dir == NULL)
|
||||
module_dir = MODULEDIR;
|
||||
|
||||
pw_log_debug("PIPEWIRE_MODULE_DIR set to: %s", module_dir);
|
||||
|
||||
if (asprintf(&filename, "%s/%s.so", module_dir, name) < 0)
|
||||
goto no_filename;
|
||||
|
||||
pw_log_debug("trying to load extension: %s (%s)", name, filename);
|
||||
|
||||
hnd = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
|
||||
|
||||
if (hnd == NULL)
|
||||
goto open_failed;
|
||||
|
||||
if ((init_func = dlsym(hnd, PIPEWIRE_SYMBOL_EXTENSION_INIT)) == NULL)
|
||||
goto no_pw_extension;
|
||||
|
||||
impl = calloc(1, sizeof(struct impl));
|
||||
if (impl == NULL)
|
||||
goto no_mem;
|
||||
|
||||
impl->hnd = hnd;
|
||||
|
||||
this = &impl->this;
|
||||
this->context = context;
|
||||
this->filename = filename;
|
||||
this->args = args ? strdup(args) : NULL;
|
||||
this->props = NULL;
|
||||
|
||||
pw_signal_init(&this->destroy_signal);
|
||||
|
||||
if (!init_func(this, (char *) args))
|
||||
goto init_failed;
|
||||
|
||||
spa_list_insert(&context->extension_list, &this->link);
|
||||
|
||||
pw_log_debug("loaded extension: %s", filename);
|
||||
|
||||
return this;
|
||||
|
||||
no_filename:
|
||||
pw_log_error("Can't create filename: %m");
|
||||
return NULL;
|
||||
open_failed:
|
||||
pw_log_error("Failed to open module: \"%s\" %s", filename, dlerror());
|
||||
free(filename);
|
||||
return NULL;
|
||||
no_pw_extension:
|
||||
pw_log_error("\"%s\" is not a pipewire extension", name);
|
||||
dlclose(hnd);
|
||||
free(filename);
|
||||
return NULL;
|
||||
no_mem:
|
||||
pw_log_error("no memory");
|
||||
dlclose(hnd);
|
||||
free(filename);
|
||||
return NULL;
|
||||
init_failed:
|
||||
pw_log_error("\"%s\" failed to initialize", name);
|
||||
pw_extension_destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Destroy a extension
|
||||
* \param extension the extension to destroy
|
||||
* \memberof pw_extension
|
||||
*/
|
||||
void pw_extension_destroy(struct pw_extension *extension)
|
||||
{
|
||||
struct impl *impl = SPA_CONTAINER_OF(extension, struct impl, this);
|
||||
|
||||
pw_signal_emit(&extension->destroy_signal, extension);
|
||||
|
||||
if (extension->filename)
|
||||
free((char *) extension->filename);
|
||||
if (extension->args)
|
||||
free((char *) extension->args);
|
||||
if (extension->props)
|
||||
pw_properties_free(extension->props);
|
||||
dlclose(impl->hnd);
|
||||
free(impl);
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
/* PipeWire
|
||||
* Copyright (C) 2016 Axis Communications <dev-gstreamer@axis.com>
|
||||
* @author Linus Svensson <linus.svensson@axis.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_EXTENSION_H__
|
||||
#define __PIPEWIRE_EXTENSION_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <pipewire/client/context.h>
|
||||
|
||||
#define PIPEWIRE_SYMBOL_EXTENSION_INIT "pipewire__extension_init"
|
||||
|
||||
/** \class pw_extension
|
||||
*
|
||||
* A dynamically loadable extension
|
||||
*/
|
||||
struct pw_extension {
|
||||
struct pw_context *context; /**< the client context */
|
||||
struct spa_list link; /**< link in the context extension_list */
|
||||
|
||||
const char *filename; /**< filename of extension */
|
||||
const char *args; /**< argument for the extension */
|
||||
struct pw_properties *props; /**< extra properties */
|
||||
|
||||
void *user_data; /**< extension user_data */
|
||||
|
||||
/** Emited when the extension is destroyed */
|
||||
PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_extension *extension));
|
||||
};
|
||||
|
||||
/** Module init function signature \memberof pw_extension
|
||||
*
|
||||
* \param extension A \ref pw_extension
|
||||
* \param args Arguments to the extension
|
||||
* \return true on success, false otherwise
|
||||
*
|
||||
* A extension should provide an init function with this signature. This function
|
||||
* will be called when a extension is loaded.
|
||||
*/
|
||||
typedef bool (*pw_extension_init_func_t) (struct pw_extension *extension, char *args);
|
||||
|
||||
struct pw_extension *
|
||||
pw_extension_load(struct pw_context *context,
|
||||
const char *name, const char *args);
|
||||
|
||||
void
|
||||
pw_extension_destroy(struct pw_extension *extension);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __PIPEWIRE_EXTENSION_H__ */
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "pipewire/client/pipewire.h"
|
||||
|
||||
#include "pipewire/client/context.h"
|
||||
#include "pipewire/server/remote.h"
|
||||
#include "pipewire/client/subscribe.h"
|
||||
|
||||
const char *pw_node_state_as_string(enum pw_node_state state)
|
||||
|
|
@ -118,8 +118,6 @@ static struct spa_dict *pw_spa_dict_copy(struct spa_dict *dict)
|
|||
struct pw_core_info *pw_core_info_update(struct pw_core_info *info,
|
||||
const struct pw_core_info *update)
|
||||
{
|
||||
uint64_t change_mask;
|
||||
|
||||
if (update == NULL)
|
||||
return info;
|
||||
|
||||
|
|
@ -127,12 +125,9 @@ struct pw_core_info *pw_core_info_update(struct pw_core_info *info,
|
|||
info = calloc(1, sizeof(struct pw_core_info));
|
||||
if (info == NULL)
|
||||
return NULL;
|
||||
change_mask = ~0;
|
||||
} else {
|
||||
change_mask = info->change_mask | update->change_mask;
|
||||
}
|
||||
info->id = update->id;
|
||||
info->change_mask = change_mask;
|
||||
info->change_mask = update->change_mask;
|
||||
|
||||
if (update->change_mask & (1 << 0)) {
|
||||
if (info->user_name)
|
||||
|
|
@ -182,7 +177,6 @@ void pw_core_info_free(struct pw_core_info *info)
|
|||
struct pw_node_info *pw_node_info_update(struct pw_node_info *info,
|
||||
const struct pw_node_info *update)
|
||||
{
|
||||
uint64_t change_mask;
|
||||
int i;
|
||||
|
||||
if (update == NULL)
|
||||
|
|
@ -192,12 +186,9 @@ struct pw_node_info *pw_node_info_update(struct pw_node_info *info,
|
|||
info = calloc(1, sizeof(struct pw_node_info));
|
||||
if (info == NULL)
|
||||
return NULL;
|
||||
change_mask = ~0;
|
||||
} else {
|
||||
change_mask = info->change_mask | update->change_mask;
|
||||
}
|
||||
info->id = update->id;
|
||||
info->change_mask = change_mask;
|
||||
info->change_mask = update->change_mask;
|
||||
|
||||
if (update->change_mask & (1 << 0)) {
|
||||
if (info->name)
|
||||
|
|
@ -285,8 +276,6 @@ void pw_node_info_free(struct pw_node_info *info)
|
|||
struct pw_module_info *pw_module_info_update(struct pw_module_info *info,
|
||||
const struct pw_module_info *update)
|
||||
{
|
||||
uint64_t change_mask;
|
||||
|
||||
if (update == NULL)
|
||||
return info;
|
||||
|
||||
|
|
@ -294,12 +283,9 @@ struct pw_module_info *pw_module_info_update(struct pw_module_info *info,
|
|||
info = calloc(1, sizeof(struct pw_module_info));
|
||||
if (info == NULL)
|
||||
return NULL;
|
||||
change_mask = ~0;
|
||||
} else {
|
||||
change_mask = info->change_mask | update->change_mask;
|
||||
}
|
||||
info->id = update->id;
|
||||
info->change_mask = change_mask;
|
||||
info->change_mask = update->change_mask;
|
||||
|
||||
if (update->change_mask & (1 << 0)) {
|
||||
if (info->name)
|
||||
|
|
@ -341,8 +327,6 @@ void pw_module_info_free(struct pw_module_info *info)
|
|||
struct pw_client_info *pw_client_info_update(struct pw_client_info *info,
|
||||
const struct pw_client_info *update)
|
||||
{
|
||||
uint64_t change_mask;
|
||||
|
||||
if (update == NULL)
|
||||
return info;
|
||||
|
||||
|
|
@ -350,12 +334,9 @@ struct pw_client_info *pw_client_info_update(struct pw_client_info *info,
|
|||
info = calloc(1, sizeof(struct pw_client_info));
|
||||
if (info == NULL)
|
||||
return NULL;
|
||||
change_mask = ~0;
|
||||
} else {
|
||||
change_mask = info->change_mask | update->change_mask;
|
||||
}
|
||||
info->id = update->id;
|
||||
info->change_mask = change_mask;
|
||||
info->change_mask = update->change_mask;
|
||||
|
||||
if (update->change_mask & (1 << 0)) {
|
||||
if (info->props)
|
||||
|
|
@ -375,8 +356,6 @@ void pw_client_info_free(struct pw_client_info *info)
|
|||
struct pw_link_info *pw_link_info_update(struct pw_link_info *info,
|
||||
const struct pw_link_info *update)
|
||||
{
|
||||
uint64_t change_mask;
|
||||
|
||||
if (update == NULL)
|
||||
return info;
|
||||
|
||||
|
|
@ -384,12 +363,9 @@ struct pw_link_info *pw_link_info_update(struct pw_link_info *info,
|
|||
info = calloc(1, sizeof(struct pw_link_info));
|
||||
if (info == NULL)
|
||||
return NULL;
|
||||
change_mask = ~0;
|
||||
} else {
|
||||
change_mask = info->change_mask | update->change_mask;
|
||||
}
|
||||
info->id = update->id;
|
||||
info->change_mask = change_mask;
|
||||
info->change_mask = update->change_mask;
|
||||
|
||||
if (update->change_mask & (1 << 0))
|
||||
info->output_node_id = update->output_node_id;
|
||||
|
|
|
|||
|
|
@ -27,9 +27,6 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct pw_context;
|
||||
|
||||
#include <pipewire/client/context.h>
|
||||
#include <pipewire/client/properties.h>
|
||||
|
||||
/** \enum pw_node_state The different node states \memberof pw_node */
|
||||
|
|
@ -102,19 +99,6 @@ pw_core_info_update(struct pw_core_info *info,
|
|||
/** Free a \ref pw_core_info \memberof pw_introspect */
|
||||
void pw_core_info_free(struct pw_core_info *info);
|
||||
|
||||
/** Callback with information about the PipeWire core
|
||||
* \param c A \ref pw_context
|
||||
* \param res A result code
|
||||
* \param info a \ref pw_core_info
|
||||
* \param user_data user data as passed to \ref pw_context_get_core_info()
|
||||
*
|
||||
* \memberof pw_introspect
|
||||
*/
|
||||
typedef void (*pw_core_info_cb_t) (struct pw_context *c,
|
||||
int res, const struct pw_core_info *info, void *user_data);
|
||||
|
||||
void pw_context_get_core_info(struct pw_context *context, pw_core_info_cb_t cb, void *user_data);
|
||||
|
||||
/** The module information. Extra information can be added in later versions \memberof pw_introspect */
|
||||
struct pw_module_info {
|
||||
uint32_t id; /**< server side id of the module */
|
||||
|
|
@ -133,28 +117,6 @@ pw_module_info_update(struct pw_module_info *info,
|
|||
/** Free a \ref pw_module_info \memberof pw_introspect */
|
||||
void pw_module_info_free(struct pw_module_info *info);
|
||||
|
||||
|
||||
|
||||
/** Callback with information about a module
|
||||
* \param c A \ref pw_context
|
||||
* \param res A result code
|
||||
* \param info a \ref pw_module_info
|
||||
* \param user_data user data as passed to \ref pw_context_list_module_info()
|
||||
*
|
||||
* \memberof pw_introspect
|
||||
*/
|
||||
typedef void (*pw_module_info_cb_t) (struct pw_context *c,
|
||||
int res, const struct pw_module_info *info, void *user_data);
|
||||
|
||||
void
|
||||
pw_context_list_module_info(struct pw_context *context,
|
||||
pw_module_info_cb_t cb, void *user_data);
|
||||
|
||||
|
||||
void
|
||||
pw_context_get_module_info_by_id(struct pw_context *context,
|
||||
uint32_t id, pw_module_info_cb_t cb, void *user_data);
|
||||
|
||||
/** The client information. Extra information can be added in later versions \memberof pw_introspect */
|
||||
struct pw_client_info {
|
||||
uint32_t id; /**< server side id of the client */
|
||||
|
|
@ -171,25 +133,6 @@ pw_client_info_update(struct pw_client_info *info,
|
|||
void pw_client_info_free(struct pw_client_info *info);
|
||||
|
||||
|
||||
/** Callback with information about a client
|
||||
* \param c A \ref pw_context
|
||||
* \param res A result code
|
||||
* \param info a \ref pw_client_info
|
||||
* \param user_data user data as passed to \ref pw_context_list_client_info()
|
||||
*
|
||||
* \memberof pw_introspect
|
||||
*/
|
||||
typedef void (*pw_client_info_cb_t) (struct pw_context *c,
|
||||
int res, const struct pw_client_info *info, void *user_data);
|
||||
|
||||
void
|
||||
pw_context_list_client_info(struct pw_context *context,
|
||||
pw_client_info_cb_t cb, void *user_data);
|
||||
|
||||
void
|
||||
pw_context_get_client_info_by_id(struct pw_context *context,
|
||||
uint32_t id, pw_client_info_cb_t cb, void *user_data);
|
||||
|
||||
/** The node information. Extra information can be added in later versions \memberof pw_introspect */
|
||||
struct pw_node_info {
|
||||
uint32_t id; /**< server side id of the node */
|
||||
|
|
@ -215,24 +158,6 @@ pw_node_info_update(struct pw_node_info *info,
|
|||
void
|
||||
pw_node_info_free(struct pw_node_info *info);
|
||||
|
||||
/** Callback with information about a node
|
||||
* \param c A \ref pw_context
|
||||
* \param res A result code
|
||||
* \param info a \ref pw_node_info
|
||||
* \param user_data user data as passed to \ref pw_context_list_node_info()
|
||||
*
|
||||
* \memberof pw_introspect
|
||||
*/
|
||||
typedef void (*pw_node_info_cb_t) (struct pw_context *c,
|
||||
int res, const struct pw_node_info *info, void *user_data);
|
||||
|
||||
void
|
||||
pw_context_list_node_info(struct pw_context *context, pw_node_info_cb_t cb, void *user_data);
|
||||
|
||||
void
|
||||
pw_context_get_node_info_by_id(struct pw_context *context,
|
||||
uint32_t id, pw_node_info_cb_t cb, void *user_data);
|
||||
|
||||
|
||||
/** The link information. Extra information can be added in later versions \memberof pw_introspect */
|
||||
struct pw_link_info {
|
||||
|
|
@ -252,25 +177,6 @@ pw_link_info_update(struct pw_link_info *info,
|
|||
void
|
||||
pw_link_info_free(struct pw_link_info *info);
|
||||
|
||||
|
||||
/** Callback with information about a link
|
||||
* \param c A \ref pw_context
|
||||
* \param res A result code
|
||||
* \param info a \ref pw_link_info
|
||||
* \param user_data user data as passed to \ref pw_context_list_link_info()
|
||||
*
|
||||
* \memberof pw_introspect
|
||||
*/
|
||||
typedef void (*pw_link_info_cb_t) (struct pw_context *c,
|
||||
int res, const struct pw_link_info *info, void *user_data);
|
||||
|
||||
void
|
||||
pw_context_list_link_info(struct pw_context *context, pw_link_info_cb_t cb, void *user_data);
|
||||
|
||||
void
|
||||
pw_context_get_link_info_by_id(struct pw_context *context,
|
||||
uint32_t id, pw_link_info_cb_t cb, void *user_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
pipewire_headers = [
|
||||
'array.h',
|
||||
'connection.h',
|
||||
'context.h',
|
||||
'extension.h',
|
||||
'interfaces.h',
|
||||
'introspect.h',
|
||||
'log.h',
|
||||
|
|
@ -16,7 +13,6 @@ pipewire_headers = [
|
|||
'rtkit.h',
|
||||
'sig.h',
|
||||
'stream.h',
|
||||
'subscribe.h',
|
||||
'thread-loop.h',
|
||||
'transport.h',
|
||||
'type.h',
|
||||
|
|
@ -24,9 +20,6 @@ pipewire_headers = [
|
|||
]
|
||||
|
||||
pipewire_sources = [
|
||||
'connection.c',
|
||||
'context.c',
|
||||
'extension.c',
|
||||
'introspect.c',
|
||||
'log.c',
|
||||
'loop.c',
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ struct pw_protocol *pw_protocol_get(const char *name)
|
|||
protocol = calloc(1, sizeof(struct pw_protocol));
|
||||
protocol->name = name;
|
||||
spa_list_init(&protocol->iface_list);
|
||||
spa_list_init(&protocol->connection_list);
|
||||
spa_list_init(&protocol->listener_list);
|
||||
spa_list_insert(impl->protocol_list.prev, &protocol->link);
|
||||
|
||||
pw_log_info("Created protocol %s", name);
|
||||
|
|
|
|||
|
|
@ -29,9 +29,27 @@ extern "C" {
|
|||
|
||||
#include <pipewire/client/subscribe.h>
|
||||
#include <pipewire/client/type.h>
|
||||
#include <pipewire/client/properties.h>
|
||||
|
||||
#define PW_TYPE_PROTOCOL__Native PW_TYPE_PROTOCOL_BASE "Native"
|
||||
|
||||
struct pw_protocol_connection {
|
||||
struct spa_list link;
|
||||
struct pw_remote *remote;
|
||||
|
||||
int (*connect) (struct pw_protocol_connection *conn);
|
||||
int (*connect_fd) (struct pw_protocol_connection *conn, int fd);
|
||||
int (*disconnect) (struct pw_protocol_connection *conn);
|
||||
int (*destroy) (struct pw_protocol_connection *conn);
|
||||
};
|
||||
|
||||
struct pw_protocol_listener {
|
||||
struct spa_list link;
|
||||
struct pw_core *core;
|
||||
|
||||
int (*destroy) (struct pw_protocol_listener *listen);
|
||||
};
|
||||
|
||||
struct pw_protocol_iface {
|
||||
struct spa_list link;
|
||||
const struct pw_interface *client_iface;
|
||||
|
|
@ -42,6 +60,16 @@ struct pw_protocol {
|
|||
struct spa_list link;
|
||||
const char *name;
|
||||
struct spa_list iface_list;
|
||||
struct spa_list connection_list;
|
||||
struct spa_list listener_list;
|
||||
|
||||
struct pw_protocol_connection * (*new_connection) (struct pw_protocol *protocol,
|
||||
struct pw_remote *remote,
|
||||
struct pw_properties *properties);
|
||||
struct pw_protocol_listener * (*add_listener) (struct pw_protocol *protocol,
|
||||
struct pw_core *core,
|
||||
struct pw_properties *properties);
|
||||
void *protocol_private;
|
||||
};
|
||||
|
||||
struct pw_protocol *pw_protocol_get(const char *name);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <pipewire/client/log.h>
|
||||
#include <pipewire/client/proxy.h>
|
||||
#include <pipewire/server/core.h>
|
||||
|
||||
/** \cond */
|
||||
struct proxy {
|
||||
|
|
@ -28,7 +29,7 @@ struct proxy {
|
|||
|
||||
/** Create a proxy object with a given id and type
|
||||
*
|
||||
* \param context Context object
|
||||
* \param remote Remote object
|
||||
* \param id Id of the new object, SPA_ID_INVALID will choose a new id
|
||||
* \param type Type of the proxy object
|
||||
* \return A newly allocated proxy object or NULL on failure
|
||||
|
|
@ -36,11 +37,11 @@ struct proxy {
|
|||
* This function creates a new proxy object with the supplied id and type. The
|
||||
* proxy object will have an id assigned from the client id space.
|
||||
*
|
||||
* \sa pw_context
|
||||
* \sa pw_remote
|
||||
*
|
||||
* \memberof pw_proxy
|
||||
*/
|
||||
struct pw_proxy *pw_proxy_new(struct pw_context *context,
|
||||
struct pw_proxy *pw_proxy_new(struct pw_remote *remote,
|
||||
uint32_t id, uint32_t type,
|
||||
size_t user_data_size)
|
||||
{
|
||||
|
|
@ -52,14 +53,14 @@ struct pw_proxy *pw_proxy_new(struct pw_context *context,
|
|||
return NULL;
|
||||
|
||||
this = &impl->this;
|
||||
this->context = context;
|
||||
this->remote = remote;
|
||||
this->type = type;
|
||||
|
||||
pw_signal_init(&this->destroy_signal);
|
||||
|
||||
if (id == SPA_ID_INVALID) {
|
||||
id = pw_map_insert_new(&context->objects, this);
|
||||
} else if (!pw_map_insert_at(&context->objects, id, this))
|
||||
id = pw_map_insert_new(&remote->objects, this);
|
||||
} else if (!pw_map_insert_at(&remote->objects, id, this))
|
||||
goto in_use;
|
||||
|
||||
this->id = id;
|
||||
|
|
@ -67,18 +68,18 @@ struct pw_proxy *pw_proxy_new(struct pw_context *context,
|
|||
if (user_data_size > 0)
|
||||
this->user_data = SPA_MEMBER(impl, sizeof(struct proxy), void);
|
||||
|
||||
this->iface = pw_protocol_get_interface(context->protocol,
|
||||
spa_type_map_get_type(context->type.map, type),
|
||||
this->iface = pw_protocol_get_interface(remote->protocol,
|
||||
spa_type_map_get_type(remote->core->type.map, type),
|
||||
false);
|
||||
|
||||
spa_list_insert(&this->context->proxy_list, &this->link);
|
||||
spa_list_insert(&this->remote->proxy_list, &this->link);
|
||||
|
||||
pw_log_debug("proxy %p: new %u", this, this->id);
|
||||
pw_log_debug("proxy %p: new %u, remote %p", this, this->id, remote);
|
||||
|
||||
return this;
|
||||
|
||||
in_use:
|
||||
pw_log_error("proxy %p: id %u in use for context %p", this, id, context);
|
||||
pw_log_error("proxy %p: id %u in use for remote %p", this, id, remote);
|
||||
free(impl);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -100,7 +101,7 @@ int pw_proxy_set_implementation(struct pw_proxy *proxy,
|
|||
*
|
||||
* \param proxy Proxy object to destroy
|
||||
*
|
||||
* \note This is normally called by \ref pw_context when the server
|
||||
* \note This is normally called by \ref pw_remote when the server
|
||||
* decides to destroy the server side object
|
||||
* \memberof pw_proxy
|
||||
*/
|
||||
|
|
@ -111,7 +112,7 @@ void pw_proxy_destroy(struct pw_proxy *proxy)
|
|||
pw_log_debug("proxy %p: destroy %u", proxy, proxy->id);
|
||||
pw_signal_emit(&proxy->destroy_signal, proxy);
|
||||
|
||||
pw_map_remove(&proxy->context->objects, proxy->id);
|
||||
pw_map_remove(&proxy->remote->objects, proxy->id);
|
||||
spa_list_remove(&proxy->link);
|
||||
|
||||
if (proxy->destroy)
|
||||
|
|
|
|||
|
|
@ -24,10 +24,9 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <pipewire/client/connection.h>
|
||||
#include <pipewire/client/context.h>
|
||||
#include <pipewire/client/type.h>
|
||||
#include <pipewire/client/utils.h>
|
||||
#include <pipewire/server/remote.h>
|
||||
|
||||
/** \page page_proxy Proxy
|
||||
*
|
||||
|
|
@ -88,8 +87,8 @@ extern "C" {
|
|||
* See \ref page_proxy
|
||||
*/
|
||||
struct pw_proxy {
|
||||
struct pw_context *context; /**< the owner context of this proxy */
|
||||
struct spa_list link; /**< link in the context */
|
||||
struct pw_remote *remote; /**< the owner remote of this proxy */
|
||||
struct spa_list link; /**< link in the remote */
|
||||
|
||||
uint32_t id; /**< client side id */
|
||||
uint32_t type; /**< object type id */
|
||||
|
|
@ -107,7 +106,7 @@ struct pw_proxy {
|
|||
};
|
||||
|
||||
struct pw_proxy *
|
||||
pw_proxy_new(struct pw_context *context,
|
||||
pw_proxy_new(struct pw_remote *remote,
|
||||
uint32_t id,
|
||||
uint32_t type,
|
||||
size_t user_data_size);
|
||||
|
|
|
|||
|
|
@ -30,10 +30,10 @@
|
|||
#include "pipewire/client/interfaces.h"
|
||||
#include "pipewire/client/array.h"
|
||||
#include "pipewire/client/connection.h"
|
||||
#include "pipewire/client/context.h"
|
||||
#include "pipewire/client/stream.h"
|
||||
#include "pipewire/client/transport.h"
|
||||
#include "pipewire/client/utils.h"
|
||||
#include "pipewire/client/stream.h"
|
||||
#include "pipewire/extensions/client-node.h"
|
||||
|
||||
/** \cond */
|
||||
|
|
@ -180,7 +180,7 @@ const char *pw_stream_state_as_string(enum pw_stream_state state)
|
|||
return "invalid-state";
|
||||
}
|
||||
|
||||
struct pw_stream *pw_stream_new(struct pw_context *context,
|
||||
struct pw_stream *pw_stream_new(struct pw_remote *remote,
|
||||
const char *name, struct pw_properties *props)
|
||||
{
|
||||
struct stream *impl;
|
||||
|
|
@ -203,9 +203,9 @@ struct pw_stream *pw_stream_new(struct pw_context *context,
|
|||
|
||||
this->properties = props;
|
||||
|
||||
this->context = context;
|
||||
this->remote = remote;
|
||||
this->name = strdup(name);
|
||||
impl->type_client_node = spa_type_map_get_id(context->type.map, PIPEWIRE_TYPE_NODE_BASE "Client");
|
||||
impl->type_client_node = spa_type_map_get_id(remote->core->type.map, PIPEWIRE_TYPE_NODE_BASE "Client");
|
||||
|
||||
pw_signal_init(&this->destroy_signal);
|
||||
pw_signal_init(&this->state_changed);
|
||||
|
|
@ -224,7 +224,7 @@ struct pw_stream *pw_stream_new(struct pw_context *context,
|
|||
impl->pending_seq = SPA_ID_INVALID;
|
||||
spa_list_init(&impl->free);
|
||||
|
||||
spa_list_insert(&context->stream_list, &this->link);
|
||||
spa_list_insert(&remote->stream_list, &this->link);
|
||||
|
||||
return this;
|
||||
|
||||
|
|
@ -238,11 +238,11 @@ static void unhandle_socket(struct pw_stream *stream)
|
|||
struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
|
||||
|
||||
if (impl->rtsocket_source) {
|
||||
pw_loop_destroy_source(stream->context->loop, impl->rtsocket_source);
|
||||
pw_loop_destroy_source(stream->remote->core->data_loop, impl->rtsocket_source);
|
||||
impl->rtsocket_source = NULL;
|
||||
}
|
||||
if (impl->timeout_source) {
|
||||
pw_loop_destroy_source(stream->context->loop, impl->timeout_source);
|
||||
pw_loop_destroy_source(stream->remote->core->data_loop, impl->timeout_source);
|
||||
impl->timeout_source = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -349,6 +349,7 @@ static void add_port_update(struct pw_stream *stream, uint32_t change_mask)
|
|||
{
|
||||
struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
|
||||
|
||||
|
||||
pw_client_node_do_port_update(impl->node_proxy,
|
||||
impl->direction,
|
||||
impl->port_id,
|
||||
|
|
@ -367,7 +368,7 @@ static inline void send_need_input(struct pw_stream *stream)
|
|||
uint64_t cmd = 1;
|
||||
|
||||
pw_transport_add_event(impl->trans,
|
||||
&SPA_EVENT_INIT(stream->context->type.event_transport.NeedInput));
|
||||
&SPA_EVENT_INIT(stream->remote->core->type.event_transport.NeedInput));
|
||||
write(impl->rtwritefd, &cmd, 8);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -378,7 +379,7 @@ static inline void send_have_output(struct pw_stream *stream)
|
|||
uint64_t cmd = 1;
|
||||
|
||||
pw_transport_add_event(impl->trans,
|
||||
&SPA_EVENT_INIT(stream->context->type.event_transport.HaveOutput));
|
||||
&SPA_EVENT_INIT(stream->remote->core->type.event_transport.HaveOutput));
|
||||
write(impl->rtwritefd, &cmd, 8);
|
||||
}
|
||||
|
||||
|
|
@ -387,7 +388,7 @@ static void add_request_clock_update(struct pw_stream *stream)
|
|||
struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
|
||||
|
||||
pw_client_node_do_event(impl->node_proxy, (struct spa_event *)
|
||||
&SPA_EVENT_NODE_REQUEST_CLOCK_UPDATE_INIT(stream->context->type.
|
||||
&SPA_EVENT_NODE_REQUEST_CLOCK_UPDATE_INIT(stream->remote->core->type.
|
||||
event_node.
|
||||
RequestClockUpdate,
|
||||
SPA_EVENT_NODE_REQUEST_CLOCK_UPDATE_TIME,
|
||||
|
|
@ -465,9 +466,9 @@ static inline void reuse_buffer(struct pw_stream *stream, uint32_t id)
|
|||
static void handle_rtnode_event(struct pw_stream *stream, struct spa_event *event)
|
||||
{
|
||||
struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
|
||||
struct pw_context *context = impl->this.context;
|
||||
struct pw_remote *remote = impl->this.remote;
|
||||
|
||||
if (SPA_EVENT_TYPE(event) == context->type.event_transport.HaveOutput) {
|
||||
if (SPA_EVENT_TYPE(event) == remote->core->type.event_transport.HaveOutput) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < impl->trans->area->n_input_ports; i++) {
|
||||
|
|
@ -482,7 +483,7 @@ static void handle_rtnode_event(struct pw_stream *stream, struct spa_event *even
|
|||
input->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
send_need_input(stream);
|
||||
} else if (SPA_EVENT_TYPE(event) == context->type.event_transport.NeedInput) {
|
||||
} else if (SPA_EVENT_TYPE(event) == remote->core->type.event_transport.NeedInput) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < impl->trans->area->n_output_ports; i++) {
|
||||
|
|
@ -498,7 +499,7 @@ static void handle_rtnode_event(struct pw_stream *stream, struct spa_event *even
|
|||
impl->in_need_buffer = true;
|
||||
pw_signal_emit(&stream->need_buffer, stream);
|
||||
impl->in_need_buffer = false;
|
||||
} else if (SPA_EVENT_TYPE(event) == context->type.event_transport.ReuseBuffer) {
|
||||
} else if (SPA_EVENT_TYPE(event) == remote->core->type.event_transport.ReuseBuffer) {
|
||||
struct pw_event_transport_reuse_buffer *p =
|
||||
(struct pw_event_transport_reuse_buffer *) event;
|
||||
|
||||
|
|
@ -547,15 +548,15 @@ static void handle_socket(struct pw_stream *stream, int rtreadfd, int rtwritefd)
|
|||
|
||||
impl->rtreadfd = rtreadfd;
|
||||
impl->rtwritefd = rtwritefd;
|
||||
impl->rtsocket_source = pw_loop_add_io(stream->context->loop,
|
||||
impl->rtsocket_source = pw_loop_add_io(stream->remote->core->data_loop,
|
||||
impl->rtreadfd,
|
||||
SPA_IO_ERR | SPA_IO_HUP,
|
||||
true, on_rtsocket_condition, stream);
|
||||
|
||||
impl->timeout_source = pw_loop_add_timer(stream->context->loop, on_timeout, stream);
|
||||
impl->timeout_source = pw_loop_add_timer(stream->remote->core->main_loop, on_timeout, stream);
|
||||
interval.tv_sec = 0;
|
||||
interval.tv_nsec = 100000000;
|
||||
pw_loop_update_timer(stream->context->loop, impl->timeout_source, NULL, &interval, false);
|
||||
pw_loop_update_timer(stream->remote->core->main_loop, impl->timeout_source, NULL, &interval, false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -563,26 +564,26 @@ static bool
|
|||
handle_node_command(struct pw_stream *stream, uint32_t seq, const struct spa_command *command)
|
||||
{
|
||||
struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
|
||||
struct pw_context *context = stream->context;
|
||||
struct pw_remote *remote = stream->remote;
|
||||
|
||||
if (SPA_COMMAND_TYPE(command) == context->type.command_node.Pause) {
|
||||
if (SPA_COMMAND_TYPE(command) == remote->core->type.command_node.Pause) {
|
||||
add_async_complete(stream, seq, SPA_RESULT_OK);
|
||||
|
||||
if (stream->state == PW_STREAM_STATE_STREAMING) {
|
||||
pw_log_debug("stream %p: pause %d", stream, seq);
|
||||
|
||||
pw_loop_update_io(stream->context->loop,
|
||||
pw_loop_update_io(stream->remote->core->data_loop,
|
||||
impl->rtsocket_source, SPA_IO_ERR | SPA_IO_HUP);
|
||||
|
||||
stream_set_state(stream, PW_STREAM_STATE_PAUSED, NULL);
|
||||
}
|
||||
} else if (SPA_COMMAND_TYPE(command) == context->type.command_node.Start) {
|
||||
} else if (SPA_COMMAND_TYPE(command) == remote->core->type.command_node.Start) {
|
||||
add_async_complete(stream, seq, SPA_RESULT_OK);
|
||||
|
||||
if (stream->state == PW_STREAM_STATE_PAUSED) {
|
||||
pw_log_debug("stream %p: start %d %d", stream, seq, impl->direction);
|
||||
|
||||
pw_loop_update_io(stream->context->loop,
|
||||
pw_loop_update_io(stream->remote->core->data_loop,
|
||||
impl->rtsocket_source,
|
||||
SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP);
|
||||
|
||||
|
|
@ -595,7 +596,7 @@ handle_node_command(struct pw_stream *stream, uint32_t seq, const struct spa_com
|
|||
}
|
||||
stream_set_state(stream, PW_STREAM_STATE_STREAMING, NULL);
|
||||
}
|
||||
} else if (SPA_COMMAND_TYPE(command) == context->type.command_node.ClockUpdate) {
|
||||
} else if (SPA_COMMAND_TYPE(command) == remote->core->type.command_node.ClockUpdate) {
|
||||
struct spa_command_node_clock_update *cu = (__typeof__(cu)) command;
|
||||
|
||||
if (cu->body.flags.value & SPA_COMMAND_NODE_CLOCK_UPDATE_FLAG_LIVE) {
|
||||
|
|
@ -791,13 +792,13 @@ client_node_use_buffers(void *object,
|
|||
SPA_MEMBER(bid->buf_ptr, offset + sizeof(struct spa_chunk) * j,
|
||||
struct spa_chunk);
|
||||
|
||||
if (d->type == stream->context->type.data.Id) {
|
||||
if (d->type == stream->remote->core->type.data.Id) {
|
||||
struct mem_id *bmid = find_mem(stream, SPA_PTR_TO_UINT32(d->data));
|
||||
d->type = stream->context->type.data.MemFd;
|
||||
d->type = stream->remote->core->type.data.MemFd;
|
||||
d->data = NULL;
|
||||
d->fd = bmid->fd;
|
||||
pw_log_debug(" data %d %u -> fd %d", j, bmid->id, bmid->fd);
|
||||
} else if (d->type == stream->context->type.data.MemPtr) {
|
||||
} else if (d->type == stream->remote->core->type.data.MemPtr) {
|
||||
d->data = SPA_MEMBER(bid->buf_ptr, SPA_PTR_TO_INT(d->data), void);
|
||||
d->fd = -1;
|
||||
pw_log_debug(" data %d %u -> mem %p", j, bid->id, d->data);
|
||||
|
|
@ -913,7 +914,7 @@ pw_stream_connect(struct pw_stream *stream,
|
|||
if (flags & PW_STREAM_FLAG_AUTOCONNECT)
|
||||
pw_properties_set(stream->properties, "pipewire.autoconnect", "1");
|
||||
|
||||
impl->node_proxy = pw_proxy_new(stream->context,
|
||||
impl->node_proxy = pw_proxy_new(stream->remote,
|
||||
SPA_ID_INVALID,
|
||||
impl->type_client_node,
|
||||
0);
|
||||
|
|
@ -927,7 +928,7 @@ pw_stream_connect(struct pw_stream *stream,
|
|||
pw_signal_add(&impl->node_proxy->destroy_signal,
|
||||
&impl->node_proxy_destroy, on_node_proxy_destroy);
|
||||
|
||||
pw_core_do_create_node(stream->context->core_proxy,
|
||||
pw_core_do_create_node(stream->remote->core_proxy,
|
||||
"client-node",
|
||||
"client-node",
|
||||
&stream->properties->dict,
|
||||
|
|
@ -1009,7 +1010,7 @@ bool pw_stream_recycle_buffer(struct pw_stream *stream, uint32_t id)
|
|||
{
|
||||
struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
|
||||
struct pw_event_transport_reuse_buffer rb = PW_EVENT_TRANSPORT_REUSE_BUFFER_INIT
|
||||
(stream->context->type.event_transport.ReuseBuffer, impl->port_id, id);
|
||||
(stream->remote->core->type.event_transport.ReuseBuffer, impl->port_id, id);
|
||||
struct buffer_id *bid;
|
||||
uint64_t cmd = 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
#include <spa/buffer.h>
|
||||
#include <spa/format.h>
|
||||
|
||||
#include <pipewire/client/context.h>
|
||||
#include <pipewire/server/remote.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -204,8 +204,8 @@ struct pw_time {
|
|||
* See also \ref page_streams and \ref page_client_api
|
||||
*/
|
||||
struct pw_stream {
|
||||
struct pw_context *context; /**< the owner context */
|
||||
struct spa_list link; /**< link in the context */
|
||||
struct pw_remote *remote; /**< the owner remote */
|
||||
struct spa_list link; /**< link in the remote */
|
||||
|
||||
char *name; /**< the name of the stream */
|
||||
uint32_t node_id; /**< node id for remote node, available from
|
||||
|
|
@ -243,7 +243,7 @@ struct pw_stream {
|
|||
/** Create a new unconneced \ref pw_stream \memberof pw_stream
|
||||
* \return a newly allocated \ref pw_stream */
|
||||
struct pw_stream *
|
||||
pw_stream_new(struct pw_context *context, /**< a \ref pw_context */
|
||||
pw_stream_new(struct pw_remote *remote, /**< a \ref pw_remote */
|
||||
const char *name, /**< a stream name */
|
||||
struct pw_properties *props /**< stream properties, ownership is taken */);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,63 +0,0 @@
|
|||
/* 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_SUBSCRIBE_H__
|
||||
#define __PIPEWIRE_SUBSCRIBE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PIPEWIRE_TYPE__Core "PipeWire:Object:Core"
|
||||
#define PIPEWIRE_TYPE_CORE_BASE PIPEWIRE_TYPE__Core ":"
|
||||
|
||||
#define PIPEWIRE_TYPE__Registry "PipeWire:Object:Registry"
|
||||
#define PIPEWIRE_TYPE_REGISYRY_BASE PIPEWIRE_TYPE__Registry ":"
|
||||
|
||||
#define PIPEWIRE_TYPE__Node "PipeWire:Object:Node"
|
||||
#define PIPEWIRE_TYPE_NODE_BASE PIPEWIRE_TYPE__Node ":"
|
||||
|
||||
#define PIPEWIRE_TYPE__Client "PipeWire:Object:Client"
|
||||
#define PIPEWIRE_TYPE_CLIENT_BASE PIPEWIRE_TYPE__Client ":"
|
||||
|
||||
#define PIPEWIRE_TYPE__Link "PipeWire:Object:Link"
|
||||
#define PIPEWIRE_TYPE_LINK_BASE PIPEWIRE_TYPE__Link ":"
|
||||
|
||||
#define PIPEWIRE_TYPE__Module "PipeWire:Object:Module"
|
||||
#define PIPEWIRE_TYPE_MODULE_BASE PIPEWIRE_TYPE__Module ":"
|
||||
|
||||
#define PW_TYPE__Protocol "PipeWire:Protocol"
|
||||
#define PW_TYPE_PROTOCOL_BASE PW_TYPE__Protocol ":"
|
||||
|
||||
/** \enum pw_subscription_event
|
||||
* subscription events
|
||||
*/
|
||||
enum pw_subscription_event {
|
||||
PW_SUBSCRIPTION_EVENT_NEW = 0,
|
||||
PW_SUBSCRIPTION_EVENT_CHANGE = 1,
|
||||
PW_SUBSCRIPTION_EVENT_REMOVE = 2,
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __PIPEWIRE_SUBSCRIBE_H__ */
|
||||
|
|
@ -33,6 +33,27 @@ extern "C" {
|
|||
#include <pipewire/client/map.h>
|
||||
#include <pipewire/client/transport.h>
|
||||
|
||||
#define PIPEWIRE_TYPE__Core "PipeWire:Object:Core"
|
||||
#define PIPEWIRE_TYPE_CORE_BASE PIPEWIRE_TYPE__Core ":"
|
||||
|
||||
#define PIPEWIRE_TYPE__Registry "PipeWire:Object:Registry"
|
||||
#define PIPEWIRE_TYPE_REGISYRY_BASE PIPEWIRE_TYPE__Registry ":"
|
||||
|
||||
#define PIPEWIRE_TYPE__Node "PipeWire:Object:Node"
|
||||
#define PIPEWIRE_TYPE_NODE_BASE PIPEWIRE_TYPE__Node ":"
|
||||
|
||||
#define PIPEWIRE_TYPE__Client "PipeWire:Object:Client"
|
||||
#define PIPEWIRE_TYPE_CLIENT_BASE PIPEWIRE_TYPE__Client ":"
|
||||
|
||||
#define PIPEWIRE_TYPE__Link "PipeWire:Object:Link"
|
||||
#define PIPEWIRE_TYPE_LINK_BASE PIPEWIRE_TYPE__Link ":"
|
||||
|
||||
#define PIPEWIRE_TYPE__Module "PipeWire:Object:Module"
|
||||
#define PIPEWIRE_TYPE_MODULE_BASE PIPEWIRE_TYPE__Module ":"
|
||||
|
||||
#define PW_TYPE__Protocol "PipeWire:Protocol"
|
||||
#define PW_TYPE_PROTOCOL_BASE PW_TYPE__Protocol ":"
|
||||
|
||||
/** \class pw_interface
|
||||
* \brief The interface definition
|
||||
*
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
loop = pw_main_loop_new();
|
||||
|
||||
core = pw_core_new(loop, NULL);
|
||||
core = pw_core_new(loop->loop, NULL);
|
||||
|
||||
pw_daemon_config_run_commands(config, core);
|
||||
|
||||
|
|
|
|||
532
pipewire/examples/local-v4l2.c
Normal file
532
pipewire/examples/local-v4l2.c
Normal file
|
|
@ -0,0 +1,532 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include <spa/type-map.h>
|
||||
#include <spa/format-utils.h>
|
||||
#include <spa/video/format-utils.h>
|
||||
#include <spa/format-builder.h>
|
||||
#include <spa/props.h>
|
||||
|
||||
#include <pipewire/client/pipewire.h>
|
||||
#include <pipewire/client/sig.h>
|
||||
#include <pipewire/server/module.h>
|
||||
#include <pipewire/server/node-factory.h>
|
||||
#include <spa/lib/debug.h>
|
||||
|
||||
struct type {
|
||||
uint32_t format;
|
||||
uint32_t props;
|
||||
struct spa_type_meta meta;
|
||||
struct spa_type_data data;
|
||||
struct spa_type_media_type media_type;
|
||||
struct spa_type_media_subtype media_subtype;
|
||||
struct spa_type_format_video format_video;
|
||||
struct spa_type_video_format video_format;
|
||||
};
|
||||
|
||||
static inline void init_type(struct type *type, struct spa_type_map *map)
|
||||
{
|
||||
type->format = spa_type_map_get_id(map, SPA_TYPE__Format);
|
||||
type->props = spa_type_map_get_id(map, SPA_TYPE__Props);
|
||||
spa_type_meta_map(map, &type->meta);
|
||||
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_video_map(map, &type->format_video);
|
||||
spa_type_video_format_map(map, &type->video_format);
|
||||
}
|
||||
|
||||
#define WIDTH 640
|
||||
#define HEIGHT 480
|
||||
#define BPP 3
|
||||
|
||||
struct data {
|
||||
struct type type;
|
||||
|
||||
const char *path;
|
||||
|
||||
SDL_Renderer *renderer;
|
||||
SDL_Window *window;
|
||||
SDL_Texture *texture;
|
||||
|
||||
bool running;
|
||||
struct pw_loop *loop;
|
||||
struct spa_source *timer;
|
||||
|
||||
struct pw_core *core;
|
||||
struct pw_node *node;
|
||||
struct pw_port *port;
|
||||
struct spa_port_info port_info;
|
||||
|
||||
struct pw_node *v4l2;
|
||||
|
||||
struct pw_link *link;
|
||||
|
||||
uint8_t buffer[1024];
|
||||
|
||||
struct spa_video_info_raw format;
|
||||
int32_t stride;
|
||||
|
||||
uint8_t params_buffer[1024];
|
||||
struct spa_param *params[2];
|
||||
|
||||
struct spa_buffer *buffers[32];
|
||||
int n_buffers;
|
||||
};
|
||||
|
||||
static void handle_events(struct data *data)
|
||||
{
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_QUIT:
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct {
|
||||
Uint32 format;
|
||||
uint32_t id;
|
||||
} video_formats[] = {
|
||||
{
|
||||
SDL_PIXELFORMAT_UNKNOWN, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_INDEX1LSB, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_UNKNOWN, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_INDEX1LSB, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_INDEX1MSB, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_INDEX4LSB, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_INDEX4MSB, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_INDEX8, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_RGB332, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_RGB444, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_RGB555, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_BGR555, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_ARGB4444, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_RGBA4444, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_ABGR4444, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_BGRA4444, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_ARGB1555, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_RGBA5551, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_ABGR1555, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_BGRA5551, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_RGB565, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_BGR565, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_RGB24, offsetof(struct spa_type_video_format, RGB),}, {
|
||||
SDL_PIXELFORMAT_RGB888, offsetof(struct spa_type_video_format, RGB),}, {
|
||||
SDL_PIXELFORMAT_RGBX8888, offsetof(struct spa_type_video_format, RGBx),}, {
|
||||
SDL_PIXELFORMAT_BGR24, offsetof(struct spa_type_video_format, BGR),}, {
|
||||
SDL_PIXELFORMAT_BGR888, offsetof(struct spa_type_video_format, BGR),}, {
|
||||
SDL_PIXELFORMAT_BGRX8888, offsetof(struct spa_type_video_format, BGRx),}, {
|
||||
SDL_PIXELFORMAT_ARGB2101010, offsetof(struct spa_type_video_format, UNKNOWN),}, {
|
||||
SDL_PIXELFORMAT_RGBA8888, offsetof(struct spa_type_video_format, RGBA),}, {
|
||||
SDL_PIXELFORMAT_ARGB8888, offsetof(struct spa_type_video_format, ARGB),}, {
|
||||
SDL_PIXELFORMAT_BGRA8888, offsetof(struct spa_type_video_format, BGRA),}, {
|
||||
SDL_PIXELFORMAT_ABGR8888, offsetof(struct spa_type_video_format, ABGR),}, {
|
||||
SDL_PIXELFORMAT_YV12, offsetof(struct spa_type_video_format, YV12),}, {
|
||||
SDL_PIXELFORMAT_IYUV, offsetof(struct spa_type_video_format, I420),}, {
|
||||
SDL_PIXELFORMAT_YUY2, offsetof(struct spa_type_video_format, YUY2),}, {
|
||||
SDL_PIXELFORMAT_UYVY, offsetof(struct spa_type_video_format, UYVY),}, {
|
||||
SDL_PIXELFORMAT_YVYU, offsetof(struct spa_type_video_format, YVYU),}, {
|
||||
SDL_PIXELFORMAT_NV12, offsetof(struct spa_type_video_format, NV12),}, {
|
||||
SDL_PIXELFORMAT_NV21, offsetof(struct spa_type_video_format, NV21),}};
|
||||
|
||||
static uint32_t sdl_format_to_id(struct data *data, Uint32 format)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SPA_N_ELEMENTS(video_formats); i++) {
|
||||
if (video_formats[i].format == format)
|
||||
return *SPA_MEMBER(&data->type.video_format, video_formats[i].id, uint32_t);
|
||||
}
|
||||
return data->type.video_format.UNKNOWN;
|
||||
}
|
||||
|
||||
static Uint32 id_to_sdl_format(struct data *data, uint32_t id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SPA_N_ELEMENTS(video_formats); i++) {
|
||||
if (*SPA_MEMBER(&data->type.video_format, video_formats[i].id, uint32_t) == id)
|
||||
return video_formats[i].format;
|
||||
}
|
||||
return SDL_PIXELFORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
#define PROP(f,key,type,...) \
|
||||
SPA_POD_PROP (f,key,0,type,1,__VA_ARGS__)
|
||||
#define PROP_U_MM(f,key,type,...) \
|
||||
SPA_POD_PROP (f,key,SPA_POD_PROP_FLAG_UNSET | \
|
||||
SPA_POD_PROP_RANGE_MIN_MAX,type,3,__VA_ARGS__)
|
||||
|
||||
static int impl_port_enum_formats(struct pw_port *port,
|
||||
struct spa_format **format,
|
||||
const struct spa_format *filter,
|
||||
int32_t index)
|
||||
{
|
||||
struct data *data = port->user_data;
|
||||
const struct spa_format *formats[1];
|
||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(data->buffer, sizeof(data->buffer));
|
||||
struct spa_pod_frame f[2];
|
||||
SDL_RendererInfo info;
|
||||
int i, c;
|
||||
|
||||
if (index != 0)
|
||||
return SPA_RESULT_ENUM_END;
|
||||
|
||||
SDL_GetRendererInfo(data->renderer, &info);
|
||||
|
||||
spa_pod_builder_push_format(&b, &f[0], data->type.format,
|
||||
data->type.media_type.video,
|
||||
data->type.media_subtype.raw);
|
||||
|
||||
spa_pod_builder_push_prop(&b, &f[1], data->type.format_video.format,
|
||||
SPA_POD_PROP_FLAG_UNSET |
|
||||
SPA_POD_PROP_RANGE_ENUM);
|
||||
for (i = 0, c = 0; i < info.num_texture_formats; i++) {
|
||||
uint32_t id = sdl_format_to_id(data, info.texture_formats[i]);
|
||||
if (id == 0)
|
||||
continue;
|
||||
if (c++ == 0)
|
||||
spa_pod_builder_id(&b, id);
|
||||
spa_pod_builder_id(&b, id);
|
||||
}
|
||||
for (i = 0; i < SPA_N_ELEMENTS(video_formats); i++) {
|
||||
uint32_t id =
|
||||
*SPA_MEMBER(&data->type.video_format, video_formats[i].id,
|
||||
uint32_t);
|
||||
if (id != data->type.video_format.UNKNOWN)
|
||||
spa_pod_builder_id(&b, id);
|
||||
}
|
||||
spa_pod_builder_pop(&b, &f[1]);
|
||||
spa_pod_builder_add(&b,
|
||||
PROP_U_MM(&f[1], data->type.format_video.size, SPA_POD_TYPE_RECTANGLE,
|
||||
WIDTH, HEIGHT,
|
||||
1, 1, info.max_texture_width, info.max_texture_height),
|
||||
PROP_U_MM(&f[1], data->type.format_video.framerate, SPA_POD_TYPE_FRACTION,
|
||||
25, 1,
|
||||
0, 1, 30, 1),
|
||||
0);
|
||||
spa_pod_builder_pop(&b, &f[0]);
|
||||
formats[0] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_format);
|
||||
|
||||
spa_debug_format(formats[0]);
|
||||
|
||||
*format = (struct spa_format *)formats[0];
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static int impl_port_set_format(struct pw_port *port, uint32_t flags, struct spa_format *format)
|
||||
{
|
||||
struct data *data = port->user_data;
|
||||
struct pw_core *core = data->core;
|
||||
struct spa_pod_builder b = { NULL };
|
||||
struct spa_pod_frame f[2];
|
||||
Uint32 sdl_format;
|
||||
void *d;
|
||||
|
||||
if (format == NULL) {
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
spa_debug_format(format);
|
||||
|
||||
spa_format_video_raw_parse(format, &data->format, &data->type.format_video);
|
||||
|
||||
sdl_format = id_to_sdl_format(data, data->format.format);
|
||||
if (sdl_format == SDL_PIXELFORMAT_UNKNOWN)
|
||||
return SPA_RESULT_ERROR;
|
||||
|
||||
data->texture = SDL_CreateTexture(data->renderer,
|
||||
sdl_format,
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
data->format.size.width,
|
||||
data->format.size.height);
|
||||
SDL_LockTexture(data->texture, NULL, &d, &data->stride);
|
||||
SDL_UnlockTexture(data->texture);
|
||||
|
||||
spa_pod_builder_init(&b, data->params_buffer, sizeof(data->params_buffer));
|
||||
spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_buffers.Buffers,
|
||||
PROP(&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT,
|
||||
data->stride * data->format.size.height),
|
||||
PROP(&f[1], core->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT,
|
||||
data->stride),
|
||||
PROP_U_MM(&f[1], core->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT,
|
||||
32,
|
||||
2, 32),
|
||||
PROP(&f[1], core->type.param_alloc_buffers.align, SPA_POD_TYPE_INT,
|
||||
16));
|
||||
data->params[0] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param);
|
||||
|
||||
spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_meta_enable.MetaEnable,
|
||||
PROP(&f[1], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID,
|
||||
core->type.meta.Header),
|
||||
PROP(&f[1], core->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT,
|
||||
sizeof(struct spa_meta_header)));
|
||||
data->params[1] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param);
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static int impl_port_get_format(struct pw_port *port, const struct spa_format **format)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int impl_port_get_info(struct pw_port *port, const struct spa_port_info **info)
|
||||
{
|
||||
struct data *data = port->user_data;
|
||||
|
||||
data->port_info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS;
|
||||
data->port_info.rate = 0;
|
||||
data->port_info.props = NULL;
|
||||
|
||||
*info = &data->port_info;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static int impl_port_enum_params(struct pw_port *port, uint32_t index, struct spa_param **param)
|
||||
{
|
||||
struct data *data = port->user_data;
|
||||
|
||||
if (index >= 2)
|
||||
return SPA_RESULT_ENUM_END;
|
||||
|
||||
*param = data->params[index];
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static int impl_port_set_param(struct pw_port *port, struct spa_param *param)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int impl_port_use_buffers(struct pw_port *port, struct spa_buffer **buffers, uint32_t n_buffers)
|
||||
{
|
||||
struct data *data = port->user_data;
|
||||
int i;
|
||||
for (i = 0; i < n_buffers; i++)
|
||||
data->buffers[i] = buffers[i];
|
||||
data->n_buffers = n_buffers;
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static int impl_port_alloc_buffers(struct pw_port *port,
|
||||
struct spa_param **params, uint32_t n_params,
|
||||
struct spa_buffer **buffers, uint32_t *n_buffers)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int impl_port_reuse_buffer(struct pw_port *port, uint32_t buffer_id)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int impl_port_send_command(struct pw_port *port, struct spa_command *command)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static const struct pw_port_implementation impl_port = {
|
||||
PW_VERSION_PORT_IMPLEMENTATION,
|
||||
impl_port_enum_formats,
|
||||
impl_port_set_format,
|
||||
impl_port_get_format,
|
||||
impl_port_get_info,
|
||||
impl_port_enum_params,
|
||||
impl_port_set_param,
|
||||
impl_port_use_buffers,
|
||||
impl_port_alloc_buffers,
|
||||
impl_port_reuse_buffer,
|
||||
impl_port_send_command,
|
||||
};
|
||||
|
||||
static int impl_node_get_props(struct pw_node *node, struct spa_props **props)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int impl_node_set_props(struct pw_node *node, const struct spa_props *props)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int impl_node_send_command(struct pw_node *node,
|
||||
struct spa_command *command)
|
||||
{
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static struct pw_port* impl_node_add_port(struct pw_node *node,
|
||||
enum pw_direction direction,
|
||||
uint32_t port_id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int impl_node_process_input(struct pw_node *node)
|
||||
{
|
||||
struct data *data = node->user_data;
|
||||
struct pw_port *port = data->port;
|
||||
struct spa_buffer *buf;
|
||||
uint8_t *map;
|
||||
void *sdata, *ddata;
|
||||
int sstride, dstride, ostride;
|
||||
int i;
|
||||
uint8_t *src, *dst;
|
||||
|
||||
buf = port->buffers[port->io.buffer_id];
|
||||
|
||||
if (buf->datas[0].type == data->type.data.MemFd ||
|
||||
buf->datas[0].type == data->type.data.DmaBuf) {
|
||||
map = mmap(NULL, buf->datas[0].maxsize + buf->datas[0].mapoffset, PROT_READ,
|
||||
MAP_PRIVATE, buf->datas[0].fd, 0);
|
||||
sdata = SPA_MEMBER(map, buf->datas[0].mapoffset, uint8_t);
|
||||
} else if (buf->datas[0].type == data->type.data.MemPtr) {
|
||||
map = NULL;
|
||||
sdata = buf->datas[0].data;
|
||||
} else
|
||||
return SPA_RESULT_ERROR;
|
||||
|
||||
if (SDL_LockTexture(data->texture, NULL, &ddata, &dstride) < 0) {
|
||||
fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError());
|
||||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
sstride = buf->datas[0].chunk->stride;
|
||||
ostride = SPA_MIN(sstride, dstride);
|
||||
|
||||
src = sdata;
|
||||
dst = ddata;
|
||||
for (i = 0; i < data->format.size.height; i++) {
|
||||
memcpy(dst, src, ostride);
|
||||
src += sstride;
|
||||
dst += dstride;
|
||||
}
|
||||
SDL_UnlockTexture(data->texture);
|
||||
|
||||
SDL_RenderClear(data->renderer);
|
||||
SDL_RenderCopy(data->renderer, data->texture, NULL, NULL);
|
||||
SDL_RenderPresent(data->renderer);
|
||||
|
||||
if (map)
|
||||
munmap(map, buf->datas[0].maxsize);
|
||||
|
||||
handle_events(data);
|
||||
|
||||
port->io.status = SPA_RESULT_NEED_BUFFER;
|
||||
|
||||
return SPA_RESULT_NEED_BUFFER;
|
||||
}
|
||||
|
||||
static int impl_node_process_output(struct pw_node *node)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static const struct pw_node_implementation impl_node = {
|
||||
PW_VERSION_NODE_IMPLEMENTATION,
|
||||
impl_node_get_props,
|
||||
impl_node_set_props,
|
||||
impl_node_send_command,
|
||||
impl_node_add_port,
|
||||
impl_node_process_input,
|
||||
impl_node_process_output,
|
||||
};
|
||||
|
||||
static void make_nodes(struct data *data)
|
||||
{
|
||||
struct pw_node_factory *factory;
|
||||
struct pw_properties *props;
|
||||
|
||||
data->node = pw_node_new(data->core, NULL, "SDL-sink", NULL, 0);
|
||||
data->node->user_data = data;
|
||||
data->node->implementation = &impl_node;
|
||||
|
||||
data->port = pw_port_new(PW_DIRECTION_INPUT, 0, 0);
|
||||
data->port->user_data = data;
|
||||
data->port->implementation = &impl_port;
|
||||
pw_port_add(data->port, data->node);
|
||||
pw_node_export(data->node);
|
||||
|
||||
factory = pw_core_find_node_factory(data->core, "spa-node-factory");
|
||||
|
||||
props = pw_properties_new("spa.library.name", "v4l2/libspa-v4l2",
|
||||
"spa.factory.name", "v4l2-source", NULL);
|
||||
data->v4l2 = pw_node_factory_create_node(factory, NULL, "v4l2-source", props);
|
||||
|
||||
data->link = pw_link_new(data->core,
|
||||
pw_node_get_free_port(data->v4l2, PW_DIRECTION_OUTPUT),
|
||||
data->port,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
pw_link_activate(data->link);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct data data = { 0, };
|
||||
char *err;
|
||||
|
||||
pw_init(&argc, &argv);
|
||||
|
||||
data.loop = pw_loop_new();
|
||||
data.running = true;
|
||||
data.core = pw_core_new(data.loop, NULL);
|
||||
data.path = argc > 1 ? argv[1] : NULL;
|
||||
|
||||
pw_module_load(data.core, "libpipewire-module-spa-node-factory", NULL, &err);
|
||||
|
||||
init_type(&data.type, data.core->type.map);
|
||||
|
||||
spa_debug_set_type_map(data.core->type.map);
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||
printf("can't initialize SDL: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SDL_CreateWindowAndRenderer
|
||||
(WIDTH, HEIGHT, SDL_WINDOW_RESIZABLE, &data.window, &data.renderer)) {
|
||||
printf("can't create window: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
make_nodes(&data);
|
||||
|
||||
pw_loop_enter(data.loop);
|
||||
while (data.running) {
|
||||
pw_loop_iterate(data.loop, -1);
|
||||
}
|
||||
pw_loop_leave(data.loop);
|
||||
|
||||
pw_loop_destroy(data.loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,13 +1,18 @@
|
|||
executable('video-src',
|
||||
'video-src.c',
|
||||
install: false,
|
||||
dependencies : [pipewire_dep],
|
||||
dependencies : [pipewirecore_dep],
|
||||
)
|
||||
|
||||
if sdl_dep.found()
|
||||
executable('video-play',
|
||||
'video-play.c',
|
||||
install: false,
|
||||
dependencies : [pipewire_dep,sdl_dep],
|
||||
dependencies : [pipewire_dep,pipewirecore_dep, sdl_dep],
|
||||
)
|
||||
executable('local-v4l2',
|
||||
'local-v4l2.c',
|
||||
install: false,
|
||||
dependencies : [pipewire_dep,pipewirecore_dep, sdl_dep],
|
||||
)
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -72,7 +72,8 @@ struct data {
|
|||
struct pw_loop *loop;
|
||||
struct spa_source *timer;
|
||||
|
||||
struct pw_context *context;
|
||||
struct pw_core *core;
|
||||
struct pw_remote *remote;
|
||||
struct pw_listener on_state_changed;
|
||||
|
||||
struct pw_stream *stream;
|
||||
|
|
@ -234,7 +235,8 @@ on_stream_format_changed(struct pw_listener *listener,
|
|||
struct pw_stream *stream, struct spa_format *format)
|
||||
{
|
||||
struct data *data = SPA_CONTAINER_OF(listener, struct data, on_stream_format_changed);
|
||||
struct pw_context *ctx = stream->context;
|
||||
struct pw_remote *remote = stream->remote;
|
||||
struct pw_core *core = remote->core;
|
||||
struct spa_pod_builder b = { NULL };
|
||||
struct spa_pod_frame f[2];
|
||||
struct spa_param *params[2];
|
||||
|
|
@ -265,35 +267,35 @@ on_stream_format_changed(struct pw_listener *listener,
|
|||
SDL_UnlockTexture(data->texture);
|
||||
|
||||
spa_pod_builder_init(&b, data->params_buffer, sizeof(data->params_buffer));
|
||||
spa_pod_builder_object(&b, &f[0], 0, ctx->type.param_alloc_buffers.Buffers,
|
||||
PROP(&f[1], ctx->type.param_alloc_buffers.size, SPA_POD_TYPE_INT,
|
||||
spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_buffers.Buffers,
|
||||
PROP(&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT,
|
||||
data->stride * data->format.size.height),
|
||||
PROP(&f[1], ctx->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT,
|
||||
PROP(&f[1], core->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT,
|
||||
data->stride),
|
||||
PROP_U_MM(&f[1], ctx->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT,
|
||||
PROP_U_MM(&f[1], core->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT,
|
||||
32,
|
||||
2, 32),
|
||||
PROP(&f[1], ctx->type.param_alloc_buffers.align, SPA_POD_TYPE_INT,
|
||||
PROP(&f[1], core->type.param_alloc_buffers.align, SPA_POD_TYPE_INT,
|
||||
16));
|
||||
params[0] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param);
|
||||
|
||||
spa_pod_builder_object(&b, &f[0], 0, ctx->type.param_alloc_meta_enable.MetaEnable,
|
||||
PROP(&f[1], ctx->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID,
|
||||
ctx->type.meta.Header),
|
||||
PROP(&f[1], ctx->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT,
|
||||
spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_meta_enable.MetaEnable,
|
||||
PROP(&f[1], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID,
|
||||
core->type.meta.Header),
|
||||
PROP(&f[1], core->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT,
|
||||
sizeof(struct spa_meta_header)));
|
||||
params[1] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param);
|
||||
|
||||
pw_stream_finish_format(stream, SPA_RESULT_OK, params, 2);
|
||||
}
|
||||
|
||||
static void on_state_changed(struct pw_listener *listener, struct pw_context *context)
|
||||
static void on_state_changed(struct pw_listener *listener, struct pw_remote *remote)
|
||||
{
|
||||
struct data *data = SPA_CONTAINER_OF(listener, struct data, on_state_changed);
|
||||
|
||||
switch (context->state) {
|
||||
switch (remote->state) {
|
||||
case PW_CONTEXT_STATE_ERROR:
|
||||
printf("context error: %s\n", context->error);
|
||||
printf("remote error: %s\n", remote->error);
|
||||
data->running = false;
|
||||
break;
|
||||
|
||||
|
|
@ -306,10 +308,10 @@ static void on_state_changed(struct pw_listener *listener, struct pw_context *co
|
|||
SDL_RendererInfo info;
|
||||
int i, c;
|
||||
|
||||
printf("context state: \"%s\"\n",
|
||||
pw_context_state_as_string(context->state));
|
||||
printf("remote state: \"%s\"\n",
|
||||
pw_remote_state_as_string(remote->state));
|
||||
|
||||
data->stream = pw_stream_new(context, "video-play", NULL);
|
||||
data->stream = pw_stream_new(remote, "video-play", NULL);
|
||||
|
||||
SDL_GetRendererInfo(data->renderer, &info);
|
||||
|
||||
|
|
@ -364,7 +366,7 @@ static void on_state_changed(struct pw_listener *listener, struct pw_context *co
|
|||
break;
|
||||
}
|
||||
default:
|
||||
printf("context state: \"%s\"\n", pw_context_state_as_string(context->state));
|
||||
printf("remote state: \"%s\"\n", pw_remote_state_as_string(remote->state));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -377,12 +379,13 @@ int main(int argc, char *argv[])
|
|||
|
||||
data.loop = pw_loop_new();
|
||||
data.running = true;
|
||||
data.context = pw_context_new(data.loop, "video-play", NULL);
|
||||
data.core = pw_core_new(data.loop, NULL);
|
||||
data.remote = pw_remote_new(data.core, NULL);
|
||||
data.path = argc > 1 ? argv[1] : NULL;
|
||||
|
||||
init_type(&data.type, data.context->type.map);
|
||||
init_type(&data.type, data.core->type.map);
|
||||
|
||||
spa_debug_set_type_map(data.context->type.map);
|
||||
spa_debug_set_type_map(data.core->type.map);
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||
printf("can't initialize SDL: %s\n", SDL_GetError());
|
||||
|
|
@ -395,9 +398,9 @@ int main(int argc, char *argv[])
|
|||
return -1;
|
||||
}
|
||||
|
||||
pw_signal_add(&data.context->state_changed, &data.on_state_changed, on_state_changed);
|
||||
pw_signal_add(&data.remote->state_changed, &data.on_state_changed, on_state_changed);
|
||||
|
||||
pw_context_connect(data.context, PW_CONTEXT_FLAG_NO_REGISTRY);
|
||||
pw_remote_connect(data.remote);
|
||||
|
||||
pw_loop_enter(data.loop);
|
||||
while (data.running) {
|
||||
|
|
@ -405,7 +408,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
pw_loop_leave(data.loop);
|
||||
|
||||
pw_context_destroy(data.context);
|
||||
pw_remote_destroy(data.remote);
|
||||
pw_loop_destroy(data.loop);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -64,7 +64,8 @@ struct data {
|
|||
struct pw_loop *loop;
|
||||
struct spa_source *timer;
|
||||
|
||||
struct pw_context *context;
|
||||
struct pw_core *core;
|
||||
struct pw_remote *remote;
|
||||
struct pw_listener on_state_changed;
|
||||
|
||||
struct pw_stream *stream;
|
||||
|
|
@ -175,7 +176,8 @@ on_stream_format_changed(struct pw_listener *listener,
|
|||
struct pw_stream *stream, struct spa_format *format)
|
||||
{
|
||||
struct data *data = SPA_CONTAINER_OF(listener, struct data, on_stream_format_changed);
|
||||
struct pw_context *ctx = stream->context;
|
||||
struct pw_remote *remote = stream->remote;
|
||||
struct pw_core *core = remote->core;
|
||||
struct spa_pod_builder b = { NULL };
|
||||
struct spa_pod_frame f[2];
|
||||
struct spa_param *params[2];
|
||||
|
|
@ -189,49 +191,49 @@ on_stream_format_changed(struct pw_listener *listener,
|
|||
data->stride = SPA_ROUND_UP_N(data->format.size.width * BPP, 4);
|
||||
|
||||
spa_pod_builder_init(&b, data->params_buffer, sizeof(data->params_buffer));
|
||||
spa_pod_builder_object(&b, &f[0], 0, ctx->type.param_alloc_buffers.Buffers,
|
||||
PROP(&f[1], ctx->type.param_alloc_buffers.size, SPA_POD_TYPE_INT,
|
||||
spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_buffers.Buffers,
|
||||
PROP(&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT,
|
||||
data->stride * data->format.size.height),
|
||||
PROP(&f[1], ctx->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT,
|
||||
PROP(&f[1], core->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT,
|
||||
data->stride),
|
||||
PROP_U_MM(&f[1], ctx->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT,
|
||||
PROP_U_MM(&f[1], core->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT,
|
||||
32,
|
||||
2, 32),
|
||||
PROP(&f[1], ctx->type.param_alloc_buffers.align, SPA_POD_TYPE_INT,
|
||||
PROP(&f[1], core->type.param_alloc_buffers.align, SPA_POD_TYPE_INT,
|
||||
16));
|
||||
params[0] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param);
|
||||
|
||||
spa_pod_builder_object(&b, &f[0], 0, ctx->type.param_alloc_meta_enable.MetaEnable,
|
||||
PROP(&f[1], ctx->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID,
|
||||
ctx->type.meta.Header),
|
||||
PROP(&f[1], ctx->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT,
|
||||
spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_meta_enable.MetaEnable,
|
||||
PROP(&f[1], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID,
|
||||
core->type.meta.Header),
|
||||
PROP(&f[1], core->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT,
|
||||
sizeof(struct spa_meta_header)));
|
||||
params[1] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param);
|
||||
|
||||
pw_stream_finish_format(stream, SPA_RESULT_OK, params, 2);
|
||||
}
|
||||
|
||||
static void on_state_changed(struct pw_listener *listener, struct pw_context *context)
|
||||
static void on_state_changed(struct pw_listener *listener, struct pw_remote *remote)
|
||||
{
|
||||
struct data *data = SPA_CONTAINER_OF(listener, struct data, on_state_changed);
|
||||
|
||||
switch (context->state) {
|
||||
case PW_CONTEXT_STATE_ERROR:
|
||||
printf("context error: %s\n", context->error);
|
||||
switch (remote->state) {
|
||||
case PW_REMOTE_STATE_ERROR:
|
||||
printf("remote error: %s\n", remote->error);
|
||||
data->running = false;
|
||||
break;
|
||||
|
||||
case PW_CONTEXT_STATE_CONNECTED:
|
||||
case PW_REMOTE_STATE_CONNECTED:
|
||||
{
|
||||
const struct spa_format *formats[1];
|
||||
uint8_t buffer[1024];
|
||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
|
||||
struct spa_pod_frame f[2];
|
||||
|
||||
printf("context state: \"%s\"\n",
|
||||
pw_context_state_as_string(context->state));
|
||||
printf("remote state: \"%s\"\n",
|
||||
pw_remote_state_as_string(remote->state));
|
||||
|
||||
data->stream = pw_stream_new(context, "video-src", NULL);
|
||||
data->stream = pw_stream_new(remote, "video-src", NULL);
|
||||
|
||||
spa_pod_builder_format(&b, &f[0], data->type.format,
|
||||
data->type.media_type.video,
|
||||
|
|
@ -257,7 +259,7 @@ static void on_state_changed(struct pw_listener *listener, struct pw_context *co
|
|||
break;
|
||||
}
|
||||
default:
|
||||
printf("context state: \"%s\"\n", pw_context_state_as_string(context->state));
|
||||
printf("remote state: \"%s\"\n", pw_remote_state_as_string(remote->state));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -270,15 +272,16 @@ int main(int argc, char *argv[])
|
|||
|
||||
data.loop = pw_loop_new();
|
||||
data.running = true;
|
||||
data.context = pw_context_new(data.loop, "video-src", NULL);
|
||||
data.core = pw_core_new(data.loop, NULL);
|
||||
data.remote = pw_remote_new(data.core, NULL);
|
||||
|
||||
init_type(&data.type, data.context->type.map);
|
||||
init_type(&data.type, data.core->type.map);
|
||||
|
||||
data.timer = pw_loop_add_timer(data.loop, on_timeout, &data);
|
||||
|
||||
pw_signal_add(&data.context->state_changed, &data.on_state_changed, on_state_changed);
|
||||
pw_signal_add(&data.remote->state_changed, &data.on_state_changed, on_state_changed);
|
||||
|
||||
pw_context_connect(data.context, PW_CONTEXT_FLAG_NO_REGISTRY);
|
||||
pw_remote_connect(data.remote);
|
||||
|
||||
pw_loop_enter(data.loop);
|
||||
while (data.running) {
|
||||
|
|
@ -286,7 +289,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
pw_loop_leave(data.loop);
|
||||
|
||||
pw_context_destroy(data.context);
|
||||
pw_remote_destroy(data.remote);
|
||||
pw_loop_destroy(data.loop);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ new_node (GstPipeWireDeviceProvider *self, const struct pw_node_info *info)
|
|||
type = GST_PIPEWIRE_DEVICE_TYPE_SINK;
|
||||
|
||||
for (i = 0; i < info->n_input_formats; i++) {
|
||||
GstCaps *c1 = gst_caps_from_format (info->input_formats[i], self->context->type.map);
|
||||
GstCaps *c1 = gst_caps_from_format (info->input_formats[i], self->core->type.map);
|
||||
if (c1)
|
||||
gst_caps_append (caps, c1);
|
||||
}
|
||||
|
|
@ -215,7 +215,7 @@ new_node (GstPipeWireDeviceProvider *self, const struct pw_node_info *info)
|
|||
else if (info->max_output_ports > 0 && info->max_input_ports == 0) {
|
||||
type = GST_PIPEWIRE_DEVICE_TYPE_SOURCE;
|
||||
for (i = 0; i < info->n_output_formats; i++) {
|
||||
GstCaps *c1 = gst_caps_from_format (info->output_formats[i], self->context->type.map);
|
||||
GstCaps *c1 = gst_caps_from_format (info->output_formats[i], self->core->type.map);
|
||||
if (c1)
|
||||
gst_caps_append (caps, c1);
|
||||
}
|
||||
|
|
@ -242,22 +242,6 @@ new_node (GstPipeWireDeviceProvider *self, const struct pw_node_info *info)
|
|||
props);
|
||||
}
|
||||
|
||||
static void
|
||||
get_node_info_cb (struct pw_context *context,
|
||||
int res,
|
||||
const struct pw_node_info *info,
|
||||
gpointer user_data)
|
||||
{
|
||||
GstPipeWireDeviceProvider *self = user_data;
|
||||
|
||||
if (info) {
|
||||
GstDevice *dev;
|
||||
dev = new_node (self, info);
|
||||
if (dev)
|
||||
gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), dev);
|
||||
}
|
||||
}
|
||||
|
||||
static GstPipeWireDevice *
|
||||
find_device (GstDeviceProvider *provider, uint32_t id)
|
||||
{
|
||||
|
|
@ -279,66 +263,11 @@ find_device (GstDeviceProvider *provider, uint32_t id)
|
|||
}
|
||||
|
||||
static void
|
||||
on_context_subscription (struct pw_listener *listener,
|
||||
struct pw_context *context,
|
||||
enum pw_subscription_event event,
|
||||
uint32_t type,
|
||||
uint32_t id)
|
||||
{
|
||||
GstPipeWireDeviceProvider *self = SPA_CONTAINER_OF (listener, GstPipeWireDeviceProvider, ctx_subscription);
|
||||
GstDeviceProvider *provider = GST_DEVICE_PROVIDER (self);
|
||||
GstPipeWireDevice *dev;
|
||||
|
||||
if (type != context->type.node)
|
||||
return;
|
||||
|
||||
dev = find_device (provider, id);
|
||||
|
||||
if (event == PW_SUBSCRIPTION_EVENT_NEW) {
|
||||
if (dev == NULL)
|
||||
pw_context_get_node_info_by_id (context,
|
||||
id,
|
||||
get_node_info_cb,
|
||||
self);
|
||||
} else if (event == PW_SUBSCRIPTION_EVENT_REMOVE) {
|
||||
if (dev != NULL) {
|
||||
gst_device_provider_device_remove (GST_DEVICE_PROVIDER (self),
|
||||
GST_DEVICE (dev));
|
||||
}
|
||||
}
|
||||
if (dev)
|
||||
gst_object_unref (dev);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GstPipeWireDeviceProvider *self;
|
||||
gboolean end;
|
||||
GList **devices;
|
||||
} InfoData;
|
||||
|
||||
static void
|
||||
list_node_info_cb (struct pw_context *c,
|
||||
int res,
|
||||
const struct pw_node_info *info,
|
||||
void *user_data)
|
||||
{
|
||||
InfoData *data = user_data;
|
||||
if (info) {
|
||||
GstDevice *dev = new_node (data->self, info);
|
||||
if (dev)
|
||||
*data->devices = g_list_prepend (*data->devices, gst_object_ref_sink (dev));
|
||||
} else {
|
||||
data->end = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_core_info_cb (struct pw_context *c,
|
||||
int res,
|
||||
const struct pw_core_info *info,
|
||||
void *user_data)
|
||||
get_core_info (struct pw_remote *remote,
|
||||
void *user_data)
|
||||
{
|
||||
GstDeviceProvider *provider = user_data;
|
||||
struct pw_core_info *info = remote->info;
|
||||
const gchar *value;
|
||||
|
||||
if (info == NULL || info->props == NULL)
|
||||
|
|
@ -361,35 +290,113 @@ get_core_info_cb (struct pw_context *c,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_sync_reply (struct pw_listener *listener, struct pw_remote *remote, uint32_t seq)
|
||||
{
|
||||
GstPipeWireDeviceProvider *self = SPA_CONTAINER_OF (listener, GstPipeWireDeviceProvider, on_sync_reply);
|
||||
if (seq == 1)
|
||||
pw_core_do_sync(self->registry->remote->core_proxy, 2);
|
||||
else if (seq == 2)
|
||||
self->end = true;
|
||||
}
|
||||
|
||||
static void node_event_info(void *object, struct pw_node_info *info)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
GstPipeWireDeviceProvider *self = proxy->object;
|
||||
GstDevice *dev;
|
||||
|
||||
dev = new_node (self, info);
|
||||
if (dev) {
|
||||
if(self->list_only)
|
||||
*self->devices = g_list_prepend (*self->devices, gst_object_ref_sink (dev));
|
||||
else
|
||||
gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), dev);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pw_node_events node_events = {
|
||||
&node_event_info
|
||||
};
|
||||
|
||||
static void registry_event_global(void *object, uint32_t id, const char *type, uint32_t version)
|
||||
{
|
||||
struct pw_proxy *registry = object;
|
||||
GstPipeWireDeviceProvider *self = registry->object;
|
||||
struct pw_remote *remote = registry->remote;
|
||||
struct pw_core *core = remote->core;
|
||||
struct pw_proxy *proxy = NULL;
|
||||
|
||||
if (strcmp(type, PIPEWIRE_TYPE__Node))
|
||||
return;
|
||||
|
||||
proxy = pw_proxy_new(remote, SPA_ID_INVALID, core->type.node, 0);
|
||||
if (proxy == NULL)
|
||||
goto no_mem;
|
||||
|
||||
pw_proxy_set_implementation(proxy, self, PW_VERSION_NODE, &node_events, NULL);
|
||||
pw_registry_do_bind(registry, id, version, proxy->id);
|
||||
return;
|
||||
|
||||
no_mem:
|
||||
GST_ERROR_OBJECT(self, "failed to create proxy");
|
||||
return;
|
||||
}
|
||||
|
||||
static void registry_event_global_remove(void *object, uint32_t id)
|
||||
{
|
||||
struct pw_proxy *registry = object;
|
||||
GstPipeWireDeviceProvider *self = registry->object;
|
||||
GstDeviceProvider *provider = GST_DEVICE_PROVIDER (self);
|
||||
GstPipeWireDevice *dev;
|
||||
|
||||
dev = find_device (provider, id);
|
||||
if (dev != NULL) {
|
||||
gst_device_provider_device_remove (provider, GST_DEVICE (dev));
|
||||
gst_object_unref (dev);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pw_registry_events registry_events = {
|
||||
registry_event_global,
|
||||
registry_event_global_remove,
|
||||
};
|
||||
|
||||
static GList *
|
||||
gst_pipewire_device_provider_probe (GstDeviceProvider * provider)
|
||||
{
|
||||
GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (provider);
|
||||
struct pw_loop *l = NULL;
|
||||
struct pw_context *c = NULL;
|
||||
InfoData data;
|
||||
struct pw_core *c = NULL;
|
||||
struct pw_remote *r = NULL;
|
||||
struct pw_proxy *reg = NULL;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "starting probe");
|
||||
|
||||
if (!(l = pw_loop_new ()))
|
||||
return NULL;
|
||||
|
||||
if (!(c = pw_context_new (l, self->client_name, NULL)))
|
||||
if (!(c = pw_core_new (l, NULL)))
|
||||
return NULL;
|
||||
|
||||
if (!(r = pw_remote_new (c, NULL)))
|
||||
goto failed;
|
||||
|
||||
pw_context_connect (c, 0);
|
||||
pw_signal_add(&r->sync_reply, &self->on_sync_reply, on_sync_reply);
|
||||
|
||||
pw_remote_connect (r);
|
||||
|
||||
for (;;) {
|
||||
enum pw_context_state state;
|
||||
enum pw_remote_state state;
|
||||
|
||||
state = c->state;
|
||||
state = r->state;
|
||||
|
||||
if (state <= 0) {
|
||||
GST_ERROR_OBJECT (self, "Failed to connect: %s", c->error);
|
||||
GST_ERROR_OBJECT (self, "Failed to connect: %s", r->error);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (state == PW_CONTEXT_STATE_CONNECTED)
|
||||
if (state == PW_REMOTE_STATE_CONNECTED)
|
||||
break;
|
||||
|
||||
/* Wait until something happens */
|
||||
|
|
@ -397,30 +404,31 @@ gst_pipewire_device_provider_probe (GstDeviceProvider * provider)
|
|||
}
|
||||
GST_DEBUG_OBJECT (self, "connected");
|
||||
|
||||
pw_context_get_core_info (c,
|
||||
get_core_info_cb,
|
||||
self);
|
||||
get_core_info (r, self);
|
||||
|
||||
self->end = FALSE;
|
||||
self->list_only = TRUE;
|
||||
self->devices = NULL;
|
||||
|
||||
reg = pw_proxy_new(r, SPA_ID_INVALID, c->type.registry, 0);
|
||||
pw_proxy_set_implementation(reg, self, PW_VERSION_REGISTRY, ®istry_events, NULL);
|
||||
pw_core_do_get_registry(r->core_proxy, reg->id);
|
||||
pw_core_do_sync(r->core_proxy, 1);
|
||||
|
||||
data.self = self;
|
||||
data.end = FALSE;
|
||||
data.devices = NULL;
|
||||
pw_context_list_node_info (c,
|
||||
list_node_info_cb,
|
||||
&data);
|
||||
for (;;) {
|
||||
if (c->state <= 0)
|
||||
if (r->state <= 0)
|
||||
break;
|
||||
if (data.end)
|
||||
if (self->end)
|
||||
break;
|
||||
pw_loop_iterate (l, -1);
|
||||
}
|
||||
|
||||
pw_context_disconnect (c);
|
||||
pw_context_destroy (c);
|
||||
pw_remote_disconnect (r);
|
||||
pw_remote_destroy (r);
|
||||
pw_core_destroy (c);
|
||||
pw_loop_destroy (l);
|
||||
|
||||
return *data.devices;
|
||||
return *self->devices;
|
||||
|
||||
failed:
|
||||
pw_loop_destroy (l);
|
||||
|
|
@ -428,24 +436,24 @@ failed:
|
|||
}
|
||||
|
||||
static void
|
||||
on_context_state_changed (struct pw_listener *listener,
|
||||
struct pw_context *context)
|
||||
on_remote_state_changed (struct pw_listener *listener,
|
||||
struct pw_remote *remote)
|
||||
{
|
||||
GstPipeWireDeviceProvider *self = SPA_CONTAINER_OF (listener, GstPipeWireDeviceProvider, ctx_state_changed);
|
||||
enum pw_context_state state;
|
||||
GstPipeWireDeviceProvider *self = SPA_CONTAINER_OF (listener, GstPipeWireDeviceProvider, remote_state_changed);
|
||||
enum pw_remote_state state;
|
||||
|
||||
state= context->state;
|
||||
state= remote->state;
|
||||
|
||||
GST_DEBUG ("got context state %d", state);
|
||||
GST_DEBUG ("got remote state %d", state);
|
||||
|
||||
switch (state) {
|
||||
case PW_CONTEXT_STATE_CONNECTING:
|
||||
case PW_REMOTE_STATE_CONNECTING:
|
||||
break;
|
||||
case PW_CONTEXT_STATE_UNCONNECTED:
|
||||
case PW_CONTEXT_STATE_CONNECTED:
|
||||
case PW_REMOTE_STATE_UNCONNECTED:
|
||||
case PW_REMOTE_STATE_CONNECTED:
|
||||
break;
|
||||
case PW_CONTEXT_STATE_ERROR:
|
||||
GST_ERROR_OBJECT (self, "context error: %s", context->error);
|
||||
case PW_REMOTE_STATE_ERROR:
|
||||
GST_ERROR_OBJECT (self, "remote error: %s", remote->error);
|
||||
break;
|
||||
}
|
||||
pw_thread_loop_signal (self->main_loop, FALSE);
|
||||
|
|
@ -459,12 +467,18 @@ gst_pipewire_device_provider_start (GstDeviceProvider * provider)
|
|||
GST_DEBUG_OBJECT (self, "starting provider");
|
||||
|
||||
self->loop = pw_loop_new ();
|
||||
self->list_only = FALSE;
|
||||
|
||||
if (!(self->main_loop = pw_thread_loop_new (self->loop, "pipewire-device-monitor"))) {
|
||||
GST_ERROR_OBJECT (self, "Could not create PipeWire mainloop");
|
||||
goto failed_main_loop;
|
||||
}
|
||||
|
||||
if (!(self->core = pw_core_new (self->loop, NULL))) {
|
||||
GST_ERROR_OBJECT (self, "Could not create PipeWire core");
|
||||
goto failed_core;
|
||||
}
|
||||
|
||||
if (pw_thread_loop_start (self->main_loop) != SPA_RESULT_OK) {
|
||||
GST_ERROR_OBJECT (self, "Could not start PipeWire mainloop");
|
||||
goto failed_start;
|
||||
|
|
@ -472,49 +486,53 @@ gst_pipewire_device_provider_start (GstDeviceProvider * provider)
|
|||
|
||||
pw_thread_loop_lock (self->main_loop);
|
||||
|
||||
if (!(self->context = pw_context_new (self->loop, self->client_name, NULL))) {
|
||||
GST_ERROR_OBJECT (self, "Failed to create context");
|
||||
goto failed_context;
|
||||
if (!(self->remote = pw_remote_new (self->core, NULL))) {
|
||||
GST_ERROR_OBJECT (self, "Failed to create remote");
|
||||
goto failed_remote;
|
||||
}
|
||||
|
||||
pw_signal_add (&self->context->state_changed,
|
||||
&self->ctx_state_changed,
|
||||
on_context_state_changed);
|
||||
pw_signal_add (&self->context->subscription,
|
||||
&self->ctx_subscription,
|
||||
on_context_subscription);
|
||||
pw_signal_add (&self->remote->state_changed,
|
||||
&self->remote_state_changed,
|
||||
on_remote_state_changed);
|
||||
|
||||
pw_context_connect (self->context, 0);
|
||||
pw_remote_connect (self->remote);
|
||||
for (;;) {
|
||||
enum pw_context_state state;
|
||||
enum pw_remote_state state;
|
||||
|
||||
state = self->context->state;
|
||||
state = self->remote->state;
|
||||
|
||||
if (state <= 0) {
|
||||
GST_WARNING_OBJECT (self, "Failed to connect: %s", self->context->error);
|
||||
GST_WARNING_OBJECT (self, "Failed to connect: %s", self->remote->error);
|
||||
goto not_running;
|
||||
}
|
||||
|
||||
if (state == PW_CONTEXT_STATE_CONNECTED)
|
||||
if (state == PW_REMOTE_STATE_CONNECTED)
|
||||
break;
|
||||
|
||||
/* Wait until something happens */
|
||||
pw_thread_loop_wait (self->main_loop);
|
||||
}
|
||||
GST_DEBUG_OBJECT (self, "connected");
|
||||
pw_context_get_core_info (self->context,
|
||||
get_core_info_cb,
|
||||
self);
|
||||
get_core_info (self->remote, self);
|
||||
|
||||
self->registry = pw_proxy_new(self->remote, SPA_ID_INVALID, self->core->type.registry, 0);
|
||||
pw_proxy_set_implementation(self->registry, self, PW_VERSION_REGISTRY, ®istry_events, NULL);
|
||||
pw_core_do_get_registry(self->remote->core_proxy, self->registry->id);
|
||||
pw_core_do_sync(self->remote->core_proxy, 1);
|
||||
|
||||
pw_thread_loop_unlock (self->main_loop);
|
||||
|
||||
return TRUE;
|
||||
|
||||
not_running:
|
||||
pw_context_destroy (self->context);
|
||||
self->context = NULL;
|
||||
failed_context:
|
||||
pw_remote_destroy (self->remote);
|
||||
self->remote = NULL;
|
||||
failed_remote:
|
||||
pw_thread_loop_unlock (self->main_loop);
|
||||
failed_start:
|
||||
pw_core_destroy (self->core);
|
||||
self->core = NULL;
|
||||
failed_core:
|
||||
pw_thread_loop_destroy (self->main_loop);
|
||||
self->main_loop = NULL;
|
||||
failed_main_loop:
|
||||
|
|
@ -528,10 +546,10 @@ gst_pipewire_device_provider_stop (GstDeviceProvider * provider)
|
|||
{
|
||||
GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (provider);
|
||||
|
||||
if (self->context) {
|
||||
pw_context_disconnect (self->context);
|
||||
pw_context_destroy (self->context);
|
||||
self->context = NULL;
|
||||
if (self->remote) {
|
||||
pw_remote_disconnect (self->remote);
|
||||
pw_remote_destroy (self->remote);
|
||||
self->remote = NULL;
|
||||
}
|
||||
if (self->main_loop) {
|
||||
pw_thread_loop_destroy (self->main_loop);
|
||||
|
|
|
|||
|
|
@ -84,9 +84,14 @@ struct _GstPipeWireDeviceProvider {
|
|||
struct pw_loop *loop;
|
||||
struct pw_thread_loop *main_loop;
|
||||
|
||||
struct pw_context *context;
|
||||
struct pw_listener ctx_state_changed;
|
||||
struct pw_listener ctx_subscription;
|
||||
struct pw_core *core;
|
||||
struct pw_remote *remote;
|
||||
struct pw_proxy *registry;
|
||||
gboolean end;
|
||||
gboolean list_only;
|
||||
GList **devices;
|
||||
struct pw_listener remote_state_changed;
|
||||
struct pw_listener on_sync_reply;
|
||||
};
|
||||
|
||||
struct _GstPipeWireDeviceProviderClass {
|
||||
|
|
|
|||
|
|
@ -235,7 +235,8 @@ gst_pipewire_sink_class_init (GstPipeWireSinkClass * klass)
|
|||
static void
|
||||
pool_activated (GstPipeWirePool *pool, GstPipeWireSink *sink)
|
||||
{
|
||||
struct pw_context *ctx = sink->stream->context;
|
||||
struct pw_remote *remote = sink->stream->remote;
|
||||
struct pw_core *core = remote->core;
|
||||
GstStructure *config;
|
||||
GstCaps *caps;
|
||||
guint size;
|
||||
|
|
@ -250,36 +251,36 @@ pool_activated (GstPipeWirePool *pool, GstPipeWireSink *sink)
|
|||
gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers, &max_buffers);
|
||||
|
||||
spa_pod_builder_init (&b, buffer, sizeof (buffer));
|
||||
spa_pod_builder_push_object (&b, &f[0], 0, ctx->type.param_alloc_buffers.Buffers);
|
||||
spa_pod_builder_push_object (&b, &f[0], 0, core->type.param_alloc_buffers.Buffers);
|
||||
if (size == 0)
|
||||
spa_pod_builder_add (&b,
|
||||
PROP_U_MM (&f[1], ctx->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, 0, 0, INT32_MAX), 0);
|
||||
PROP_U_MM (&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, 0, 0, INT32_MAX), 0);
|
||||
else
|
||||
spa_pod_builder_add (&b,
|
||||
PROP_MM (&f[1], ctx->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, size, size, INT32_MAX), 0);
|
||||
PROP_MM (&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, size, size, INT32_MAX), 0);
|
||||
|
||||
spa_pod_builder_add (&b,
|
||||
PROP_MM (&f[1], ctx->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT, 0, 0, INT32_MAX),
|
||||
PROP_U_MM (&f[1], ctx->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT, min_buffers, min_buffers, max_buffers ? max_buffers : INT32_MAX),
|
||||
PROP (&f[1], ctx->type.param_alloc_buffers.align, SPA_POD_TYPE_INT, 16),
|
||||
PROP_MM (&f[1], core->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT, 0, 0, INT32_MAX),
|
||||
PROP_U_MM (&f[1], core->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT, min_buffers, min_buffers, max_buffers ? max_buffers : INT32_MAX),
|
||||
PROP (&f[1], core->type.param_alloc_buffers.align, SPA_POD_TYPE_INT, 16),
|
||||
0);
|
||||
spa_pod_builder_pop (&b, &f[0]);
|
||||
port_params[0] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param);
|
||||
|
||||
spa_pod_builder_object (&b, &f[0], 0, ctx->type.param_alloc_meta_enable.MetaEnable,
|
||||
PROP (&f[1], ctx->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, ctx->type.meta.Header),
|
||||
PROP (&f[1], ctx->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_meta_header)));
|
||||
spa_pod_builder_object (&b, &f[0], 0, core->type.param_alloc_meta_enable.MetaEnable,
|
||||
PROP (&f[1], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, core->type.meta.Header),
|
||||
PROP (&f[1], core->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_meta_header)));
|
||||
port_params[1] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param);
|
||||
|
||||
spa_pod_builder_object (&b, &f[0], 0, ctx->type.param_alloc_meta_enable.MetaEnable,
|
||||
PROP (&f[1], ctx->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, ctx->type.meta.Ringbuffer),
|
||||
PROP (&f[1], ctx->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_meta_ringbuffer)),
|
||||
PROP (&f[1], ctx->type.param_alloc_meta_enable.ringbufferSize, SPA_POD_TYPE_INT,
|
||||
spa_pod_builder_object (&b, &f[0], 0, core->type.param_alloc_meta_enable.MetaEnable,
|
||||
PROP (&f[1], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, core->type.meta.Ringbuffer),
|
||||
PROP (&f[1], core->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_meta_ringbuffer)),
|
||||
PROP (&f[1], core->type.param_alloc_meta_enable.ringbufferSize, SPA_POD_TYPE_INT,
|
||||
size * SPA_MAX (4,
|
||||
SPA_MAX (min_buffers, max_buffers))),
|
||||
PROP (&f[1], ctx->type.param_alloc_meta_enable.ringbufferStride, SPA_POD_TYPE_INT, 0),
|
||||
PROP (&f[1], ctx->type.param_alloc_meta_enable.ringbufferBlocks, SPA_POD_TYPE_INT, 1),
|
||||
PROP (&f[1], ctx->type.param_alloc_meta_enable.ringbufferAlign, SPA_POD_TYPE_INT, 16));
|
||||
PROP (&f[1], core->type.param_alloc_meta_enable.ringbufferStride, SPA_POD_TYPE_INT, 0),
|
||||
PROP (&f[1], core->type.param_alloc_meta_enable.ringbufferBlocks, SPA_POD_TYPE_INT, 1),
|
||||
PROP (&f[1], core->type.param_alloc_meta_enable.ringbufferAlign, SPA_POD_TYPE_INT, 16));
|
||||
port_params[2] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param);
|
||||
|
||||
pw_thread_loop_lock (sink->main_loop);
|
||||
|
|
@ -304,6 +305,7 @@ gst_pipewire_sink_init (GstPipeWireSink * sink)
|
|||
|
||||
sink->loop = pw_loop_new ();
|
||||
sink->main_loop = pw_thread_loop_new (sink->loop, "pipewire-sink-loop");
|
||||
sink->core = pw_core_new (sink->loop, NULL);
|
||||
GST_DEBUG ("loop %p %p", sink->loop, sink->main_loop);
|
||||
}
|
||||
|
||||
|
|
@ -441,6 +443,7 @@ on_add_buffer (struct pw_listener *listener,
|
|||
GstBuffer *buf;
|
||||
uint32_t i;
|
||||
ProcessMemData data;
|
||||
struct pw_core *core = pwsink->remote->core;
|
||||
|
||||
GST_LOG_OBJECT (pwsink, "add buffer");
|
||||
|
||||
|
|
@ -454,20 +457,20 @@ on_add_buffer (struct pw_listener *listener,
|
|||
data.sink = gst_object_ref (pwsink);
|
||||
data.id = id;
|
||||
data.buf = b;
|
||||
data.header = spa_buffer_find_meta (b, stream->context->type.meta.Header);
|
||||
data.header = spa_buffer_find_meta (b, core->type.meta.Header);
|
||||
|
||||
for (i = 0; i < b->n_datas; i++) {
|
||||
struct spa_data *d = &b->datas[i];
|
||||
GstMemory *gmem = NULL;
|
||||
|
||||
if (d->type == stream->context->type.data.MemFd ||
|
||||
d->type == stream->context->type.data.DmaBuf) {
|
||||
if (d->type == core->type.data.MemFd ||
|
||||
d->type == core->type.data.DmaBuf) {
|
||||
gmem = gst_fd_allocator_alloc (pwsink->allocator, dup (d->fd),
|
||||
d->mapoffset + d->maxsize, GST_FD_MEMORY_FLAG_NONE);
|
||||
gst_memory_resize (gmem, d->chunk->offset + d->mapoffset, d->chunk->size);
|
||||
data.offset = d->mapoffset;
|
||||
}
|
||||
else if (d->type == stream->context->type.data.MemPtr) {
|
||||
else if (d->type == core->type.data.MemPtr) {
|
||||
gmem = gst_memory_new_wrapped (0, d->data, d->maxsize, d->chunk->offset,
|
||||
d->chunk->size, NULL, NULL);
|
||||
data.offset = 0;
|
||||
|
|
@ -623,7 +626,7 @@ gst_pipewire_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
|||
|
||||
pwsink = GST_PIPEWIRE_SINK (bsink);
|
||||
|
||||
possible = gst_caps_to_format_all (caps, pwsink->ctx->type.map);
|
||||
possible = gst_caps_to_format_all (caps, pwsink->remote->core->type.map);
|
||||
|
||||
pw_thread_loop_lock (pwsink->main_loop);
|
||||
state = pwsink->stream->state;
|
||||
|
|
@ -755,7 +758,7 @@ gst_pipewire_sink_start (GstBaseSink * basesink)
|
|||
}
|
||||
|
||||
pw_thread_loop_lock (pwsink->main_loop);
|
||||
pwsink->stream = pw_stream_new (pwsink->ctx, pwsink->client_name, props);
|
||||
pwsink->stream = pw_stream_new (pwsink->remote, pwsink->client_name, props);
|
||||
pwsink->pool->stream = pwsink->stream;
|
||||
|
||||
pw_signal_add (&pwsink->stream->state_changed, &pwsink->stream_state_changed, on_state_changed);
|
||||
|
|
@ -789,23 +792,23 @@ gst_pipewire_sink_stop (GstBaseSink * basesink)
|
|||
}
|
||||
|
||||
static void
|
||||
on_ctx_state_changed (struct pw_listener *listener,
|
||||
struct pw_context *ctx)
|
||||
on_remote_state_changed (struct pw_listener *listener,
|
||||
struct pw_remote *remote)
|
||||
{
|
||||
GstPipeWireSink *pwsink = SPA_CONTAINER_OF (listener, GstPipeWireSink, ctx_state_changed);
|
||||
enum pw_context_state state;
|
||||
GstPipeWireSink *pwsink = SPA_CONTAINER_OF (listener, GstPipeWireSink, remote_state_changed);
|
||||
enum pw_remote_state state;
|
||||
|
||||
state = ctx->state;
|
||||
GST_DEBUG ("got context state %d", state);
|
||||
state = remote->state;
|
||||
GST_DEBUG ("got remote state %d", state);
|
||||
|
||||
switch (state) {
|
||||
case PW_CONTEXT_STATE_UNCONNECTED:
|
||||
case PW_CONTEXT_STATE_CONNECTING:
|
||||
case PW_CONTEXT_STATE_CONNECTED:
|
||||
case PW_REMOTE_STATE_UNCONNECTED:
|
||||
case PW_REMOTE_STATE_CONNECTING:
|
||||
case PW_REMOTE_STATE_CONNECTED:
|
||||
break;
|
||||
case PW_CONTEXT_STATE_ERROR:
|
||||
case PW_REMOTE_STATE_ERROR:
|
||||
GST_ELEMENT_ERROR (pwsink, RESOURCE, FAILED,
|
||||
("context error: %s", ctx->error), (NULL));
|
||||
("remote error: %s", remote->error), (NULL));
|
||||
break;
|
||||
}
|
||||
pw_thread_loop_signal (pwsink->main_loop, FALSE);
|
||||
|
|
@ -818,19 +821,19 @@ gst_pipewire_sink_open (GstPipeWireSink * pwsink)
|
|||
goto mainloop_error;
|
||||
|
||||
pw_thread_loop_lock (pwsink->main_loop);
|
||||
pwsink->ctx = pw_context_new (pwsink->loop, g_get_application_name (), NULL);
|
||||
pwsink->remote = pw_remote_new (pwsink->core, NULL);
|
||||
|
||||
pw_signal_add (&pwsink->ctx->state_changed, &pwsink->ctx_state_changed, on_ctx_state_changed);
|
||||
pw_signal_add (&pwsink->remote->state_changed, &pwsink->remote_state_changed, on_remote_state_changed);
|
||||
|
||||
pw_context_connect (pwsink->ctx, PW_CONTEXT_FLAG_NO_REGISTRY);
|
||||
pw_remote_connect (pwsink->remote);
|
||||
|
||||
while (TRUE) {
|
||||
enum pw_context_state state = pwsink->ctx->state;
|
||||
enum pw_remote_state state = pwsink->remote->state;
|
||||
|
||||
if (state == PW_CONTEXT_STATE_CONNECTED)
|
||||
if (state == PW_REMOTE_STATE_CONNECTED)
|
||||
break;
|
||||
|
||||
if (state == PW_CONTEXT_STATE_ERROR)
|
||||
if (state == PW_REMOTE_STATE_ERROR)
|
||||
goto connect_error;
|
||||
|
||||
pw_thread_loop_wait (pwsink->main_loop);
|
||||
|
|
@ -860,16 +863,16 @@ gst_pipewire_sink_close (GstPipeWireSink * pwsink)
|
|||
if (pwsink->stream) {
|
||||
pw_stream_disconnect (pwsink->stream);
|
||||
}
|
||||
if (pwsink->ctx) {
|
||||
pw_context_disconnect (pwsink->ctx);
|
||||
if (pwsink->remote) {
|
||||
pw_remote_disconnect (pwsink->remote);
|
||||
|
||||
while (TRUE) {
|
||||
enum pw_context_state state = pwsink->ctx->state;
|
||||
enum pw_remote_state state = pwsink->remote->state;
|
||||
|
||||
if (state == PW_CONTEXT_STATE_UNCONNECTED)
|
||||
if (state == PW_REMOTE_STATE_UNCONNECTED)
|
||||
break;
|
||||
|
||||
if (state == PW_CONTEXT_STATE_ERROR)
|
||||
if (state == PW_REMOTE_STATE_ERROR)
|
||||
break;
|
||||
|
||||
pw_thread_loop_wait (pwsink->main_loop);
|
||||
|
|
@ -884,9 +887,9 @@ gst_pipewire_sink_close (GstPipeWireSink * pwsink)
|
|||
pwsink->stream = NULL;
|
||||
}
|
||||
|
||||
if (pwsink->ctx) {
|
||||
pw_context_destroy (pwsink->ctx);
|
||||
pwsink->ctx = NULL;
|
||||
if (pwsink->remote) {
|
||||
pw_remote_destroy (pwsink->remote);
|
||||
pwsink->remote = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
|
|
|||
|
|
@ -80,8 +80,9 @@ struct _GstPipeWireSink {
|
|||
struct pw_loop *loop;
|
||||
struct pw_thread_loop *main_loop;
|
||||
|
||||
struct pw_context *ctx;
|
||||
struct pw_listener ctx_state_changed;
|
||||
struct pw_core *core;
|
||||
struct pw_remote *remote;
|
||||
struct pw_listener remote_state_changed;
|
||||
|
||||
struct pw_stream *stream;
|
||||
struct pw_listener stream_state_changed;
|
||||
|
|
|
|||
|
|
@ -307,6 +307,7 @@ gst_pipewire_src_init (GstPipeWireSrc * src)
|
|||
|
||||
src->loop = pw_loop_new ();
|
||||
src->main_loop = pw_thread_loop_new (src->loop, "pipewire-main-loop");
|
||||
src->core = pw_core_new (src->loop, NULL);
|
||||
GST_DEBUG ("loop %p, mainloop %p", src->loop, src->main_loop);
|
||||
|
||||
}
|
||||
|
|
@ -359,7 +360,8 @@ on_add_buffer (struct pw_listener *listener,
|
|||
GstBuffer *buf;
|
||||
uint32_t i;
|
||||
ProcessMemData data;
|
||||
struct pw_context *ctx = pwsrc->stream->context;
|
||||
struct pw_remote *remote = pwsrc->stream->remote;
|
||||
struct pw_core *core = remote->core;
|
||||
|
||||
GST_LOG_OBJECT (pwsrc, "add buffer");
|
||||
|
||||
|
|
@ -374,19 +376,19 @@ on_add_buffer (struct pw_listener *listener,
|
|||
data.src = gst_object_ref (pwsrc);
|
||||
data.id = id;
|
||||
data.buf = b;
|
||||
data.header = spa_buffer_find_meta (b, ctx->type.meta.Header);
|
||||
data.header = spa_buffer_find_meta (b, core->type.meta.Header);
|
||||
|
||||
for (i = 0; i < b->n_datas; i++) {
|
||||
struct spa_data *d = &b->datas[i];
|
||||
GstMemory *gmem = NULL;
|
||||
|
||||
if (d->type == ctx->type.data.MemFd || d->type == ctx->type.data.DmaBuf) {
|
||||
if (d->type == core->type.data.MemFd || d->type == core->type.data.DmaBuf) {
|
||||
gmem = gst_fd_allocator_alloc (pwsrc->fd_allocator, dup (d->fd),
|
||||
d->mapoffset + d->maxsize, GST_FD_MEMORY_FLAG_NONE);
|
||||
gst_memory_resize (gmem, d->chunk->offset + d->mapoffset, d->chunk->size);
|
||||
data.offset = d->mapoffset;
|
||||
}
|
||||
else if (d->type == ctx->type.data.MemPtr) {
|
||||
else if (d->type == core->type.data.MemPtr) {
|
||||
gmem = gst_memory_new_wrapped (0, d->data, d->maxsize, d->chunk->offset + d->mapoffset,
|
||||
d->chunk->size, NULL, NULL);
|
||||
data.offset = 0;
|
||||
|
|
@ -543,7 +545,7 @@ gst_pipewire_src_stream_start (GstPipeWireSrc *pwsrc)
|
|||
if (state == PW_STREAM_STATE_ERROR)
|
||||
goto start_error;
|
||||
|
||||
if (pwsrc->ctx->state == PW_CONTEXT_STATE_ERROR)
|
||||
if (pwsrc->remote->state == PW_REMOTE_STATE_ERROR)
|
||||
goto start_error;
|
||||
|
||||
pw_thread_loop_wait (pwsrc->main_loop);
|
||||
|
|
@ -583,7 +585,7 @@ wait_negotiated (GstPipeWireSrc *this)
|
|||
if (state == PW_STREAM_STATE_ERROR)
|
||||
break;
|
||||
|
||||
if (this->ctx->state == PW_CONTEXT_STATE_ERROR)
|
||||
if (this->remote->state == PW_REMOTE_STATE_ERROR)
|
||||
break;
|
||||
|
||||
if (this->started)
|
||||
|
|
@ -634,7 +636,7 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc)
|
|||
GST_DEBUG_OBJECT (basesrc, "have common caps: %" GST_PTR_FORMAT, caps);
|
||||
|
||||
/* open a connection with these caps */
|
||||
possible = gst_caps_to_format_all (caps, pwsrc->ctx->type.map);
|
||||
possible = gst_caps_to_format_all (caps, pwsrc->remote->core->type.map);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
/* first disconnect */
|
||||
|
|
@ -679,7 +681,7 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc)
|
|||
if (state == PW_STREAM_STATE_ERROR)
|
||||
goto connect_error;
|
||||
|
||||
if (pwsrc->ctx->state == PW_CONTEXT_STATE_ERROR)
|
||||
if (pwsrc->remote->state == PW_REMOTE_STATE_ERROR)
|
||||
goto connect_error;
|
||||
|
||||
pw_thread_loop_wait (pwsrc->main_loop);
|
||||
|
|
@ -738,7 +740,8 @@ on_format_changed (struct pw_listener *listener,
|
|||
GstPipeWireSrc *pwsrc = SPA_CONTAINER_OF (listener, GstPipeWireSrc, stream_format_changed);
|
||||
GstCaps *caps;
|
||||
gboolean res;
|
||||
struct pw_context *ctx = stream->context;
|
||||
struct pw_remote *remote = stream->remote;
|
||||
struct pw_core *core = remote->core;
|
||||
|
||||
if (format == NULL) {
|
||||
GST_DEBUG_OBJECT (pwsrc, "clear format");
|
||||
|
|
@ -746,7 +749,7 @@ on_format_changed (struct pw_listener *listener,
|
|||
return;
|
||||
}
|
||||
|
||||
caps = gst_caps_from_format (format, pwsrc->ctx->type.map);
|
||||
caps = gst_caps_from_format (format, core->type.map);
|
||||
GST_DEBUG_OBJECT (pwsrc, "we got format %" GST_PTR_FORMAT, caps);
|
||||
res = gst_base_src_set_caps (GST_BASE_SRC (pwsrc), caps);
|
||||
gst_caps_unref (caps);
|
||||
|
|
@ -758,16 +761,16 @@ on_format_changed (struct pw_listener *listener,
|
|||
struct spa_pod_frame f[2];
|
||||
|
||||
spa_pod_builder_init (&b, buffer, sizeof (buffer));
|
||||
spa_pod_builder_object (&b, &f[0], 0, ctx->type.param_alloc_buffers.Buffers,
|
||||
PROP_U_MM (&f[1], ctx->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, 0, 0, INT32_MAX),
|
||||
PROP_U_MM (&f[1], ctx->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT, 0, 0, INT32_MAX),
|
||||
PROP_U_MM (&f[1], ctx->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT, 16, 0, INT32_MAX),
|
||||
PROP (&f[1], ctx->type.param_alloc_buffers.align, SPA_POD_TYPE_INT, 16));
|
||||
spa_pod_builder_object (&b, &f[0], 0, core->type.param_alloc_buffers.Buffers,
|
||||
PROP_U_MM (&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, 0, 0, INT32_MAX),
|
||||
PROP_U_MM (&f[1], core->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT, 0, 0, INT32_MAX),
|
||||
PROP_U_MM (&f[1], core->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT, 16, 0, INT32_MAX),
|
||||
PROP (&f[1], core->type.param_alloc_buffers.align, SPA_POD_TYPE_INT, 16));
|
||||
params[0] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param);
|
||||
|
||||
spa_pod_builder_object (&b, &f[0], 0, ctx->type.param_alloc_meta_enable.MetaEnable,
|
||||
PROP (&f[1], ctx->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, ctx->type.meta.Header),
|
||||
PROP (&f[1], ctx->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_meta_header)));
|
||||
spa_pod_builder_object (&b, &f[0], 0, core->type.param_alloc_meta_enable.MetaEnable,
|
||||
PROP (&f[1], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, core->type.meta.Header),
|
||||
PROP (&f[1], core->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_meta_header)));
|
||||
params[1] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param);
|
||||
|
||||
GST_DEBUG_OBJECT (pwsrc, "doing finish format");
|
||||
|
|
@ -969,22 +972,22 @@ gst_pipewire_src_stop (GstBaseSrc * basesrc)
|
|||
}
|
||||
|
||||
static void
|
||||
on_ctx_state_changed (struct pw_listener *listener,
|
||||
struct pw_context *ctx)
|
||||
on_remote_state_changed (struct pw_listener *listener,
|
||||
struct pw_remote *remote)
|
||||
{
|
||||
GstPipeWireSrc *pwsrc = SPA_CONTAINER_OF (listener, GstPipeWireSrc, ctx_state_changed);
|
||||
enum pw_context_state state = ctx->state;
|
||||
GstPipeWireSrc *pwsrc = SPA_CONTAINER_OF (listener, GstPipeWireSrc, remote_state_changed);
|
||||
enum pw_remote_state state = remote->state;
|
||||
|
||||
GST_DEBUG ("got context state %s", pw_context_state_as_string (state));
|
||||
GST_DEBUG ("got remote state %s", pw_remote_state_as_string (state));
|
||||
|
||||
switch (state) {
|
||||
case PW_CONTEXT_STATE_UNCONNECTED:
|
||||
case PW_CONTEXT_STATE_CONNECTING:
|
||||
case PW_CONTEXT_STATE_CONNECTED:
|
||||
case PW_REMOTE_STATE_UNCONNECTED:
|
||||
case PW_REMOTE_STATE_CONNECTING:
|
||||
case PW_REMOTE_STATE_CONNECTED:
|
||||
break;
|
||||
case PW_CONTEXT_STATE_ERROR:
|
||||
case PW_REMOTE_STATE_ERROR:
|
||||
GST_ELEMENT_ERROR (pwsrc, RESOURCE, FAILED,
|
||||
("context error: %s", ctx->error), (NULL));
|
||||
("remote error: %s", remote->error), (NULL));
|
||||
break;
|
||||
}
|
||||
pw_thread_loop_signal (pwsrc->main_loop, FALSE);
|
||||
|
|
@ -1013,20 +1016,20 @@ gst_pipewire_src_open (GstPipeWireSrc * pwsrc)
|
|||
goto mainloop_failed;
|
||||
|
||||
pw_thread_loop_lock (pwsrc->main_loop);
|
||||
pwsrc->ctx = pw_context_new (pwsrc->loop, g_get_application_name (), NULL);
|
||||
pwsrc->remote = pw_remote_new (pwsrc->core, NULL);
|
||||
|
||||
pw_signal_add (&pwsrc->ctx->state_changed, &pwsrc->ctx_state_changed, on_ctx_state_changed);
|
||||
pw_signal_add (&pwsrc->remote->state_changed, &pwsrc->remote_state_changed, on_remote_state_changed);
|
||||
|
||||
pw_context_connect (pwsrc->ctx, PW_CONTEXT_FLAG_NO_REGISTRY);
|
||||
pw_remote_connect (pwsrc->remote);
|
||||
|
||||
while (TRUE) {
|
||||
enum pw_context_state state = pwsrc->ctx->state;
|
||||
enum pw_remote_state state = pwsrc->remote->state;
|
||||
|
||||
GST_DEBUG ("waiting for CONNECTED, now %s", pw_context_state_as_string (state));
|
||||
if (state == PW_CONTEXT_STATE_CONNECTED)
|
||||
GST_DEBUG ("waiting for CONNECTED, now %s", pw_remote_state_as_string (state));
|
||||
if (state == PW_REMOTE_STATE_CONNECTED)
|
||||
break;
|
||||
|
||||
if (state == PW_CONTEXT_STATE_ERROR)
|
||||
if (state == PW_REMOTE_STATE_ERROR)
|
||||
goto connect_error;
|
||||
|
||||
pw_thread_loop_wait (pwsrc->main_loop);
|
||||
|
|
@ -1039,7 +1042,7 @@ gst_pipewire_src_open (GstPipeWireSrc * pwsrc)
|
|||
props = NULL;
|
||||
}
|
||||
|
||||
pwsrc->stream = pw_stream_new (pwsrc->ctx, pwsrc->client_name, props);
|
||||
pwsrc->stream = pw_stream_new (pwsrc->remote, pwsrc->client_name, props);
|
||||
|
||||
pw_signal_add (&pwsrc->stream->state_changed, &pwsrc->stream_state_changed, on_state_changed);
|
||||
pw_signal_add (&pwsrc->stream->format_changed, &pwsrc->stream_format_changed, on_format_changed);
|
||||
|
|
@ -1075,8 +1078,8 @@ gst_pipewire_src_close (GstPipeWireSrc * pwsrc)
|
|||
pw_stream_destroy (pwsrc->stream);
|
||||
pwsrc->stream = NULL;
|
||||
|
||||
pw_context_destroy (pwsrc->ctx);
|
||||
pwsrc->ctx = NULL;
|
||||
pw_remote_destroy (pwsrc->remote);
|
||||
pwsrc->remote = NULL;
|
||||
|
||||
GST_OBJECT_LOCK (pwsrc);
|
||||
g_clear_object (&pwsrc->clock);
|
||||
|
|
|
|||
|
|
@ -67,8 +67,9 @@ struct _GstPipeWireSrc {
|
|||
struct pw_loop *loop;
|
||||
struct pw_thread_loop *main_loop;
|
||||
|
||||
struct pw_context *ctx;
|
||||
struct pw_listener ctx_state_changed;
|
||||
struct pw_core *core;
|
||||
struct pw_remote *remote;
|
||||
struct pw_listener remote_state_changed;
|
||||
|
||||
struct pw_stream *stream;
|
||||
struct pw_listener stream_state_changed;
|
||||
|
|
|
|||
|
|
@ -1,66 +0,0 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pipewire/client/interfaces.h"
|
||||
#include "pipewire/client/context.h"
|
||||
#include "pipewire/client/extension.h"
|
||||
|
||||
struct pw_protocol *pw_protocol_native_ext_client_node_init(void);
|
||||
|
||||
struct impl {
|
||||
struct pw_context *context;
|
||||
struct pw_properties *properties;
|
||||
};
|
||||
|
||||
static struct impl *extension_new(struct pw_context *context, struct pw_properties *properties)
|
||||
{
|
||||
struct impl *impl;
|
||||
|
||||
impl = calloc(1, sizeof(struct impl));
|
||||
pw_log_debug("extension %p: new", impl);
|
||||
|
||||
impl->context = context;
|
||||
impl->properties = properties;
|
||||
|
||||
pw_protocol_native_ext_client_node_init();
|
||||
|
||||
return impl;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void extension_destroy(struct impl *impl)
|
||||
{
|
||||
pw_log_debug("extension %p: destroy", impl);
|
||||
|
||||
free(impl);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool pipewire__extension_init(struct pw_extension *extension, const char *args)
|
||||
{
|
||||
extension_new(extension->context, NULL);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pipewire/client/interfaces.h"
|
||||
#include "pipewire/client/context.h"
|
||||
#include "pipewire/client/extension.h"
|
||||
|
||||
struct pw_protocol *pw_protocol_native_init(void);
|
||||
|
||||
struct impl {
|
||||
struct pw_context *context;
|
||||
struct pw_properties *properties;
|
||||
};
|
||||
|
||||
static struct impl *extension_new(struct pw_context *context, struct pw_properties *properties)
|
||||
{
|
||||
struct impl *impl;
|
||||
|
||||
impl = calloc(1, sizeof(struct impl));
|
||||
pw_log_debug("extension %p: new", impl);
|
||||
|
||||
impl->context = context;
|
||||
impl->properties = properties;
|
||||
|
||||
pw_protocol_native_init();
|
||||
|
||||
return impl;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void extension_destroy(struct impl *impl)
|
||||
{
|
||||
pw_log_debug("extension %p: destroy", impl);
|
||||
|
||||
free(impl);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool pipewire__extension_init(struct pw_extension *extension, const char *args)
|
||||
{
|
||||
extension_new(extension->context, NULL);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -37,8 +37,8 @@ pipewire_module_client_node = shared_library('pipewire-module-client-node',
|
|||
[ 'module-client-node.c',
|
||||
'module-client-node/client-node.c',
|
||||
'module-client-node/protocol-native.c',
|
||||
'spa/spa-node.c',
|
||||
'extension-client-node.c', ],
|
||||
'module-protocol-native/connection.c',
|
||||
'spa/spa-node.c', ],
|
||||
c_args : pipewire_module_c_args,
|
||||
include_directories : [configinc, spa_inc],
|
||||
link_with : spalib,
|
||||
|
|
@ -59,7 +59,7 @@ pipewire_module_client_node = shared_library('pipewire-module-client-node',
|
|||
pipewire_module_protocol_native = shared_library('pipewire-module-protocol-native',
|
||||
[ 'module-protocol-native.c',
|
||||
'module-protocol-native/protocol-native.c',
|
||||
'extension-protocol-native.c' ],
|
||||
'module-protocol-native/connection.c' ],
|
||||
c_args : pipewire_module_c_args,
|
||||
include_directories : [configinc, spa_inc],
|
||||
link_with : spalib,
|
||||
|
|
|
|||
|
|
@ -37,14 +37,13 @@ struct impl {
|
|||
};
|
||||
|
||||
static struct pw_node *create_node(struct pw_node_factory *factory,
|
||||
struct pw_client *client,
|
||||
struct pw_resource *resource,
|
||||
const char *name,
|
||||
struct pw_properties *properties,
|
||||
uint32_t new_id)
|
||||
struct pw_properties *properties)
|
||||
{
|
||||
struct pw_client_node *node;
|
||||
|
||||
node = pw_client_node_new(client, new_id, name, properties);
|
||||
node = pw_client_node_new(resource, name, properties);
|
||||
if (node == NULL)
|
||||
goto no_mem;
|
||||
|
||||
|
|
@ -52,8 +51,8 @@ static struct pw_node *create_node(struct pw_node_factory *factory,
|
|||
|
||||
no_mem:
|
||||
pw_log_error("can't create node");
|
||||
pw_core_notify_error(client->core_resource,
|
||||
client->core_resource->id, SPA_RESULT_NO_MEMORY, "no memory");
|
||||
pw_core_notify_error(resource->client->core_resource,
|
||||
resource->client->core_resource->id, SPA_RESULT_NO_MEMORY, "no memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -68,6 +67,7 @@ static struct impl *module_new(struct pw_core *core, struct pw_properties *prope
|
|||
|
||||
impl->this.core = core;
|
||||
impl->this.name = "client-node";
|
||||
impl->this.type = spa_type_map_get_id(core->type.map, PIPEWIRE_TYPE__ClientNode);
|
||||
pw_signal_init(&impl->this.destroy_signal);
|
||||
impl->this.create_node = create_node;
|
||||
|
||||
|
|
|
|||
|
|
@ -1132,41 +1132,33 @@ static void on_node_free(struct pw_listener *listener, struct pw_node *node)
|
|||
*
|
||||
* \memberof pw_client_node
|
||||
*/
|
||||
struct pw_client_node *pw_client_node_new(struct pw_client *client,
|
||||
uint32_t id,
|
||||
struct pw_client_node *pw_client_node_new(struct pw_resource *resource,
|
||||
const char *name,
|
||||
struct pw_properties *properties)
|
||||
{
|
||||
struct impl *impl;
|
||||
struct pw_client_node *this;
|
||||
struct pw_core *core = resource->client->core;
|
||||
|
||||
impl = calloc(1, sizeof(struct impl));
|
||||
if (impl == NULL)
|
||||
return NULL;
|
||||
|
||||
this = &impl->this;
|
||||
this->client = client;
|
||||
|
||||
impl->core = client->core;
|
||||
impl->core = core;
|
||||
impl->fds[0] = impl->fds[1] = -1;
|
||||
pw_log_debug("client-node %p: new", impl);
|
||||
|
||||
impl->type_client_node = spa_type_map_get_id(client->core->type.map, PIPEWIRE_TYPE__ClientNode);
|
||||
impl->type_client_node = spa_type_map_get_id(core->type.map, PIPEWIRE_TYPE__ClientNode);
|
||||
|
||||
pw_signal_init(&this->destroy_signal);
|
||||
|
||||
proxy_init(&impl->proxy, NULL, client->core->support, client->core->n_support);
|
||||
proxy_init(&impl->proxy, NULL, core->support, core->n_support);
|
||||
impl->proxy.impl = impl;
|
||||
|
||||
this->resource = pw_resource_new(client,
|
||||
id,
|
||||
impl->type_client_node,
|
||||
0);
|
||||
|
||||
if (this->resource == NULL)
|
||||
goto error_no_resource;
|
||||
|
||||
this->node = pw_spa_node_new(client->core,
|
||||
this->resource = resource;
|
||||
this->node = pw_spa_node_new(core,
|
||||
this->resource,
|
||||
name,
|
||||
true,
|
||||
|
|
@ -1192,7 +1184,6 @@ struct pw_client_node *pw_client_node_new(struct pw_client *client,
|
|||
|
||||
error_no_node:
|
||||
pw_resource_destroy(this->resource);
|
||||
error_no_resource:
|
||||
proxy_clear(&impl->proxy);
|
||||
free(impl);
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -34,15 +34,13 @@ extern "C" {
|
|||
struct pw_client_node {
|
||||
struct pw_node *node;
|
||||
|
||||
struct pw_client *client;
|
||||
struct pw_resource *resource;
|
||||
|
||||
PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_client_node *node));
|
||||
};
|
||||
|
||||
struct pw_client_node *
|
||||
pw_client_node_new(struct pw_client *client,
|
||||
uint32_t id,
|
||||
pw_client_node_new(struct pw_resource *resource,
|
||||
const char *name,
|
||||
struct pw_properties *properties);
|
||||
|
||||
|
|
|
|||
|
|
@ -24,93 +24,35 @@
|
|||
|
||||
#include "pipewire/client/interfaces.h"
|
||||
#include "pipewire/client/protocol.h"
|
||||
#include "pipewire/client/connection.h"
|
||||
#include "pipewire/server/client.h"
|
||||
#include "pipewire/extensions/client-node.h"
|
||||
|
||||
#include "pipewire/modules/module-protocol-native/connection.h"
|
||||
|
||||
/** \cond */
|
||||
struct builder {
|
||||
struct spa_pod_builder b;
|
||||
struct pw_connection *connection;
|
||||
};
|
||||
|
||||
typedef bool(*demarshal_func_t) (void *object, void *data, size_t size);
|
||||
|
||||
/** \endcond */
|
||||
|
||||
static uint32_t write_pod(struct spa_pod_builder *b, uint32_t ref, const void *data, uint32_t size)
|
||||
{
|
||||
if (ref == -1)
|
||||
ref = b->offset;
|
||||
|
||||
if (b->size <= b->offset) {
|
||||
b->size = SPA_ROUND_UP_N(b->offset + size, 4096);
|
||||
b->data = pw_connection_begin_write(((struct builder *) b)->connection, b->size);
|
||||
}
|
||||
memcpy(b->data + ref, data, size);
|
||||
return ref;
|
||||
}
|
||||
|
||||
static void core_update_map_client(struct pw_context *context)
|
||||
{
|
||||
uint32_t diff, base, i;
|
||||
const char **types;
|
||||
|
||||
base = context->n_types;
|
||||
diff = spa_type_map_get_size(context->type.map) - base;
|
||||
if (diff == 0)
|
||||
return;
|
||||
|
||||
types = alloca(diff * sizeof(char *));
|
||||
for (i = 0; i < diff; i++, base++)
|
||||
types[i] = spa_type_map_get_type(context->type.map, base);
|
||||
|
||||
pw_core_do_update_types(context->core_proxy, context->n_types, diff, types);
|
||||
context->n_types += diff;
|
||||
}
|
||||
|
||||
static void core_update_map_server(struct pw_client *client)
|
||||
{
|
||||
uint32_t diff, base, i;
|
||||
struct pw_core *core = client->core;
|
||||
const char **types;
|
||||
|
||||
base = client->n_types;
|
||||
diff = spa_type_map_get_size(core->type.map) - base;
|
||||
if (diff == 0)
|
||||
return;
|
||||
|
||||
types = alloca(diff * sizeof(char *));
|
||||
for (i = 0; i < diff; i++, base++)
|
||||
types[i] = spa_type_map_get_type(core->type.map, base);
|
||||
|
||||
pw_core_notify_update_types(client->core_resource, client->n_types, diff, types);
|
||||
client->n_types += diff;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
client_node_marshal_done(void *object, int seq, int res)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_connection *connection = proxy->context->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct pw_connection *connection = proxy->remote->protocol_private;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
if (connection == NULL)
|
||||
return;
|
||||
b = pw_connection_begin_write_proxy(connection, proxy, PW_CLIENT_NODE_METHOD_DONE);
|
||||
|
||||
core_update_map_client(proxy->context);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f,
|
||||
spa_pod_builder_struct(b, &f,
|
||||
SPA_POD_TYPE_INT, seq,
|
||||
SPA_POD_TYPE_INT, res);
|
||||
|
||||
pw_connection_end_write(connection, proxy->id, PW_CLIENT_NODE_METHOD_DONE, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
client_node_marshal_update(void *object,
|
||||
uint32_t change_mask,
|
||||
|
|
@ -118,21 +60,18 @@ client_node_marshal_update(void *object,
|
|||
uint32_t max_output_ports, const struct spa_props *props)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_connection *connection = proxy->context->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct pw_connection *connection = proxy->remote->protocol_private;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
if (connection == NULL)
|
||||
return;
|
||||
b = pw_connection_begin_write_proxy(connection, proxy, PW_CLIENT_NODE_METHOD_UPDATE);
|
||||
|
||||
core_update_map_client(proxy->context);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f,
|
||||
spa_pod_builder_struct(b, &f,
|
||||
SPA_POD_TYPE_INT, change_mask,
|
||||
SPA_POD_TYPE_INT, max_input_ports,
|
||||
SPA_POD_TYPE_INT, max_output_ports, SPA_POD_TYPE_POD, props);
|
||||
|
||||
pw_connection_end_write(connection, proxy->id, PW_CLIENT_NODE_METHOD_UPDATE, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -147,78 +86,68 @@ client_node_marshal_port_update(void *object,
|
|||
const struct spa_param **params, const struct spa_port_info *info)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_connection *connection = proxy->context->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct pw_connection *connection = proxy->remote->protocol_private;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f[2];
|
||||
int i;
|
||||
|
||||
if (connection == NULL)
|
||||
return;
|
||||
b = pw_connection_begin_write_proxy(connection, proxy, PW_CLIENT_NODE_METHOD_PORT_UPDATE);
|
||||
|
||||
core_update_map_client(proxy->context);
|
||||
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRUCT, &f[0],
|
||||
SPA_POD_TYPE_INT, direction,
|
||||
SPA_POD_TYPE_INT, port_id,
|
||||
SPA_POD_TYPE_INT, change_mask, SPA_POD_TYPE_INT, n_possible_formats, 0);
|
||||
|
||||
for (i = 0; i < n_possible_formats; i++)
|
||||
spa_pod_builder_add(&b.b, SPA_POD_TYPE_POD, possible_formats[i], 0);
|
||||
spa_pod_builder_add(b, SPA_POD_TYPE_POD, possible_formats[i], 0);
|
||||
|
||||
spa_pod_builder_add(&b.b, SPA_POD_TYPE_POD, format, SPA_POD_TYPE_INT, n_params, 0);
|
||||
spa_pod_builder_add(b, SPA_POD_TYPE_POD, format, SPA_POD_TYPE_INT, n_params, 0);
|
||||
|
||||
for (i = 0; i < n_params; i++) {
|
||||
const struct spa_param *p = params[i];
|
||||
spa_pod_builder_add(&b.b, SPA_POD_TYPE_POD, p, 0);
|
||||
spa_pod_builder_add(b, SPA_POD_TYPE_POD, p, 0);
|
||||
}
|
||||
|
||||
if (info) {
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRUCT, &f[1],
|
||||
SPA_POD_TYPE_INT, info->flags, SPA_POD_TYPE_INT, info->rate, 0);
|
||||
spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f[1], 0);
|
||||
spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f[1], 0);
|
||||
} else {
|
||||
spa_pod_builder_add(&b.b, SPA_POD_TYPE_POD, NULL, 0);
|
||||
spa_pod_builder_add(b, SPA_POD_TYPE_POD, NULL, 0);
|
||||
}
|
||||
spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f[0], 0);
|
||||
spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f[0], 0);
|
||||
|
||||
pw_connection_end_write(connection, proxy->id, PW_CLIENT_NODE_METHOD_PORT_UPDATE,
|
||||
b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void client_node_marshal_event_method(void *object, struct spa_event *event)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_connection *connection = proxy->context->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct pw_connection *connection = proxy->remote->protocol_private;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
if (connection == NULL)
|
||||
return;
|
||||
b = pw_connection_begin_write_proxy(connection, proxy, PW_CLIENT_NODE_METHOD_EVENT);
|
||||
|
||||
core_update_map_client(proxy->context);
|
||||
spa_pod_builder_struct(b, &f, SPA_POD_TYPE_POD, event);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f, SPA_POD_TYPE_POD, event);
|
||||
|
||||
pw_connection_end_write(connection, proxy->id, PW_CLIENT_NODE_METHOD_EVENT, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void client_node_marshal_destroy(void *object)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_connection *connection = proxy->context->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct pw_connection *connection = proxy->remote->protocol_private;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
if (connection == NULL)
|
||||
return;
|
||||
b = pw_connection_begin_write_proxy(connection, proxy, PW_CLIENT_NODE_METHOD_DESTROY);
|
||||
|
||||
core_update_map_client(proxy->context);
|
||||
spa_pod_builder_struct(b, &f, 0);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f, 0);
|
||||
|
||||
pw_connection_end_write(connection, proxy->id, PW_CLIENT_NODE_METHOD_DESTROY, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static bool client_node_demarshal_set_props(void *object, void *data, size_t size)
|
||||
|
|
@ -245,7 +174,7 @@ static bool client_node_demarshal_event_event(void *object, void *data, size_t s
|
|||
const struct spa_event *event;
|
||||
|
||||
if (!spa_pod_iter_struct(&it, data, size) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) ||
|
||||
!spa_pod_iter_get(&it, SPA_POD_TYPE_OBJECT, &event, 0))
|
||||
return false;
|
||||
|
||||
|
|
@ -295,7 +224,7 @@ static bool client_node_demarshal_set_format(void *object, void *data, size_t si
|
|||
const struct spa_format *format = NULL;
|
||||
|
||||
if (!spa_pod_iter_struct(&it, data, size) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) ||
|
||||
!spa_pod_iter_get(&it,
|
||||
SPA_POD_TYPE_INT, &seq,
|
||||
SPA_POD_TYPE_INT, &direction,
|
||||
|
|
@ -318,7 +247,7 @@ static bool client_node_demarshal_set_param(void *object, void *data, size_t siz
|
|||
const struct spa_param *param = NULL;
|
||||
|
||||
if (!spa_pod_iter_struct(&it, data, size) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) ||
|
||||
!spa_pod_iter_get(&it,
|
||||
SPA_POD_TYPE_INT, &seq,
|
||||
SPA_POD_TYPE_INT, &direction,
|
||||
|
|
@ -335,12 +264,12 @@ static bool client_node_demarshal_add_mem(void *object, void *data, size_t size)
|
|||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct spa_pod_iter it;
|
||||
struct pw_connection *connection = proxy->context->protocol_private;
|
||||
struct pw_connection *connection = proxy->remote->protocol_private;
|
||||
uint32_t direction, port_id, mem_id, type, memfd_idx, flags, offset, sz;
|
||||
int memfd;
|
||||
|
||||
if (!spa_pod_iter_struct(&it, data, size) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) ||
|
||||
!spa_pod_iter_get(&it,
|
||||
SPA_POD_TYPE_INT, &direction,
|
||||
SPA_POD_TYPE_INT, &port_id,
|
||||
|
|
@ -371,7 +300,7 @@ static bool client_node_demarshal_use_buffers(void *object, void *data, size_t s
|
|||
int i, j;
|
||||
|
||||
if (!spa_pod_iter_struct(&it, data, size) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) ||
|
||||
!spa_pod_iter_get(&it,
|
||||
SPA_POD_TYPE_INT, &seq,
|
||||
SPA_POD_TYPE_INT, &direction,
|
||||
|
|
@ -433,7 +362,7 @@ static bool client_node_demarshal_node_command(void *object, void *data, size_t
|
|||
uint32_t seq;
|
||||
|
||||
if (!spa_pod_iter_struct(&it, data, size) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) ||
|
||||
!spa_pod_iter_get(&it, SPA_POD_TYPE_INT, &seq, SPA_POD_TYPE_OBJECT, &command, 0))
|
||||
return false;
|
||||
|
||||
|
|
@ -449,7 +378,7 @@ static bool client_node_demarshal_port_command(void *object, void *data, size_t
|
|||
uint32_t direction, port_id;
|
||||
|
||||
if (!spa_pod_iter_struct(&it, data, size) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) ||
|
||||
!spa_pod_iter_get(&it,
|
||||
SPA_POD_TYPE_INT, &direction,
|
||||
SPA_POD_TYPE_INT, &port_id,
|
||||
|
|
@ -467,7 +396,7 @@ static bool client_node_demarshal_transport(void *object, void *data, size_t siz
|
|||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct spa_pod_iter it;
|
||||
struct pw_connection *connection = proxy->context->protocol_private;
|
||||
struct pw_connection *connection = proxy->remote->protocol_private;
|
||||
uint32_t node_id, ridx, widx, memfd_idx, offset, sz;
|
||||
int readfd, writefd, memfd;
|
||||
|
||||
|
|
@ -498,31 +427,30 @@ client_node_marshal_set_props(void *object, uint32_t seq, const struct spa_props
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_SET_PROPS);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f,
|
||||
spa_pod_builder_struct(b, &f,
|
||||
SPA_POD_TYPE_INT, seq,
|
||||
SPA_POD_TYPE_POD, props);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_SET_PROPS,
|
||||
b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void client_node_marshal_event_event(void *object, const struct spa_event *event)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_EVENT);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f, SPA_POD_TYPE_POD, event);
|
||||
spa_pod_builder_struct(b, &f, SPA_POD_TYPE_POD, event);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_EVENT, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -531,17 +459,16 @@ client_node_marshal_add_port(void *object,
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_ADD_PORT);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f,
|
||||
spa_pod_builder_struct(b, &f,
|
||||
SPA_POD_TYPE_INT, seq,
|
||||
SPA_POD_TYPE_INT, direction, SPA_POD_TYPE_INT, port_id);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_ADD_PORT,
|
||||
b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -550,17 +477,16 @@ client_node_marshal_remove_port(void *object,
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_REMOVE_PORT);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f,
|
||||
spa_pod_builder_struct(b, &f,
|
||||
SPA_POD_TYPE_INT, seq,
|
||||
SPA_POD_TYPE_INT, direction, SPA_POD_TYPE_INT, port_id);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_REMOVE_PORT,
|
||||
b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -573,20 +499,19 @@ client_node_marshal_set_format(void *object,
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_SET_FORMAT);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f,
|
||||
spa_pod_builder_struct(b, &f,
|
||||
SPA_POD_TYPE_INT, seq,
|
||||
SPA_POD_TYPE_INT, direction,
|
||||
SPA_POD_TYPE_INT, port_id,
|
||||
SPA_POD_TYPE_INT, flags,
|
||||
SPA_POD_TYPE_POD, format);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_SET_FORMAT,
|
||||
b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -598,19 +523,18 @@ client_node_marshal_set_param(void *object,
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_SET_PARAM);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f,
|
||||
spa_pod_builder_struct(b, &f,
|
||||
SPA_POD_TYPE_INT, seq,
|
||||
SPA_POD_TYPE_INT, direction,
|
||||
SPA_POD_TYPE_INT, port_id,
|
||||
SPA_POD_TYPE_POD, param);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_SET_PARAM,
|
||||
b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -623,12 +547,12 @@ client_node_marshal_add_mem(void *object,
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_ADD_MEM);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f,
|
||||
spa_pod_builder_struct(b, &f,
|
||||
SPA_POD_TYPE_INT, direction,
|
||||
SPA_POD_TYPE_INT, port_id,
|
||||
SPA_POD_TYPE_INT, mem_id,
|
||||
|
|
@ -637,7 +561,7 @@ client_node_marshal_add_mem(void *object,
|
|||
SPA_POD_TYPE_INT, flags,
|
||||
SPA_POD_TYPE_INT, offset, SPA_POD_TYPE_INT, size);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_ADD_MEM, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -649,13 +573,13 @@ client_node_marshal_use_buffers(void *object,
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
uint32_t i, j;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_USE_BUFFERS);
|
||||
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRUCT, &f,
|
||||
SPA_POD_TYPE_INT, seq,
|
||||
SPA_POD_TYPE_INT, direction,
|
||||
|
|
@ -664,7 +588,7 @@ client_node_marshal_use_buffers(void *object,
|
|||
for (i = 0; i < n_buffers; i++) {
|
||||
struct spa_buffer *buf = buffers[i].buffer;
|
||||
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_INT, buffers[i].mem_id,
|
||||
SPA_POD_TYPE_INT, buffers[i].offset,
|
||||
SPA_POD_TYPE_INT, buffers[i].size,
|
||||
|
|
@ -672,13 +596,13 @@ client_node_marshal_use_buffers(void *object,
|
|||
|
||||
for (j = 0; j < buf->n_metas; j++) {
|
||||
struct spa_meta *m = &buf->metas[j];
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_ID, m->type, SPA_POD_TYPE_INT, m->size, 0);
|
||||
}
|
||||
spa_pod_builder_add(&b.b, SPA_POD_TYPE_INT, buf->n_datas, 0);
|
||||
spa_pod_builder_add(b, SPA_POD_TYPE_INT, buf->n_datas, 0);
|
||||
for (j = 0; j < buf->n_datas; j++) {
|
||||
struct spa_data *d = &buf->datas[j];
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_ID, d->type,
|
||||
SPA_POD_TYPE_INT, SPA_PTR_TO_UINT32(d->data),
|
||||
SPA_POD_TYPE_INT, d->flags,
|
||||
|
|
@ -686,10 +610,9 @@ client_node_marshal_use_buffers(void *object,
|
|||
SPA_POD_TYPE_INT, d->maxsize, 0);
|
||||
}
|
||||
}
|
||||
spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_USE_BUFFERS,
|
||||
b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -697,15 +620,14 @@ client_node_marshal_node_command(void *object, uint32_t seq, const struct spa_co
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_NODE_COMMAND);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f, SPA_POD_TYPE_INT, seq, SPA_POD_TYPE_POD, command);
|
||||
spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, seq, SPA_POD_TYPE_POD, command);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_NODE_COMMAND,
|
||||
b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -716,18 +638,17 @@ client_node_marshal_port_command(void *object,
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_PORT_COMMAND);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f,
|
||||
spa_pod_builder_struct(b, &f,
|
||||
SPA_POD_TYPE_INT, direction,
|
||||
SPA_POD_TYPE_INT, port_id,
|
||||
SPA_POD_TYPE_POD, command);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_PORT_COMMAND,
|
||||
b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void client_node_marshal_transport(void *object, uint32_t node_id, int readfd, int writefd,
|
||||
|
|
@ -735,20 +656,19 @@ static void client_node_marshal_transport(void *object, uint32_t node_id, int re
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_TRANSPORT);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f,
|
||||
spa_pod_builder_struct(b, &f,
|
||||
SPA_POD_TYPE_INT, node_id,
|
||||
SPA_POD_TYPE_INT, pw_connection_add_fd(connection, readfd),
|
||||
SPA_POD_TYPE_INT, pw_connection_add_fd(connection, writefd),
|
||||
SPA_POD_TYPE_INT, pw_connection_add_fd(connection, memfd),
|
||||
SPA_POD_TYPE_INT, offset, SPA_POD_TYPE_INT, size);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_TRANSPORT,
|
||||
b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -484,14 +484,14 @@ static void dispatch_cb(struct spa_loop_utils *utils, struct spa_source *source,
|
|||
struct impl *impl = userdata;
|
||||
|
||||
if (dbus_connection_dispatch(impl->bus) == DBUS_DISPATCH_COMPLETE)
|
||||
pw_loop_enable_idle(impl->core->main_loop->loop, source, false);
|
||||
pw_loop_enable_idle(impl->core->main_loop, source, false);
|
||||
}
|
||||
|
||||
static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *userdata)
|
||||
{
|
||||
struct impl *impl = userdata;
|
||||
|
||||
pw_loop_enable_idle(impl->core->main_loop->loop,
|
||||
pw_loop_enable_idle(impl->core->main_loop,
|
||||
impl->dispatch_event, status == DBUS_DISPATCH_COMPLETE ? false : true);
|
||||
}
|
||||
|
||||
|
|
@ -552,7 +552,7 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *userdata)
|
|||
|
||||
/* we dup because dbus tends to add the same fd multiple times and our epoll
|
||||
* implementation does not like that */
|
||||
source = pw_loop_add_io(impl->core->main_loop->loop,
|
||||
source = pw_loop_add_io(impl->core->main_loop,
|
||||
dup(dbus_watch_get_unix_fd(watch)),
|
||||
dbus_to_io(watch), true, handle_io_event, watch);
|
||||
|
||||
|
|
@ -566,7 +566,7 @@ static void remove_watch(DBusWatch *watch, void *userdata)
|
|||
struct spa_source *source;
|
||||
|
||||
if ((source = dbus_watch_get_data(watch)))
|
||||
pw_loop_destroy_source(impl->core->main_loop->loop, source);
|
||||
pw_loop_destroy_source(impl->core->main_loop, source);
|
||||
}
|
||||
|
||||
static void toggle_watch(DBusWatch *watch, void *userdata)
|
||||
|
|
@ -576,7 +576,7 @@ static void toggle_watch(DBusWatch *watch, void *userdata)
|
|||
|
||||
source = dbus_watch_get_data(watch);
|
||||
|
||||
pw_loop_update_io(impl->core->main_loop->loop, source, dbus_to_io(watch));
|
||||
pw_loop_update_io(impl->core->main_loop, source, dbus_to_io(watch));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -606,14 +606,14 @@ static dbus_bool_t add_timeout(DBusTimeout *timeout, void *userdata)
|
|||
if (!dbus_timeout_get_enabled(timeout))
|
||||
return FALSE;
|
||||
|
||||
source = pw_loop_add_timer(impl->core->main_loop->loop, handle_timer_event, timeout);
|
||||
source = pw_loop_add_timer(impl->core->main_loop, handle_timer_event, timeout);
|
||||
|
||||
dbus_timeout_set_data(timeout, source, NULL);
|
||||
|
||||
t = dbus_timeout_get_interval(timeout) * SPA_NSEC_PER_MSEC;
|
||||
ts.tv_sec = t / SPA_NSEC_PER_SEC;
|
||||
ts.tv_nsec = t % SPA_NSEC_PER_SEC;
|
||||
pw_loop_update_timer(impl->core->main_loop->loop, source, &ts, NULL, false);
|
||||
pw_loop_update_timer(impl->core->main_loop, source, &ts, NULL, false);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -623,7 +623,7 @@ static void remove_timeout(DBusTimeout *timeout, void *userdata)
|
|||
struct spa_source *source;
|
||||
|
||||
if ((source = dbus_timeout_get_data(timeout)))
|
||||
pw_loop_destroy_source(impl->core->main_loop->loop, source);
|
||||
pw_loop_destroy_source(impl->core->main_loop, source);
|
||||
}
|
||||
|
||||
static void toggle_timeout(DBusTimeout *timeout, void *userdata)
|
||||
|
|
@ -642,14 +642,14 @@ static void toggle_timeout(DBusTimeout *timeout, void *userdata)
|
|||
} else {
|
||||
tsp = NULL;
|
||||
}
|
||||
pw_loop_update_timer(impl->core->main_loop->loop, source, tsp, NULL, false);
|
||||
pw_loop_update_timer(impl->core->main_loop, source, tsp, NULL, false);
|
||||
}
|
||||
|
||||
static void wakeup_main(void *userdata)
|
||||
{
|
||||
struct impl *impl = userdata;
|
||||
|
||||
pw_loop_enable_idle(impl->core->main_loop->loop, impl->dispatch_event, true);
|
||||
pw_loop_enable_idle(impl->core->main_loop, impl->dispatch_event, true);
|
||||
}
|
||||
|
||||
static struct impl *module_new(struct pw_core *core, struct pw_properties *properties)
|
||||
|
|
@ -669,7 +669,7 @@ static struct impl *module_new(struct pw_core *core, struct pw_properties *prope
|
|||
if (impl->bus == NULL)
|
||||
goto error;
|
||||
|
||||
impl->dispatch_event = pw_loop_add_idle(core->main_loop->loop, false, dispatch_cb, impl);
|
||||
impl->dispatch_event = pw_loop_add_idle(core->main_loop, false, dispatch_cb, impl);
|
||||
|
||||
dbus_connection_set_exit_on_disconnect(impl->bus, false);
|
||||
dbus_connection_set_dispatch_status_function(impl->bus, dispatch_status, impl, NULL);
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ static void client_destroy(void *data)
|
|||
struct pw_client *client = data;
|
||||
struct client *this = client->user_data;
|
||||
|
||||
pw_loop_destroy_source(this->impl->core->main_loop->loop, this->source);
|
||||
pw_loop_destroy_source(this->impl->core->main_loop, this->source);
|
||||
spa_list_remove(&this->link);
|
||||
|
||||
close(this->fd);
|
||||
|
|
@ -407,7 +407,7 @@ on_busy_changed(struct pw_listener *listener,
|
|||
if (!client->busy)
|
||||
mask |= SPA_IO_IN;
|
||||
|
||||
pw_loop_update_io(c->impl->core->main_loop->loop, c->source, mask);
|
||||
pw_loop_update_io(c->impl->core->main_loop, c->source, mask);
|
||||
|
||||
if (!client->busy)
|
||||
process_messages(c);
|
||||
|
|
@ -453,7 +453,7 @@ static struct client *client_new(struct impl *impl, int fd)
|
|||
this = client->user_data;
|
||||
this->impl = impl;
|
||||
this->fd = fd;
|
||||
this->source = pw_loop_add_io(impl->core->main_loop->loop,
|
||||
this->source = pw_loop_add_io(impl->core->main_loop,
|
||||
this->fd,
|
||||
SPA_IO_ERR | SPA_IO_HUP, false, connection_data, this);
|
||||
if (this->source == NULL)
|
||||
|
|
@ -622,7 +622,7 @@ socket_data(struct spa_loop_utils *utils,
|
|||
return;
|
||||
}
|
||||
|
||||
pw_loop_update_io(impl->core->main_loop->loop,
|
||||
pw_loop_update_io(impl->core->main_loop,
|
||||
client->source, SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP);
|
||||
}
|
||||
|
||||
|
|
@ -644,7 +644,7 @@ static bool add_socket(struct impl *impl, struct socket *s)
|
|||
return false;
|
||||
}
|
||||
|
||||
s->loop = impl->core->main_loop->loop;
|
||||
s->loop = impl->core->main_loop;
|
||||
s->source = pw_loop_add_io(s->loop, s->fd, SPA_IO_IN, false, socket_data, impl);
|
||||
if (s->source == NULL)
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "pipewire/client/connection.h"
|
||||
#include "pipewire/client/pipewire.h"
|
||||
#include "pipewire/client/log.h"
|
||||
#include "pipewire/client/interfaces.h"
|
||||
|
|
@ -54,7 +55,22 @@ struct pw_protocol *pw_protocol_native_init(void);
|
|||
|
||||
typedef bool(*demarshal_func_t) (void *object, void *data, size_t size);
|
||||
|
||||
struct socket {
|
||||
struct connection {
|
||||
struct pw_protocol_connection this;
|
||||
|
||||
int fd;
|
||||
|
||||
struct spa_source *source;
|
||||
struct pw_connection *connection;
|
||||
|
||||
bool disconnecting;
|
||||
struct pw_listener need_flush;
|
||||
struct spa_source *flush_event;
|
||||
};
|
||||
|
||||
struct listener {
|
||||
struct pw_protocol_listener this;
|
||||
|
||||
int fd;
|
||||
int fd_lock;
|
||||
struct sockaddr_un addr;
|
||||
|
|
@ -62,8 +78,6 @@ struct socket {
|
|||
|
||||
struct pw_loop *loop;
|
||||
struct spa_source *source;
|
||||
char *core_name;
|
||||
struct spa_list link;
|
||||
};
|
||||
|
||||
struct impl {
|
||||
|
|
@ -73,7 +87,6 @@ struct impl {
|
|||
struct pw_protocol *protocol;
|
||||
struct pw_properties *properties;
|
||||
|
||||
struct spa_list socket_list;
|
||||
struct spa_list client_list;
|
||||
|
||||
struct spa_loop_control_hooks hooks;
|
||||
|
|
@ -94,7 +107,7 @@ static void client_destroy(void *data)
|
|||
struct pw_client *client = data;
|
||||
struct native_client *this = client->user_data;
|
||||
|
||||
pw_loop_destroy_source(this->impl->core->main_loop->loop, this->source);
|
||||
pw_loop_destroy_source(this->impl->core->main_loop, this->source);
|
||||
spa_list_remove(&this->link);
|
||||
|
||||
pw_connection_destroy(this->connection);
|
||||
|
|
@ -153,7 +166,7 @@ on_busy_changed(struct pw_listener *listener,
|
|||
if (!client->busy)
|
||||
mask |= SPA_IO_IN;
|
||||
|
||||
pw_loop_update_io(c->impl->core->main_loop->loop, c->source, mask);
|
||||
pw_loop_update_io(c->impl->core->main_loop, c->source, mask);
|
||||
|
||||
if (!client->busy)
|
||||
process_messages(c);
|
||||
|
|
@ -209,7 +222,7 @@ static struct native_client *client_new(struct impl *impl, int fd)
|
|||
this = client->user_data;
|
||||
this->impl = impl;
|
||||
this->fd = fd;
|
||||
this->source = pw_loop_add_io(impl->core->main_loop->loop,
|
||||
this->source = pw_loop_add_io(impl->core->main_loop,
|
||||
this->fd,
|
||||
SPA_IO_ERR | SPA_IO_HUP, false, connection_data, this);
|
||||
if (this->source == NULL)
|
||||
|
|
@ -233,41 +246,29 @@ static struct native_client *client_new(struct impl *impl, int fd)
|
|||
return this;
|
||||
|
||||
no_connection:
|
||||
pw_loop_destroy_source(impl->core->main_loop->loop, this->source);
|
||||
pw_loop_destroy_source(impl->core->main_loop, this->source);
|
||||
no_source:
|
||||
free(this);
|
||||
no_client:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct socket *create_socket(void)
|
||||
static void destroy_listener(struct listener *l)
|
||||
{
|
||||
struct socket *s;
|
||||
|
||||
if ((s = calloc(1, sizeof(struct socket))) == NULL)
|
||||
return NULL;
|
||||
|
||||
s->fd = -1;
|
||||
s->fd_lock = -1;
|
||||
return s;
|
||||
if (l->source)
|
||||
pw_loop_destroy_source(l->loop, l->source);
|
||||
if (l->addr.sun_path[0])
|
||||
unlink(l->addr.sun_path);
|
||||
if (l->fd >= 0)
|
||||
close(l->fd);
|
||||
if (l->lock_addr[0])
|
||||
unlink(l->lock_addr);
|
||||
if (l->fd_lock >= 0)
|
||||
close(l->fd_lock);
|
||||
free(l);
|
||||
}
|
||||
|
||||
static void destroy_socket(struct socket *s)
|
||||
{
|
||||
if (s->source)
|
||||
pw_loop_destroy_source(s->loop, s->source);
|
||||
if (s->addr.sun_path[0])
|
||||
unlink(s->addr.sun_path);
|
||||
if (s->fd >= 0)
|
||||
close(s->fd);
|
||||
if (s->lock_addr[0])
|
||||
unlink(s->lock_addr);
|
||||
if (s->fd_lock >= 0)
|
||||
close(s->fd_lock);
|
||||
free(s);
|
||||
}
|
||||
|
||||
static bool init_socket_name(struct socket *s, const char *name)
|
||||
static bool init_socket_name(struct listener *l, const char *name)
|
||||
{
|
||||
int name_size;
|
||||
const char *runtime_dir;
|
||||
|
|
@ -277,57 +278,55 @@ static bool init_socket_name(struct socket *s, const char *name)
|
|||
return false;
|
||||
}
|
||||
|
||||
s->addr.sun_family = AF_LOCAL;
|
||||
name_size = snprintf(s->addr.sun_path, sizeof(s->addr.sun_path),
|
||||
l->addr.sun_family = AF_LOCAL;
|
||||
name_size = snprintf(l->addr.sun_path, sizeof(l->addr.sun_path),
|
||||
"%s/%s", runtime_dir, name) + 1;
|
||||
|
||||
s->core_name = (s->addr.sun_path + name_size - 1) - strlen(name);
|
||||
|
||||
if (name_size > (int) sizeof(s->addr.sun_path)) {
|
||||
if (name_size > (int) sizeof(l->addr.sun_path)) {
|
||||
pw_log_error("socket path \"%s/%s\" plus null terminator exceeds 108 bytes",
|
||||
runtime_dir, name);
|
||||
*s->addr.sun_path = 0;
|
||||
*l->addr.sun_path = 0;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool lock_socket(struct socket *s)
|
||||
static bool lock_socket(struct listener *l)
|
||||
{
|
||||
struct stat socket_stat;
|
||||
|
||||
snprintf(s->lock_addr, sizeof(s->lock_addr), "%s%s", s->addr.sun_path, LOCK_SUFFIX);
|
||||
snprintf(l->lock_addr, sizeof(l->lock_addr), "%s%s", l->addr.sun_path, LOCK_SUFFIX);
|
||||
|
||||
s->fd_lock = open(s->lock_addr, O_CREAT | O_CLOEXEC,
|
||||
l->fd_lock = open(l->lock_addr, O_CREAT | O_CLOEXEC,
|
||||
(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
|
||||
|
||||
if (s->fd_lock < 0) {
|
||||
pw_log_error("unable to open lockfile %s check permissions", s->lock_addr);
|
||||
if (l->fd_lock < 0) {
|
||||
pw_log_error("unable to open lockfile %s check permissions", l->lock_addr);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (flock(s->fd_lock, LOCK_EX | LOCK_NB) < 0) {
|
||||
if (flock(l->fd_lock, LOCK_EX | LOCK_NB) < 0) {
|
||||
pw_log_error("unable to lock lockfile %s, maybe another daemon is running",
|
||||
s->lock_addr);
|
||||
l->lock_addr);
|
||||
goto err_fd;
|
||||
}
|
||||
|
||||
if (stat(s->addr.sun_path, &socket_stat) < 0) {
|
||||
if (stat(l->addr.sun_path, &socket_stat) < 0) {
|
||||
if (errno != ENOENT) {
|
||||
pw_log_error("did not manage to stat file %s\n", s->addr.sun_path);
|
||||
pw_log_error("did not manage to stat file %s\n", l->addr.sun_path);
|
||||
goto err_fd;
|
||||
}
|
||||
} else if (socket_stat.st_mode & S_IWUSR || socket_stat.st_mode & S_IWGRP) {
|
||||
unlink(s->addr.sun_path);
|
||||
unlink(l->addr.sun_path);
|
||||
}
|
||||
return true;
|
||||
|
||||
err_fd:
|
||||
close(s->fd_lock);
|
||||
s->fd_lock = -1;
|
||||
close(l->fd_lock);
|
||||
l->fd_lock = -1;
|
||||
err:
|
||||
*s->lock_addr = 0;
|
||||
*s->addr.sun_path = 0;
|
||||
*l->lock_addr = 0;
|
||||
*l->addr.sun_path = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -355,83 +354,309 @@ socket_data(struct spa_loop_utils *utils,
|
|||
return;
|
||||
}
|
||||
|
||||
pw_loop_update_io(impl->core->main_loop->loop,
|
||||
pw_loop_update_io(impl->core->main_loop,
|
||||
client->source, SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP);
|
||||
}
|
||||
|
||||
static bool add_socket(struct impl *impl, struct socket *s)
|
||||
static bool add_socket(struct impl *impl, struct listener *l)
|
||||
{
|
||||
socklen_t size;
|
||||
|
||||
if ((s->fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0)
|
||||
if ((l->fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0)
|
||||
return false;
|
||||
|
||||
size = offsetof(struct sockaddr_un, sun_path) +strlen(s->addr.sun_path);
|
||||
if (bind(s->fd, (struct sockaddr *) &s->addr, size) < 0) {
|
||||
size = offsetof(struct sockaddr_un, sun_path) + strlen(l->addr.sun_path);
|
||||
if (bind(l->fd, (struct sockaddr *) &l->addr, size) < 0) {
|
||||
pw_log_error("bind() failed with error: %m");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (listen(s->fd, 128) < 0) {
|
||||
if (listen(l->fd, 128) < 0) {
|
||||
pw_log_error("listen() failed with error: %m");
|
||||
return false;
|
||||
}
|
||||
|
||||
s->loop = impl->core->main_loop->loop;
|
||||
s->source = pw_loop_add_io(s->loop, s->fd, SPA_IO_IN, false, socket_data, impl);
|
||||
if (s->source == NULL)
|
||||
l->loop = impl->core->main_loop;
|
||||
l->source = pw_loop_add_io(l->loop, l->fd, SPA_IO_IN, false, socket_data, impl);
|
||||
if (l->source == NULL)
|
||||
return false;
|
||||
|
||||
spa_list_insert(impl->socket_list.prev, &s->link);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_name(struct pw_properties *properties)
|
||||
{
|
||||
const char *name = NULL;
|
||||
|
||||
if (properties)
|
||||
name = pw_properties_get(properties, "pipewire.core.name");
|
||||
if (name == NULL)
|
||||
name = getenv("PIPEWIRE_CORE");
|
||||
if (name == NULL)
|
||||
name = "pipewire-0";
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static int impl_connect(struct pw_protocol_connection *conn)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
socklen_t size;
|
||||
const char *runtime_dir, *name = NULL;
|
||||
int name_size, fd;
|
||||
|
||||
if ((runtime_dir = getenv("XDG_RUNTIME_DIR")) == NULL) {
|
||||
pw_log_error("connect failed: XDG_RUNTIME_DIR not set in the environment");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (name == NULL)
|
||||
name = getenv("PIPEWIRE_CORE");
|
||||
if (name == NULL)
|
||||
name = "pipewire-0";
|
||||
|
||||
if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0)
|
||||
return -1;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_LOCAL;
|
||||
name_size = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", runtime_dir, name) + 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);
|
||||
goto error_close;
|
||||
};
|
||||
|
||||
size = offsetof(struct sockaddr_un, sun_path) + name_size;
|
||||
|
||||
if (connect(fd, (struct sockaddr *) &addr, size) < 0) {
|
||||
goto error_close;
|
||||
}
|
||||
|
||||
return conn->connect_fd(conn, fd);
|
||||
|
||||
error_close:
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
on_remote_data(struct spa_loop_utils *utils,
|
||||
struct spa_source *source, int fd, enum spa_io mask, void *data)
|
||||
{
|
||||
struct connection *impl = data;
|
||||
struct pw_remote *this = impl->this.remote;
|
||||
struct pw_connection *conn = impl->connection;
|
||||
|
||||
if (mask & (SPA_IO_ERR | SPA_IO_HUP)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mask & SPA_IO_IN) {
|
||||
uint8_t opcode;
|
||||
uint32_t id;
|
||||
uint32_t size;
|
||||
void *message;
|
||||
|
||||
while (!impl->disconnecting
|
||||
&& pw_connection_get_next(conn, &opcode, &id, &message, &size)) {
|
||||
struct pw_proxy *proxy;
|
||||
const demarshal_func_t *demarshal;
|
||||
|
||||
pw_log_trace("protocol-native %p: got message %d from %u", this, opcode, id);
|
||||
|
||||
proxy = pw_map_lookup(&this->objects, id);
|
||||
if (proxy == NULL) {
|
||||
pw_log_error("protocol-native %p: could not find proxy %u", this, id);
|
||||
continue;
|
||||
}
|
||||
if (opcode >= proxy->iface->n_events) {
|
||||
pw_log_error("protocol-native %p: invalid method %u for %u", this, opcode,
|
||||
id);
|
||||
continue;
|
||||
}
|
||||
|
||||
demarshal = proxy->iface->events;
|
||||
if (demarshal[opcode]) {
|
||||
if (!demarshal[opcode] (proxy, message, size))
|
||||
pw_log_error
|
||||
("protocol-native %p: invalid message received %u for %u", this,
|
||||
opcode, id);
|
||||
} else
|
||||
pw_log_error("protocol-native %p: function %d not implemented on %u", this,
|
||||
opcode, id);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void do_flush_event(struct spa_loop_utils *utils, struct spa_source *source, void *data)
|
||||
{
|
||||
struct connection *impl = data;
|
||||
if (impl->connection)
|
||||
if (!pw_connection_flush(impl->connection))
|
||||
impl->this.disconnect(&impl->this);
|
||||
}
|
||||
|
||||
static void on_need_flush(struct pw_listener *listener, struct pw_connection *connection)
|
||||
{
|
||||
struct connection *impl = SPA_CONTAINER_OF(listener, struct connection, need_flush);
|
||||
struct pw_remote *remote = impl->this.remote;
|
||||
pw_loop_signal_event(remote->core->main_loop, impl->flush_event);
|
||||
}
|
||||
|
||||
static int impl_connect_fd(struct pw_protocol_connection *conn, int fd)
|
||||
{
|
||||
struct connection *impl = SPA_CONTAINER_OF(conn, struct connection, this);
|
||||
struct pw_remote *remote = impl->this.remote;
|
||||
|
||||
impl->connection = pw_connection_new(fd);
|
||||
if (impl->connection == NULL)
|
||||
goto error_close;
|
||||
|
||||
conn->remote->protocol_private = impl->connection;
|
||||
|
||||
pw_signal_add(&impl->connection->need_flush, &impl->need_flush, on_need_flush);
|
||||
|
||||
impl->fd = fd;
|
||||
impl->source = pw_loop_add_io(remote->core->main_loop,
|
||||
fd,
|
||||
SPA_IO_IN | SPA_IO_HUP | SPA_IO_ERR,
|
||||
false, on_remote_data, impl);
|
||||
|
||||
return 0;
|
||||
|
||||
error_close:
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int impl_disconnect(struct pw_protocol_connection *conn)
|
||||
{
|
||||
struct connection *impl = SPA_CONTAINER_OF(conn, struct connection, this);
|
||||
struct pw_remote *remote = impl->this.remote;
|
||||
|
||||
impl->disconnecting = true;
|
||||
|
||||
if (impl->source)
|
||||
pw_loop_destroy_source(remote->core->main_loop, impl->source);
|
||||
impl->source = NULL;
|
||||
|
||||
if (impl->connection)
|
||||
pw_connection_destroy(impl->connection);
|
||||
impl->connection = NULL;
|
||||
|
||||
if (impl->fd != -1)
|
||||
close(impl->fd);
|
||||
impl->fd = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int impl_destroy(struct pw_protocol_connection *conn)
|
||||
{
|
||||
struct connection *impl = SPA_CONTAINER_OF(conn, struct connection, this);
|
||||
struct pw_remote *remote = conn->remote;
|
||||
|
||||
pw_loop_destroy_source(remote->core->main_loop, impl->flush_event);
|
||||
|
||||
spa_list_remove(&conn->link);
|
||||
free(impl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pw_protocol_connection *
|
||||
impl_new_connection(struct pw_protocol *protocol,
|
||||
struct pw_remote *remote,
|
||||
struct pw_properties *properties)
|
||||
{
|
||||
struct impl *impl = protocol->protocol_private;
|
||||
struct connection *c;
|
||||
struct pw_protocol_connection *this;
|
||||
|
||||
if ((c = calloc(1, sizeof(struct connection))) == NULL)
|
||||
return NULL;
|
||||
|
||||
this = &c->this;
|
||||
this->remote = remote;
|
||||
|
||||
this->connect = impl_connect;
|
||||
this->connect_fd = impl_connect_fd;
|
||||
this->disconnect = impl_disconnect;
|
||||
this->destroy = impl_destroy;
|
||||
|
||||
c->flush_event = pw_loop_add_event(remote->core->main_loop, do_flush_event, c);
|
||||
|
||||
spa_list_insert(impl->protocol->connection_list.prev, &c->this.link);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
static struct pw_protocol_listener *
|
||||
impl_add_listener(struct pw_protocol *protocol,
|
||||
struct pw_core *core,
|
||||
struct pw_properties *properties)
|
||||
{
|
||||
struct impl *impl = protocol->protocol_private;
|
||||
struct listener *l;
|
||||
const char *name;
|
||||
|
||||
if ((l = calloc(1, sizeof(struct listener))) == NULL)
|
||||
return NULL;
|
||||
|
||||
l->fd = -1;
|
||||
l->fd_lock = -1;
|
||||
|
||||
name = get_name(properties);
|
||||
|
||||
if (!init_socket_name(l, name))
|
||||
goto error;
|
||||
|
||||
if (!lock_socket(l))
|
||||
goto error;
|
||||
|
||||
if (!add_socket(impl, l))
|
||||
goto error;
|
||||
|
||||
spa_list_insert(impl->protocol->listener_list.prev, &l->this.link);
|
||||
|
||||
impl->hooks.before = on_before_hook;
|
||||
pw_loop_add_hooks(impl->core->main_loop, &impl->hooks);
|
||||
|
||||
pw_log_info("protocol-native %p: Added listener", protocol);
|
||||
|
||||
return &l->this;
|
||||
|
||||
error:
|
||||
destroy_listener(l);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct impl *pw_protocol_native_new(struct pw_core *core, struct pw_properties *properties)
|
||||
{
|
||||
struct impl *impl;
|
||||
struct socket *s;
|
||||
const char *name;
|
||||
|
||||
impl = calloc(1, sizeof(struct impl));
|
||||
pw_log_debug("protocol-native %p: new", impl);
|
||||
|
||||
impl->core = core;
|
||||
impl->properties = properties;
|
||||
impl->protocol = pw_protocol_native_init();
|
||||
impl->protocol->new_connection = impl_new_connection;
|
||||
impl->protocol->add_listener = impl_add_listener;
|
||||
impl->protocol->protocol_private = impl;
|
||||
pw_log_debug("protocol-native %p: new %p", impl, impl->protocol);
|
||||
|
||||
name = NULL;
|
||||
if (impl->properties)
|
||||
name = pw_properties_get(impl->properties, "pipewire.core.name");
|
||||
if (name == NULL)
|
||||
name = getenv("PIPEWIRE_CORE");
|
||||
if (name == NULL)
|
||||
name = "pipewire-0";
|
||||
|
||||
s = create_socket();
|
||||
|
||||
spa_list_init(&impl->socket_list);
|
||||
spa_list_init(&impl->client_list);
|
||||
|
||||
if (!init_socket_name(s, name))
|
||||
goto error;
|
||||
|
||||
if (!lock_socket(s))
|
||||
goto error;
|
||||
|
||||
if (!add_socket(impl, s))
|
||||
goto error;
|
||||
|
||||
impl->hooks.before = on_before_hook;
|
||||
pw_loop_add_hooks(impl->core->main_loop->loop, &impl->hooks);
|
||||
impl_add_listener(impl->protocol, core, properties);
|
||||
|
||||
return impl;
|
||||
|
||||
error:
|
||||
destroy_socket(s);
|
||||
free(impl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
|
|
|||
|
|
@ -27,9 +27,8 @@
|
|||
|
||||
#include <spa/lib/debug.h>
|
||||
|
||||
#include "pipewire.h"
|
||||
#include <pipewire/client/pipewire.h>
|
||||
#include "connection.h"
|
||||
#include "log.h"
|
||||
|
||||
/** \cond */
|
||||
|
||||
|
|
@ -52,10 +51,14 @@ struct buffer {
|
|||
bool update;
|
||||
};
|
||||
|
||||
struct pw_connection_impl {
|
||||
struct impl {
|
||||
struct pw_connection this;
|
||||
|
||||
struct buffer in, out;
|
||||
|
||||
uint32_t dest_id;
|
||||
uint8_t opcode;
|
||||
struct spa_pod_builder builder;
|
||||
};
|
||||
|
||||
/** \endcond */
|
||||
|
|
@ -70,7 +73,7 @@ struct pw_connection_impl {
|
|||
*/
|
||||
int pw_connection_get_fd(struct pw_connection *conn, uint32_t index)
|
||||
{
|
||||
struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this);
|
||||
struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this);
|
||||
|
||||
if (index < 0 || index >= impl->in.n_fds)
|
||||
return -1;
|
||||
|
|
@ -88,7 +91,7 @@ int pw_connection_get_fd(struct pw_connection *conn, uint32_t index)
|
|||
*/
|
||||
uint32_t pw_connection_add_fd(struct pw_connection *conn, int fd)
|
||||
{
|
||||
struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this);
|
||||
struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this);
|
||||
uint32_t index, i;
|
||||
|
||||
for (i = 0; i < impl->out.n_fds; i++) {
|
||||
|
|
@ -186,10 +189,10 @@ static void clear_buffer(struct buffer *buf)
|
|||
*/
|
||||
struct pw_connection *pw_connection_new(int fd)
|
||||
{
|
||||
struct pw_connection_impl *impl;
|
||||
struct impl *impl;
|
||||
struct pw_connection *this;
|
||||
|
||||
impl = calloc(1, sizeof(struct pw_connection_impl));
|
||||
impl = calloc(1, sizeof(struct impl));
|
||||
if (impl == NULL)
|
||||
return NULL;
|
||||
|
||||
|
|
@ -229,7 +232,7 @@ struct pw_connection *pw_connection_new(int fd)
|
|||
*/
|
||||
void pw_connection_destroy(struct pw_connection *conn)
|
||||
{
|
||||
struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this);
|
||||
struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this);
|
||||
|
||||
pw_log_debug("connection %p: destroy", conn);
|
||||
|
||||
|
|
@ -261,7 +264,7 @@ pw_connection_get_next(struct pw_connection *conn,
|
|||
void **dt,
|
||||
uint32_t *sz)
|
||||
{
|
||||
struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this);
|
||||
struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this);
|
||||
size_t len, size;
|
||||
uint8_t *data;
|
||||
struct buffer *buf;
|
||||
|
|
@ -326,20 +329,9 @@ pw_connection_get_next(struct pw_connection *conn,
|
|||
return true;
|
||||
}
|
||||
|
||||
/** Start writing \a size bytes
|
||||
*
|
||||
* \param conn the connection
|
||||
* \param size the number of bytes to write
|
||||
* \return memory to write into
|
||||
*
|
||||
* Makes sure that \a size bytes can be written to \a conn and
|
||||
* returns a pointer to the memory to write into
|
||||
*
|
||||
* \memberof pw_connection
|
||||
*/
|
||||
void *pw_connection_begin_write(struct pw_connection *conn, uint32_t size)
|
||||
static inline void *begin_write(struct pw_connection *conn, uint32_t size)
|
||||
{
|
||||
struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this);
|
||||
struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this);
|
||||
uint32_t *p;
|
||||
struct buffer *buf = &impl->out;
|
||||
/* 4 for dest_id, 1 for opcode, 3 for size and size for payload */
|
||||
|
|
@ -347,28 +339,91 @@ void *pw_connection_begin_write(struct pw_connection *conn, uint32_t size)
|
|||
return p + 2;
|
||||
}
|
||||
|
||||
/** End writing to the connection
|
||||
*
|
||||
* \param conn the connection
|
||||
* \param dest_id the destination id
|
||||
* \param opcode the opcode
|
||||
* \param size the total written size
|
||||
*
|
||||
* Finnish writing a message of \a size to \a conn and write the
|
||||
* \a dest_id and \a opcode and final size to the connection
|
||||
*
|
||||
* \memberof pw_connection
|
||||
*/
|
||||
void
|
||||
pw_connection_end_write(struct pw_connection *conn, uint32_t dest_id, uint8_t opcode, uint32_t size)
|
||||
static uint32_t write_pod(struct spa_pod_builder *b, uint32_t ref, const void *data, uint32_t size)
|
||||
{
|
||||
struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this);
|
||||
uint32_t *p;
|
||||
struct impl *impl = SPA_CONTAINER_OF(b, struct impl, builder);
|
||||
|
||||
if (ref == -1)
|
||||
ref = b->offset;
|
||||
|
||||
if (b->size <= b->offset) {
|
||||
b->size = SPA_ROUND_UP_N(b->offset + size, 4096);
|
||||
b->data = begin_write(&impl->this, b->size);
|
||||
}
|
||||
memcpy(b->data + ref, data, size);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
struct spa_pod_builder *
|
||||
pw_connection_begin_write_resource(struct pw_connection *conn,
|
||||
struct pw_resource *resource,
|
||||
uint8_t opcode)
|
||||
{
|
||||
struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this);
|
||||
uint32_t diff, base, i, b;
|
||||
struct pw_client *client = resource->client;
|
||||
struct pw_core *core = client->core;
|
||||
const char **types;
|
||||
|
||||
base = client->n_types;
|
||||
diff = spa_type_map_get_size(core->type.map) - base;
|
||||
if (diff > 0) {
|
||||
types = alloca(diff * sizeof(char *));
|
||||
for (i = 0, b = base; i < diff; i++, b++)
|
||||
types[i] = spa_type_map_get_type(core->type.map, b);
|
||||
|
||||
client->n_types += diff;
|
||||
pw_core_notify_update_types(client->core_resource, base, diff, types);
|
||||
}
|
||||
|
||||
impl->dest_id = resource->id;
|
||||
impl->opcode = opcode;
|
||||
impl->builder = (struct spa_pod_builder) { NULL, 0, 0, NULL, write_pod };
|
||||
|
||||
return &impl->builder;
|
||||
}
|
||||
|
||||
struct spa_pod_builder *
|
||||
pw_connection_begin_write_proxy(struct pw_connection *conn,
|
||||
struct pw_proxy *proxy,
|
||||
uint8_t opcode)
|
||||
{
|
||||
struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this);
|
||||
uint32_t diff, base, i, b;
|
||||
const char **types;
|
||||
struct pw_remote *remote = proxy->remote;
|
||||
struct pw_core *core = remote->core;
|
||||
|
||||
base = remote->n_types;
|
||||
diff = spa_type_map_get_size(core->type.map) - base;
|
||||
if (diff > 0) {
|
||||
types = alloca(diff * sizeof(char *));
|
||||
for (i = 0, b = base; i < diff; i++, b++)
|
||||
types[i] = spa_type_map_get_type(core->type.map, b);
|
||||
|
||||
remote->n_types += diff;
|
||||
pw_core_do_update_types(remote->core_proxy, base, diff, types);
|
||||
}
|
||||
|
||||
impl->dest_id = proxy->id;
|
||||
impl->opcode = opcode;
|
||||
impl->builder = (struct spa_pod_builder) { NULL, 0, 0, NULL, write_pod };
|
||||
|
||||
return &impl->builder;
|
||||
}
|
||||
|
||||
void
|
||||
pw_connection_end_write(struct pw_connection *conn,
|
||||
struct spa_pod_builder *builder)
|
||||
{
|
||||
struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this);
|
||||
uint32_t *p, size = builder->offset;
|
||||
struct buffer *buf = &impl->out;
|
||||
|
||||
p = connection_ensure_size(conn, buf, 8 + size);
|
||||
*p++ = dest_id;
|
||||
*p++ = (opcode << 24) | (size & 0xffffff);
|
||||
*p++ = impl->dest_id;
|
||||
*p++ = (impl->opcode << 24) | (size & 0xffffff);
|
||||
|
||||
buf->buffer_size += 8 + size;
|
||||
|
||||
|
|
@ -391,7 +446,7 @@ pw_connection_end_write(struct pw_connection *conn, uint32_t dest_id, uint8_t op
|
|||
*/
|
||||
bool pw_connection_flush(struct pw_connection *conn)
|
||||
{
|
||||
struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this);
|
||||
struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this);
|
||||
ssize_t len;
|
||||
struct msghdr msg = { 0 };
|
||||
struct iovec iov[1];
|
||||
|
|
@ -463,7 +518,7 @@ bool pw_connection_flush(struct pw_connection *conn)
|
|||
*/
|
||||
bool pw_connection_clear(struct pw_connection *conn)
|
||||
{
|
||||
struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this);
|
||||
struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this);
|
||||
|
||||
clear_buffer(&impl->out);
|
||||
clear_buffer(&impl->in);
|
||||
|
|
@ -61,12 +61,20 @@ pw_connection_get_next(struct pw_connection *conn,
|
|||
uint32_t *dest_id,
|
||||
void **data, uint32_t *size);
|
||||
|
||||
void *
|
||||
pw_connection_begin_write(struct pw_connection *conn, uint32_t size);
|
||||
struct spa_pod_builder *
|
||||
pw_connection_begin_write_resource(struct pw_connection *conn,
|
||||
struct pw_resource *resource,
|
||||
uint8_t opcode);
|
||||
|
||||
struct spa_pod_builder *
|
||||
pw_connection_begin_write_proxy(struct pw_connection *conn,
|
||||
struct pw_proxy *proxy,
|
||||
uint8_t opcode);
|
||||
|
||||
|
||||
void
|
||||
pw_connection_end_write(struct pw_connection *conn,
|
||||
uint32_t dest_id, uint8_t opcode, uint32_t size);
|
||||
struct spa_pod_builder *builder);
|
||||
|
||||
bool
|
||||
pw_connection_flush(struct pw_connection *conn);
|
||||
|
|
@ -24,129 +24,66 @@
|
|||
|
||||
#include "pipewire/client/protocol.h"
|
||||
#include "pipewire/client/interfaces.h"
|
||||
#include "pipewire/client/connection.h"
|
||||
#include "pipewire/server/resource.h"
|
||||
|
||||
#include "connection.h"
|
||||
|
||||
/** \cond */
|
||||
struct builder {
|
||||
struct spa_pod_builder b;
|
||||
struct pw_connection *connection;
|
||||
};
|
||||
|
||||
typedef bool(*demarshal_func_t) (void *object, void *data, size_t size);
|
||||
|
||||
/** \endcond */
|
||||
|
||||
static uint32_t write_pod(struct spa_pod_builder *b, uint32_t ref, const void *data, uint32_t size)
|
||||
{
|
||||
if (ref == -1)
|
||||
ref = b->offset;
|
||||
|
||||
if (b->size <= b->offset) {
|
||||
b->size = SPA_ROUND_UP_N(b->offset + size, 4096);
|
||||
b->data = pw_connection_begin_write(((struct builder *) b)->connection, b->size);
|
||||
}
|
||||
memcpy(b->data + ref, data, size);
|
||||
return ref;
|
||||
}
|
||||
|
||||
static void core_update_map_client(struct pw_context *context)
|
||||
{
|
||||
uint32_t diff, base, i;
|
||||
const char **types;
|
||||
|
||||
base = context->n_types;
|
||||
diff = spa_type_map_get_size(context->type.map) - base;
|
||||
if (diff == 0)
|
||||
return;
|
||||
|
||||
types = alloca(diff * sizeof(char *));
|
||||
for (i = 0; i < diff; i++, base++)
|
||||
types[i] = spa_type_map_get_type(context->type.map, base);
|
||||
|
||||
pw_core_do_update_types(context->core_proxy, context->n_types, diff, types);
|
||||
context->n_types += diff;
|
||||
}
|
||||
|
||||
static void core_update_map_server(struct pw_client *client)
|
||||
{
|
||||
uint32_t diff, base, i;
|
||||
struct pw_core *core = client->core;
|
||||
const char **types;
|
||||
|
||||
base = client->n_types;
|
||||
diff = spa_type_map_get_size(core->type.map) - base;
|
||||
if (diff == 0)
|
||||
return;
|
||||
|
||||
types = alloca(diff * sizeof(char *));
|
||||
for (i = 0; i < diff; i++, base++)
|
||||
types[i] = spa_type_map_get_type(core->type.map, base);
|
||||
|
||||
pw_core_notify_update_types(client->core_resource, client->n_types, diff, types);
|
||||
client->n_types += diff;
|
||||
}
|
||||
|
||||
|
||||
static void core_marshal_client_update(void *object, const struct spa_dict *props)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_connection *connection = proxy->context->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct pw_connection *connection = proxy->remote->protocol_private;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
int i, n_items;
|
||||
|
||||
if (connection == NULL)
|
||||
return;
|
||||
|
||||
core_update_map_client(proxy->context);
|
||||
b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_CLIENT_UPDATE);
|
||||
|
||||
n_items = props ? props->n_items : 0;
|
||||
|
||||
spa_pod_builder_add(&b.b, SPA_POD_TYPE_STRUCT, &f, SPA_POD_TYPE_INT, n_items, 0);
|
||||
spa_pod_builder_add(b, SPA_POD_TYPE_STRUCT, &f, SPA_POD_TYPE_INT, n_items, 0);
|
||||
|
||||
for (i = 0; i < n_items; i++) {
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRING, props->items[i].key,
|
||||
SPA_POD_TYPE_STRING, props->items[i].value, 0);
|
||||
}
|
||||
spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
|
||||
pw_connection_end_write(connection, proxy->id, PW_CORE_METHOD_CLIENT_UPDATE, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void core_marshal_sync(void *object, uint32_t seq)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_connection *connection = proxy->context->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct pw_connection *connection = proxy->remote->protocol_private;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
if (connection == NULL)
|
||||
return;
|
||||
b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_SYNC);
|
||||
|
||||
core_update_map_client(proxy->context);
|
||||
spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, seq);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f, SPA_POD_TYPE_INT, seq);
|
||||
|
||||
pw_connection_end_write(connection, proxy->id, PW_CORE_METHOD_SYNC, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void core_marshal_get_registry(void *object, uint32_t new_id)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_connection *connection = proxy->context->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct pw_connection *connection = proxy->remote->protocol_private;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
if (connection == NULL)
|
||||
return;
|
||||
b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_GET_REGISTRY);
|
||||
|
||||
core_update_map_client(proxy->context);
|
||||
spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, new_id);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f, SPA_POD_TYPE_INT, new_id);
|
||||
|
||||
pw_connection_end_write(connection, proxy->id, PW_CORE_METHOD_GET_REGISTRY, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -155,31 +92,28 @@ core_marshal_create_node(void *object,
|
|||
const char *name, const struct spa_dict *props, uint32_t new_id)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_connection *connection = proxy->context->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct pw_connection *connection = proxy->remote->protocol_private;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
uint32_t i, n_items;
|
||||
|
||||
if (connection == NULL)
|
||||
return;
|
||||
|
||||
core_update_map_client(proxy->context);
|
||||
b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_CREATE_NODE);
|
||||
|
||||
n_items = props ? props->n_items : 0;
|
||||
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRUCT, &f,
|
||||
SPA_POD_TYPE_STRING, factory_name,
|
||||
SPA_POD_TYPE_STRING, name, SPA_POD_TYPE_INT, n_items, 0);
|
||||
|
||||
for (i = 0; i < n_items; i++) {
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRING, props->items[i].key,
|
||||
SPA_POD_TYPE_STRING, props->items[i].value, 0);
|
||||
}
|
||||
spa_pod_builder_add(&b.b, SPA_POD_TYPE_INT, new_id, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
spa_pod_builder_add(b, SPA_POD_TYPE_INT, new_id, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
|
||||
pw_connection_end_write(connection, proxy->id, PW_CORE_METHOD_CREATE_NODE, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -193,19 +127,16 @@ core_marshal_create_link(void *object,
|
|||
uint32_t new_id)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_connection *connection = proxy->context->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct pw_connection *connection = proxy->remote->protocol_private;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
uint32_t i, n_items;
|
||||
|
||||
if (connection == NULL)
|
||||
return;
|
||||
|
||||
core_update_map_client(proxy->context);
|
||||
b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_CREATE_LINK);
|
||||
|
||||
n_items = props ? props->n_items : 0;
|
||||
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRUCT, &f,
|
||||
SPA_POD_TYPE_INT, output_node_id,
|
||||
SPA_POD_TYPE_INT, output_port_id,
|
||||
|
|
@ -215,39 +146,38 @@ core_marshal_create_link(void *object,
|
|||
SPA_POD_TYPE_INT, n_items, 0);
|
||||
|
||||
for (i = 0; i < n_items; i++) {
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRING, props->items[i].key,
|
||||
SPA_POD_TYPE_STRING, props->items[i].value, 0);
|
||||
}
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_INT, new_id,
|
||||
-SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
|
||||
pw_connection_end_write(connection, proxy->id, PW_CORE_METHOD_CREATE_LINK, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void
|
||||
core_marshal_update_types_client(void *object, uint32_t first_id, uint32_t n_types, const char **types)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_connection *connection = proxy->context->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct pw_connection *connection = proxy->remote->protocol_private;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
uint32_t i;
|
||||
|
||||
if (connection == NULL)
|
||||
return;
|
||||
b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_UPDATE_TYPES);
|
||||
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRUCT, &f,
|
||||
SPA_POD_TYPE_INT, first_id, SPA_POD_TYPE_INT, n_types, 0);
|
||||
|
||||
for (i = 0; i < n_types; i++) {
|
||||
spa_pod_builder_add(&b.b, SPA_POD_TYPE_STRING, types[i], 0);
|
||||
spa_pod_builder_add(b, SPA_POD_TYPE_STRING, types[i], 0);
|
||||
}
|
||||
spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
|
||||
pw_connection_end_write(connection, proxy->id, PW_CORE_METHOD_UPDATE_TYPES, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static bool core_demarshal_info(void *object, void *data, size_t size)
|
||||
|
|
@ -351,15 +281,15 @@ static void core_marshal_info(void *object, struct pw_core_info *info)
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
uint32_t i, n_items;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CORE_EVENT_INFO);
|
||||
|
||||
n_items = info->props ? info->props->n_items : 0;
|
||||
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRUCT, &f,
|
||||
SPA_POD_TYPE_INT, info->id,
|
||||
SPA_POD_TYPE_LONG, info->change_mask,
|
||||
|
|
@ -370,27 +300,27 @@ static void core_marshal_info(void *object, struct pw_core_info *info)
|
|||
SPA_POD_TYPE_INT, info->cookie, SPA_POD_TYPE_INT, n_items, 0);
|
||||
|
||||
for (i = 0; i < n_items; i++) {
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRING, info->props->items[i].key,
|
||||
SPA_POD_TYPE_STRING, info->props->items[i].value, 0);
|
||||
}
|
||||
spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CORE_EVENT_INFO, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void core_marshal_done(void *object, uint32_t seq)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CORE_EVENT_DONE);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f, SPA_POD_TYPE_INT, seq);
|
||||
spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, seq);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CORE_EVENT_DONE, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void core_marshal_error(void *object, uint32_t id, int res, const char *error, ...)
|
||||
|
|
@ -398,35 +328,35 @@ static void core_marshal_error(void *object, uint32_t id, int res, const char *e
|
|||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
char buffer[128];
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
va_list ap;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CORE_EVENT_ERROR);
|
||||
|
||||
va_start(ap, error);
|
||||
vsnprintf(buffer, sizeof(buffer), error, ap);
|
||||
va_end(ap);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f,
|
||||
spa_pod_builder_struct(b, &f,
|
||||
SPA_POD_TYPE_INT, id,
|
||||
SPA_POD_TYPE_INT, res, SPA_POD_TYPE_STRING, buffer);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CORE_EVENT_ERROR, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void core_marshal_remove_id(void *object, uint32_t id)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CORE_EVENT_REMOVE_ID);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f, SPA_POD_TYPE_INT, id);
|
||||
spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, id);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CORE_EVENT_REMOVE_ID, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -434,20 +364,22 @@ core_marshal_update_types_server(void *object, uint32_t first_id, uint32_t n_typ
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
uint32_t i;
|
||||
|
||||
spa_pod_builder_add(&b.b,
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CORE_EVENT_UPDATE_TYPES);
|
||||
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRUCT, &f,
|
||||
SPA_POD_TYPE_INT, first_id, SPA_POD_TYPE_INT, n_types, 0);
|
||||
|
||||
for (i = 0; i < n_types; i++) {
|
||||
spa_pod_builder_add(&b.b, SPA_POD_TYPE_STRING, types[i], 0);
|
||||
spa_pod_builder_add(b, SPA_POD_TYPE_STRING, types[i], 0);
|
||||
}
|
||||
spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CORE_EVENT_UPDATE_TYPES, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static bool core_demarshal_client_update(void *object, void *data, size_t size)
|
||||
|
|
@ -594,32 +526,31 @@ static void registry_marshal_global(void *object, uint32_t id, const char *type,
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_REGISTRY_EVENT_GLOBAL);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f,
|
||||
spa_pod_builder_struct(b, &f,
|
||||
SPA_POD_TYPE_INT, id,
|
||||
SPA_POD_TYPE_STRING, type,
|
||||
SPA_POD_TYPE_INT, version);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_REGISTRY_EVENT_GLOBAL, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static void registry_marshal_global_remove(void *object, uint32_t id)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_REGISTRY_EVENT_GLOBAL_REMOVE);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f, SPA_POD_TYPE_INT, id);
|
||||
spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, id);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_REGISTRY_EVENT_GLOBAL_REMOVE,
|
||||
b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static bool registry_demarshal_bind(void *object, void *data, size_t size)
|
||||
|
|
@ -643,15 +574,15 @@ static void module_marshal_info(void *object, struct pw_module_info *info)
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
uint32_t i, n_items;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_MODULE_EVENT_INFO);
|
||||
|
||||
n_items = info->props ? info->props->n_items : 0;
|
||||
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRUCT, &f,
|
||||
SPA_POD_TYPE_INT, info->id,
|
||||
SPA_POD_TYPE_LONG, info->change_mask,
|
||||
|
|
@ -660,13 +591,13 @@ static void module_marshal_info(void *object, struct pw_module_info *info)
|
|||
SPA_POD_TYPE_STRING, info->args, SPA_POD_TYPE_INT, n_items, 0);
|
||||
|
||||
for (i = 0; i < n_items; i++) {
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRING, info->props->items[i].key,
|
||||
SPA_POD_TYPE_STRING, info->props->items[i].value, 0);
|
||||
}
|
||||
spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_MODULE_EVENT_INFO, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static bool module_demarshal_info(void *object, void *data, size_t size)
|
||||
|
|
@ -702,13 +633,13 @@ static void node_marshal_info(void *object, struct pw_node_info *info)
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
uint32_t i, n_items;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_NODE_EVENT_INFO);
|
||||
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRUCT, &f,
|
||||
SPA_POD_TYPE_INT, info->id,
|
||||
SPA_POD_TYPE_LONG, info->change_mask,
|
||||
|
|
@ -718,30 +649,30 @@ static void node_marshal_info(void *object, struct pw_node_info *info)
|
|||
SPA_POD_TYPE_INT, info->n_input_formats, 0);
|
||||
|
||||
for (i = 0; i < info->n_input_formats; i++)
|
||||
spa_pod_builder_add(&b.b, SPA_POD_TYPE_POD, info->input_formats[i], 0);
|
||||
spa_pod_builder_add(b, SPA_POD_TYPE_POD, info->input_formats[i], 0);
|
||||
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_INT, info->max_output_ports,
|
||||
SPA_POD_TYPE_INT, info->n_output_ports,
|
||||
SPA_POD_TYPE_INT, info->n_output_formats, 0);
|
||||
|
||||
for (i = 0; i < info->n_output_formats; i++)
|
||||
spa_pod_builder_add(&b.b, SPA_POD_TYPE_POD, info->output_formats[i], 0);
|
||||
spa_pod_builder_add(b, SPA_POD_TYPE_POD, info->output_formats[i], 0);
|
||||
|
||||
n_items = info->props ? info->props->n_items : 0;
|
||||
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_INT, info->state,
|
||||
SPA_POD_TYPE_STRING, info->error, SPA_POD_TYPE_INT, n_items, 0);
|
||||
|
||||
for (i = 0; i < n_items; i++) {
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRING, info->props->items[i].key,
|
||||
SPA_POD_TYPE_STRING, info->props->items[i].value, 0);
|
||||
}
|
||||
spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_NODE_EVENT_INFO, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static bool node_demarshal_info(void *object, void *data, size_t size)
|
||||
|
|
@ -753,7 +684,7 @@ static bool node_demarshal_info(void *object, void *data, size_t size)
|
|||
int i;
|
||||
|
||||
if (!spa_pod_iter_struct(&it, data, size) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) ||
|
||||
!spa_pod_iter_get(&it,
|
||||
SPA_POD_TYPE_INT, &info.id,
|
||||
SPA_POD_TYPE_LONG, &info.change_mask,
|
||||
|
|
@ -801,27 +732,27 @@ static void client_marshal_info(void *object, struct pw_client_info *info)
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
uint32_t i, n_items;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_EVENT_INFO);
|
||||
|
||||
n_items = info->props ? info->props->n_items : 0;
|
||||
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRUCT, &f,
|
||||
SPA_POD_TYPE_INT, info->id,
|
||||
SPA_POD_TYPE_LONG, info->change_mask, SPA_POD_TYPE_INT, n_items, 0);
|
||||
|
||||
for (i = 0; i < n_items; i++) {
|
||||
spa_pod_builder_add(&b.b,
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_TYPE_STRING, info->props->items[i].key,
|
||||
SPA_POD_TYPE_STRING, info->props->items[i].value, 0);
|
||||
}
|
||||
spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_CLIENT_EVENT_INFO, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static bool client_demarshal_info(void *object, void *data, size_t size)
|
||||
|
|
@ -855,12 +786,12 @@ static void link_marshal_info(void *object, struct pw_link_info *info)
|
|||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_connection *connection = resource->client->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
core_update_map_server(resource->client);
|
||||
b = pw_connection_begin_write_resource(connection, resource, PW_LINK_EVENT_INFO);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f,
|
||||
spa_pod_builder_struct(b, &f,
|
||||
SPA_POD_TYPE_INT, info->id,
|
||||
SPA_POD_TYPE_LONG, info->change_mask,
|
||||
SPA_POD_TYPE_INT, info->output_node_id,
|
||||
|
|
@ -869,7 +800,7 @@ static void link_marshal_info(void *object, struct pw_link_info *info)
|
|||
SPA_POD_TYPE_INT, info->input_port_id,
|
||||
SPA_POD_TYPE_POD, info->format);
|
||||
|
||||
pw_connection_end_write(connection, resource->id, PW_LINK_EVENT_INFO, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static bool link_demarshal_info(void *object, void *data, size_t size)
|
||||
|
|
@ -879,7 +810,7 @@ static bool link_demarshal_info(void *object, void *data, size_t size)
|
|||
struct pw_link_info info = { 0, };
|
||||
|
||||
if (!spa_pod_iter_struct(&it, data, size) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) ||
|
||||
!pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) ||
|
||||
!spa_pod_iter_get(&it,
|
||||
SPA_POD_TYPE_INT, &info.id,
|
||||
SPA_POD_TYPE_LONG, &info.change_mask,
|
||||
|
|
@ -929,21 +860,18 @@ static bool registry_demarshal_global_remove(void *object, void *data, size_t si
|
|||
static void registry_marshal_bind(void *object, uint32_t id, uint32_t version, uint32_t new_id)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_connection *connection = proxy->context->protocol_private;
|
||||
struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
|
||||
struct pw_connection *connection = proxy->remote->protocol_private;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
if (connection == NULL)
|
||||
return;
|
||||
b = pw_connection_begin_write_proxy(connection, proxy, PW_REGISTRY_METHOD_BIND);
|
||||
|
||||
core_update_map_client(proxy->context);
|
||||
|
||||
spa_pod_builder_struct(&b.b, &f,
|
||||
spa_pod_builder_struct(b, &f,
|
||||
SPA_POD_TYPE_INT, id,
|
||||
SPA_POD_TYPE_INT, version,
|
||||
SPA_POD_TYPE_INT, new_id);
|
||||
|
||||
pw_connection_end_write(connection, proxy->id, PW_REGISTRY_METHOD_BIND, b.b.offset);
|
||||
pw_connection_end_write(connection, b);
|
||||
}
|
||||
|
||||
static const struct pw_core_methods pw_protocol_native_client_core_methods = {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ static struct node_info *find_node_info(struct impl *impl, struct pw_node *node)
|
|||
static void remove_idle_timeout(struct node_info *info)
|
||||
{
|
||||
if (info->idle_timeout) {
|
||||
pw_loop_destroy_source(info->impl->core->main_loop->loop, info->idle_timeout);
|
||||
pw_loop_destroy_source(info->impl->core->main_loop, info->idle_timeout);
|
||||
info->idle_timeout = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -102,11 +102,11 @@ on_node_state_changed(struct pw_listener *listener,
|
|||
struct timespec value;
|
||||
|
||||
pw_log_debug("module %p: node %p became idle", impl, node);
|
||||
info->idle_timeout = pw_loop_add_timer(impl->core->main_loop->loop,
|
||||
info->idle_timeout = pw_loop_add_timer(impl->core->main_loop,
|
||||
idle_timeout, info);
|
||||
value.tv_sec = 3;
|
||||
value.tv_nsec = 0;
|
||||
pw_loop_update_timer(impl->core->main_loop->loop,
|
||||
pw_loop_update_timer(impl->core->main_loop,
|
||||
info->idle_timeout, &value, NULL, false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,3 +22,13 @@ pipewire_module_spa_node = shared_library('pipewire-module-spa-node',
|
|||
install_dir : '@0@/pipewire-0.1'.format(get_option('libdir')),
|
||||
dependencies : [mathlib, dl_lib, pipewire_dep, pipewirecore_dep],
|
||||
)
|
||||
|
||||
pipewire_module_spa_node_factory = shared_library('pipewire-module-spa-node-factory',
|
||||
[ 'module-node-factory.c', 'spa-node.c' ],
|
||||
c_args : pipewire_module_spa_c_args,
|
||||
include_directories : [configinc, spa_inc],
|
||||
link_with : spalib,
|
||||
install : true,
|
||||
install_dir : '@0@/pipewire-0.1'.format(get_option('libdir')),
|
||||
dependencies : [mathlib, dl_lib, pipewire_dep, pipewirecore_dep],
|
||||
)
|
||||
|
|
|
|||
117
pipewire/modules/spa/module-node-factory.c
Normal file
117
pipewire/modules/spa/module-node-factory.c
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pipewire/client/interfaces.h"
|
||||
#include "pipewire/server/core.h"
|
||||
#include "pipewire/server/module.h"
|
||||
#include "spa-node.h"
|
||||
|
||||
struct impl {
|
||||
struct pw_node_factory this;
|
||||
struct pw_properties *properties;
|
||||
};
|
||||
|
||||
static struct pw_node *create_node(struct pw_node_factory *factory,
|
||||
struct pw_resource *resource,
|
||||
const char *name,
|
||||
struct pw_properties *properties)
|
||||
{
|
||||
struct pw_node *node;
|
||||
const char *lib, *factory_name;
|
||||
|
||||
if (properties == NULL)
|
||||
goto no_properties;
|
||||
|
||||
lib = pw_properties_get(properties, "spa.library.name");
|
||||
factory_name = pw_properties_get(properties, "spa.factory.name");
|
||||
|
||||
if(lib == NULL || factory_name == NULL)
|
||||
goto no_properties;
|
||||
|
||||
node = pw_spa_node_load(factory->core,
|
||||
NULL,
|
||||
lib,
|
||||
factory_name,
|
||||
name,
|
||||
properties);
|
||||
if (node == NULL)
|
||||
goto no_mem;
|
||||
|
||||
return node;
|
||||
|
||||
no_properties:
|
||||
pw_log_error("missing properties");
|
||||
if (resource) {
|
||||
pw_core_notify_error(resource->client->core_resource,
|
||||
resource->client->core_resource->id,
|
||||
SPA_RESULT_INVALID_ARGUMENTS, "missing properties");
|
||||
}
|
||||
return NULL;
|
||||
no_mem:
|
||||
pw_log_error("can't create node");
|
||||
if (resource) {
|
||||
pw_core_notify_error(resource->client->core_resource,
|
||||
resource->client->core_resource->id,
|
||||
SPA_RESULT_NO_MEMORY, "no memory");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct impl *module_new(struct pw_core *core, struct pw_properties *properties)
|
||||
{
|
||||
struct impl *impl;
|
||||
|
||||
impl = calloc(1, sizeof(struct impl));
|
||||
pw_log_debug("module %p: new", impl);
|
||||
|
||||
impl->properties = properties;
|
||||
|
||||
impl->this.core = core;
|
||||
impl->this.name = "spa-node-factory";
|
||||
pw_signal_init(&impl->this.destroy_signal);
|
||||
impl->this.create_node = create_node;
|
||||
|
||||
spa_list_insert(core->node_factory_list.prev, &impl->this.link);
|
||||
|
||||
pw_core_add_global(core, NULL, core->type.node_factory, 0, impl, NULL, &impl->this.global);
|
||||
|
||||
return impl;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void module_destroy(struct impl *impl)
|
||||
{
|
||||
pw_log_debug("module %p: destroy", impl);
|
||||
|
||||
free(impl);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool pipewire__module_init(struct pw_module *module, const char *args)
|
||||
{
|
||||
module_new(module->core, NULL);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -270,12 +270,26 @@ node_impl_add_port(struct pw_node *node,
|
|||
return make_port(node, direction, port_id);
|
||||
}
|
||||
|
||||
static int node_impl_schedule_input(struct pw_node *node)
|
||||
{
|
||||
struct impl *impl = node->user_data;
|
||||
return spa_node_process_input(impl->node);
|
||||
}
|
||||
|
||||
static int node_impl_schedule_output(struct pw_node *node)
|
||||
{
|
||||
struct impl *impl = node->user_data;
|
||||
return spa_node_process_output(impl->node);
|
||||
}
|
||||
|
||||
static const struct pw_node_implementation node_impl = {
|
||||
PW_VERSION_NODE_IMPLEMENTATION,
|
||||
node_impl_get_props,
|
||||
node_impl_set_props,
|
||||
node_impl_send_command,
|
||||
node_impl_add_port,
|
||||
node_impl_schedule_input,
|
||||
node_impl_schedule_output,
|
||||
};
|
||||
|
||||
static void pw_spa_node_destroy(void *object)
|
||||
|
|
@ -347,16 +361,16 @@ on_node_reuse_buffer(struct spa_node *node, uint32_t port_id, uint32_t buffer_id
|
|||
{
|
||||
struct impl *impl = user_data;
|
||||
struct pw_node *this = impl->this;
|
||||
struct spa_graph_port *p;
|
||||
struct spa_graph_port *p, *pp;
|
||||
|
||||
spa_list_for_each(p, &this->rt.node.ports[SPA_DIRECTION_INPUT], link) {
|
||||
if (p->port_id != port_id)
|
||||
continue;
|
||||
|
||||
if (p->peer && p->peer->node->methods->reuse_buffer) {
|
||||
struct spa_graph_node *n = p->peer->node;
|
||||
n->methods->reuse_buffer(p->peer, buffer_id, n->user_data);
|
||||
}
|
||||
pp = p->peer;
|
||||
if (pp && pp->methods->reuse_buffer)
|
||||
pp->methods->reuse_buffer(pp, buffer_id, pp->user_data);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -403,8 +417,6 @@ pw_spa_node_new(struct pw_core *core,
|
|||
|
||||
this->destroy = pw_spa_node_destroy;
|
||||
this->implementation = &node_impl;
|
||||
this->rt.methods = spa_graph_scheduler_default;
|
||||
this->rt.node.user_data = node;
|
||||
this->clock = clock;
|
||||
|
||||
impl = this->user_data;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __USE_GNU
|
||||
#define __USE_GNU
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <pipewire/client/introspect.h>
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ struct impl {
|
|||
struct pw_core this;
|
||||
|
||||
struct spa_support support[4];
|
||||
struct pw_data_loop *data_loop;
|
||||
};
|
||||
|
||||
/** \endcond */
|
||||
|
|
@ -152,6 +153,7 @@ core_create_node(void *object,
|
|||
uint32_t new_id)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_resource *node_resource;
|
||||
struct pw_client *client = resource->client;
|
||||
struct pw_node_factory *factory;
|
||||
struct pw_properties *properties;
|
||||
|
|
@ -160,15 +162,22 @@ core_create_node(void *object,
|
|||
if (factory == NULL)
|
||||
goto no_factory;
|
||||
|
||||
node_resource = pw_resource_new(client,
|
||||
new_id,
|
||||
factory->type,
|
||||
0);
|
||||
if (node_resource == NULL)
|
||||
goto no_resource;
|
||||
|
||||
if (props) {
|
||||
properties = pw_properties_new_dict(props);
|
||||
if (properties == NULL)
|
||||
goto no_mem;
|
||||
goto no_properties;
|
||||
} else
|
||||
properties = NULL;
|
||||
|
||||
/* error will be posted */
|
||||
pw_node_factory_create_node(factory, client, name, properties, new_id);
|
||||
pw_node_factory_create_node(factory, node_resource, name, properties);
|
||||
properties = NULL;
|
||||
|
||||
done:
|
||||
|
|
@ -180,8 +189,14 @@ core_create_node(void *object,
|
|||
resource->id, SPA_RESULT_INVALID_ARGUMENTS, "unknown factory name");
|
||||
goto done;
|
||||
|
||||
no_mem:
|
||||
no_resource:
|
||||
pw_log_error("can't create resource");
|
||||
goto no_mem;
|
||||
no_properties:
|
||||
pw_log_error("can't create properties");
|
||||
pw_resource_destroy(node_resource);
|
||||
goto no_mem;
|
||||
no_mem:
|
||||
pw_core_notify_error(client->core_resource,
|
||||
resource->id, SPA_RESULT_NO_MEMORY, "no memory");
|
||||
goto done;
|
||||
|
|
@ -271,7 +286,7 @@ core_bind_func(struct pw_global *global, struct pw_client *client, uint32_t vers
|
|||
*
|
||||
* \memberof pw_core
|
||||
*/
|
||||
struct pw_core *pw_core_new(struct pw_main_loop *main_loop, struct pw_properties *properties)
|
||||
struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *properties)
|
||||
{
|
||||
struct impl *impl;
|
||||
struct pw_core *this;
|
||||
|
|
@ -281,10 +296,11 @@ struct pw_core *pw_core_new(struct pw_main_loop *main_loop, struct pw_properties
|
|||
return NULL;
|
||||
|
||||
this = &impl->this;
|
||||
this->data_loop = pw_data_loop_new();
|
||||
if (this->data_loop == NULL)
|
||||
impl->data_loop = pw_data_loop_new();
|
||||
if (impl->data_loop == NULL)
|
||||
goto no_data_loop;
|
||||
|
||||
this->data_loop = impl->data_loop->loop;
|
||||
this->main_loop = main_loop;
|
||||
this->properties = properties;
|
||||
|
||||
|
|
@ -297,14 +313,15 @@ struct pw_core *pw_core_new(struct pw_main_loop *main_loop, struct pw_properties
|
|||
spa_debug_set_type_map(this->type.map);
|
||||
|
||||
impl->support[0] = SPA_SUPPORT_INIT(SPA_TYPE__TypeMap, this->type.map);
|
||||
impl->support[1] = SPA_SUPPORT_INIT(SPA_TYPE_LOOP__DataLoop, this->data_loop->loop->loop);
|
||||
impl->support[2] = SPA_SUPPORT_INIT(SPA_TYPE_LOOP__MainLoop, this->main_loop->loop->loop);
|
||||
impl->support[1] = SPA_SUPPORT_INIT(SPA_TYPE_LOOP__DataLoop, this->data_loop->loop);
|
||||
impl->support[2] = SPA_SUPPORT_INIT(SPA_TYPE_LOOP__MainLoop, this->main_loop->loop);
|
||||
impl->support[3] = SPA_SUPPORT_INIT(SPA_TYPE__Log, pw_log_get());
|
||||
this->support = impl->support;
|
||||
this->n_support = 4;
|
||||
|
||||
pw_data_loop_start(this->data_loop);
|
||||
pw_data_loop_start(impl->data_loop);
|
||||
|
||||
spa_list_init(&this->remote_list);
|
||||
spa_list_init(&this->resource_list);
|
||||
spa_list_init(&this->registry_resource_list);
|
||||
spa_list_init(&this->global_list);
|
||||
|
|
@ -312,6 +329,7 @@ struct pw_core *pw_core_new(struct pw_main_loop *main_loop, struct pw_properties
|
|||
spa_list_init(&this->node_list);
|
||||
spa_list_init(&this->node_factory_list);
|
||||
spa_list_init(&this->link_list);
|
||||
pw_signal_init(&this->info_changed);
|
||||
pw_signal_init(&this->destroy_signal);
|
||||
pw_signal_init(&this->global_added);
|
||||
pw_signal_init(&this->global_removed);
|
||||
|
|
@ -348,7 +366,7 @@ void pw_core_destroy(struct pw_core *core)
|
|||
pw_log_debug("core %p: destroy", core);
|
||||
pw_signal_emit(&core->destroy_signal, core);
|
||||
|
||||
pw_data_loop_destroy(core->data_loop);
|
||||
pw_data_loop_destroy(impl->data_loop);
|
||||
|
||||
pw_map_clear(&core->objects);
|
||||
|
||||
|
|
@ -497,6 +515,8 @@ void pw_core_update_properties(struct pw_core *core, const struct spa_dict *dict
|
|||
core->info.change_mask = PW_CORE_CHANGE_MASK_PROPS;
|
||||
core->info.props = core->properties ? &core->properties->dict : NULL;
|
||||
|
||||
pw_signal_emit(&core->info_changed, core);
|
||||
|
||||
spa_list_for_each(resource, &core->resource_list, link) {
|
||||
pw_core_notify_info(resource, &core->info);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,6 +148,8 @@ struct pw_core {
|
|||
struct pw_global *global; /**< the global of the core */
|
||||
|
||||
struct pw_core_info info; /**< info about the core */
|
||||
/** Emited when the core info is updated */
|
||||
PW_SIGNAL(info_changed, (struct pw_listener *listener, struct pw_core *core));
|
||||
|
||||
struct pw_properties *properties; /**< properties of the core */
|
||||
|
||||
|
|
@ -158,6 +160,7 @@ struct pw_core {
|
|||
|
||||
struct pw_map objects; /**< map of known objects */
|
||||
|
||||
struct spa_list remote_list; /**< list of remote connections */
|
||||
struct spa_list resource_list; /**< list of core resources */
|
||||
struct spa_list registry_resource_list; /**< list of registry resources */
|
||||
struct spa_list global_list; /**< list of globals */
|
||||
|
|
@ -166,8 +169,8 @@ struct pw_core {
|
|||
struct spa_list node_factory_list; /**< list of node factories */
|
||||
struct spa_list link_list; /**< list of links */
|
||||
|
||||
struct pw_main_loop *main_loop; /**< main loop for control */
|
||||
struct pw_data_loop *data_loop; /**< data loop for data passing */
|
||||
struct pw_loop *main_loop; /**< main loop for control */
|
||||
struct pw_loop *data_loop; /**< data loop for data passing */
|
||||
|
||||
struct spa_support *support; /**< support for spa plugins */
|
||||
uint32_t n_support; /**< number of support items */
|
||||
|
|
@ -189,7 +192,7 @@ struct pw_core {
|
|||
};
|
||||
|
||||
struct pw_core *
|
||||
pw_core_new(struct pw_main_loop *main_loop, struct pw_properties *props);
|
||||
pw_core_new(struct pw_loop *main_loop, struct pw_properties *props);
|
||||
|
||||
void
|
||||
pw_core_destroy(struct pw_core *core);
|
||||
|
|
|
|||
|
|
@ -774,7 +774,7 @@ static void input_remove(struct pw_link *this, struct pw_port *port)
|
|||
pw_signal_remove(&impl->input_port_destroy);
|
||||
pw_signal_remove(&impl->input_async_complete);
|
||||
|
||||
pw_loop_invoke(port->node->data_loop->loop,
|
||||
pw_loop_invoke(port->node->data_loop,
|
||||
do_remove_input, 1, 0, NULL, true, this);
|
||||
|
||||
clear_port_buffers(this, this->input);
|
||||
|
|
@ -797,7 +797,7 @@ static void output_remove(struct pw_link *this, struct pw_port *port)
|
|||
pw_signal_remove(&impl->output_port_destroy);
|
||||
pw_signal_remove(&impl->output_async_complete);
|
||||
|
||||
pw_loop_invoke(port->node->data_loop->loop,
|
||||
pw_loop_invoke(port->node->data_loop,
|
||||
do_remove_output, 1, 0, NULL, true, this);
|
||||
|
||||
clear_port_buffers(this, this->output);
|
||||
|
|
@ -865,7 +865,7 @@ bool pw_link_activate(struct pw_link *this)
|
|||
impl->active = true;
|
||||
|
||||
pw_log_debug("link %p: activate", this);
|
||||
pw_loop_invoke(this->output->node->data_loop->loop,
|
||||
pw_loop_invoke(this->output->node->data_loop,
|
||||
do_activate_link, SPA_ID_INVALID, 0, NULL, false, this);
|
||||
|
||||
this->output->node->n_used_output_links++;
|
||||
|
|
@ -896,7 +896,7 @@ bool pw_link_deactivate(struct pw_link *this)
|
|||
|
||||
impl->active = false;
|
||||
pw_log_debug("link %p: deactivate", this);
|
||||
pw_loop_invoke(this->output->node->data_loop->loop,
|
||||
pw_loop_invoke(this->output->node->data_loop,
|
||||
do_deactivate_link, SPA_ID_INVALID, 0, NULL, true, this);
|
||||
|
||||
input_node = this->input->node;
|
||||
|
|
@ -1007,7 +1007,7 @@ struct pw_link *pw_link_new(struct pw_core *core,
|
|||
this = &impl->this;
|
||||
pw_log_debug("link %p: new", this);
|
||||
|
||||
impl->work = pw_work_queue_new(core->main_loop->loop);
|
||||
impl->work = pw_work_queue_new(core->main_loop);
|
||||
|
||||
this->core = core;
|
||||
this->properties = properties;
|
||||
|
|
@ -1073,10 +1073,10 @@ struct pw_link *pw_link_new(struct pw_core *core,
|
|||
0,
|
||||
&this->io);
|
||||
|
||||
pw_loop_invoke(output_node->data_loop->loop,
|
||||
pw_loop_invoke(output_node->data_loop,
|
||||
do_add_link,
|
||||
SPA_ID_INVALID, sizeof(struct pw_port *), &output, false, this);
|
||||
pw_loop_invoke(input_node->data_loop->loop,
|
||||
pw_loop_invoke(input_node->data_loop,
|
||||
do_add_link,
|
||||
SPA_ID_INVALID, sizeof(struct pw_port *), &input, false, this);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ extern "C" {
|
|||
#include <spa/ringbuffer.h>
|
||||
|
||||
#include <pipewire/client/mem.h>
|
||||
#include <pipewire/client/introspect.h>
|
||||
|
||||
#include <pipewire/server/core.h>
|
||||
#include <pipewire/server/port.h>
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ pipewirecore_headers = [
|
|||
'node.h',
|
||||
'node-factory.h',
|
||||
'port.h',
|
||||
'remote.h',
|
||||
'resource.h',
|
||||
# 'spa-node.h',
|
||||
'work-queue.h',
|
||||
]
|
||||
|
||||
|
|
@ -25,8 +25,8 @@ pipewirecore_sources = [
|
|||
'node.c',
|
||||
'node-factory.c',
|
||||
'port.c',
|
||||
'remote.c',
|
||||
'resource.c',
|
||||
# 'spa-node.c',
|
||||
'work-queue.c',
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -42,16 +42,16 @@ struct pw_node_factory {
|
|||
struct pw_global *global; /**< global for this factory */
|
||||
|
||||
const char *name; /**< the factory name */
|
||||
uint32_t type; /**< type of the created nodes */
|
||||
|
||||
/** Emited when the factory is destroyed */
|
||||
PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_node_factory *object));
|
||||
|
||||
/** The function to create a node from this factory */
|
||||
struct pw_node *(*create_node) (struct pw_node_factory *factory,
|
||||
struct pw_client *client,
|
||||
struct pw_resource *resource,
|
||||
const char *name,
|
||||
struct pw_properties *properties,
|
||||
uint32_t new_id);
|
||||
struct pw_properties *properties);
|
||||
};
|
||||
|
||||
#define pw_node_factory_create_node(f,...) (f)->create_node((f),__VA_ARGS__)
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ void pw_node_export(struct pw_node *this)
|
|||
this->owner,
|
||||
this->core->type.node, 0, this, node_bind_func, &this->global);
|
||||
|
||||
pw_loop_invoke(this->data_loop->loop, do_node_add, 1, 0, NULL, false, this);
|
||||
pw_loop_invoke(this->data_loop, do_node_add, 1, 0, NULL, false, this);
|
||||
|
||||
update_info(this);
|
||||
|
||||
|
|
@ -272,6 +272,26 @@ void pw_node_export(struct pw_node *this)
|
|||
pw_node_update_state(this, PW_NODE_STATE_SUSPENDED, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
graph_impl_process_input(struct spa_graph_node *node, void *user_data)
|
||||
{
|
||||
struct pw_node *this = user_data;
|
||||
return this->implementation->process_input(this);
|
||||
}
|
||||
|
||||
static int
|
||||
graph_impl_process_output(struct spa_graph_node *node, void *user_data)
|
||||
{
|
||||
struct pw_node *this = user_data;
|
||||
return this->implementation->process_output(this);
|
||||
}
|
||||
|
||||
static const struct spa_graph_node_methods graph_methods = {
|
||||
SPA_VERSION_GRAPH_NODE_METHODS,
|
||||
graph_impl_process_input,
|
||||
graph_impl_process_output,
|
||||
};
|
||||
|
||||
struct pw_node *pw_node_new(struct pw_core *core,
|
||||
struct pw_resource *owner,
|
||||
const char *name,
|
||||
|
|
@ -293,7 +313,7 @@ struct pw_node *pw_node_new(struct pw_core *core,
|
|||
if (user_data_size > 0)
|
||||
this->user_data = SPA_MEMBER(impl, sizeof(struct impl), void);
|
||||
|
||||
impl->work = pw_work_queue_new(this->core->main_loop->loop);
|
||||
impl->work = pw_work_queue_new(this->core->main_loop);
|
||||
|
||||
this->info.name = strdup(name);
|
||||
this->properties = properties;
|
||||
|
|
@ -324,9 +344,10 @@ struct pw_node *pw_node_new(struct pw_core *core,
|
|||
spa_list_init(&this->output_ports);
|
||||
pw_map_init(&this->output_port_map, 64, 64);
|
||||
|
||||
spa_graph_node_init(&this->rt.node,
|
||||
&this->rt.methods,
|
||||
this);
|
||||
spa_graph_node_init(&this->rt.node);
|
||||
spa_graph_node_set_methods(&this->rt.node,
|
||||
&graph_methods,
|
||||
this);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
|
@ -361,7 +382,7 @@ void pw_node_destroy(struct pw_node *node)
|
|||
pw_log_debug("node %p: destroy", impl);
|
||||
pw_signal_emit(&node->destroy_signal, node);
|
||||
|
||||
pw_loop_invoke(node->data_loop->loop, do_node_remove, 1, 0, NULL, true, node);
|
||||
pw_loop_invoke(node->data_loop, do_node_remove, 1, 0, NULL, true, node);
|
||||
|
||||
if (impl->exported) {
|
||||
spa_list_remove(&node->link);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ extern "C" {
|
|||
#include <spa/node.h>
|
||||
|
||||
#include <pipewire/client/mem.h>
|
||||
#include <pipewire/client/introspect.h>
|
||||
#include <pipewire/client/transport.h>
|
||||
|
||||
#include <pipewire/server/core.h>
|
||||
|
|
@ -57,6 +58,10 @@ struct pw_node_implementation {
|
|||
struct pw_port* (*add_port) (struct pw_node *node,
|
||||
enum pw_direction direction,
|
||||
uint32_t port_id);
|
||||
|
||||
int (*process_input) (struct pw_node *node);
|
||||
|
||||
int (*process_output) (struct pw_node *node);
|
||||
};
|
||||
|
||||
/** \page page_node Node
|
||||
|
|
@ -132,10 +137,9 @@ struct pw_node {
|
|||
PW_SIGNAL(event, (struct pw_listener *listener,
|
||||
struct pw_node *node, struct spa_event *event));
|
||||
|
||||
struct pw_data_loop *data_loop; /**< the data loop for this node */
|
||||
struct pw_loop *data_loop; /**< the data loop for this node */
|
||||
|
||||
struct {
|
||||
struct spa_graph_node_methods methods;
|
||||
struct spa_graph_scheduler *sched;
|
||||
struct spa_graph_node node;
|
||||
} rt;
|
||||
|
|
|
|||
|
|
@ -74,15 +74,19 @@ static int schedule_tee_output(struct spa_graph_node *node, void *user_data)
|
|||
return SPA_RESULT_NEED_BUFFER;
|
||||
}
|
||||
|
||||
static const struct spa_graph_node_methods schedule_tee_node = {
|
||||
SPA_VERSION_GRAPH_NODE_METHODS,
|
||||
schedule_tee_input,
|
||||
schedule_tee_output,
|
||||
};
|
||||
|
||||
static int schedule_tee_reuse_buffer(struct spa_graph_port *port, uint32_t buffer_id, void *user_data)
|
||||
{
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static const struct spa_graph_node_methods schedule_tee = {
|
||||
SPA_VERSION_GRAPH_NODE_METHODS,
|
||||
schedule_tee_input,
|
||||
schedule_tee_output,
|
||||
static const struct spa_graph_port_methods schedule_tee_port = {
|
||||
SPA_VERSION_GRAPH_PORT_METHODS,
|
||||
schedule_tee_reuse_buffer,
|
||||
};
|
||||
|
||||
|
|
@ -114,15 +118,18 @@ static int schedule_mix_output(struct spa_graph_node *node, void *user_data)
|
|||
return SPA_RESULT_NEED_BUFFER;
|
||||
}
|
||||
|
||||
static const struct spa_graph_node_methods schedule_mix_node = {
|
||||
SPA_VERSION_GRAPH_NODE_METHODS,
|
||||
schedule_mix_input,
|
||||
schedule_mix_output,
|
||||
};
|
||||
|
||||
static int schedule_mix_reuse_buffer(struct spa_graph_port *port, uint32_t buffer_id, void *user_data)
|
||||
{
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static const struct spa_graph_node_methods schedule_mix = {
|
||||
SPA_VERSION_GRAPH_NODE_METHODS,
|
||||
schedule_mix_input,
|
||||
schedule_mix_output,
|
||||
static const struct spa_graph_port_methods schedule_mix_port = {
|
||||
SPA_VERSION_GRAPH_PORT_METHODS,
|
||||
schedule_mix_reuse_buffer,
|
||||
};
|
||||
|
||||
|
|
@ -159,16 +166,22 @@ struct pw_port *pw_port_new(enum pw_direction direction,
|
|||
this->port_id,
|
||||
0,
|
||||
&this->io);
|
||||
spa_graph_node_init(&this->rt.mix_node,
|
||||
this->direction == PW_DIRECTION_INPUT ?
|
||||
&schedule_mix :
|
||||
&schedule_tee,
|
||||
this);
|
||||
spa_graph_node_init(&this->rt.mix_node);
|
||||
spa_graph_node_set_methods(&this->rt.mix_node,
|
||||
this->direction == PW_DIRECTION_INPUT ?
|
||||
&schedule_mix_node :
|
||||
&schedule_tee_node,
|
||||
this);
|
||||
spa_graph_port_init(&this->rt.mix_port,
|
||||
pw_direction_reverse(this->direction),
|
||||
0,
|
||||
0,
|
||||
&this->io);
|
||||
spa_graph_port_set_methods(&this->rt.mix_port,
|
||||
this->direction == PW_DIRECTION_INPUT ?
|
||||
&schedule_mix_port :
|
||||
&schedule_tee_port,
|
||||
this);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -204,7 +217,7 @@ void pw_port_add(struct pw_port *port, struct pw_node *node)
|
|||
}
|
||||
|
||||
port->rt.graph = node->rt.sched->graph;
|
||||
pw_loop_invoke(node->data_loop->loop, do_add_port, SPA_ID_INVALID, 0, NULL, false, port);
|
||||
pw_loop_invoke(node->data_loop, do_add_port, SPA_ID_INVALID, 0, NULL, false, port);
|
||||
|
||||
port_update_state(port, PW_PORT_STATE_CONFIGURE);
|
||||
|
||||
|
|
@ -238,7 +251,7 @@ void pw_port_destroy(struct pw_port *port)
|
|||
pw_signal_emit(&port->destroy_signal, port);
|
||||
|
||||
if (node) {
|
||||
pw_loop_invoke(port->node->data_loop->loop, do_remove_port, SPA_ID_INVALID, 0, NULL, true, port);
|
||||
pw_loop_invoke(port->node->data_loop, do_remove_port, SPA_ID_INVALID, 0, NULL, true, port);
|
||||
|
||||
if (port->direction == PW_DIRECTION_INPUT) {
|
||||
pw_map_remove(&node->input_port_map, port->port_id);
|
||||
|
|
@ -330,7 +343,7 @@ int pw_port_use_buffers(struct pw_port *port, struct spa_buffer **buffers, uint3
|
|||
return SPA_RESULT_NO_FORMAT;
|
||||
|
||||
if (port->state > PW_PORT_STATE_PAUSED) {
|
||||
pw_loop_invoke(port->node->data_loop->loop,
|
||||
pw_loop_invoke(port->node->data_loop,
|
||||
do_port_pause, 0, 0, NULL, true, port);
|
||||
port_update_state (port, PW_PORT_STATE_PAUSED);
|
||||
}
|
||||
|
|
@ -362,7 +375,7 @@ int pw_port_alloc_buffers(struct pw_port *port,
|
|||
return SPA_RESULT_NO_FORMAT;
|
||||
|
||||
if (port->state > PW_PORT_STATE_PAUSED) {
|
||||
pw_loop_invoke(port->node->data_loop->loop,
|
||||
pw_loop_invoke(port->node->data_loop,
|
||||
do_port_pause, 0, 0, NULL, true, port);
|
||||
port_update_state (port, PW_PORT_STATE_PAUSED);
|
||||
}
|
||||
|
|
|
|||
289
pipewire/server/remote.c
Normal file
289
pipewire/server/remote.c
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "pipewire/client/pipewire.h"
|
||||
|
||||
#include "pipewire/client/introspect.h"
|
||||
#include "pipewire/client/interfaces.h"
|
||||
#include "pipewire/client/connection.h"
|
||||
|
||||
#include "pipewire/server/remote.h"
|
||||
#include "pipewire/server/core.h"
|
||||
#include "pipewire/server/module.h"
|
||||
|
||||
#include <spa/lib/debug.h>
|
||||
|
||||
/** \cond */
|
||||
struct remote {
|
||||
struct pw_remote this;
|
||||
};
|
||||
/** \endcond */
|
||||
|
||||
const char *pw_remote_state_as_string(enum pw_remote_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case PW_REMOTE_STATE_ERROR:
|
||||
return "error";
|
||||
case PW_REMOTE_STATE_UNCONNECTED:
|
||||
return "unconnected";
|
||||
case PW_REMOTE_STATE_CONNECTING:
|
||||
return "connecting";
|
||||
case PW_REMOTE_STATE_CONNECTED:
|
||||
return "connected";
|
||||
}
|
||||
return "invalid-state";
|
||||
}
|
||||
|
||||
static void
|
||||
remote_update_state(struct pw_remote *remote, enum pw_remote_state state, const char *fmt, ...)
|
||||
{
|
||||
if (remote->state != state) {
|
||||
if (remote->error)
|
||||
free(remote->error);
|
||||
|
||||
if (fmt) {
|
||||
va_list varargs;
|
||||
|
||||
va_start(varargs, fmt);
|
||||
if (vasprintf(&remote->error, fmt, varargs) < 0) {
|
||||
pw_log_debug("remote %p: error formating message: %m", remote);
|
||||
remote->error = NULL;
|
||||
}
|
||||
va_end(varargs);
|
||||
} else {
|
||||
remote->error = NULL;
|
||||
}
|
||||
pw_log_debug("remote %p: update state from %s -> %s (%s)", remote,
|
||||
pw_remote_state_as_string(remote->state),
|
||||
pw_remote_state_as_string(state), remote->error);
|
||||
|
||||
remote->state = state;
|
||||
pw_signal_emit(&remote->state_changed, remote);
|
||||
}
|
||||
}
|
||||
|
||||
static void core_event_info(void *object, struct pw_core_info *info)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_remote *this = proxy->remote;
|
||||
|
||||
pw_log_debug("got core info");
|
||||
this->info = pw_core_info_update(this->info, info);
|
||||
pw_signal_emit(&this->info_changed, this);
|
||||
}
|
||||
|
||||
static void core_event_done(void *object, uint32_t seq)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_remote *this = proxy->remote;
|
||||
|
||||
pw_log_debug("core event done %d", seq);
|
||||
if (seq == 0)
|
||||
remote_update_state(this, PW_REMOTE_STATE_CONNECTED, NULL);
|
||||
|
||||
pw_signal_emit(&this->sync_reply, this, seq);
|
||||
}
|
||||
|
||||
static void core_event_error(void *object, uint32_t id, int res, const char *error, ...)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_remote *this = proxy->remote;
|
||||
remote_update_state(this, PW_REMOTE_STATE_ERROR, error);
|
||||
}
|
||||
|
||||
static void core_event_remove_id(void *object, uint32_t id)
|
||||
{
|
||||
struct pw_proxy *core_proxy = object;
|
||||
struct pw_remote *this = core_proxy->remote;
|
||||
struct pw_proxy *proxy;
|
||||
|
||||
proxy = pw_map_lookup(&this->objects, id);
|
||||
if (proxy) {
|
||||
pw_log_debug("remote %p: object remove %u", this, id);
|
||||
pw_proxy_destroy(proxy);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
core_event_update_types(void *object, uint32_t first_id, uint32_t n_types, const char **types)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct pw_remote *this = proxy->remote;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_types; i++, first_id++) {
|
||||
uint32_t this_id = spa_type_map_get_id(this->core->type.map, types[i]);
|
||||
if (!pw_map_insert_at(&this->types, first_id, PW_MAP_ID_TO_PTR(this_id)))
|
||||
pw_log_error("can't add type for client");
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pw_core_events core_events = {
|
||||
&core_event_update_types,
|
||||
&core_event_done,
|
||||
&core_event_error,
|
||||
&core_event_remove_id,
|
||||
&core_event_info,
|
||||
};
|
||||
|
||||
struct pw_remote *pw_remote_new(struct pw_core *core,
|
||||
struct pw_properties *properties)
|
||||
{
|
||||
struct remote *impl;
|
||||
struct pw_remote *this;
|
||||
|
||||
impl = calloc(1, sizeof(struct remote));
|
||||
if (impl == NULL)
|
||||
return NULL;
|
||||
|
||||
this = &impl->this;
|
||||
pw_log_debug("remote %p: new", impl);
|
||||
|
||||
this->core = core;
|
||||
|
||||
if (properties == NULL)
|
||||
properties = pw_properties_new(NULL, NULL);
|
||||
if (properties == NULL)
|
||||
goto no_mem;
|
||||
|
||||
pw_fill_context_properties(properties);
|
||||
this->properties = properties;
|
||||
|
||||
this->state = PW_REMOTE_STATE_UNCONNECTED;
|
||||
|
||||
pw_map_init(&this->objects, 64, 32);
|
||||
pw_map_init(&this->types, 64, 32);
|
||||
|
||||
spa_list_init(&this->proxy_list);
|
||||
spa_list_init(&this->stream_list);
|
||||
|
||||
pw_signal_init(&this->info_changed);
|
||||
pw_signal_init(&this->sync_reply);
|
||||
pw_signal_init(&this->state_changed);
|
||||
pw_signal_init(&this->destroy_signal);
|
||||
|
||||
pw_module_load(core, "libpipewire-module-protocol-native", NULL, NULL);
|
||||
pw_module_load(core, "libpipewire-module-client-node", NULL, NULL);
|
||||
this->protocol = pw_protocol_get(PW_TYPE_PROTOCOL__Native);
|
||||
|
||||
this->conn = this->protocol->new_connection(this->protocol, this, properties);
|
||||
|
||||
spa_list_insert(core->remote_list.prev, &this->link);
|
||||
|
||||
return this;
|
||||
|
||||
no_mem:
|
||||
free(impl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pw_remote_destroy(struct pw_remote *remote)
|
||||
{
|
||||
struct remote *impl = SPA_CONTAINER_OF(remote, struct remote, this);
|
||||
struct pw_proxy *proxy, *t2;
|
||||
|
||||
pw_log_debug("remote %p: destroy", remote);
|
||||
pw_signal_emit(&remote->destroy_signal, remote);
|
||||
|
||||
if (remote->state != PW_REMOTE_STATE_UNCONNECTED)
|
||||
pw_remote_disconnect(remote);
|
||||
|
||||
remote->conn->destroy(remote->conn);
|
||||
|
||||
spa_list_for_each_safe(proxy, t2, &remote->proxy_list, link)
|
||||
pw_proxy_destroy(proxy);
|
||||
|
||||
pw_map_clear(&remote->objects);
|
||||
pw_map_clear(&remote->types);
|
||||
|
||||
spa_list_remove(&remote->link);
|
||||
|
||||
if (remote->info)
|
||||
pw_core_info_free (remote->info);
|
||||
|
||||
if (remote->properties)
|
||||
pw_properties_free(remote->properties);
|
||||
free(remote->error);
|
||||
free(impl);
|
||||
}
|
||||
|
||||
static int do_connect(struct pw_remote *remote)
|
||||
{
|
||||
remote->core_proxy = pw_proxy_new(remote, 0, remote->core->type.core, 0);
|
||||
if (remote->core_proxy == NULL)
|
||||
goto no_proxy;
|
||||
|
||||
pw_proxy_set_implementation(remote->core_proxy, remote, PW_VERSION_CORE,
|
||||
&core_events, NULL);
|
||||
|
||||
pw_core_do_client_update(remote->core_proxy, &remote->properties->dict);
|
||||
pw_core_do_sync(remote->core_proxy, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
no_proxy:
|
||||
remote->conn->disconnect(remote->conn);
|
||||
remote_update_state(remote, PW_REMOTE_STATE_ERROR, "can't connect: no memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pw_remote_connect(struct pw_remote *remote)
|
||||
{
|
||||
int res;
|
||||
|
||||
remote_update_state(remote, PW_REMOTE_STATE_CONNECTING, NULL);
|
||||
|
||||
if ((res = remote->conn->connect(remote->conn)) < 0) {
|
||||
remote_update_state(remote, PW_REMOTE_STATE_ERROR, "connect failed");
|
||||
return res;
|
||||
}
|
||||
|
||||
return do_connect(remote);
|
||||
}
|
||||
|
||||
int pw_remote_connect_fd(struct pw_remote *remote, int fd)
|
||||
{
|
||||
int res;
|
||||
|
||||
remote_update_state(remote, PW_REMOTE_STATE_CONNECTING, NULL);
|
||||
|
||||
if ((res = remote->conn->connect_fd(remote->conn, fd)) < 0) {
|
||||
remote_update_state(remote, PW_REMOTE_STATE_ERROR, "connect_fd failed");
|
||||
return res;
|
||||
}
|
||||
|
||||
return do_connect(remote);
|
||||
}
|
||||
|
||||
void pw_remote_disconnect(struct pw_remote *remote)
|
||||
{
|
||||
remote->conn->disconnect(remote->conn);
|
||||
|
||||
if (remote->core_proxy)
|
||||
pw_proxy_destroy(remote->core_proxy);
|
||||
remote->core_proxy = NULL;
|
||||
|
||||
remote_update_state(remote, PW_REMOTE_STATE_UNCONNECTED, NULL);
|
||||
}
|
||||
181
pipewire/server/remote.h
Normal file
181
pipewire/server/remote.h
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/* 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_REMOTE_H__
|
||||
#define __PIPEWIRE_REMOTE_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \page page_remote_api Remote API
|
||||
*
|
||||
* \section sec_remote_api_overview Overview
|
||||
*
|
||||
* The remote API allows you to connect to a remote PipeWire and
|
||||
* perform actions on the PipeWire graph. This includes
|
||||
*
|
||||
* \li introspecting the objects on the server
|
||||
* \li Creating nodes
|
||||
* \li Linking nodes on their ports
|
||||
* \li providing media to the server for playback or consumption
|
||||
* \li retrieving media from the server
|
||||
*
|
||||
* \section sec_remote_api_loop Event Loop Abstraction
|
||||
*
|
||||
* Most API is asynchronous and based around an event loop. Methods will
|
||||
* start an operation which will cause a state change of the \ref pw_context
|
||||
* object. Connect to the state_changed signal to be notified of these
|
||||
* state changes.
|
||||
*
|
||||
* The most convenient way to deal with the asynchronous calls is probably
|
||||
* with the thread loop (See \subpage page_thread_loop for more details).
|
||||
*
|
||||
* \subsection ssec_remote_api_proxy Proxy
|
||||
*
|
||||
* Proxies are local representations of remote resources. They
|
||||
* allow communication between local and remote objects.
|
||||
*
|
||||
* The \ref pw_remote maintains a list of all proxies, including a core
|
||||
* proxy that is used to get access to other proxy objects.
|
||||
*
|
||||
* See also \subpage page_proxy
|
||||
*
|
||||
* \section sec_remote_api_remote Remote
|
||||
*
|
||||
* \subsection ssec_remote_create Create
|
||||
*
|
||||
* To create a new remote use pw_remote_new(). You will
|
||||
* need to pass a \ref pw_core implementation for event and data loop.
|
||||
*
|
||||
* A typical loop would be created with pw_thread_loop_new() but
|
||||
* other implementation are possible.
|
||||
*
|
||||
* You will also need to pass properties for the remote. Use
|
||||
* pw_fill_remote_properties() to get a default set of properties.
|
||||
*
|
||||
* After creating the remote, you can track the state of the remote
|
||||
* by listening for the state_changed signal.
|
||||
*
|
||||
* \subsection ssec_remote_api_remote_connect Connecting
|
||||
*
|
||||
* A remote must be connected to a server before any operation can be
|
||||
* issued. Calling pw_remote_connect() will initiate the connection
|
||||
* procedure.
|
||||
*
|
||||
* When connecting, the remote will automatically create a core
|
||||
* proxy to get access to the registry and types.
|
||||
*
|
||||
* \subsection ssec_remote_api_remote_disconnect Disconnect
|
||||
*
|
||||
* Use pw_remote_disconnect() to disconnect from the remote.
|
||||
*/
|
||||
|
||||
struct pw_remote;
|
||||
|
||||
#include <pipewire/client/map.h>
|
||||
#include <pipewire/client/loop.h>
|
||||
#include <pipewire/client/properties.h>
|
||||
#include <pipewire/client/protocol.h>
|
||||
#include <pipewire/client/proxy.h>
|
||||
#include <pipewire/client/type.h>
|
||||
#include <pipewire/server/core.h>
|
||||
|
||||
/** \enum pw_remote_state The state of a \ref pw_remote \memberof pw_remote */
|
||||
enum pw_remote_state {
|
||||
PW_REMOTE_STATE_ERROR = -1, /**< remote is in error */
|
||||
PW_REMOTE_STATE_UNCONNECTED = 0, /**< not connected */
|
||||
PW_REMOTE_STATE_CONNECTING = 1, /**< connecting to remote PipeWire */
|
||||
PW_REMOTE_STATE_CONNECTED = 2, /**< remote is connected and ready */
|
||||
};
|
||||
|
||||
/** Convert a \ref pw_remote_state to a readable string \memberof pw_remote */
|
||||
const char *pw_remote_state_as_string(enum pw_remote_state state);
|
||||
|
||||
/** \class pw_remote
|
||||
*
|
||||
* \brief Represents a connection with the PipeWire server
|
||||
*
|
||||
* a \ref pw_remote is created and used to connect to the server.
|
||||
* A \ref pw_proxy for the core object will automatically be created
|
||||
* when connecting.
|
||||
*
|
||||
* See also \ref page_client_api
|
||||
*/
|
||||
struct pw_remote {
|
||||
struct pw_core *core; /**< core */
|
||||
struct spa_list link; /**< link in core remote_list */
|
||||
struct pw_properties *properties; /**< extra properties */
|
||||
|
||||
struct pw_proxy *core_proxy; /**< proxy for the core object */
|
||||
struct pw_map objects; /**< map of client side proxy objects
|
||||
* indexed with the client id */
|
||||
struct pw_core_info *info; /**< info about the remote core */
|
||||
/** Signal emited when the core info changed */
|
||||
PW_SIGNAL(info_changed, (struct pw_listener *listener, struct pw_remote *remote));
|
||||
|
||||
/** Signal emited when a reply to a sync was received */
|
||||
PW_SIGNAL(sync_reply, (struct pw_listener *listener, struct pw_remote *remote, uint32_t seq));
|
||||
|
||||
uint32_t n_types; /**< number of client types */
|
||||
struct pw_map types; /**< client types */
|
||||
|
||||
struct spa_list proxy_list; /**< list of \ref pw_proxy objects */
|
||||
struct spa_list stream_list; /**< list of \ref pw_proxy objects */
|
||||
|
||||
struct pw_protocol *protocol; /**< the protocol in use */
|
||||
void *protocol_private; /**< private data for the protocol */
|
||||
struct pw_protocol_connection *conn; /**< the protocol connection */
|
||||
|
||||
enum pw_remote_state state;
|
||||
char *error;
|
||||
/** Signal emited when the state changes */
|
||||
PW_SIGNAL(state_changed, (struct pw_listener *listener, struct pw_remote *remote));
|
||||
|
||||
/** Signal emited when the remote is destroyed */
|
||||
PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_remote *remote));
|
||||
};
|
||||
|
||||
/** Create a new unconnected remote \memberof pw_remote
|
||||
* \return a new unconnected remote */
|
||||
struct pw_remote *
|
||||
pw_remote_new(struct pw_core *core, /**< a \ref pw_core */
|
||||
struct pw_properties *properties /**< optional properties, ownership of
|
||||
* the properties is taken.*/ );
|
||||
|
||||
/** Destroy a remote \memberof pw_remote */
|
||||
void pw_remote_destroy(struct pw_remote *remote);
|
||||
|
||||
/** Connect to a remote PipeWire \memberof pw_remote
|
||||
* \return true on success. */
|
||||
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. */
|
||||
int pw_remote_connect_fd(struct pw_remote *remote, int fd);
|
||||
|
||||
/** Disconnect from the remote PipeWire. \memberof pw_remote */
|
||||
void pw_remote_disconnect(struct pw_remote *remote);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __PIPEWIRE_REMOTE_H__ */
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "pipewire/client/interfaces.h"
|
||||
#include "pipewire/client/protocol.h"
|
||||
#include "pipewire/server/resource.h"
|
||||
|
||||
/** \cond */
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ extern "C" {
|
|||
#include <spa/list.h>
|
||||
|
||||
#include <pipewire/client/sig.h>
|
||||
#include <pipewire/client/utils.h>
|
||||
#include <pipewire/server/core.h>
|
||||
|
||||
/** \page page_resource Resource
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
executable('pipewire-monitor',
|
||||
'pipewire-monitor.c',
|
||||
install: true,
|
||||
dependencies : [pipewire_dep],
|
||||
dependencies : [pipewirecore_dep],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -26,10 +26,16 @@
|
|||
struct data {
|
||||
bool running;
|
||||
struct pw_loop *loop;
|
||||
struct pw_context *context;
|
||||
struct pw_core *core;
|
||||
struct pw_remote *remote;
|
||||
struct pw_proxy *registry_proxy;
|
||||
|
||||
struct pw_listener on_info_changed;
|
||||
struct pw_listener on_state_changed;
|
||||
struct pw_listener on_subscription;
|
||||
};
|
||||
|
||||
struct proxy_data {
|
||||
void *info;
|
||||
};
|
||||
|
||||
static void print_properties(struct spa_dict *props, char mark)
|
||||
|
|
@ -45,24 +51,16 @@ static void print_properties(struct spa_dict *props, char mark)
|
|||
}
|
||||
}
|
||||
|
||||
struct dumpdata {
|
||||
bool print_mark;
|
||||
bool print_all;
|
||||
};
|
||||
#define MARK_CHANGE(f) ((print_mark && ((info)->change_mask & (1 << (f)))) ? '*' : ' ')
|
||||
|
||||
#define MARK_CHANGE(f) ((data->print_mark && ((info)->change_mask & (1 << (f)))) ? '*' : ' ')
|
||||
|
||||
static void
|
||||
dump_core_info(struct pw_context *c, int res, const struct pw_core_info *info, void *user_data)
|
||||
static void on_info_changed(struct pw_listener *listener, struct pw_remote *remote)
|
||||
{
|
||||
struct dumpdata *data = user_data;
|
||||
|
||||
if (info == NULL)
|
||||
return;
|
||||
struct pw_core_info *info = remote->info;
|
||||
bool print_all = true, print_mark = false;
|
||||
|
||||
printf("\tid: %u\n", info->id);
|
||||
printf("\ttype: %s\n", PIPEWIRE_TYPE__Core);
|
||||
if (data->print_all) {
|
||||
if (print_all) {
|
||||
printf("%c\tuser-name: \"%s\"\n", MARK_CHANGE(0), info->user_name);
|
||||
printf("%c\thost-name: \"%s\"\n", MARK_CHANGE(1), info->host_name);
|
||||
printf("%c\tversion: \"%s\"\n", MARK_CHANGE(2), info->version);
|
||||
|
|
@ -72,35 +70,59 @@ dump_core_info(struct pw_context *c, int res, const struct pw_core_info *info, v
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dump_client_info(struct pw_context *c, int res, const struct pw_client_info *info, void *user_data)
|
||||
static void module_event_info(void *object, struct pw_module_info *info)
|
||||
{
|
||||
struct dumpdata *data = user_data;
|
||||
struct pw_proxy *proxy = object;
|
||||
struct proxy_data *data = proxy->user_data;
|
||||
bool print_all, print_mark;
|
||||
|
||||
if (info == NULL)
|
||||
return;
|
||||
print_all = true;
|
||||
if (data->info == NULL) {
|
||||
printf("added:\n");
|
||||
print_mark = false;
|
||||
}
|
||||
else {
|
||||
printf("changed:\n");
|
||||
print_mark = true;
|
||||
}
|
||||
|
||||
info = data->info = pw_module_info_update(data->info, info);
|
||||
|
||||
printf("\tid: %u\n", info->id);
|
||||
printf("\ttype: %s\n", PIPEWIRE_TYPE__Client);
|
||||
if (data->print_all) {
|
||||
print_properties(info->props, MARK_CHANGE(0));
|
||||
printf("\ttype: %s\n", PIPEWIRE_TYPE__Module);
|
||||
if (print_all) {
|
||||
printf("%c\tname: \"%s\"\n", MARK_CHANGE(0), info->name);
|
||||
printf("%c\tfilename: \"%s\"\n", MARK_CHANGE(1), info->filename);
|
||||
printf("%c\targs: \"%s\"\n", MARK_CHANGE(2), info->args);
|
||||
print_properties(info->props, MARK_CHANGE(3));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dump_node_info(struct pw_context *c, int res, const struct pw_node_info *info, void *user_data)
|
||||
{
|
||||
struct dumpdata *data = user_data;
|
||||
static const struct pw_module_events module_events = {
|
||||
&module_event_info,
|
||||
};
|
||||
|
||||
if (info == NULL) {
|
||||
if (res != SPA_RESULT_ENUM_END)
|
||||
printf("\tError introspecting node: %d\n", res);
|
||||
return;
|
||||
static void node_event_info(void *object, struct pw_node_info *info)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct proxy_data *data = proxy->user_data;
|
||||
bool print_all, print_mark;
|
||||
|
||||
print_all = true;
|
||||
if (data->info == NULL) {
|
||||
printf("added:\n");
|
||||
print_mark = false;
|
||||
}
|
||||
else {
|
||||
printf("changed:\n");
|
||||
print_mark = true;
|
||||
}
|
||||
|
||||
info = data->info = pw_node_info_update(data->info, info);
|
||||
|
||||
printf("\tid: %u\n", info->id);
|
||||
printf("\ttype: %s\n", PIPEWIRE_TYPE__Node);
|
||||
if (data->print_all) {
|
||||
if (print_all) {
|
||||
int i;
|
||||
|
||||
printf("%c\tname: \"%s\"\n", MARK_CHANGE(0), info->name);
|
||||
|
|
@ -123,41 +145,60 @@ dump_node_info(struct pw_context *c, int res, const struct pw_node_info *info, v
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dump_module_info(struct pw_context *c, int res, const struct pw_module_info *info, void *user_data)
|
||||
{
|
||||
struct dumpdata *data = user_data;
|
||||
static const struct pw_node_events node_events = {
|
||||
&node_event_info
|
||||
};
|
||||
|
||||
if (info == NULL) {
|
||||
if (res != SPA_RESULT_ENUM_END)
|
||||
printf("\tError introspecting module: %d\n", res);
|
||||
return;
|
||||
static void client_event_info(void *object, struct pw_client_info *info)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct proxy_data *data = proxy->user_data;
|
||||
bool print_all, print_mark;
|
||||
|
||||
print_all = true;
|
||||
if (data->info == NULL) {
|
||||
printf("added:\n");
|
||||
print_mark = false;
|
||||
}
|
||||
else {
|
||||
printf("changed:\n");
|
||||
print_mark = true;
|
||||
}
|
||||
|
||||
info = data->info = pw_client_info_update(data->info, info);
|
||||
|
||||
printf("\tid: %u\n", info->id);
|
||||
printf("\ttype: %s\n", PIPEWIRE_TYPE__Module);
|
||||
if (data->print_all) {
|
||||
printf("%c\tname: \"%s\"\n", MARK_CHANGE(0), info->name);
|
||||
printf("%c\tfilename: \"%s\"\n", MARK_CHANGE(1), info->filename);
|
||||
printf("%c\targs: \"%s\"\n", MARK_CHANGE(2), info->args);
|
||||
print_properties(info->props, MARK_CHANGE(3));
|
||||
printf("\ttype: %s\n", PIPEWIRE_TYPE__Client);
|
||||
if (print_all) {
|
||||
print_properties(info->props, MARK_CHANGE(0));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dump_link_info(struct pw_context *c, int res, const struct pw_link_info *info, void *user_data)
|
||||
{
|
||||
struct dumpdata *data = user_data;
|
||||
static const struct pw_client_events client_events = {
|
||||
&client_event_info
|
||||
};
|
||||
|
||||
if (info == NULL) {
|
||||
if (res != SPA_RESULT_ENUM_END)
|
||||
printf("\tError introspecting link: %d\n", res);
|
||||
return;
|
||||
static void link_event_info(void *object, struct pw_link_info *info)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct proxy_data *data = proxy->user_data;
|
||||
bool print_all, print_mark;
|
||||
|
||||
print_all = true;
|
||||
if (data->info == NULL) {
|
||||
printf("added:\n");
|
||||
print_mark = false;
|
||||
}
|
||||
else {
|
||||
printf("changed:\n");
|
||||
print_mark = true;
|
||||
}
|
||||
|
||||
info = data->info = pw_link_info_update(data->info, info);
|
||||
|
||||
printf("\tid: %u\n", info->id);
|
||||
printf("\ttype: %s\n", PIPEWIRE_TYPE__Link);
|
||||
if (data->print_all) {
|
||||
if (print_all) {
|
||||
printf("%c\toutput-node-id: %u\n", MARK_CHANGE(0), info->output_node_id);
|
||||
printf("%c\toutput-port-id: %u\n", MARK_CHANGE(1), info->output_port_id);
|
||||
printf("%c\tinput-node-id: %u\n", MARK_CHANGE(2), info->input_node_id);
|
||||
|
|
@ -170,88 +211,136 @@ dump_link_info(struct pw_context *c, int res, const struct pw_link_info *info, v
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dump_object(struct pw_context *context, uint32_t type, uint32_t id, struct dumpdata *data)
|
||||
{
|
||||
if (type == context->type.core) {
|
||||
pw_context_get_core_info(context, dump_core_info, data);
|
||||
} else if (type == context->type.node) {
|
||||
pw_context_get_node_info_by_id(context, id, dump_node_info, data);
|
||||
} else if (type == context->type.module) {
|
||||
pw_context_get_module_info_by_id(context, id, dump_module_info, data);
|
||||
} else if (type == context->type.client) {
|
||||
pw_context_get_client_info_by_id(context, id, dump_client_info, data);
|
||||
} else if (type == context->type.link) {
|
||||
pw_context_get_link_info_by_id(context, id, dump_link_info, data);
|
||||
} else {
|
||||
printf("\tid: %u\n", id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
static const struct pw_link_events link_events = {
|
||||
&link_event_info
|
||||
};
|
||||
|
||||
static void
|
||||
on_subscription(struct pw_listener *listener,
|
||||
struct pw_context *context,
|
||||
enum pw_subscription_event event, uint32_t type, uint32_t id)
|
||||
destroy_proxy (void *data)
|
||||
{
|
||||
struct dumpdata dd;
|
||||
struct pw_proxy *proxy = data;
|
||||
struct proxy_data *user_data = proxy->user_data;
|
||||
struct pw_core *core = proxy->remote->core;
|
||||
|
||||
switch (event) {
|
||||
case PW_SUBSCRIPTION_EVENT_NEW:
|
||||
printf("added:\n");
|
||||
dd.print_mark = false;
|
||||
dd.print_all = true;
|
||||
dump_object(context, type, id, &dd);
|
||||
break;
|
||||
if (user_data->info == NULL)
|
||||
return;
|
||||
|
||||
case PW_SUBSCRIPTION_EVENT_CHANGE:
|
||||
printf("changed:\n");
|
||||
dd.print_mark = true;
|
||||
dd.print_all = true;
|
||||
dump_object(context, type, id, &dd);
|
||||
break;
|
||||
|
||||
case PW_SUBSCRIPTION_EVENT_REMOVE:
|
||||
printf("removed:\n");
|
||||
dd.print_mark = false;
|
||||
dd.print_all = false;
|
||||
dump_object(context, type, id, &dd);
|
||||
break;
|
||||
}
|
||||
if (proxy->type == core->type.core) {
|
||||
pw_core_info_free (user_data->info);
|
||||
} else if (proxy->type == core->type.node) {
|
||||
pw_node_info_free (user_data->info);
|
||||
} else if (proxy->type == core->type.module) {
|
||||
pw_module_info_free (user_data->info);
|
||||
} else if (proxy->type == core->type.client) {
|
||||
pw_client_info_free (user_data->info);
|
||||
} else if (proxy->type == core->type.link) {
|
||||
pw_link_info_free (user_data->info);
|
||||
}
|
||||
user_data->info = NULL;
|
||||
}
|
||||
|
||||
static void on_state_changed(struct pw_listener *listener, struct pw_context *context)
|
||||
|
||||
static void registry_event_global(void *object, uint32_t id, const char *type, uint32_t version)
|
||||
{
|
||||
struct pw_proxy *registry_proxy = object;
|
||||
struct data *data = registry_proxy->object;
|
||||
struct pw_core *core = data->core;
|
||||
struct pw_remote *remote = registry_proxy->remote;
|
||||
struct pw_proxy *proxy = NULL;
|
||||
uint32_t proxy_type, client_version;
|
||||
const void *implementation;
|
||||
|
||||
if (!strcmp(type, PIPEWIRE_TYPE__Node)) {
|
||||
proxy_type = core->type.node;
|
||||
implementation = &node_events;
|
||||
client_version = PW_VERSION_NODE;
|
||||
} else if (!strcmp(type, PIPEWIRE_TYPE__Module)) {
|
||||
proxy_type = core->type.module;
|
||||
implementation = &module_events;
|
||||
client_version = PW_VERSION_MODULE;
|
||||
} else if (!strcmp(type, PIPEWIRE_TYPE__Client)) {
|
||||
proxy_type = core->type.client;
|
||||
implementation = &client_events;
|
||||
client_version = PW_VERSION_CLIENT;
|
||||
} else if (!strcmp(type, PIPEWIRE_TYPE__Link)) {
|
||||
proxy_type = core->type.link;
|
||||
implementation = &link_events;
|
||||
client_version = PW_VERSION_LINK;
|
||||
} else
|
||||
return;
|
||||
|
||||
proxy = pw_proxy_new(remote, SPA_ID_INVALID, proxy_type, sizeof(struct proxy_data));
|
||||
if (proxy == NULL)
|
||||
goto no_mem;
|
||||
|
||||
pw_proxy_set_implementation(proxy, data, client_version, implementation, destroy_proxy);
|
||||
|
||||
pw_registry_do_bind(registry_proxy, id, version, proxy->id);
|
||||
|
||||
return;
|
||||
|
||||
no_mem:
|
||||
printf("failed to create proxy");
|
||||
return;
|
||||
}
|
||||
|
||||
static void registry_event_global_remove(void *object, uint32_t id)
|
||||
{
|
||||
printf("removed:\n");
|
||||
printf("\tid: %u\n", id);
|
||||
}
|
||||
|
||||
static const struct pw_registry_events registry_events = {
|
||||
registry_event_global,
|
||||
registry_event_global_remove,
|
||||
};
|
||||
|
||||
static void on_state_changed(struct pw_listener *listener, struct pw_remote *remote)
|
||||
{
|
||||
struct data *data = SPA_CONTAINER_OF(listener, struct data, on_state_changed);
|
||||
|
||||
switch (context->state) {
|
||||
switch (remote->state) {
|
||||
case PW_CONTEXT_STATE_ERROR:
|
||||
printf("context error: %s\n", context->error);
|
||||
printf("remote error: %s\n", remote->error);
|
||||
data->running = false;
|
||||
break;
|
||||
|
||||
case PW_CONTEXT_STATE_CONNECTED:
|
||||
printf("remote state: \"%s\"\n", pw_remote_state_as_string(remote->state));
|
||||
|
||||
data->registry_proxy = pw_proxy_new(data->remote,
|
||||
SPA_ID_INVALID,
|
||||
data->core->type.registry,
|
||||
0);
|
||||
pw_proxy_set_implementation(data->registry_proxy, data, PW_VERSION_REGISTRY,
|
||||
®istry_events, NULL);
|
||||
|
||||
pw_core_do_get_registry(data->remote->core_proxy,
|
||||
data->registry_proxy->id);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("context state: \"%s\"\n", pw_context_state_as_string(context->state));
|
||||
printf("remote state: \"%s\"\n", pw_remote_state_as_string(remote->state));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct data data;
|
||||
struct data data = { 0 };
|
||||
|
||||
pw_init(&argc, &argv);
|
||||
|
||||
data.loop = pw_loop_new();
|
||||
data.running = true;
|
||||
data.context = pw_context_new(data.loop, "pipewire-monitor", NULL);
|
||||
data.core = pw_core_new(data.loop, NULL);
|
||||
data.remote = pw_remote_new(data.core, NULL);
|
||||
|
||||
pw_signal_add(&data.context->state_changed, &data.on_state_changed, on_state_changed);
|
||||
pw_signal_add(&data.remote->info_changed, &data.on_info_changed, on_info_changed);
|
||||
pw_signal_add(&data.remote->state_changed, &data.on_state_changed, on_state_changed);
|
||||
|
||||
pw_signal_add(&data.context->subscription, &data.on_subscription, on_subscription);
|
||||
|
||||
pw_context_connect(data.context, 0);
|
||||
pw_remote_connect(data.remote);
|
||||
|
||||
pw_loop_enter(data.loop);
|
||||
while (data.running) {
|
||||
|
|
@ -259,7 +348,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
pw_loop_leave(data.loop);
|
||||
|
||||
pw_context_destroy(data.context);
|
||||
pw_remote_destroy(data.remote);
|
||||
pw_loop_destroy(data.loop);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -96,8 +96,8 @@ static inline bool spa_graph_scheduler_iterate(struct spa_graph_scheduler *sched
|
|||
|
||||
switch (n->action) {
|
||||
case SPA_GRAPH_ACTION_IN:
|
||||
n->state = n->methods->schedule_input(n, n->user_data);
|
||||
debug("node %p scheduled input state %d\n", n, n->state);
|
||||
n->state = n->methods->process_input(n, n->user_data);
|
||||
debug("node %p processed input state %d\n", n, n->state);
|
||||
if (n == sched->node)
|
||||
break;
|
||||
n->action = SPA_GRAPH_ACTION_CHECK;
|
||||
|
|
@ -105,8 +105,8 @@ static inline bool spa_graph_scheduler_iterate(struct spa_graph_scheduler *sched
|
|||
break;
|
||||
|
||||
case SPA_GRAPH_ACTION_OUT:
|
||||
n->state = n->methods->schedule_output(n, n->user_data);
|
||||
debug("node %p scheduled output state %d\n", n, n->state);
|
||||
n->state = n->methods->process_output(n, n->user_data);
|
||||
debug("node %p processed output state %d\n", n, n->state);
|
||||
n->action = SPA_GRAPH_ACTION_CHECK;
|
||||
spa_list_insert(sched->ready.prev, &n->ready_link);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -38,32 +38,36 @@ static inline void spa_graph_scheduler_init(struct spa_graph_scheduler *sched,
|
|||
sched->node = NULL;
|
||||
}
|
||||
|
||||
static inline int spa_graph_scheduler_input(struct spa_graph_node *node, void *user_data)
|
||||
static inline int spa_graph_node_scheduler_input(struct spa_graph_node *node, void *user_data)
|
||||
{
|
||||
struct spa_node *n = node->user_data;
|
||||
return spa_node_process_input(n);
|
||||
}
|
||||
|
||||
static inline int spa_graph_scheduler_output(struct spa_graph_node *node, void *user_data)
|
||||
static inline int spa_graph_node_scheduler_output(struct spa_graph_node *node, void *user_data)
|
||||
{
|
||||
struct spa_node *n = node->user_data;
|
||||
return spa_node_process_output(n);
|
||||
}
|
||||
|
||||
static inline int spa_graph_scheduler_reuse_buffer(struct spa_graph_port *port,
|
||||
uint32_t buffer_id, void *user_data)
|
||||
|
||||
static const struct spa_graph_node_methods spa_graph_node_scheduler_default = {
|
||||
SPA_VERSION_GRAPH_NODE_METHODS,
|
||||
spa_graph_node_scheduler_input,
|
||||
spa_graph_node_scheduler_output,
|
||||
};
|
||||
|
||||
static inline int spa_graph_port_scheduler_reuse_buffer(struct spa_graph_port *port,
|
||||
uint32_t buffer_id, void *user_data)
|
||||
{
|
||||
printf("port %p reuse buffer %d\n", port, buffer_id);
|
||||
struct spa_graph_node *node = port->node;
|
||||
struct spa_node *n = node->user_data;
|
||||
return spa_node_port_reuse_buffer(n, port->port_id, buffer_id);
|
||||
struct spa_node *node = port->node->user_data;
|
||||
return spa_node_port_reuse_buffer(node, port->port_id, buffer_id);
|
||||
}
|
||||
|
||||
static const struct spa_graph_node_methods spa_graph_scheduler_default = {
|
||||
SPA_VERSION_GRAPH_NODE_METHODS,
|
||||
spa_graph_scheduler_input,
|
||||
spa_graph_scheduler_output,
|
||||
spa_graph_scheduler_reuse_buffer,
|
||||
static const struct spa_graph_port_methods spa_graph_port_scheduler_default = {
|
||||
SPA_VERSION_GRAPH_PORT_METHODS,
|
||||
spa_graph_port_scheduler_reuse_buffer,
|
||||
};
|
||||
|
||||
static inline void spa_graph_scheduler_pull(struct spa_graph_scheduler *sched, struct spa_graph_node *node)
|
||||
|
|
@ -92,8 +96,8 @@ static inline void spa_graph_scheduler_pull(struct spa_graph_scheduler *sched, s
|
|||
}
|
||||
|
||||
spa_list_for_each_safe(n, t, &ready, ready_link) {
|
||||
n->state = n->methods->schedule_output(n, n->user_data);
|
||||
debug("peer %p scheduled out %d\n", n, n->state);
|
||||
n->state = n->methods->process_output(n, n->user_data);
|
||||
debug("peer %p processed out %d\n", n, n->state);
|
||||
if (n->state == SPA_RESULT_NEED_BUFFER)
|
||||
spa_graph_scheduler_pull(sched, n);
|
||||
else {
|
||||
|
|
@ -109,8 +113,8 @@ static inline void spa_graph_scheduler_pull(struct spa_graph_scheduler *sched, s
|
|||
debug("node %p %d %d\n", node, node->ready_in, node->required_in);
|
||||
|
||||
if (node->required_in > 0 && node->ready_in == node->required_in) {
|
||||
node->state = node->methods->schedule_input(node, node->user_data);
|
||||
debug("node %p scheduled in %d\n", node, node->state);
|
||||
node->state = node->methods->process_input(node, node->user_data);
|
||||
debug("node %p processed in %d\n", node, node->state);
|
||||
if (node->state == SPA_RESULT_HAVE_BUFFER) {
|
||||
spa_list_for_each(p, &node->ports[SPA_DIRECTION_OUTPUT], link) {
|
||||
if (p->io->status == SPA_RESULT_HAVE_BUFFER)
|
||||
|
|
@ -154,8 +158,8 @@ static inline void spa_graph_scheduler_push(struct spa_graph_scheduler *sched, s
|
|||
}
|
||||
|
||||
spa_list_for_each_safe(n, t, &ready, ready_link) {
|
||||
n->state = n->methods->schedule_input(n, n->user_data);
|
||||
debug("peer %p scheduled in %d\n", n, n->state);
|
||||
n->state = n->methods->process_input(n, n->user_data);
|
||||
debug("peer %p processed in %d\n", n, n->state);
|
||||
if (n->state == SPA_RESULT_HAVE_BUFFER)
|
||||
spa_graph_scheduler_push(sched, n);
|
||||
else {
|
||||
|
|
@ -169,8 +173,8 @@ static inline void spa_graph_scheduler_push(struct spa_graph_scheduler *sched, s
|
|||
n->ready_link.next = NULL;
|
||||
}
|
||||
|
||||
node->state = node->methods->schedule_output(node, node->user_data);
|
||||
debug("node %p scheduled out %d\n", node, node->state);
|
||||
node->state = node->methods->process_output(node, node->user_data);
|
||||
debug("node %p processed out %d\n", node, node->state);
|
||||
if (node->state == SPA_RESULT_NEED_BUFFER) {
|
||||
node->ready_in = 0;
|
||||
spa_list_for_each(p, &node->ports[SPA_DIRECTION_INPUT], link) {
|
||||
|
|
|
|||
|
|
@ -46,8 +46,14 @@ struct spa_graph {
|
|||
struct spa_graph_node_methods {
|
||||
uint32_t version;
|
||||
|
||||
int (*schedule_input) (struct spa_graph_node *node, void *user_data);
|
||||
int (*schedule_output) (struct spa_graph_node *node, void *user_data);
|
||||
int (*process_input) (struct spa_graph_node *node, void *user_data);
|
||||
int (*process_output) (struct spa_graph_node *node, void *user_data);
|
||||
};
|
||||
|
||||
#define SPA_VERSION_GRAPH_PORT_METHODS 0
|
||||
struct spa_graph_port_methods {
|
||||
uint32_t version;
|
||||
|
||||
int (*reuse_buffer) (struct spa_graph_port *port, uint32_t buffer_id, void *user_data);
|
||||
};
|
||||
|
||||
|
|
@ -62,11 +68,11 @@ struct spa_graph_node {
|
|||
#define SPA_GRAPH_ACTION_IN 1
|
||||
#define SPA_GRAPH_ACTION_OUT 2
|
||||
uint32_t action;
|
||||
const struct spa_graph_node_methods *methods;
|
||||
void *user_data;
|
||||
uint32_t max_in;
|
||||
uint32_t required_in;
|
||||
uint32_t ready_in;
|
||||
const struct spa_graph_node_methods *methods;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct spa_graph_port {
|
||||
|
|
@ -77,6 +83,8 @@ struct spa_graph_port {
|
|||
uint32_t flags;
|
||||
struct spa_port_io *io;
|
||||
struct spa_graph_port *peer;
|
||||
const struct spa_graph_port_methods *methods;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
static inline void spa_graph_init(struct spa_graph *graph)
|
||||
|
|
@ -85,19 +93,24 @@ static inline void spa_graph_init(struct spa_graph *graph)
|
|||
}
|
||||
|
||||
static inline void
|
||||
spa_graph_node_init(struct spa_graph_node *node,
|
||||
const struct spa_graph_node_methods *methods,
|
||||
void *user_data)
|
||||
spa_graph_node_init(struct spa_graph_node *node)
|
||||
{
|
||||
spa_list_init(&node->ports[SPA_DIRECTION_INPUT]);
|
||||
spa_list_init(&node->ports[SPA_DIRECTION_OUTPUT]);
|
||||
node->flags = 0;
|
||||
node->methods = methods;
|
||||
node->user_data = user_data;
|
||||
node->max_in = node->required_in = node->ready_in = 0;
|
||||
debug("node %p init\n", node);
|
||||
}
|
||||
|
||||
static inline void
|
||||
spa_graph_node_set_methods(struct spa_graph_node *node,
|
||||
const struct spa_graph_node_methods *methods,
|
||||
void *user_data)
|
||||
{
|
||||
node->methods = methods;
|
||||
node->user_data = user_data;
|
||||
}
|
||||
|
||||
static inline void
|
||||
spa_graph_node_add(struct spa_graph *graph,
|
||||
struct spa_graph_node *node)
|
||||
|
|
@ -123,6 +136,15 @@ spa_graph_port_init(struct spa_graph_port *port,
|
|||
port->io = io;
|
||||
}
|
||||
|
||||
static inline void
|
||||
spa_graph_port_set_methods(struct spa_graph_port *port,
|
||||
const struct spa_graph_port_methods *methods,
|
||||
void *user_data)
|
||||
{
|
||||
port->methods = methods;
|
||||
port->user_data = user_data;
|
||||
}
|
||||
|
||||
static inline void
|
||||
spa_graph_port_add(struct spa_graph_node *node,
|
||||
struct spa_graph_port *port)
|
||||
|
|
|
|||
|
|
@ -340,12 +340,14 @@ static int make_nodes(struct data *data, const char *device)
|
|||
spa_node_port_set_io(data->volume, SPA_DIRECTION_OUTPUT, 0, &data->volume_sink_io[0]);
|
||||
spa_node_port_set_io(data->sink, SPA_DIRECTION_INPUT, 0, &data->volume_sink_io[0]);
|
||||
|
||||
spa_graph_node_init(&data->source_node, &spa_graph_scheduler_default, data->source);
|
||||
spa_graph_node_init(&data->source_node);
|
||||
spa_graph_node_set_methods(&data->source_node, &spa_graph_scheduler_default, data->source);
|
||||
spa_graph_node_add(&data->graph, &data->source_node);
|
||||
spa_graph_port_init(&data->source_out, SPA_DIRECTION_OUTPUT, 0, 0, &data->source_volume_io[0]);
|
||||
spa_graph_port_add(&data->source_node, &data->source_out);
|
||||
|
||||
spa_graph_node_init(&data->volume_node, &spa_graph_scheduler_default, data->volume);
|
||||
spa_graph_node_init(&data->volume_node);
|
||||
spa_graph_node_set_methods(&data->volume_node, &spa_graph_scheduler_default, data->volume);
|
||||
spa_graph_node_add(&data->graph, &data->volume_node);
|
||||
spa_graph_port_init(&data->volume_in, SPA_DIRECTION_INPUT, 0, 0, &data->source_volume_io[0]);
|
||||
spa_graph_port_add(&data->volume_node, &data->volume_in);
|
||||
|
|
@ -355,7 +357,8 @@ static int make_nodes(struct data *data, const char *device)
|
|||
spa_graph_port_init(&data->volume_out, SPA_DIRECTION_OUTPUT, 0, 0, &data->volume_sink_io[0]);
|
||||
spa_graph_port_add(&data->volume_node, &data->volume_out);
|
||||
|
||||
spa_graph_node_init(&data->sink_node, &spa_graph_scheduler_default, data->sink);
|
||||
spa_graph_node_init(&data->sink_node);
|
||||
spa_graph_node_set_methods(&data->sink_node, &spa_graph_scheduler_default, data->sink);
|
||||
spa_graph_node_add(&data->graph, &data->sink_node);
|
||||
spa_graph_port_init(&data->sink_in, SPA_DIRECTION_INPUT, 0, 0, &data->volume_sink_io[0]);
|
||||
spa_graph_port_add(&data->sink_node, &data->sink_in);
|
||||
|
|
|
|||
|
|
@ -418,17 +418,20 @@ static int make_nodes(struct data *data, const char *device)
|
|||
spa_node_port_set_io(data->sink, SPA_DIRECTION_INPUT, 0, &data->mix_sink_io[0]);
|
||||
|
||||
#ifdef USE_GRAPH
|
||||
spa_graph_node_init(&data->source1_node, &spa_graph_scheduler_default, data->source1);
|
||||
spa_graph_node_init(&data->source1_node);
|
||||
spa_graph_node_set_methods(&data->source1_node, &spa_graph_scheduler_default, data->source1);
|
||||
spa_graph_port_init(&data->source1_out, SPA_DIRECTION_OUTPUT, 0, 0, &data->source1_mix_io[0]);
|
||||
spa_graph_port_add(&data->source1_node, &data->source1_out);
|
||||
spa_graph_node_add(&data->graph, &data->source1_node);
|
||||
|
||||
spa_graph_node_init(&data->source2_node, &spa_graph_scheduler_default, data->source2);
|
||||
spa_graph_node_init(&data->source2_node);
|
||||
spa_graph_node_set_methods(&data->source2_node, &spa_graph_scheduler_default, data->source2);
|
||||
spa_graph_port_init(&data->source2_out, SPA_DIRECTION_OUTPUT, 0, 0, &data->source2_mix_io[0]);
|
||||
spa_graph_port_add(&data->source2_node, &data->source2_out);
|
||||
spa_graph_node_add(&data->graph, &data->source2_node);
|
||||
|
||||
spa_graph_node_init(&data->mix_node, &spa_graph_scheduler_default, data->mix);
|
||||
spa_graph_node_init(&data->mix_node);
|
||||
spa_graph_node_set_methods(&data->mix_node, &spa_graph_scheduler_default, data->mix);
|
||||
spa_graph_port_init(&data->mix_in[0], SPA_DIRECTION_INPUT,
|
||||
data->mix_ports[0], 0, &data->source1_mix_io[0]);
|
||||
spa_graph_port_add(&data->mix_node, &data->mix_in[0]);
|
||||
|
|
@ -443,7 +446,8 @@ static int make_nodes(struct data *data, const char *device)
|
|||
spa_graph_port_init(&data->mix_out, SPA_DIRECTION_OUTPUT, 0, 0, &data->mix_sink_io[0]);
|
||||
spa_graph_port_add(&data->mix_node, &data->mix_out);
|
||||
|
||||
spa_graph_node_init(&data->sink_node, &spa_graph_scheduler_default, data->sink);
|
||||
spa_graph_node_init(&data->sink_node);
|
||||
spa_graph_node_set_methods(&data->sink_node, &spa_graph_scheduler_default, data->sink);
|
||||
spa_graph_port_init(&data->sink_in, SPA_DIRECTION_INPUT, 0, 0, &data->mix_sink_io[0]);
|
||||
spa_graph_port_add(&data->sink_node, &data->sink_in);
|
||||
spa_graph_node_add(&data->graph, &data->sink_node);
|
||||
|
|
|
|||
|
|
@ -366,14 +366,16 @@ static int make_nodes(struct data *data)
|
|||
spa_node_port_set_io(data->source, SPA_DIRECTION_OUTPUT, 0, &data->source_sink_io[0]);
|
||||
spa_node_port_set_io(data->sink, SPA_DIRECTION_INPUT, 0, &data->source_sink_io[0]);
|
||||
|
||||
spa_graph_node_init(&data->source_node, &spa_graph_scheduler_default, data->source);
|
||||
spa_graph_node_init(&data->source_node);
|
||||
spa_graph_node_set_methods(&data->source_node, &spa_graph_scheduler_default, data->source);
|
||||
spa_graph_node_add(&data->graph, &data->source_node);
|
||||
|
||||
data->source_node.flags = (data->mode & MODE_ASYNC_PUSH) ? SPA_GRAPH_NODE_FLAG_ASYNC : 0;
|
||||
spa_graph_port_init( &data->source_out, SPA_DIRECTION_OUTPUT, 0, 0, &data->source_sink_io[0]);
|
||||
spa_graph_port_add(&data->source_node, &data->source_out);
|
||||
|
||||
spa_graph_node_init(&data->sink_node, &spa_graph_scheduler_default, data->sink);
|
||||
spa_graph_node_init(&data->sink_node);
|
||||
spa_graph_node_set_methods(&data->sink_node, &spa_graph_scheduler_default, data->sink);
|
||||
spa_graph_node_add(&data->graph, &data->sink_node);
|
||||
|
||||
data->sink_node.flags = (data->mode & MODE_ASYNC_PULL) ? SPA_GRAPH_NODE_FLAG_ASYNC : 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue