remote: remove the remote

Mostly rename pw_remote_* to pw_core_proxy_*
This commit is contained in:
Wim Taymans 2019-12-06 13:40:23 +01:00
parent 3d79970d88
commit ca6f1bd2f1
20 changed files with 608 additions and 1063 deletions

View file

@ -581,7 +581,6 @@ on_remote_data(void *data, int fd, uint32_t mask)
{ {
struct client *impl = data; struct client *impl = data;
struct pw_core_proxy *this = impl->this.core_proxy; struct pw_core_proxy *this = impl->this.core_proxy;
struct pw_remote *remote = pw_proxy_get_remote((struct pw_proxy*)this);
struct pw_protocol_native_connection *conn = impl->connection; struct pw_protocol_native_connection *conn = impl->connection;
struct pw_core *core = pw_core_proxy_get_core(this); struct pw_core *core = pw_core_proxy_get_core(this);
struct pw_loop *loop = pw_core_get_main_loop(core); struct pw_loop *loop = pw_core_get_main_loop(core);
@ -623,7 +622,7 @@ on_remote_data(void *data, int fd, uint32_t mask)
pw_log_trace(NAME" %p: got message %d from %u seq:%d", pw_log_trace(NAME" %p: got message %d from %u seq:%d",
this, msg->opcode, msg->id, msg->seq); this, msg->opcode, msg->id, msg->seq);
remote->recv_seq = msg->seq; this->recv_seq = msg->seq;
if (debug_messages) { if (debug_messages) {
fprintf(stderr, "<<<<<<<<< in: id:%d op:%d size:%d seq:%d\n", fprintf(stderr, "<<<<<<<<< in: id:%d op:%d size:%d seq:%d\n",
@ -672,7 +671,7 @@ error:
pw_log_error(NAME" %p: got connection error %d (%s)", impl, res, spa_strerror(res)); pw_log_error(NAME" %p: got connection error %d (%s)", impl, res, spa_strerror(res));
pw_proxy_notify((struct pw_proxy*)this, pw_proxy_notify((struct pw_proxy*)this,
struct pw_core_proxy_events, error, 0, 0, struct pw_core_proxy_events, error, 0, 0,
remote->recv_seq, res, "connection error"); this->recv_seq, res, "connection error");
pw_loop_destroy_source(loop, impl->source); pw_loop_destroy_source(loop, impl->source);
impl->source = NULL; impl->source = NULL;
pw_core_proxy_disconnect(this); pw_core_proxy_disconnect(this);
@ -924,28 +923,28 @@ const static struct pw_protocol_implementaton protocol_impl = {
static struct spa_pod_builder * static struct spa_pod_builder *
impl_ext_begin_proxy(struct pw_proxy *proxy, uint8_t opcode, struct pw_protocol_native_message **msg) impl_ext_begin_proxy(struct pw_proxy *proxy, uint8_t opcode, struct pw_protocol_native_message **msg)
{ {
struct client *impl = SPA_CONTAINER_OF(proxy->remote->conn, struct client, this); struct client *impl = SPA_CONTAINER_OF(proxy->core_proxy->conn, struct client, this);
return pw_protocol_native_connection_begin(impl->connection, proxy->id, opcode, msg); return pw_protocol_native_connection_begin(impl->connection, proxy->id, opcode, msg);
} }
static uint32_t impl_ext_add_proxy_fd(struct pw_proxy *proxy, int fd) static uint32_t impl_ext_add_proxy_fd(struct pw_proxy *proxy, int fd)
{ {
struct client *impl = SPA_CONTAINER_OF(proxy->remote->conn, struct client, this); struct client *impl = SPA_CONTAINER_OF(proxy->core_proxy->conn, struct client, this);
return pw_protocol_native_connection_add_fd(impl->connection, fd); return pw_protocol_native_connection_add_fd(impl->connection, fd);
} }
static int impl_ext_get_proxy_fd(struct pw_proxy *proxy, uint32_t index) static int impl_ext_get_proxy_fd(struct pw_proxy *proxy, uint32_t index)
{ {
struct client *impl = SPA_CONTAINER_OF(proxy->remote->conn, struct client, this); struct client *impl = SPA_CONTAINER_OF(proxy->core_proxy->conn, struct client, this);
return pw_protocol_native_connection_get_fd(impl->connection, index); return pw_protocol_native_connection_get_fd(impl->connection, index);
} }
static int impl_ext_end_proxy(struct pw_proxy *proxy, static int impl_ext_end_proxy(struct pw_proxy *proxy,
struct spa_pod_builder *builder) struct spa_pod_builder *builder)
{ {
struct client *impl = SPA_CONTAINER_OF(proxy->remote->conn, struct client, this); struct pw_core_proxy *core_proxy = proxy->core_proxy;
struct pw_remote *remote = proxy->remote; struct client *impl = SPA_CONTAINER_OF(core_proxy->conn, struct client, this);
return remote->send_seq = pw_protocol_native_connection_end(impl->connection, builder); return core_proxy->send_seq = pw_protocol_native_connection_end(impl->connection, builder);
} }
static struct spa_pod_builder * static struct spa_pod_builder *

429
src/pipewire/core-proxy.c Normal file
View file

@ -0,0 +1,429 @@
/* PipeWire
*
* Copyright © 2018 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <sys/mman.h>
#include <spa/pod/parser.h>
#include <spa/debug/types.h>
#include "pipewire/pipewire.h"
#include "pipewire/private.h"
#include "extensions/protocol-native.h"
#define NAME "core-proxy"
/** \cond */
/** \endcond */
static void core_event_ping(void *data, uint32_t id, int seq)
{
struct pw_core_proxy *this = data;
pw_log_debug(NAME" %p: object %u ping %u", this, id, seq);
pw_core_proxy_pong(this->core_proxy, id, seq);
}
static void core_event_done(void *data, uint32_t id, int seq)
{
struct pw_core_proxy *this = data;
struct pw_proxy *proxy;
pw_log_trace(NAME" %p: object %u done %d", this, id, seq);
proxy = pw_map_lookup(&this->objects, id);
if (proxy)
pw_proxy_emit_done(proxy, seq);
}
static void core_event_error(void *data, uint32_t id, int seq, int res, const char *message)
{
struct pw_core_proxy *this = data;
struct pw_proxy *proxy;
pw_log_error(NAME" %p: object error %u: seq:%d %d (%s): %s", this, id, seq,
res, spa_strerror(res), message);
proxy = pw_map_lookup(&this->objects, id);
if (proxy)
pw_proxy_emit_error(proxy, seq, res, message);
}
static void core_event_remove_id(void *data, uint32_t id)
{
struct pw_core_proxy *this = data;
struct pw_proxy *proxy;
pw_log_debug(NAME" %p: object remove %u", this, id);
if ((proxy = pw_map_lookup(&this->objects, id)) != NULL)
pw_proxy_remove(proxy);
}
static void core_event_bound_id(void *data, uint32_t id, uint32_t global_id)
{
struct pw_core_proxy *this = data;
struct pw_proxy *proxy;
pw_log_debug(NAME" %p: proxy %u bound %u", this, id, global_id);
if ((proxy = pw_map_lookup(&this->objects, id)) != NULL) {
pw_proxy_emit_bound(proxy, global_id);
}
}
static void core_event_add_mem(void *data, uint32_t id, uint32_t type, int fd, uint32_t flags)
{
struct pw_core_proxy *this = data;
struct pw_memblock *m;
pw_log_debug(NAME" %p: add mem %u type:%u fd:%d flags:%u", this, id, type, fd, flags);
m = pw_mempool_import(this->pool, flags, type, fd);
if (m->id != id) {
pw_log_error(NAME" %p: invalid mem id %u, expected %u",
this, id, m->id);
pw_memblock_unref(m);
}
}
static void core_event_remove_mem(void *data, uint32_t id)
{
struct pw_core_proxy *this = data;
pw_log_debug(NAME" %p: remove mem %u", this, id);
pw_mempool_unref_id(this->pool, id);
}
static const struct pw_core_proxy_events core_events = {
PW_VERSION_CORE_PROXY_EVENTS,
.error = core_event_error,
.ping = core_event_ping,
.done = core_event_done,
.remove_id = core_event_remove_id,
.bound_id = core_event_bound_id,
.add_mem = core_event_add_mem,
.remove_mem = core_event_remove_mem,
};
SPA_EXPORT
struct pw_core *pw_core_proxy_get_core(struct pw_core_proxy *core_proxy)
{
return core_proxy->core;
}
SPA_EXPORT
const struct pw_properties *pw_core_proxy_get_properties(struct pw_core_proxy *core_proxy)
{
return core_proxy->properties;
}
SPA_EXPORT
int pw_core_proxy_update_properties(struct pw_core_proxy *core_proxy, const struct spa_dict *dict)
{
int changed;
changed = pw_properties_update(core_proxy->properties, dict);
pw_log_debug(NAME" %p: updated %d properties", core_proxy, changed);
if (!changed)
return 0;
if (core_proxy->client_proxy)
pw_client_proxy_update_properties(core_proxy->client_proxy, &core_proxy->properties->dict);
return changed;
}
SPA_EXPORT
void *pw_core_proxy_get_user_data(struct pw_core_proxy *core_proxy)
{
return core_proxy->user_data;
}
static int destroy_proxy(void *object, void *data)
{
struct pw_core_proxy *core_proxy = data;
if (object && object != core_proxy)
pw_proxy_destroy(object);
return 0;
}
static void core_proxy_destroy(void *data)
{
struct pw_core_proxy *core_proxy = data;
struct pw_stream *stream, *s2;
struct pw_filter *filter;
pw_log_debug(NAME" %p: core proxy destroy", core_proxy);
spa_list_for_each_safe(stream, s2, &core_proxy->stream_list, link)
pw_stream_disconnect(stream);
pw_protocol_client_disconnect(core_proxy->conn);
core_proxy->client_proxy = NULL;
pw_map_for_each(&core_proxy->objects, destroy_proxy, core_proxy);
pw_map_reset(&core_proxy->objects);
pw_mempool_destroy(core_proxy->pool);
spa_list_consume(stream, &core_proxy->stream_list, link)
pw_stream_destroy(stream);
spa_list_consume(filter, &core_proxy->filter_list, link)
pw_filter_destroy(filter);
pw_protocol_client_destroy(core_proxy->conn);
spa_list_remove(&core_proxy->link);
pw_map_clear(&core_proxy->objects);
pw_log_debug(NAME" %p: free", core_proxy);
pw_properties_free(core_proxy->properties);
}
static const struct pw_proxy_events core_proxy_events = {
PW_VERSION_PROXY_EVENTS,
.destroy = core_proxy_destroy,
};
SPA_EXPORT
struct pw_client_proxy * pw_core_proxy_get_client_proxy(struct pw_core_proxy *core_proxy)
{
return core_proxy->client_proxy;
}
SPA_EXPORT
struct pw_proxy *pw_core_proxy_find_proxy(struct pw_core_proxy *core_proxy, uint32_t id)
{
return pw_map_lookup(&core_proxy->objects, id);
}
SPA_EXPORT
struct pw_proxy *pw_core_proxy_export(struct pw_core_proxy *core_proxy,
uint32_t type, struct pw_properties *props, void *object,
size_t user_data_size)
{
struct pw_proxy *proxy;
const struct pw_export_type *t;
int res;
t = pw_core_find_export_type(core_proxy->core, type);
if (t == NULL) {
res = -EPROTO;
goto error_export_type;
}
proxy = t->func(core_proxy, type, props, object, user_data_size);
if (proxy == NULL) {
res = -errno;
goto error_proxy_failed;
}
return proxy;
error_export_type:
pw_log_error(NAME" %p: can't export type %d: %s", core_proxy, type, spa_strerror(res));
goto exit_free;
error_proxy_failed:
pw_log_error(NAME" %p: failed to create proxy: %s", core_proxy, spa_strerror(res));
goto exit;
exit_free:
if (props)
pw_properties_free(props);
exit:
errno = -res;
return NULL;
}
static struct pw_core_proxy *core_proxy_new(struct pw_core *core,
struct pw_properties *properties, size_t user_data_size)
{
struct pw_core_proxy *p;
struct pw_protocol *protocol = NULL;
const char *protocol_name;
int res;
p = calloc(1, sizeof(struct pw_core_proxy) + user_data_size);
if (p == NULL) {
res = -errno;
goto exit_cleanup;
}
if (properties == NULL)
properties = pw_properties_new(NULL, NULL);
if (properties == NULL)
goto error_properties;
p->proxy.core_proxy = p;
p->core = core;
p->properties = properties;
p->pool = pw_mempool_new(NULL);
p->core_proxy = p;
if (user_data_size > 0)
p->user_data = SPA_MEMBER(p, sizeof(struct pw_core_proxy), void);
p->proxy.user_data = p->user_data;
pw_map_init(&p->objects, 64, 32);
spa_list_init(&p->stream_list);
spa_list_init(&p->filter_list);
if ((protocol_name = pw_properties_get(properties, PW_KEY_PROTOCOL)) == NULL) {
if ((protocol_name = pw_properties_get(core->properties, PW_KEY_PROTOCOL)) == NULL) {
protocol_name = PW_TYPE_INFO_PROTOCOL_Native;
if ((protocol = pw_core_find_protocol(core, protocol_name)) == NULL) {
res = -ENOTSUP;
goto error_protocol;
}
}
}
if (protocol == NULL)
protocol = pw_core_find_protocol(core, protocol_name);
if (protocol == NULL) {
res = -ENOTSUP;
goto error_protocol;
}
p->conn = pw_protocol_new_client(protocol, properties);
if (p->conn == NULL)
goto error_connection;
p->conn->core_proxy = p;
if ((res = pw_proxy_init(&p->proxy, PW_TYPE_INTERFACE_Core, PW_VERSION_CORE_PROXY)) < 0)
goto error_proxy;
p->client_proxy = (struct pw_client_proxy*)pw_proxy_new(&p->proxy,
PW_TYPE_INTERFACE_Client, PW_VERSION_CLIENT_PROXY, 0);
if (p->client_proxy == NULL) {
res = -errno;
goto error_proxy;
}
pw_core_proxy_add_listener(p, &p->core_listener, &core_events, p);
pw_proxy_add_listener(&p->proxy, &p->core_proxy_listener, &core_proxy_events, p);
pw_core_proxy_hello(p, PW_VERSION_CORE_PROXY);
pw_client_proxy_update_properties(p->client_proxy, &p->properties->dict);
spa_list_append(&core->core_proxy_list, &p->link);
return p;
error_properties:
res = -errno;
pw_log_error(NAME" %p: can't create properties: %m", p);
goto exit_free;
error_protocol:
pw_log_error(NAME" %p: can't find native protocol: %s", p, spa_strerror(res));
goto exit_free;
error_connection:
res = -errno;
pw_log_error(NAME" %p: can't create new native protocol connection: %m", p);
goto exit_free;
error_proxy:
pw_log_error(NAME" %p: can't initialize proxy: %s", p, spa_strerror(res));
goto exit_free;
exit_free:
free(p);
exit_cleanup:
if (properties)
pw_properties_free(properties);
errno = -res;
return NULL;
}
SPA_EXPORT
struct pw_core_proxy *
pw_core_connect(struct pw_core *core, struct pw_properties *properties,
size_t user_data_size)
{
struct pw_core_proxy *core_proxy;
int res;
core_proxy = core_proxy_new(core, properties, user_data_size);
if (core_proxy == NULL)
return NULL;
if ((res = pw_protocol_client_connect(core_proxy->conn,
&core_proxy->properties->dict,
NULL, NULL)) < 0)
goto error_free;
return core_proxy;
error_free:
pw_core_proxy_disconnect(core_proxy);
errno = -res;
return NULL;
}
SPA_EXPORT
struct pw_core_proxy *
pw_core_connect_fd(struct pw_core *core, int fd, struct pw_properties *properties,
size_t user_data_size)
{
struct pw_core_proxy *core_proxy;
int res;
core_proxy = core_proxy_new(core, properties, user_data_size);
if (core_proxy == NULL)
return NULL;
if ((res = pw_protocol_client_connect_fd(core_proxy->conn, fd, true)) < 0)
goto error_free;
return core_proxy;
error_free:
pw_core_proxy_disconnect(core_proxy);
errno = -res;
return NULL;
}
SPA_EXPORT
int pw_core_proxy_steal_fd(struct pw_core_proxy *proxy)
{
return pw_protocol_client_steal_fd(proxy->conn);
}
SPA_EXPORT
struct pw_mempool * pw_core_proxy_get_mempool(struct pw_core_proxy *proxy)
{
return proxy->pool;
}
SPA_EXPORT
int pw_core_proxy_disconnect(struct pw_core_proxy *proxy)
{
pw_proxy_destroy(&proxy->proxy);
return 0;
}

86
src/pipewire/core-proxy.h Normal file
View file

@ -0,0 +1,86 @@
/* PipeWire
*
* Copyright © 2018 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef PIPEWIRE_REMOTE_H
#define PIPEWIRE_REMOTE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <spa/utils/hook.h>
#include <pipewire/core.h>
#include <pipewire/properties.h>
#include <pipewire/node.h>
#include <pipewire/proxy.h>
/** Connect to a PipeWire instance \memberof pw_core_proxy
* \return a pw_core_proxy on success or NULL with errno set on error */
struct pw_core_proxy *
pw_core_connect(struct pw_core *core, /**< a \ref pw_core */
struct pw_properties *properties, /**< optional properties, ownership of
* the properties is taken.*/
size_t user_data_size /**< extra user data size */);
/** Connect to a PipeWire instance on the given socket \memberof pw_core_proxy
* \param fd the connected socket to use, the socket will be closed
* automatically on disconnect or error.
* \return a pw_core_proxy on success or NULL with errno set on error */
struct pw_core_proxy *
pw_core_connect_fd(struct pw_core *core, /**< a \ref pw_core */
int fd, /**< an fd */
struct pw_properties *properties, /**< optional properties, ownership of
* the properties is taken.*/
size_t user_data_size /**< extra user data size */);
/** Steal the fd of the core_proxy connection or < 0 on error. The core_proxy
* will be disconnected after this call. */
int pw_core_proxy_steal_fd(struct pw_core_proxy *core_proxy);
/** Get the core proxy, can only be called when connected */
int pw_core_proxy_disconnect(struct pw_core_proxy *proxy);
/** Get the client proxy */
struct pw_client_proxy * pw_core_proxy_get_client_proxy(struct pw_core_proxy *proxy);
struct pw_core * pw_core_proxy_get_core(struct pw_core_proxy *proxy);
struct pw_mempool * pw_core_proxy_get_mempool(struct pw_core_proxy *proxy);
/** Get the proxy with the given id */
struct pw_proxy *pw_core_proxy_find_proxy(struct pw_core_proxy *proxy, uint32_t id);
struct pw_proxy *pw_core_proxy_export(struct pw_core_proxy *proxy, /**< the proxy */
uint32_t type, /**< the type of object */
struct pw_properties *properties, /**< extra properties */
void *object, /**< object to export */
size_t user_data_size /**< extra user data */);
#ifdef __cplusplus
}
#endif
#endif /* PIPEWIRE_REMOTE_H */

View file

@ -570,7 +570,7 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop,
pw_map_init(&this->globals, 128, 32); pw_map_init(&this->globals, 128, 32);
spa_list_init(&this->protocol_list); spa_list_init(&this->protocol_list);
spa_list_init(&this->remote_list); spa_list_init(&this->core_proxy_list);
spa_list_init(&this->registry_resource_list); spa_list_init(&this->registry_resource_list);
spa_list_init(&this->global_list); spa_list_init(&this->global_list);
spa_list_init(&this->module_list); spa_list_init(&this->module_list);
@ -660,7 +660,7 @@ void pw_core_destroy(struct pw_core *core)
struct pw_global *global; struct pw_global *global;
struct pw_module *module; struct pw_module *module;
struct pw_device *device; struct pw_device *device;
struct pw_remote *remote; struct pw_core_proxy *core_proxy;
struct pw_resource *resource; struct pw_resource *resource;
struct pw_node *node; struct pw_node *node;
struct factory_entry *entry; struct factory_entry *entry;
@ -670,8 +670,8 @@ void pw_core_destroy(struct pw_core *core)
spa_hook_remove(&core->global_listener); spa_hook_remove(&core->global_listener);
spa_list_consume(remote, &core->remote_list, link) spa_list_consume(core_proxy, &core->core_proxy_list, link)
pw_remote_destroy(remote); pw_core_proxy_disconnect(core_proxy);
spa_list_consume(module, &core->module_list, link) spa_list_consume(module, &core->module_list, link)
pw_module_destroy(module); pw_module_destroy(module);

View file

@ -45,7 +45,7 @@ struct pw_core;
#include <pipewire/client.h> #include <pipewire/client.h>
#include <pipewire/introspect.h> #include <pipewire/introspect.h>
#include <pipewire/interfaces.h> #include <pipewire/interfaces.h>
#include <pipewire/remote.h> #include <pipewire/core-proxy.h>
#include <pipewire/global.h> #include <pipewire/global.h>
#include <pipewire/loop.h> #include <pipewire/loop.h>
#include <pipewire/factory.h> #include <pipewire/factory.h>

View file

@ -947,8 +947,6 @@ filter_new(struct pw_core *core, const char *name,
impl->core = core; impl->core = core;
// spa_list_append(&remote->filter_list, &this->link);
return impl; return impl;
error_properties: error_properties:
@ -1048,7 +1046,6 @@ void pw_filter_destroy(struct pw_filter *filter)
spa_hook_remove(&filter->core_listener); spa_hook_remove(&filter->core_listener);
filter->core_proxy = NULL; filter->core_proxy = NULL;
} }
// spa_list_remove(&filter->link);
clear_params(impl, NULL, SPA_ID_INVALID); clear_params(impl, NULL, SPA_ID_INVALID);

View file

@ -44,7 +44,7 @@ struct pw_filter;
#include <spa/node/io.h> #include <spa/node/io.h>
#include <spa/param/param.h> #include <spa/param/param.h>
#include <pipewire/remote.h> #include <pipewire/core-proxy.h>
/** \enum pw_filter_state The state of a filter \memberof pw_filter */ /** \enum pw_filter_state The state of a filter \memberof pw_filter */
enum pw_filter_state { enum pw_filter_state {

View file

@ -28,7 +28,7 @@
#include "pipewire/pipewire.h" #include "pipewire/pipewire.h"
#include "pipewire/remote.h" #include "pipewire/core-proxy.h"
SPA_EXPORT SPA_EXPORT
const char *pw_node_state_as_string(enum pw_node_state state) const char *pw_node_state_as_string(enum pw_node_state state)

View file

@ -26,7 +26,7 @@ pipewire_headers = [
'properties.h', 'properties.h',
'protocol.h', 'protocol.h',
'proxy.h', 'proxy.h',
'remote.h', 'core-proxy.h',
'resource.h', 'resource.h',
'stream.h', 'stream.h',
'thread-loop.h', 'thread-loop.h',
@ -58,7 +58,7 @@ pipewire_sources = [
'properties.c', 'properties.c',
'protocol.c', 'protocol.c',
'proxy.c', 'proxy.c',
'remote.c', 'core-proxy.c',
'resource.c', 'resource.c',
'stream.c', 'stream.c',
'thread-loop.c', 'thread-loop.c',

View file

@ -47,7 +47,7 @@ extern "C" {
#include <pipewire/port.h> #include <pipewire/port.h>
#include <pipewire/properties.h> #include <pipewire/properties.h>
#include <pipewire/proxy.h> #include <pipewire/proxy.h>
#include <pipewire/remote.h> #include <pipewire/core-proxy.h>
#include <pipewire/resource.h> #include <pipewire/resource.h>
#include <pipewire/stream.h> #include <pipewire/stream.h>
#include <pipewire/thread-loop.h> #include <pipewire/thread-loop.h>

View file

@ -34,7 +34,6 @@ extern "C" {
#include "pipewire/buffers.h" #include "pipewire/buffers.h"
#include "pipewire/map.h" #include "pipewire/map.h"
#include "pipewire/remote.h"
#include "pipewire/mem.h" #include "pipewire/mem.h"
#include "pipewire/introspect.h" #include "pipewire/introspect.h"
#include "pipewire/interfaces.h" #include "pipewire/interfaces.h"
@ -222,7 +221,7 @@ struct pw_core {
struct pw_map globals; /**< map of globals */ struct pw_map globals; /**< map of globals */
struct spa_list protocol_list; /**< list of protocols */ struct spa_list protocol_list; /**< list of protocols */
struct spa_list remote_list; /**< list of remote connections */ struct spa_list core_proxy_list; /**< list of remote connections */
struct spa_list registry_resource_list; /**< list of registry resources */ struct spa_list registry_resource_list; /**< list of registry resources */
struct spa_list module_list; /**< list of modules */ struct spa_list module_list; /**< list of modules */
struct spa_list device_list; /**< list of devices */ struct spa_list device_list; /**< list of devices */
@ -713,7 +712,7 @@ struct pw_resource {
struct pw_proxy { struct pw_proxy {
struct spa_interface impl; /**< object implementation */ struct spa_interface impl; /**< object implementation */
struct pw_remote *remote; /**< the owner remote of this proxy */ struct pw_core_proxy *core_proxy; /**< the owner core_proxy of this proxy */
uint32_t id; /**< client side id */ uint32_t id; /**< client side id */
uint32_t type; /**< type of the interface */ uint32_t type; /**< type of the interface */
@ -731,17 +730,18 @@ struct pw_proxy {
void *user_data; /**< extra user data */ void *user_data; /**< extra user data */
}; };
#define pw_remote_emit(r,m,v,...) spa_hook_list_call(&r->listener_list, struct pw_remote_events, m, v, ##__VA_ARGS__) struct pw_core_proxy {
#define pw_remote_emit_destroy(r) pw_remote_emit(r, destroy, 0) struct pw_proxy proxy;
#define pw_remote_emit_state_changed(r,o,s,e) pw_remote_emit(r, state_changed, 0, o, s, e)
struct pw_remote {
struct pw_core *core; /**< core */ struct pw_core *core; /**< core */
struct spa_list link; /**< link in core remote_list */ struct spa_list link; /**< link in core core_proxy_list */
struct pw_properties *properties; /**< extra properties */ struct pw_properties *properties; /**< extra properties */
struct pw_mempool *pool; /**< memory pool */ struct pw_mempool *pool; /**< memory pool */
struct pw_core_proxy *core_proxy; /**< proxy for the core object */ struct pw_core_proxy *core_proxy; /**< proxy for the core object */
struct spa_hook core_listener;
struct spa_hook core_proxy_listener;
struct pw_map objects; /**< map of client side proxy objects struct pw_map objects; /**< map of client side proxy objects
* indexed with the client id */ * indexed with the client id */
struct pw_client_proxy *client_proxy; /**< proxy for the client object */ struct pw_client_proxy *client_proxy; /**< proxy for the client object */
@ -899,6 +899,8 @@ pw_core_find_port(struct pw_core *core,
const struct pw_export_type *pw_core_find_export_type(struct pw_core *core, uint32_t type); const struct pw_export_type *pw_core_find_export_type(struct pw_core *core, uint32_t type);
int pw_proxy_init(struct pw_proxy *proxy, uint32_t type, uint32_t version);
int pw_proxy_install_marshal(struct pw_proxy *proxy, bool implementor); int pw_proxy_install_marshal(struct pw_proxy *proxy, bool implementor);
void pw_proxy_remove(struct pw_proxy *proxy); void pw_proxy_remove(struct pw_proxy *proxy);

View file

@ -25,7 +25,6 @@
#include <pipewire/log.h> #include <pipewire/log.h>
#include <pipewire/proxy.h> #include <pipewire/proxy.h>
#include <pipewire/core.h> #include <pipewire/core.h>
#include <pipewire/remote.h>
#include <pipewire/private.h> #include <pipewire/private.h>
#include <pipewire/type.h> #include <pipewire/type.h>
#include <pipewire/interfaces.h> #include <pipewire/interfaces.h>
@ -40,6 +39,38 @@ struct proxy {
}; };
/** \endcond */ /** \endcond */
int pw_proxy_init(struct pw_proxy *proxy, uint32_t type, uint32_t version)
{
int res;
proxy->refcount = 1;
proxy->type = type;
proxy->version = version;
proxy->id = pw_map_insert_new(&proxy->core_proxy->objects, proxy);
if (proxy->id == SPA_ID_INVALID) {
res = -errno;
pw_log_error(NAME" %p: can't allocate new id: %m", proxy);
goto error;
}
spa_hook_list_init(&proxy->listener_list);
spa_hook_list_init(&proxy->object_listener_list);
if ((res = pw_proxy_install_marshal(proxy, false)) < 0) {
pw_log_error(NAME" %p: no marshal for type %s/%d", proxy,
spa_debug_type_find_name(pw_type_info(), type),
version);
goto error_clean;
}
return 0;
error_clean:
pw_map_remove(&proxy->core_proxy->objects, proxy->id);
error:
return res;
}
/** Create a proxy object with a given id and type /** Create a proxy object with a given id and type
* *
* \param factory another proxy object that serves as a factory * \param factory another proxy object that serves as a factory
@ -50,7 +81,7 @@ struct proxy {
* This function creates a new proxy object with the supplied id and type. The * 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. * proxy object will have an id assigned from the client id space.
* *
* \sa pw_remote * \sa pw_core_proxy
* *
* \memberof pw_proxy * \memberof pw_proxy
*/ */
@ -61,7 +92,6 @@ struct pw_proxy *pw_proxy_new(struct pw_proxy *factory,
{ {
struct proxy *impl; struct proxy *impl;
struct pw_proxy *this; struct pw_proxy *this;
struct pw_remote *remote = factory->remote;
int res; int res;
impl = calloc(1, sizeof(struct proxy) + user_data_size); impl = calloc(1, sizeof(struct proxy) + user_data_size);
@ -69,38 +99,21 @@ struct pw_proxy *pw_proxy_new(struct pw_proxy *factory,
return NULL; return NULL;
this = &impl->this; this = &impl->this;
this->remote = remote; this->core_proxy = factory->core_proxy;
this->refcount = 1;
this->type = type;
this->version = version;
this->id = pw_map_insert_new(&remote->objects, this); if ((res = pw_proxy_init(this, type, version)) < 0)
if (this->id == SPA_ID_INVALID) { goto error_init;
res = -errno;
pw_log_error(NAME" %p: can't allocate new id: %m", this);
goto error_clean;
}
spa_hook_list_init(&this->listener_list);
spa_hook_list_init(&this->object_listener_list);
if ((res = pw_proxy_install_marshal(this, false)) < 0) {
pw_log_error(NAME" %p: no marshal for type %s/%d", this,
spa_debug_type_find_name(pw_type_info(), type),
version);
goto error_clean;
}
if (user_data_size > 0) if (user_data_size > 0)
this->user_data = SPA_MEMBER(impl, sizeof(struct proxy), void); this->user_data = SPA_MEMBER(impl, sizeof(struct proxy), void);
pw_log_debug(NAME" %p: new %u type %s/%d remote:%p, marshal:%p", pw_log_debug(NAME" %p: new %u type %s/%d core-proxy:%p, marshal:%p",
this, this->id, this, this->id,
spa_debug_type_find_name(pw_type_info(), type), version, spa_debug_type_find_name(pw_type_info(), type), version,
remote, this->marshal); this->core_proxy, this->marshal);
return this; return this;
error_clean: error_init:
free(impl); free(impl);
errno = -res; errno = -res;
return NULL; return NULL;
@ -109,10 +122,10 @@ error_clean:
SPA_EXPORT SPA_EXPORT
int pw_proxy_install_marshal(struct pw_proxy *this, bool implementor) int pw_proxy_install_marshal(struct pw_proxy *this, bool implementor)
{ {
struct pw_remote *remote = this->remote; struct pw_core_proxy *core_proxy = this->core_proxy;
const struct pw_protocol_marshal *marshal; const struct pw_protocol_marshal *marshal;
marshal = pw_protocol_get_marshal(remote->conn->protocol, marshal = pw_protocol_get_marshal(core_proxy->conn->protocol,
this->type, this->version, this->type, this->version,
implementor ? PW_PROTOCOL_MARSHAL_FLAG_IMPL : 0); implementor ? PW_PROTOCOL_MARSHAL_FLAG_IMPL : 0);
if (marshal == NULL) if (marshal == NULL)
@ -147,15 +160,15 @@ uint32_t pw_proxy_get_type(struct pw_proxy *proxy, uint32_t *version)
} }
SPA_EXPORT SPA_EXPORT
struct pw_remote *pw_proxy_get_remote(struct pw_proxy *proxy) struct pw_core_proxy *pw_proxy_get_core_proxy(struct pw_proxy *proxy)
{ {
return proxy->remote; return proxy->core_proxy;
} }
SPA_EXPORT SPA_EXPORT
struct pw_protocol *pw_proxy_get_protocol(struct pw_proxy *proxy) struct pw_protocol *pw_proxy_get_protocol(struct pw_proxy *proxy)
{ {
return proxy->remote->conn->protocol; return proxy->core_proxy->conn->protocol;
} }
SPA_EXPORT SPA_EXPORT
@ -180,14 +193,14 @@ void pw_proxy_add_object_listener(struct pw_proxy *proxy,
* *
* \param proxy Proxy object to destroy * \param proxy Proxy object to destroy
* *
* \note This is normally called by \ref pw_remote when the server * \note This is normally called by \ref pw_core_proxy when the server
* decides to destroy the server side object * decides to destroy the server side object
* \memberof pw_proxy * \memberof pw_proxy
*/ */
SPA_EXPORT SPA_EXPORT
void pw_proxy_destroy(struct pw_proxy *proxy) void pw_proxy_destroy(struct pw_proxy *proxy)
{ {
struct pw_remote *remote = proxy->remote; struct pw_core_proxy *core_proxy = proxy->core_proxy;
if (!proxy->zombie) { if (!proxy->zombie) {
pw_log_debug(NAME" %p: destroy %u", proxy, proxy->id); pw_log_debug(NAME" %p: destroy %u", proxy, proxy->id);
@ -196,15 +209,15 @@ void pw_proxy_destroy(struct pw_proxy *proxy)
if (!proxy->removed) { if (!proxy->removed) {
/* if the server did not remove this proxy, remove ourselves /* if the server did not remove this proxy, remove ourselves
* from the proxy objects and schedule a destroy. */ * from the proxy objects and schedule a destroy. */
if (remote->core_proxy) { if (core_proxy) {
proxy->zombie = true; proxy->zombie = true;
pw_core_proxy_destroy(remote->core_proxy, proxy); pw_core_proxy_destroy(core_proxy, proxy);
} else { } else {
proxy->removed = true; proxy->removed = true;
} }
} }
if (proxy->removed) { if (proxy->removed) {
pw_map_remove(&remote->objects, proxy->id); pw_map_remove(&core_proxy->objects, proxy->id);
pw_proxy_unref(proxy); pw_proxy_unref(proxy);
} }
@ -230,10 +243,10 @@ SPA_EXPORT
int pw_proxy_sync(struct pw_proxy *proxy, int seq) int pw_proxy_sync(struct pw_proxy *proxy, int seq)
{ {
int res = -EIO; int res = -EIO;
struct pw_remote *remote = proxy->remote; struct pw_core_proxy *core_proxy = proxy->core_proxy;
if (remote->core_proxy != NULL) { if (core_proxy != NULL) {
res = pw_core_proxy_sync(remote->core_proxy, proxy->id, seq); res = pw_core_proxy_sync(core_proxy, proxy->id, seq);
pw_log_debug(NAME" %p: %u seq:%d sync %u", proxy, proxy->id, seq, res); pw_log_debug(NAME" %p: %u seq:%d sync %u", proxy, proxy->id, seq, res);
} }
return res; return res;
@ -244,12 +257,12 @@ int pw_proxy_errorf(struct pw_proxy *proxy, int res, const char *error, ...)
{ {
va_list ap; va_list ap;
int r = -EIO; int r = -EIO;
struct pw_remote *remote = proxy->remote; struct pw_core_proxy *core_proxy = proxy->core_proxy;
va_start(ap, error); va_start(ap, error);
if (remote->core_proxy != NULL) if (core_proxy != NULL)
r = pw_core_proxy_errorv(remote->core_proxy, proxy->id, r = pw_core_proxy_errorv(core_proxy, proxy->id,
remote->recv_seq, res, error, ap); core_proxy->recv_seq, res, error, ap);
va_end(ap); va_end(ap);
return r; return r;
} }
@ -258,10 +271,10 @@ SPA_EXPORT
int pw_proxy_error(struct pw_proxy *proxy, int res, const char *error) int pw_proxy_error(struct pw_proxy *proxy, int res, const char *error)
{ {
int r = -EIO; int r = -EIO;
struct pw_remote *remote = proxy->remote; struct pw_core_proxy *core_proxy = proxy->core_proxy;
if (remote->core_proxy != NULL) if (core_proxy != NULL)
r = pw_core_proxy_error(remote->core_proxy, proxy->id, r = pw_core_proxy_error(core_proxy, proxy->id,
remote->recv_seq, res, error); core_proxy->recv_seq, res, error);
return r; return r;
} }

View file

@ -43,9 +43,8 @@ extern "C" {
* \section sec_page_proxy_core Core proxy * \section sec_page_proxy_core Core proxy
* *
* A proxy for a remote core object can be obtained by making * A proxy for a remote core object can be obtained by making
* a remote connection. See \ref pw_page_remote_api * a remote connection with \ref pw_core_connect.
* * See \ref pw_page_remote_api
* A pw_core_proxy can then be retrieved with \ref pw_remote_get_core_proxy
* *
* Some methods on proxy object allow creation of more proxy objects or * Some methods on proxy object allow creation of more proxy objects or
* create a binding between a local proxy and global resource. * create a binding between a local proxy and global resource.
@ -154,9 +153,6 @@ uint32_t pw_proxy_get_id(struct pw_proxy *proxy);
/** Get the type and version of the proxy */ /** Get the type and version of the proxy */
uint32_t pw_proxy_get_type(struct pw_proxy *proxy, uint32_t *version); uint32_t pw_proxy_get_type(struct pw_proxy *proxy, uint32_t *version);
/** Get the remote managing this proxy */
struct pw_remote *pw_proxy_get_remote(struct pw_proxy *proxy);
/** Get the protocol used for the proxy */ /** Get the protocol used for the proxy */
struct pw_protocol *pw_proxy_get_protocol(struct pw_proxy *proxy); struct pw_protocol *pw_proxy_get_protocol(struct pw_proxy *proxy);

View file

@ -1,572 +0,0 @@
/* PipeWire
*
* Copyright © 2018 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <sys/mman.h>
#include <spa/pod/parser.h>
#include <spa/debug/types.h>
#include "pipewire/pipewire.h"
#include "pipewire/private.h"
#include "extensions/protocol-native.h"
#define NAME "remote"
/** \cond */
struct remote {
struct pw_remote this;
struct spa_hook core_listener;
struct spa_hook core_proxy_listener;
size_t user_data_size;
};
/** \endcond */
static void core_event_ping(void *data, uint32_t id, int seq)
{
struct pw_remote *this = data;
pw_log_debug(NAME" %p: object %u ping %u", this, id, seq);
pw_core_proxy_pong(this->core_proxy, id, seq);
}
static void core_event_done(void *data, uint32_t id, int seq)
{
struct pw_remote *this = data;
struct pw_proxy *proxy;
pw_log_trace(NAME" %p: object %u done %d", this, id, seq);
proxy = pw_map_lookup(&this->objects, id);
if (proxy)
pw_proxy_emit_done(proxy, seq);
}
static void core_event_error(void *data, uint32_t id, int seq, int res, const char *message)
{
struct pw_remote *this = data;
struct pw_proxy *proxy;
pw_log_error(NAME" %p: object error %u: seq:%d %d (%s): %s", this, id, seq,
res, spa_strerror(res), message);
proxy = pw_map_lookup(&this->objects, id);
if (proxy)
pw_proxy_emit_error(proxy, seq, res, message);
}
static void core_event_remove_id(void *data, uint32_t id)
{
struct pw_remote *this = data;
struct pw_proxy *proxy;
pw_log_debug(NAME" %p: object remove %u", this, id);
if ((proxy = pw_map_lookup(&this->objects, id)) != NULL)
pw_proxy_remove(proxy);
}
static void core_event_bound_id(void *data, uint32_t id, uint32_t global_id)
{
struct pw_remote *this = data;
struct pw_proxy *proxy;
pw_log_debug(NAME" %p: proxy %u bound %u", this, id, global_id);
if ((proxy = pw_map_lookup(&this->objects, id)) != NULL) {
pw_proxy_emit_bound(proxy, global_id);
}
}
static void core_event_add_mem(void *data, uint32_t id, uint32_t type, int fd, uint32_t flags)
{
struct pw_remote *this = data;
struct pw_memblock *m;
pw_log_debug(NAME" %p: add mem %u type:%u fd:%d flags:%u", this, id, type, fd, flags);
m = pw_mempool_import(this->pool, flags, type, fd);
if (m->id != id) {
pw_log_error(NAME" %p: invalid mem id %u, expected %u",
this, id, m->id);
pw_memblock_unref(m);
}
}
static void core_event_remove_mem(void *data, uint32_t id)
{
struct pw_remote *this = data;
pw_log_debug(NAME" %p: remove mem %u", this, id);
pw_mempool_unref_id(this->pool, id);
}
static const struct pw_core_proxy_events core_events = {
PW_VERSION_CORE_PROXY_EVENTS,
.error = core_event_error,
.ping = core_event_ping,
.done = core_event_done,
.remove_id = core_event_remove_id,
.bound_id = core_event_bound_id,
.add_mem = core_event_add_mem,
.remove_mem = core_event_remove_mem,
};
SPA_EXPORT
struct pw_remote *pw_remote_new(struct pw_core *core,
struct pw_properties *properties,
size_t user_data_size)
{
struct remote *impl;
struct pw_remote *this;
struct pw_protocol *protocol = NULL;
const char *protocol_name;
int res;
impl = calloc(1, sizeof(struct remote) + user_data_size);
if (impl == NULL) {
res = -errno;
goto exit_cleanup;
}
this = &impl->this;
pw_log_debug(NAME" %p: new", impl);
this->core = core;
impl->user_data_size = user_data_size;
if (user_data_size > 0)
this->user_data = SPA_MEMBER(impl, sizeof(struct remote), void);
if (properties == NULL)
properties = pw_properties_new(NULL, NULL);
if (properties == NULL)
goto error_properties;
pw_fill_remote_properties(core, properties);
this->properties = properties;
pw_map_init(&this->objects, 64, 32);
spa_list_init(&this->stream_list);
spa_list_init(&this->filter_list);
if ((protocol_name = pw_properties_get(properties, PW_KEY_PROTOCOL)) == NULL) {
if ((protocol_name = pw_properties_get(core->properties, PW_KEY_PROTOCOL)) == NULL) {
protocol_name = PW_TYPE_INFO_PROTOCOL_Native;
if ((protocol = pw_core_find_protocol(core, protocol_name)) == NULL) {
goto error_protocol;
}
}
}
if (protocol == NULL)
protocol = pw_core_find_protocol(core, protocol_name);
if (protocol == NULL) {
res = -ENOTSUP;
goto error_protocol;
}
this->conn = pw_protocol_new_client(protocol, properties);
if (this->conn == NULL)
goto error_connection;
spa_list_append(&core->remote_list, &this->link);
return this;
error_properties:
res = -errno;
pw_log_error(NAME" %p: can't create properties: %m", this);
goto exit_free;
error_protocol:
pw_log_error(NAME" %p: can't load native protocol: %s", this, spa_strerror(res));
goto exit_free;
error_connection:
res = -errno;
pw_log_error(NAME" %p: can't create new native protocol connection: %m", this);
goto exit_free;
exit_free:
free(impl);
exit_cleanup:
if (properties)
pw_properties_free(properties);
errno = -res;
return NULL;
}
SPA_EXPORT
void pw_remote_destroy(struct pw_remote *remote)
{
struct remote *impl = SPA_CONTAINER_OF(remote, struct remote, this);
struct pw_stream *stream;
struct pw_filter *filter;
pw_log_debug(NAME" %p: destroy", remote);
pw_remote_disconnect(remote);
spa_list_consume(stream, &remote->stream_list, link)
pw_stream_destroy(stream);
spa_list_consume(filter, &remote->filter_list, link)
pw_filter_destroy(filter);
pw_protocol_client_destroy(remote->conn);
spa_list_remove(&remote->link);
pw_map_clear(&remote->objects);
pw_log_debug(NAME" %p: free", remote);
pw_properties_free(remote->properties);
free(impl);
}
SPA_EXPORT
struct pw_core *pw_remote_get_core(struct pw_remote *remote)
{
return remote->core;
}
SPA_EXPORT
const struct pw_properties *pw_remote_get_properties(struct pw_remote *remote)
{
return remote->properties;
}
SPA_EXPORT
int pw_remote_update_properties(struct pw_remote *remote, const struct spa_dict *dict)
{
int changed;
changed = pw_properties_update(remote->properties, dict);
pw_log_debug(NAME" %p: updated %d properties", remote, changed);
if (!changed)
return 0;
if (remote->client_proxy)
pw_client_proxy_update_properties(remote->client_proxy, &remote->properties->dict);
return changed;
}
SPA_EXPORT
void *pw_remote_get_user_data(struct pw_remote *remote)
{
return remote->user_data;
}
static void core_proxy_destroy(void *data)
{
struct pw_remote *remote = data;
struct remote *impl = SPA_CONTAINER_OF(remote, struct remote, this);
pw_log_debug(NAME" %p: core proxy destroy", remote);
if (remote->core_proxy) {
spa_hook_remove(&impl->core_proxy_listener);
spa_hook_remove(&impl->core_listener);
remote->core_proxy = NULL;
}
}
static const struct pw_proxy_events core_proxy_events = {
PW_VERSION_PROXY_EVENTS,
.destroy = core_proxy_destroy,
};
static int init_connect(struct pw_remote *remote)
{
struct remote *impl = SPA_CONTAINER_OF(remote, struct remote, this);
struct pw_proxy dummy, *core_proxy;
int res;
spa_zero(dummy);
dummy.remote = remote;
core_proxy = pw_proxy_new(&dummy,
PW_TYPE_INTERFACE_Core,
PW_VERSION_CORE_PROXY,
impl->user_data_size);
if (core_proxy == NULL) {
res = -errno;
goto error;
}
remote->core_proxy = (struct pw_core_proxy*)core_proxy;
remote->client_proxy = (struct pw_client_proxy*)pw_proxy_new(&dummy,
PW_TYPE_INTERFACE_Client, PW_VERSION_CLIENT_PROXY, 0);
if (remote->client_proxy == NULL) {
res = -errno;
goto error_clean_core_proxy;
}
remote->pool = pw_mempool_new(NULL);
pw_core_proxy_add_listener(remote->core_proxy, &impl->core_listener, &core_events, remote);
pw_proxy_add_listener(core_proxy, &impl->core_proxy_listener, &core_proxy_events, remote);
pw_core_proxy_hello(remote->core_proxy, PW_VERSION_CORE_PROXY);
pw_client_proxy_update_properties(remote->client_proxy, &remote->properties->dict);
remote->conn->core_proxy = remote->core_proxy;
return 0;
error_clean_core_proxy:
pw_proxy_remove((struct pw_proxy*)remote->core_proxy);
error:
return res;
}
SPA_EXPORT
struct pw_core_proxy * pw_remote_get_core_proxy(struct pw_remote *remote)
{
return remote->core_proxy;
}
SPA_EXPORT
struct pw_client_proxy * pw_remote_get_client_proxy(struct pw_remote *remote)
{
return remote->client_proxy;
}
SPA_EXPORT
struct pw_proxy *pw_remote_find_proxy(struct pw_remote *remote, uint32_t id)
{
return pw_map_lookup(&remote->objects, id);
}
SPA_EXPORT
int pw_remote_connect(struct pw_remote *remote)
{
int res;
if ((res = init_connect(remote)) < 0)
goto error;
if ((res = pw_protocol_client_connect(remote->conn,
&remote->properties->dict,
NULL, NULL)) < 0)
goto error;
error:
return res;
}
SPA_EXPORT
int pw_remote_connect_fd(struct pw_remote *remote, int fd)
{
int res;
if ((res = init_connect(remote)) < 0)
goto error;
if ((res = pw_protocol_client_connect_fd(remote->conn, fd, true)) < 0)
goto error;
error:
return res;
}
SPA_EXPORT
int pw_remote_steal_fd(struct pw_remote *remote)
{
int fd;
fd = pw_protocol_client_steal_fd(remote->conn);
return fd;
}
static int destroy_proxy(void *object, void *data)
{
if (object)
pw_proxy_destroy(object);
return 0;
}
SPA_EXPORT
int pw_remote_disconnect(struct pw_remote *remote)
{
struct pw_stream *stream, *s2;
pw_log_debug(NAME" %p: disconnect", remote);
spa_list_for_each_safe(stream, s2, &remote->stream_list, link)
pw_stream_disconnect(stream);
pw_protocol_client_disconnect(remote->conn);
remote->client_proxy = NULL;
pw_map_for_each(&remote->objects, destroy_proxy, remote);
pw_map_reset(&remote->objects);
pw_mempool_destroy(remote->pool);
return 0;
}
SPA_EXPORT
struct pw_proxy *pw_remote_export(struct pw_remote *remote,
uint32_t type, struct pw_properties *props, void *object,
size_t user_data_size)
{
struct pw_proxy *proxy;
const struct pw_export_type *t;
int res;
if (remote->core_proxy == NULL) {
res = -ENETDOWN;
goto error_core_proxy;
}
t = pw_core_find_export_type(remote->core, type);
if (t == NULL) {
res = -EPROTO;
goto error_export_type;
}
proxy = t->func(remote->core_proxy, type, props, object, user_data_size);
if (proxy == NULL) {
res = -errno;
goto error_proxy_failed;
}
return proxy;
error_core_proxy:
pw_log_error(NAME" %p: no core proxy: %s", remote, spa_strerror(res));
goto exit_free;
error_export_type:
pw_log_error(NAME" %p: can't export type %d: %s", remote, type, spa_strerror(res));
goto exit_free;
error_proxy_failed:
pw_log_error(NAME" %p: failed to create proxy: %s", remote, spa_strerror(res));
goto exit;
exit_free:
if (props)
pw_properties_free(props);
exit:
errno = -res;
return NULL;
}
SPA_EXPORT
struct pw_core_proxy *
pw_core_connect(struct pw_core *core, struct pw_properties *properties,
size_t user_data_size)
{
struct pw_remote *remote;
int res;
remote = pw_remote_new(core, properties, user_data_size);
if (remote == NULL)
return NULL;
if ((res = pw_remote_connect(remote)) < 0)
goto error_free;
return remote->core_proxy;
error_free:
pw_remote_destroy(remote);
errno = -res;
return NULL;
}
SPA_EXPORT
struct pw_core_proxy *
pw_core_connect_fd(struct pw_core *core, int fd, struct pw_properties *properties,
size_t user_data_size)
{
struct pw_remote *remote;
int res;
remote = pw_remote_new(core, properties, user_data_size);
if (remote == NULL)
return NULL;
if ((res = pw_remote_connect_fd(remote, fd)) < 0)
goto error_free;
return remote->core_proxy;
error_free:
pw_remote_destroy(remote);
errno = -res;
return NULL;
}
SPA_EXPORT
struct pw_client_proxy * pw_core_proxy_get_client_proxy(struct pw_core_proxy *proxy)
{
struct pw_remote *remote = ((struct pw_proxy*)proxy)->remote;
return remote->client_proxy;
}
SPA_EXPORT
struct pw_core * pw_core_proxy_get_core(struct pw_core_proxy *proxy)
{
struct pw_remote *remote = ((struct pw_proxy*)proxy)->remote;
return remote->core;
}
SPA_EXPORT
struct pw_remote * pw_core_proxy_get_remote(struct pw_core_proxy *proxy)
{
return ((struct pw_proxy*)proxy)->remote;
}
SPA_EXPORT
struct pw_mempool * pw_core_proxy_get_mempool(struct pw_core_proxy *proxy)
{
struct pw_remote *remote = ((struct pw_proxy*)proxy)->remote;
return remote->pool;
}
SPA_EXPORT
struct pw_proxy *pw_core_proxy_find_proxy(struct pw_core_proxy *proxy, uint32_t id)
{
struct pw_remote *remote = ((struct pw_proxy*)proxy)->remote;
return pw_remote_find_proxy(remote, id);
}
SPA_EXPORT
int pw_core_proxy_disconnect(struct pw_core_proxy *proxy)
{
struct pw_remote *remote = ((struct pw_proxy*)proxy)->remote;
pw_remote_destroy(remote);
return 0;
}
SPA_EXPORT
struct pw_proxy *pw_core_proxy_export(struct pw_core_proxy *proxy,
uint32_t type, struct pw_properties *properties,
void *object, size_t user_data_size)
{
struct pw_remote *remote = ((struct pw_proxy*)proxy)->remote;
return pw_remote_export(remote, type, properties, object, user_data_size);
}

View file

@ -1,213 +0,0 @@
/* PipeWire
*
* Copyright © 2018 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef PIPEWIRE_REMOTE_H
#define PIPEWIRE_REMOTE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <spa/utils/hook.h>
/** \page page_remote_api Remote API
*
* \section sec_remote_api_overview Overview
*
* The remote API allows you to connect to a remote PipeWire instance
* and perform actions on the PipeWire graph. This includes
*
* \li introspecting the objects on the instance
* \li Creating nodes
* \li Linking nodes on their ports
* \li providing media to the server for playback or consumption
* \li retrieving media from the remote instance
*
* \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_remote
* object. Connect to the state_changed event 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 local \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 event.
*
* \subsection ssec_remote_api_remote_connect Connecting
*
* A remote must be connected 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 proxy and types.
*
* \subsection ssec_remote_api_remote_registry Registry
*
* \subpage page_registry
*
*
* \subsection ssec_remote_api_remote_disconnect Disconnect
*
* Use pw_remote_disconnect() to disconnect from the remote.
*/
/** \class pw_remote
*
* \brief Represents a connection with a remote PipeWire instance
*
* a \ref pw_remote is created and used to connect to a remote PipeWire
* instance.
* A \ref pw_proxy for the core object will automatically be created
* when connecting.
*
* See also \ref page_core_api
*/
struct pw_remote;
#include <pipewire/core.h>
#include <pipewire/properties.h>
#include <pipewire/node.h>
#include <pipewire/proxy.h>
/** 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.*/
size_t user_data_size /**< extra user data size */);
/** Destroy a remote \memberof pw_remote */
void pw_remote_destroy(struct pw_remote *remote);
/** Get the core used to construct this remote */
struct pw_core *pw_remote_get_core(struct pw_remote *remote);
/** Get the remote properties */
const struct pw_properties *pw_remote_get_properties(struct pw_remote *remote);
/** Update properties */
int pw_remote_update_properties(struct pw_remote *remote, const struct spa_dict *dict);
/** Get the user_data. The size was given in \ref pw_remote_new */
void *pw_remote_get_user_data(struct pw_remote *remote);
/** Connect to a remote PipeWire \memberof pw_remote
* \return 0 on success, < 0 on error */
int pw_remote_connect(struct pw_remote *remote);
/** Connect to a remote PipeWire on the given socket \memberof pw_remote
* \param fd the connected socket to use, the socket will be closed
* automatically on disconnect or error.
* \return 0 on success, < 0 on error */
int pw_remote_connect_fd(struct pw_remote *remote, int fd);
/** Steal the fd of the remote connection or < 0 on error. The remote
* will be in the unconnected state after this call. */
int pw_remote_steal_fd(struct pw_remote *remote);
/** Get the core proxy, can only be called when connected */
struct pw_core_proxy * pw_remote_get_core_proxy(struct pw_remote *remote);
/** Get the client proxy, can only be called when connected */
struct pw_client_proxy * pw_remote_get_client_proxy(struct pw_remote *remote);
/** Get the proxy with the given id */
struct pw_proxy *pw_remote_find_proxy(struct pw_remote *remote, uint32_t id);
/** Disconnect from the remote PipeWire. \memberof pw_remote */
int pw_remote_disconnect(struct pw_remote *remote);
/** run a local node in a remote graph */
struct pw_proxy *pw_remote_export(struct pw_remote *remote, /**< the remote */
uint32_t type, /**< the type of object */
struct pw_properties *properties, /**< extra properties */
void *object, /**< object to export */
size_t user_data_size /**< extra user data */);
struct pw_core_proxy *
pw_core_connect(struct pw_core *core, /**< a \ref pw_core */
struct pw_properties *properties, /**< optional properties, ownership of
* the properties is taken.*/
size_t user_data_size /**< extra user data size */);
struct pw_core_proxy *
pw_core_connect_fd(struct pw_core *core, /**< a \ref pw_core */
int fd, /**< an fd */
struct pw_properties *properties, /**< optional properties, ownership of
* the properties is taken.*/
size_t user_data_size /**< extra user data size */);
int pw_core_proxy_disconnect(struct pw_core_proxy *proxy);
/** Get the client proxy */
struct pw_client_proxy * pw_core_proxy_get_client_proxy(struct pw_core_proxy *proxy);
struct pw_core * pw_core_proxy_get_core(struct pw_core_proxy *proxy);
struct pw_remote * pw_core_proxy_get_remote(struct pw_core_proxy *proxy);
struct pw_mempool * pw_core_proxy_get_mempool(struct pw_core_proxy *proxy);
/** Get the proxy with the given id */
struct pw_proxy *pw_core_proxy_find_proxy(struct pw_core_proxy *proxy, uint32_t id);
struct pw_proxy *pw_core_proxy_export(struct pw_core_proxy *proxy, /**< the proxy */
uint32_t type, /**< the type of object */
struct pw_properties *properties, /**< extra properties */
void *object, /**< object to export */
size_t user_data_size /**< extra user data */);
#ifdef __cplusplus
}
#endif
#endif /* PIPEWIRE_REMOTE_H */

View file

@ -96,8 +96,6 @@ struct stream {
enum spa_direction direction; enum spa_direction direction;
enum pw_stream_flags flags; enum pw_stream_flags flags;
struct spa_hook remote_listener;
struct pw_node *node; struct pw_node *node;
struct spa_port_info port_info; struct spa_port_info port_info;
@ -1068,8 +1066,6 @@ stream_new(struct pw_core *core, const char *name,
impl->core = core; impl->core = core;
// spa_list_append(&remote->stream_list, &this->link);
return impl; return impl;
error_properties: error_properties:
@ -1169,7 +1165,6 @@ void pw_stream_destroy(struct pw_stream *stream)
spa_hook_remove(&stream->core_listener); spa_hook_remove(&stream->core_listener);
stream->core_proxy = NULL; stream->core_proxy = NULL;
} }
// spa_list_remove(&stream->link);
clear_params(impl, SPA_ID_INVALID); clear_params(impl, SPA_ID_INVALID);

View file

@ -48,7 +48,7 @@ extern "C" {
* *
* For more complicated nodes such as filters or ports with multiple * For more complicated nodes such as filters or ports with multiple
* inputs and/or outputs you will need to use the pw_filter or make * inputs and/or outputs you will need to use the pw_filter or make
* a pw_node yourself and export it with \ref pw_remote_export. * a pw_node yourself and export it with \ref pw_core_proxy_export.
* *
* \section sec_create Create * \section sec_create Create
* *
@ -152,7 +152,7 @@ struct pw_stream;
#include <spa/buffer/buffer.h> #include <spa/buffer/buffer.h>
#include <spa/param/param.h> #include <spa/param/param.h>
#include <pipewire/remote.h> #include <pipewire/core-proxy.h>
/** \enum pw_stream_state The state of a stream \memberof pw_stream */ /** \enum pw_stream_state The state of a stream \memberof pw_stream */
enum pw_stream_state { enum pw_stream_state {

View file

@ -42,7 +42,7 @@
#include <pipewire/properties.h> #include <pipewire/properties.h>
#include <pipewire/protocol.h> #include <pipewire/protocol.h>
#include <pipewire/proxy.h> #include <pipewire/proxy.h>
#include <pipewire/remote.h> #include <pipewire/core-proxy.h>
#include <pipewire/resource.h> #include <pipewire/resource.h>
#include <pipewire/stream.h> #include <pipewire/stream.h>
#include <pipewire/thread-loop.h> #include <pipewire/thread-loop.h>

View file

@ -1,186 +0,0 @@
/* PipeWire
*
* Copyright © 2019 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <pipewire/pipewire.h>
#include <pipewire/main-loop.h>
#include <pipewire/remote.h>
#define TEST_FUNC(a,b,func) \
do { \
a.func = b.func; \
spa_assert(SPA_PTRDIFF(&a.func, &a) == SPA_PTRDIFF(&b.func, &b)); \
} while(0)
static void test_abi(void)
{
struct pw_remote_events ev;
struct {
uint32_t version;
void (*destroy) (void *data);
void (*state_changed) (void *data, enum pw_remote_state old,
enum pw_remote_state state, const char *error);
} test = { PW_VERSION_REMOTE_EVENTS, NULL };
TEST_FUNC(ev, test, destroy);
TEST_FUNC(ev, test, state_changed);
spa_assert(PW_VERSION_REMOTE_EVENTS == 0);
spa_assert(sizeof(ev) == sizeof(test));
spa_assert(PW_REMOTE_STATE_ERROR == -1);
spa_assert(PW_REMOTE_STATE_UNCONNECTED == 0);
spa_assert(PW_REMOTE_STATE_CONNECTING == 1);
spa_assert(PW_REMOTE_STATE_CONNECTED == 2);
spa_assert(pw_remote_state_as_string(PW_REMOTE_STATE_ERROR) != NULL);
spa_assert(pw_remote_state_as_string(PW_REMOTE_STATE_UNCONNECTED) != NULL);
spa_assert(pw_remote_state_as_string(PW_REMOTE_STATE_CONNECTING) != NULL);
spa_assert(pw_remote_state_as_string(PW_REMOTE_STATE_CONNECTED) != NULL);
}
static void remote_destroy_error(void *data)
{
spa_assert_not_reached();
}
static void remote_state_changed_error(void *data, enum pw_remote_state old,
enum pw_remote_state state, const char *error)
{
spa_assert_not_reached();
}
static const struct pw_remote_events remote_events_error =
{
PW_VERSION_REMOTE_EVENTS,
.destroy = remote_destroy_error,
.state_changed = remote_state_changed_error,
};
static int destroy_count = 0;
static void remote_destroy_count(void *data)
{
destroy_count++;
}
static void test_create(void)
{
struct pw_main_loop *loop;
struct pw_core *core;
struct pw_remote *remote;
struct pw_remote_events remote_events = remote_events_error;
struct spa_hook listener = { 0, };
const char *error = NULL;
loop = pw_main_loop_new(NULL);
core = pw_core_new(pw_main_loop_get_loop(loop), NULL, 12);
remote = pw_remote_new(core, NULL, 12);
spa_assert(remote != NULL);
pw_remote_add_listener(remote, &listener, &remote_events, remote);
/* check core */
spa_assert(pw_remote_get_core(remote) == core);
/* check user data */
spa_assert(pw_remote_get_user_data(remote) != NULL);
/* check state */
spa_assert(pw_remote_get_state(remote, &error) == PW_REMOTE_STATE_UNCONNECTED);
spa_assert(error == NULL);
/* check core proxy, only available when connected */
spa_assert(pw_remote_get_core_proxy(remote) == NULL);
/* check some non-existing proxies */
spa_assert(pw_remote_find_proxy(remote, 0) == NULL);
spa_assert(pw_remote_find_proxy(remote, 5) == NULL);
/* check destroy */
destroy_count = 0;
remote_events.destroy = remote_destroy_count;
pw_remote_destroy(remote);
spa_assert(destroy_count == 1);
pw_core_destroy(core);
pw_main_loop_destroy(loop);
}
static void test_properties(void)
{
struct pw_main_loop *loop;
struct pw_core *core;
const struct pw_properties *props;
struct pw_remote *remote;
struct pw_remote_events remote_events = remote_events_error;
struct spa_hook listener = { NULL, };
struct spa_dict_item items[3];
loop = pw_main_loop_new(NULL);
core = pw_core_new(pw_main_loop_get_loop(loop), NULL, 0);
remote = pw_remote_new(core,
pw_properties_new("foo", "bar",
"biz", "fuzz",
NULL),
0);
spa_assert(remote != NULL);
spa_assert(pw_remote_get_user_data(remote) == NULL);
pw_remote_add_listener(remote, &listener, &remote_events, remote);
props = pw_remote_get_properties(remote);
spa_assert(props != NULL);
spa_assert(!strcmp(pw_properties_get(props, "foo"), "bar"));
spa_assert(!strcmp(pw_properties_get(props, "biz"), "fuzz"));
spa_assert(pw_properties_get(props, "buzz") == NULL);
/* remove foo */
items[0] = SPA_DICT_ITEM_INIT("foo", NULL);
/* change biz */
items[1] = SPA_DICT_ITEM_INIT("biz", "buzz");
/* add buzz */
items[2] = SPA_DICT_ITEM_INIT("buzz", "frizz");
/* update properties does not emit the info_changed signal
* because that is only emited when the remote core properties
* changed */
pw_remote_update_properties(remote, &SPA_DICT_INIT(items, 3));
spa_assert(props == pw_remote_get_properties(remote));
spa_assert(pw_properties_get(props, "foo") == NULL);
spa_assert(!strcmp(pw_properties_get(props, "biz"), "buzz"));
spa_assert(!strcmp(pw_properties_get(props, "buzz"), "frizz"));
/* check destroy */
destroy_count = 0;
remote_events.destroy = remote_destroy_count;
pw_core_destroy(core);
spa_assert(destroy_count == 1);
pw_main_loop_destroy(loop);
}
int main(int argc, char *argv[])
{
pw_init(&argc, &argv);
test_abi();
test_create();
test_properties();
return 0;
}

View file

@ -33,7 +33,6 @@
#include <pipewire/interfaces.h> #include <pipewire/interfaces.h>
#include <pipewire/type.h> #include <pipewire/type.h>
#include <pipewire/remote.h>
#include <pipewire/main-loop.h> #include <pipewire/main-loop.h>
#include <pipewire/pipewire.h> #include <pipewire/pipewire.h>