client-node: remove transport area

We don't need the area anymore
This commit is contained in:
Wim Taymans 2018-04-12 10:12:40 +02:00
parent 10fff4b2f8
commit 03b914405d
8 changed files with 18 additions and 475 deletions

View file

@ -34,7 +34,7 @@
#define M_PI_M2 ( M_PI + M_PI ) #define M_PI_M2 ( M_PI + M_PI )
#define DEFAULT_RATE 44100 #define DEFAULT_RATE 44100
#define DEFAULT_CHANNELS 1 #define DEFAULT_CHANNELS 2
struct type { struct type {
struct spa_type_media_type media_type; struct spa_type_media_type media_type;

View file

@ -36,108 +36,6 @@ struct pw_client_node_proxy;
#define PW_VERSION_CLIENT_NODE 0 #define PW_VERSION_CLIENT_NODE 0
struct pw_client_node_message;
/** \class pw_client_node_transport
*
* \brief Transport object
*
* The transport object contains shared data and ringbuffers to exchange
* events and data between the server and the client in a low-latency and
* lockfree way.
*/
struct pw_client_node_transport {
void *input_data; /**< input memory for ringbuffer */
struct spa_ringbuffer *input_buffer; /**< ringbuffer for input memory */
void *output_data; /**< output memory for ringbuffer */
struct spa_ringbuffer *output_buffer; /**< ringbuffer for output memory */
/** Destroy a transport
* \param trans a transport to destroy
* \memberof pw_client_node_transport
*/
void (*destroy) (struct pw_client_node_transport *trans);
/** Add a message to the transport
* \param trans the transport to send the message on
* \param message the message to add
* \return 0 on success, < 0 on error
*
* Write \a message to the shared ringbuffer.
*/
int (*add_message) (struct pw_client_node_transport *trans, struct pw_client_node_message *message);
/** Get next message from a transport
* \param trans the transport to get the message of
* \param[out] message the message to read
* \return < 0 on error, 1 when a message is available,
* 0 when no more messages are available.
*
* Get the skeleton next message from \a trans into \a message. This function will
* only read the head and object body of the message.
*
* After the complete size of the message has been calculated, you should call
* \ref parse_message() to read the complete message contents.
*/
int (*next_message) (struct pw_client_node_transport *trans, struct pw_client_node_message *message);
/** Parse the complete message on transport
* \param trans the transport to read from
* \param[out] message memory that can hold the complete message
* \return 0 on success, < 0 on error
*
* Use this function after \ref next_message().
*/
int (*parse_message) (struct pw_client_node_transport *trans, void *message);
};
#define pw_client_node_transport_destroy(t) ((t)->destroy((t)))
#define pw_client_node_transport_add_message(t,m) ((t)->add_message((t), (m)))
#define pw_client_node_transport_next_message(t,m) ((t)->next_message((t), (m)))
#define pw_client_node_transport_parse_message(t,m) ((t)->parse_message((t), (m)))
enum pw_client_node_message_type {
PW_CLIENT_NODE_MESSAGE_PROCESS, /*< instruct the node to process */
PW_CLIENT_NODE_MESSAGE_PORT_REUSE_BUFFER, /*< reuse a buffer */
};
struct pw_client_node_message_body {
struct spa_pod_int type SPA_ALIGNED(8); /*< one of enum pw_client_node_message_type */
};
struct pw_client_node_message {
struct spa_pod_struct pod;
struct pw_client_node_message_body body;
};
struct pw_client_node_message_port_reuse_buffer_body {
struct spa_pod_int type SPA_ALIGNED(8); /*< PW_CLIENT_NODE_MESSAGE_PORT_REUSE_BUFFER */
struct spa_pod_int port_id SPA_ALIGNED(8); /*< port id */
struct spa_pod_int buffer_id SPA_ALIGNED(8); /*< buffer id to reuse */
};
struct pw_client_node_message_port_reuse_buffer {
struct spa_pod_struct pod;
struct pw_client_node_message_port_reuse_buffer_body body;
};
#define PW_CLIENT_NODE_MESSAGE_TYPE(message) (((struct pw_client_node_message*)(message))->body.type.value)
#define PW_CLIENT_NODE_MESSAGE_INIT(message) (struct pw_client_node_message) \
{ { { sizeof(struct pw_client_node_message_body), SPA_POD_TYPE_STRUCT } }, \
{ SPA_POD_INT_INIT(message) } }
#define PW_CLIENT_NODE_MESSAGE_INIT_FULL(type,size,message,...) (type) \
{ { { size, SPA_POD_TYPE_STRUCT } }, \
{ SPA_POD_INT_INIT(message), ##__VA_ARGS__ } } \
#define PW_CLIENT_NODE_MESSAGE_PORT_REUSE_BUFFER_INIT(port_id,buffer_id) \
PW_CLIENT_NODE_MESSAGE_INIT_FULL(struct pw_client_node_message_port_reuse_buffer, \
sizeof(struct pw_client_node_message_port_reuse_buffer_body), \
PW_CLIENT_NODE_MESSAGE_PORT_REUSE_BUFFER, \
SPA_POD_INT_INIT(port_id), \
SPA_POD_INT_INIT(buffer_id))
/** information about a buffer */ /** information about a buffer */
struct pw_client_node_buffer { struct pw_client_node_buffer {
uint32_t mem_id; /**< the memory id for the metadata */ uint32_t mem_id; /**< the memory id for the metadata */
@ -316,19 +214,16 @@ struct pw_client_node_proxy_events {
/** /**
* Notify of a new transport area * Notify of a new transport area
* *
* The transport area is used to exchange real-time commands between * The transport area is used to signal the client and the server.
* the client and the server.
* *
* \param node_id the node id created for this client node * \param node_id the node id created for this client node
* \param readfd fd for signal data can be read * \param readfd fd for signal data can be read
* \param writefd fd for signal data can be written * \param writefd fd for signal data can be written
* \param transport the shared transport area
*/ */
void (*transport) (void *object, void (*transport) (void *object,
uint32_t node_id, uint32_t node_id,
int readfd, int readfd,
int writefd, int writefd);
struct pw_client_node_transport *transport);
/** /**
* Notify of a property change * Notify of a property change
* *

View file

@ -47,7 +47,6 @@ pipewire_module_mixer = shared_library('pipewire-module-mixer',
pipewire_module_client_node = shared_library('pipewire-module-client-node', pipewire_module_client_node = shared_library('pipewire-module-client-node',
[ 'module-client-node.c', [ 'module-client-node.c',
'module-client-node/client-node.c', 'module-client-node/client-node.c',
'module-client-node/transport.c',
'module-client-node/protocol-native.c', 'module-client-node/protocol-native.c',
'module-protocol-native/connection.c', 'module-protocol-native/connection.c',
'spa/spa-node.c', ], 'spa/spa-node.c', ],

View file

@ -38,7 +38,6 @@
#include "pipewire/core.h" #include "pipewire/core.h"
#include "modules/spa/spa-node.h" #include "modules/spa/spa-node.h"
#include "client-node.h" #include "client-node.h"
#include "transport.h"
/** \cond */ /** \cond */
@ -141,8 +140,6 @@ struct impl {
struct node node; struct node node;
struct pw_client_node_transport *transport;
struct pw_map io_map; struct pw_map io_map;
struct pw_memblock *io_areas; struct pw_memblock *io_areas;
@ -855,21 +852,15 @@ static int
impl_node_port_reuse_buffer(struct spa_node *node, uint32_t port_id, uint32_t buffer_id) impl_node_port_reuse_buffer(struct spa_node *node, uint32_t port_id, uint32_t buffer_id)
{ {
struct node *this; struct node *this;
struct impl *impl;
this = SPA_CONTAINER_OF(node, struct node, node); this = SPA_CONTAINER_OF(node, struct node, node);
impl = this->impl;
if (!CHECK_OUT_PORT(this, SPA_DIRECTION_OUTPUT, port_id)) if (!CHECK_OUT_PORT(this, SPA_DIRECTION_OUTPUT, port_id))
return -EINVAL; return -EINVAL;
spa_log_trace(this->log, "reuse buffer %d", buffer_id); spa_log_trace(this->log, "reuse buffer %d", buffer_id);
pw_client_node_transport_add_message(impl->transport, (struct pw_client_node_message *) return -ENOTSUP;
&PW_CLIENT_NODE_MESSAGE_PORT_REUSE_BUFFER_INIT(port_id, buffer_id));
//send_process(this);
return 0;
} }
static int static int
@ -915,9 +906,6 @@ client_node_done(void *data, int seq, int res)
struct impl *impl = data; struct impl *impl = data;
struct node *this = &impl->node; struct node *this = &impl->node;
if (seq == 0 && res == 0 && impl->transport == NULL)
impl->transport = pw_client_node_transport_new();
this->callbacks->done(this->callbacks_data, seq, res); this->callbacks->done(this->callbacks_data, seq, res);
} }
@ -1176,8 +1164,7 @@ static void node_initialized(void *data)
pw_client_node_resource_transport(this->resource, pw_client_node_resource_transport(this->resource,
pw_global_get_id(pw_node_get_global(node)), pw_global_get_id(pw_node_get_global(node)),
impl->other_fds[0], impl->other_fds[0],
impl->other_fds[1], impl->other_fds[1]);
impl->transport);
} }
static void node_free(void *data) static void node_free(void *data)
@ -1187,9 +1174,6 @@ static void node_free(void *data)
pw_log_debug("client-node %p: free", &impl->this); pw_log_debug("client-node %p: free", &impl->this);
node_clear(&impl->node); node_clear(&impl->node);
if (impl->transport)
pw_client_node_transport_destroy(impl->transport);
spa_hook_remove(&impl->node_listener); spa_hook_remove(&impl->node_listener);
pw_array_clear(&impl->mems); pw_array_clear(&impl->mems);

View file

@ -29,8 +29,6 @@
#include "extensions/protocol-native.h" #include "extensions/protocol-native.h"
#include "extensions/client-node.h" #include "extensions/client-node.h"
#include "transport.h"
static void static void
client_node_marshal_done(void *object, int seq, int res) client_node_marshal_done(void *object, int seq, int res)
{ {
@ -188,33 +186,25 @@ static int client_node_demarshal_transport(void *object, void *data, size_t size
{ {
struct pw_proxy *proxy = object; struct pw_proxy *proxy = object;
struct spa_pod_parser prs; struct spa_pod_parser prs;
uint32_t node_id, ridx, widx, memfd_idx; uint32_t node_id, ridx, widx;
int readfd, writefd; int readfd, writefd;
struct pw_client_node_transport_info info;
struct pw_client_node_transport *transport;
spa_pod_parser_init(&prs, data, size, 0); spa_pod_parser_init(&prs, data, size, 0);
if (spa_pod_parser_get(&prs, if (spa_pod_parser_get(&prs,
"[" "["
"i", &node_id, "i", &node_id,
"i", &ridx, "i", &ridx,
"i", &widx, "i", &widx, NULL) < 0)
"i", &memfd_idx,
"i", &info.offset,
"i", &info.size, NULL) < 0)
return -EINVAL; return -EINVAL;
readfd = pw_protocol_native_get_proxy_fd(proxy, ridx); readfd = pw_protocol_native_get_proxy_fd(proxy, ridx);
writefd = pw_protocol_native_get_proxy_fd(proxy, widx); writefd = pw_protocol_native_get_proxy_fd(proxy, widx);
info.memfd = pw_protocol_native_get_proxy_fd(proxy, memfd_idx);
if (readfd == -1 || writefd == -1 || info.memfd == -1) if (readfd == -1 || writefd == -1)
return -EINVAL; return -EINVAL;
transport = pw_client_node_transport_new_from_info(&info);
pw_proxy_notify(proxy, struct pw_client_node_proxy_events, transport, node_id, pw_proxy_notify(proxy, struct pw_client_node_proxy_events, transport, node_id,
readfd, writefd, transport); readfd, writefd);
return 0; return 0;
} }
@ -462,24 +452,17 @@ client_node_marshal_add_mem(void *object,
pw_protocol_native_end_resource(resource, b); pw_protocol_native_end_resource(resource, b);
} }
static void client_node_marshal_transport(void *object, uint32_t node_id, int readfd, int writefd, static void client_node_marshal_transport(void *object, uint32_t node_id, int readfd, int writefd)
struct pw_client_node_transport *transport)
{ {
struct pw_resource *resource = object; struct pw_resource *resource = object;
struct spa_pod_builder *b; struct spa_pod_builder *b;
struct pw_client_node_transport_info info;
pw_client_node_transport_get_info(transport, &info);
b = pw_protocol_native_begin_resource(resource, PW_CLIENT_NODE_PROXY_EVENT_TRANSPORT); b = pw_protocol_native_begin_resource(resource, PW_CLIENT_NODE_PROXY_EVENT_TRANSPORT);
spa_pod_builder_struct(b, spa_pod_builder_struct(b,
"i", node_id, "i", node_id,
"i", pw_protocol_native_add_resource_fd(resource, readfd), "i", pw_protocol_native_add_resource_fd(resource, readfd),
"i", pw_protocol_native_add_resource_fd(resource, writefd), "i", pw_protocol_native_add_resource_fd(resource, writefd));
"i", pw_protocol_native_add_resource_fd(resource, info.memfd),
"i", info.offset,
"i", info.size);
pw_protocol_native_end_resource(resource, b); pw_protocol_native_end_resource(resource, b);
} }

View file

@ -1,261 +0,0 @@
/* PipeWire
* Copyright (C) 2016 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 <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <spa/utils/ringbuffer.h>
#include <spa/node/io.h>
#include <pipewire/log.h>
#include <extensions/client-node.h>
#include "transport.h"
/** \cond */
#define INPUT_BUFFER_SIZE (1<<12)
#define OUTPUT_BUFFER_SIZE (1<<12)
struct transport {
struct pw_client_node_transport trans;
struct pw_memblock *mem;
size_t offset;
struct pw_client_node_message current;
uint32_t current_index;
};
/** \endcond */
static size_t area_get_size(void)
{
size_t size;
size = sizeof(struct spa_ringbuffer);
size += INPUT_BUFFER_SIZE;
size += sizeof(struct spa_ringbuffer);
size += OUTPUT_BUFFER_SIZE;
return size;
}
static void transport_setup_area(void *p, struct pw_client_node_transport *trans)
{
trans->input_buffer = p;
p = SPA_MEMBER(p, sizeof(struct spa_ringbuffer), void);
trans->input_data = p;
p = SPA_MEMBER(p, INPUT_BUFFER_SIZE, void);
trans->output_buffer = p;
p = SPA_MEMBER(p, sizeof(struct spa_ringbuffer), void);
trans->output_data = p;
p = SPA_MEMBER(p, OUTPUT_BUFFER_SIZE, void);
}
static void transport_reset_area(struct pw_client_node_transport *trans)
{
spa_ringbuffer_init(trans->input_buffer);
spa_ringbuffer_init(trans->output_buffer);
}
static void destroy(struct pw_client_node_transport *trans)
{
struct transport *impl = (struct transport *) trans;
pw_log_debug("transport %p: destroy", trans);
pw_memblock_free(impl->mem);
free(impl);
}
static int add_message(struct pw_client_node_transport *trans, struct pw_client_node_message *message)
{
struct transport *impl = (struct transport *) trans;
int32_t filled, avail;
uint32_t size, index;
if (impl == NULL || message == NULL)
return -EINVAL;
filled = spa_ringbuffer_get_write_index(trans->output_buffer, &index);
avail = OUTPUT_BUFFER_SIZE - filled;
size = SPA_POD_SIZE(message);
if (avail < size)
return -ENOSPC;
spa_ringbuffer_write_data(trans->output_buffer,
trans->output_data, OUTPUT_BUFFER_SIZE,
index & (OUTPUT_BUFFER_SIZE - 1), message, size);
spa_ringbuffer_write_update(trans->output_buffer, index + size);
return 0;
}
static int next_message(struct pw_client_node_transport *trans, struct pw_client_node_message *message)
{
struct transport *impl = (struct transport *) trans;
int32_t avail;
if (impl == NULL || message == NULL)
return -EINVAL;
avail = spa_ringbuffer_get_read_index(trans->input_buffer, &impl->current_index);
if (avail < sizeof(struct pw_client_node_message))
return 0;
spa_ringbuffer_read_data(trans->input_buffer,
trans->input_data, INPUT_BUFFER_SIZE,
impl->current_index & (INPUT_BUFFER_SIZE - 1),
&impl->current, sizeof(struct pw_client_node_message));
if (avail < SPA_POD_SIZE(&impl->current))
return 0;
*message = impl->current;
return 1;
}
static int parse_message(struct pw_client_node_transport *trans, void *message)
{
struct transport *impl = (struct transport *) trans;
uint32_t size;
if (impl == NULL || message == NULL)
return -EINVAL;
size = SPA_POD_SIZE(&impl->current);
spa_ringbuffer_read_data(trans->input_buffer,
trans->input_data, INPUT_BUFFER_SIZE,
impl->current_index & (INPUT_BUFFER_SIZE - 1), message, size);
spa_ringbuffer_read_update(trans->input_buffer, impl->current_index + size);
return 0;
}
/** Create a new transport
* \return a newly allocated \ref pw_client_node_transport
* \memberof pw_client_node_transport
*/
struct pw_client_node_transport *
pw_client_node_transport_new(void)
{
struct transport *impl;
struct pw_client_node_transport *trans;
impl = calloc(1, sizeof(struct transport));
if (impl == NULL)
return NULL;
pw_log_debug("transport %p: new", impl);
trans = &impl->trans;
impl->offset = 0;
if (pw_memblock_alloc(PW_MEMBLOCK_FLAG_WITH_FD |
PW_MEMBLOCK_FLAG_MAP_READWRITE |
PW_MEMBLOCK_FLAG_SEAL,
area_get_size(),
&impl->mem) < 0)
return NULL;
transport_setup_area(impl->mem->ptr, trans);
transport_reset_area(trans);
trans->destroy = destroy;
trans->add_message = add_message;
trans->next_message = next_message;
trans->parse_message = parse_message;
return trans;
}
struct pw_client_node_transport *
pw_client_node_transport_new_from_info(struct pw_client_node_transport_info *info)
{
struct transport *impl;
struct pw_client_node_transport *trans;
void *tmp;
int res;
impl = calloc(1, sizeof(struct transport));
if (impl == NULL)
return NULL;
trans = &impl->trans;
pw_log_debug("transport %p: new from info", impl);
if ((res = pw_memblock_import(PW_MEMBLOCK_FLAG_MAP_READWRITE |
PW_MEMBLOCK_FLAG_WITH_FD,
info->memfd,
info->offset,
info->size, &impl->mem)) < 0) {
pw_log_warn("transport %p: failed to map fd %d: %s", impl, info->memfd,
spa_strerror(res));
goto mmap_failed;
}
impl->offset = info->offset;
transport_setup_area(impl->mem->ptr, trans);
tmp = trans->output_buffer;
trans->output_buffer = trans->input_buffer;
trans->input_buffer = tmp;
tmp = trans->output_data;
trans->output_data = trans->input_data;
trans->input_data = tmp;
trans->destroy = destroy;
trans->add_message = add_message;
trans->next_message = next_message;
trans->parse_message = parse_message;
return trans;
mmap_failed:
free(impl);
errno = -res;
return NULL;
}
/** Get transport info
* \param trans the transport to get info of
* \param[out] info transport info
* \return 0 on success
*
* Fill \a info with the transport info of \a trans. This information can be
* passed to the client to set up the shared transport.
*
* \memberof pw_client_node_transport
*/
int pw_client_node_transport_get_info(struct pw_client_node_transport *trans,
struct pw_client_node_transport_info *info)
{
struct transport *impl = (struct transport *) trans;
info->memfd = impl->mem->fd;
info->offset = impl->offset;
info->size = impl->mem->size;
return 0;
}

View file

@ -1,54 +0,0 @@
/* PipeWire
* Copyright (C) 2016 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_CLIENT_NODE_TRANSPORT_H__
#define __PIPEWIRE_CLIENT_NODE_TRANSPORT_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
#include <spa/utils/defs.h>
#include <pipewire/mem.h>
/** information about the transport region \memberof pw_client_node */
struct pw_client_node_transport_info {
int memfd; /**< the memfd of the transport area */
uint32_t offset; /**< offset to map \a memfd at */
uint32_t size; /**< size of memfd mapping */
};
struct pw_client_node_transport *
pw_client_node_transport_new(void);
struct pw_client_node_transport *
pw_client_node_transport_new_from_info(struct pw_client_node_transport_info *info);
int
pw_client_node_transport_get_info(struct pw_client_node_transport *trans,
struct pw_client_node_transport_info *info);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __PIPEWIRE_CLIENT_NODE_TRANSPORT_H__ */

View file

@ -91,7 +91,6 @@ struct node_data {
int rtwritefd; int rtwritefd;
struct spa_source *rtsocket_source; struct spa_source *rtsocket_source;
struct pw_client_node_transport *trans;
struct mix mix_pool[MAX_MIX]; struct mix mix_pool[MAX_MIX];
struct spa_list mix[2]; struct spa_list mix[2];
@ -610,7 +609,7 @@ static void clean_transport(struct node_data *data)
{ {
struct mem *m; struct mem *m;
if (data->trans == NULL) if (data->node_id == SPA_ID_INVALID)
return; return;
unhandle_socket(data); unhandle_socket(data);
@ -619,10 +618,9 @@ static void clean_transport(struct node_data *data)
clear_mem(data, m); clear_mem(data, m);
pw_array_clear(&data->mems); pw_array_clear(&data->mems);
pw_client_node_transport_destroy(data->trans);
close(data->rtwritefd); close(data->rtwritefd);
data->trans = NULL; data->node_id = SPA_ID_INVALID;
} }
static void mix_init(struct mix *mix, struct pw_port *port, uint32_t mix_id) static void mix_init(struct mix *mix, struct pw_port *port, uint32_t mix_id)
@ -743,8 +741,7 @@ static void client_node_add_mem(void *object,
} }
static void client_node_transport(void *object, uint32_t node_id, static void client_node_transport(void *object, uint32_t node_id,
int readfd, int writefd, int readfd, int writefd)
struct pw_client_node_transport *transport)
{ {
struct pw_proxy *proxy = object; struct pw_proxy *proxy = object;
struct node_data *data = proxy->user_data; struct node_data *data = proxy->user_data;
@ -752,10 +749,9 @@ static void client_node_transport(void *object, uint32_t node_id,
clean_transport(data); clean_transport(data);
data->node_id = node_id; data->node_id = node_id;
data->trans = transport;
pw_log_info("remote-node %p: create transport %p with fds %d %d for node %u", pw_log_info("remote-node %p: create transport with fds %d %d for node %u",
proxy, data->trans, readfd, writefd, node_id); proxy, readfd, writefd, node_id);
data->rtwritefd = writefd; data->rtwritefd = writefd;
data->rtsocket_source = pw_loop_add_io(proxy->remote->core->data_loop, data->rtsocket_source = pw_loop_add_io(proxy->remote->core->data_loop,
@ -1280,7 +1276,7 @@ static void node_proxy_destroy(void *_data)
struct node_data *data = _data; struct node_data *data = _data;
struct mix *mix, *tmp; struct mix *mix, *tmp;
if (data->trans) { if (data->node_id != SPA_ID_INVALID) {
spa_list_for_each_safe(mix, tmp, &data->mix[SPA_DIRECTION_INPUT], link) spa_list_for_each_safe(mix, tmp, &data->mix[SPA_DIRECTION_INPUT], link)
clear_mix(data, mix); clear_mix(data, mix);
spa_list_for_each_safe(mix, tmp, &data->mix[SPA_DIRECTION_OUTPUT], link) spa_list_for_each_safe(mix, tmp, &data->mix[SPA_DIRECTION_OUTPUT], link)
@ -1316,6 +1312,7 @@ struct pw_proxy *pw_remote_export(struct pw_remote *remote,
data = pw_proxy_get_user_data(proxy); data = pw_proxy_get_user_data(proxy);
data->remote = remote; data->remote = remote;
data->node = node; data->node = node;
data->node_id = SPA_ID_INVALID;
data->core = pw_node_get_core(node); data->core = pw_node_get_core(node);
data->t = pw_core_get_type(data->core); data->t = pw_core_get_type(data->core);
data->node_proxy = (struct pw_client_node_proxy *)proxy; data->node_proxy = (struct pw_client_node_proxy *)proxy;