mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-04 13:30:12 -05:00
protocol: add v0 compatibility
For flatpaks we need to be able to support older v0 protocol clients. To handle this we have: - the connection detects an old client when it receives the first message. It can do this by checking the sequence number, on old versions it contains the message size and is never 0, on new clients the sequence number is 0. - We add a new signal at the start of the connection with the detected version number. This installs the right version of the core proxy. We also move the binding of the client until the hello message is received. This way we can have a new client connect (portal), hand over the connection to an old client, which then removes the client binding again in the hello request with a v0 version. There are some changes to the passing of fds in v0 vs v3 which need to investigated some more. - bump version of our interfaces to 3. This makes it possible to have v0 and v3 protocol marshal functions. - Add version number in the proxy. This is mostly automatically done internally based on the version numbers the library is compiled with. Where the version number was in the API before, it is now actually used to look up the right protocol marshal functions. For Proxies there is usually just 1 version, the current one. It is the server that will support different versions. - Add v0 compat marshal functions to convert from and to v0 format. This has some complications. v0 has a type map it keeps in sync with the server. For this we have a static type map with mappings to our own v3 types. Pods are mostly the same except for objects that used to have arbitrary pods in v0 vs spa_pod_prop in v3. Also convert between v0 spa_pod_prop and v3 spa_pod_choice. Formats and commands are also slightly different so handle those mappings as well. We only have marshal functions for the server side (resource) v0 functions. - Add v0 compatible client-node again. It's a bit tricky to map, v0 client-node basically lets the server to the mixing and teeing and just does the processing of the internal node.
This commit is contained in:
parent
d99350635a
commit
082463efd0
26 changed files with 4814 additions and 77 deletions
|
|
@ -97,7 +97,7 @@ client_node_marshal_get_node(void *object, uint32_t version, size_t user_data_si
|
|||
struct pw_proxy *res;
|
||||
uint32_t new_id;
|
||||
|
||||
res = pw_proxy_new(object, PW_TYPE_INTERFACE_Node, user_data_size);
|
||||
res = pw_proxy_new(object, PW_TYPE_INTERFACE_Node, version, user_data_size);
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
|
|
|
|||
1343
src/modules/module-client-node/v0/client-node.c
Normal file
1343
src/modules/module-client-node/v0/client-node.c
Normal file
File diff suppressed because it is too large
Load diff
52
src/modules/module-client-node/v0/client-node.h
Normal file
52
src/modules/module-client-node/v0/client-node.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/* 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_CLIENT_NODE0_H
|
||||
#define PIPEWIRE_CLIENT_NODE0_H
|
||||
|
||||
#include <pipewire/node.h>
|
||||
|
||||
#include "ext-client-node.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \class pw_client_node0
|
||||
*
|
||||
* PipeWire client node interface
|
||||
*/
|
||||
struct pw_client_node0 {
|
||||
struct pw_node *node;
|
||||
|
||||
struct pw_resource *resource;
|
||||
};
|
||||
|
||||
struct pw_client_node0 *
|
||||
pw_client_node0_new(struct pw_resource *resource,
|
||||
struct pw_properties *properties);
|
||||
|
||||
void
|
||||
pw_client_node0_destroy(struct pw_client_node0 *node);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PIPEWIRE_CLIENT_NODE0_H */
|
||||
407
src/modules/module-client-node/v0/ext-client-node.h
Normal file
407
src/modules/module-client-node/v0/ext-client-node.h
Normal file
|
|
@ -0,0 +1,407 @@
|
|||
/* 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_EXT_CLIENT_NODE0_H__
|
||||
#define __PIPEWIRE_EXT_CLIENT_NODE0_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/param/param.h>
|
||||
#include <spa/node/node.h>
|
||||
|
||||
#include <pipewire/proxy.h>
|
||||
|
||||
#define PW_VERSION_CLIENT_NODE0 0
|
||||
|
||||
struct pw_client_node0_message;
|
||||
|
||||
/** Shared structure between client and server \memberof pw_client_node */
|
||||
struct pw_client_node0_area {
|
||||
uint32_t max_input_ports; /**< max input ports of the node */
|
||||
uint32_t n_input_ports; /**< number of input ports of the node */
|
||||
uint32_t max_output_ports; /**< max output ports of the node */
|
||||
uint32_t n_output_ports; /**< number of output ports of the node */
|
||||
};
|
||||
|
||||
/** \class pw_client_node0_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_node0_transport {
|
||||
struct pw_client_node0_area *area; /**< the transport area */
|
||||
struct spa_io_buffers *inputs; /**< array of buffer input io */
|
||||
struct spa_io_buffers *outputs; /**< array of buffer output io */
|
||||
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_node0_transport
|
||||
*/
|
||||
void (*destroy) (struct pw_client_node0_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_node0_transport *trans, struct pw_client_node0_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_node0_transport *trans, struct pw_client_node0_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_node0_transport *trans, void *message);
|
||||
};
|
||||
|
||||
#define pw_client_node0_transport_destroy(t) ((t)->destroy((t)))
|
||||
#define pw_client_node0_transport_add_message(t,m) ((t)->add_message((t), (m)))
|
||||
#define pw_client_node0_transport_next_message(t,m) ((t)->next_message((t), (m)))
|
||||
#define pw_client_node0_transport_parse_message(t,m) ((t)->parse_message((t), (m)))
|
||||
|
||||
enum pw_client_node0_message_type {
|
||||
PW_CLIENT_NODE0_MESSAGE_HAVE_OUTPUT, /*< signal that the node has output */
|
||||
PW_CLIENT_NODE0_MESSAGE_NEED_INPUT, /*< signal that the node needs input */
|
||||
PW_CLIENT_NODE0_MESSAGE_PROCESS_INPUT, /*< instruct the node to process input */
|
||||
PW_CLIENT_NODE0_MESSAGE_PROCESS_OUTPUT, /*< instruct the node output is processed */
|
||||
PW_CLIENT_NODE0_MESSAGE_PORT_REUSE_BUFFER, /*< reuse a buffer */
|
||||
};
|
||||
|
||||
struct pw_client_node0_message_body {
|
||||
struct spa_pod_int type SPA_ALIGNED(8); /*< one of enum pw_client_node0_message_type */
|
||||
};
|
||||
|
||||
struct pw_client_node0_message {
|
||||
struct spa_pod_struct pod;
|
||||
struct pw_client_node0_message_body body;
|
||||
};
|
||||
|
||||
struct pw_client_node0_message_port_reuse_buffer_body {
|
||||
struct spa_pod_int type SPA_ALIGNED(8); /*< PW_CLIENT_NODE0_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_node0_message_port_reuse_buffer {
|
||||
struct spa_pod_struct pod;
|
||||
struct pw_client_node0_message_port_reuse_buffer_body body;
|
||||
};
|
||||
|
||||
#define PW_CLIENT_NODE0_MESSAGE_TYPE(message) (((struct pw_client_node0_message*)(message))->body.type.value)
|
||||
|
||||
#define PW_CLIENT_NODE0_MESSAGE_INIT(message) (struct pw_client_node0_message) \
|
||||
{ { { sizeof(struct pw_client_node0_message_body), SPA_TYPE_Struct } }, \
|
||||
{ SPA_POD_INIT_Int(message) } }
|
||||
|
||||
#define PW_CLIENT_NODE0_MESSAGE_INIT_FULL(type,size,message,...) (type) \
|
||||
{ { { size, SPA_TYPE_Struct } }, \
|
||||
{ SPA_POD_INIT_Int(message), ##__VA_ARGS__ } } \
|
||||
|
||||
#define PW_CLIENT_NODE0_MESSAGE_PORT_REUSE_BUFFER_INIT(port_id,buffer_id) \
|
||||
PW_CLIENT_NODE0_MESSAGE_INIT_FULL(struct pw_client_node0_message_port_reuse_buffer, \
|
||||
sizeof(struct pw_client_node0_message_port_reuse_buffer_body), \
|
||||
PW_CLIENT_NODE0_MESSAGE_PORT_REUSE_BUFFER, \
|
||||
SPA_POD_INIT_Int(port_id), \
|
||||
SPA_POD_INIT_Int(buffer_id))
|
||||
|
||||
/** information about a buffer */
|
||||
struct pw_client_node0_buffer {
|
||||
uint32_t mem_id; /**< the memory id for the metadata */
|
||||
uint32_t offset; /**< offset in memory */
|
||||
uint32_t size; /**< size in memory */
|
||||
struct spa_buffer *buffer; /**< buffer describing metadata and buffer memory */
|
||||
};
|
||||
|
||||
#define PW_CLIENT_NODE0_PROXY_METHOD_DONE 0
|
||||
#define PW_CLIENT_NODE0_PROXY_METHOD_UPDATE 1
|
||||
#define PW_CLIENT_NODE0_PROXY_METHOD_PORT_UPDATE 2
|
||||
#define PW_CLIENT_NODE0_PROXY_METHOD_SET_ACTIVE 3
|
||||
#define PW_CLIENT_NODE0_PROXY_METHOD_EVENT 4
|
||||
#define PW_CLIENT_NODE0_PROXY_METHOD_DESTROY 5
|
||||
#define PW_CLIENT_NODE0_PROXY_METHOD_NUM 6
|
||||
|
||||
/** \ref pw_client_node methods */
|
||||
struct pw_client_node0_proxy_methods {
|
||||
#define PW_VERSION_CLIENT_NODE0_PROXY_METHODS 0
|
||||
uint32_t version;
|
||||
|
||||
/** Complete an async operation */
|
||||
void (*done) (void *object, int seq, int res);
|
||||
|
||||
/**
|
||||
* Update the node ports and properties
|
||||
*
|
||||
* Update the maximum number of ports and the params of the
|
||||
* client node.
|
||||
* \param change_mask bitfield with changed parameters
|
||||
* \param max_input_ports new max input ports
|
||||
* \param max_output_ports new max output ports
|
||||
* \param params new params
|
||||
*/
|
||||
void (*update) (void *object,
|
||||
#define PW_CLIENT_NODE0_UPDATE_MAX_INPUTS (1 << 0)
|
||||
#define PW_CLIENT_NODE0_UPDATE_MAX_OUTPUTS (1 << 1)
|
||||
#define PW_CLIENT_NODE0_UPDATE_PARAMS (1 << 2)
|
||||
uint32_t change_mask,
|
||||
uint32_t max_input_ports,
|
||||
uint32_t max_output_ports,
|
||||
uint32_t n_params,
|
||||
const struct spa_pod **params);
|
||||
|
||||
/**
|
||||
* Update a node port
|
||||
*
|
||||
* Update the information of one port of a node.
|
||||
* \param direction the direction of the port
|
||||
* \param port_id the port id to update
|
||||
* \param change_mask a bitfield of changed items
|
||||
* \param n_params number of port parameters
|
||||
* \param params array of port parameters
|
||||
* \param info port information
|
||||
*/
|
||||
void (*port_update) (void *object,
|
||||
enum spa_direction direction,
|
||||
uint32_t port_id,
|
||||
#define PW_CLIENT_NODE0_PORT_UPDATE_PARAMS (1 << 0)
|
||||
#define PW_CLIENT_NODE0_PORT_UPDATE_INFO (1 << 1)
|
||||
uint32_t change_mask,
|
||||
uint32_t n_params,
|
||||
const struct spa_pod **params,
|
||||
const struct spa_port_info *info);
|
||||
/**
|
||||
* Activate or deactivate the node
|
||||
*/
|
||||
void (*set_active) (void *object, bool active);
|
||||
/**
|
||||
* Send an event to the node
|
||||
* \param event the event to send
|
||||
*/
|
||||
void (*event) (void *object, struct spa_event *event);
|
||||
/**
|
||||
* Destroy the client_node
|
||||
*/
|
||||
void (*destroy) (void *object);
|
||||
};
|
||||
|
||||
#define PW_CLIENT_NODE0_PROXY_EVENT_ADD_MEM 0
|
||||
#define PW_CLIENT_NODE0_PROXY_EVENT_TRANSPORT 1
|
||||
#define PW_CLIENT_NODE0_PROXY_EVENT_SET_PARAM 2
|
||||
#define PW_CLIENT_NODE0_PROXY_EVENT_EVENT 3
|
||||
#define PW_CLIENT_NODE0_PROXY_EVENT_COMMAND 4
|
||||
#define PW_CLIENT_NODE0_PROXY_EVENT_ADD_PORT 5
|
||||
#define PW_CLIENT_NODE0_PROXY_EVENT_REMOVE_PORT 6
|
||||
#define PW_CLIENT_NODE0_PROXY_EVENT_PORT_SET_PARAM 7
|
||||
#define PW_CLIENT_NODE0_PROXY_EVENT_PORT_USE_BUFFERS 8
|
||||
#define PW_CLIENT_NODE0_PROXY_EVENT_PORT_COMMAND 9
|
||||
#define PW_CLIENT_NODE0_PROXY_EVENT_PORT_SET_IO 10
|
||||
#define PW_CLIENT_NODE0_PROXY_EVENT_NUM 11
|
||||
|
||||
/** \ref pw_client_node events */
|
||||
struct pw_client_node0_proxy_events {
|
||||
#define PW_VERSION_CLIENT_NODE0_PROXY_EVENTS 0
|
||||
uint32_t version;
|
||||
/**
|
||||
* Memory was added to a node
|
||||
*
|
||||
* \param mem_id the id of the memory
|
||||
* \param type the memory type
|
||||
* \param memfd the fd of the memory
|
||||
* \param flags flags for the \a memfd
|
||||
*/
|
||||
void (*add_mem) (void *object,
|
||||
uint32_t mem_id,
|
||||
uint32_t type,
|
||||
int memfd,
|
||||
uint32_t flags);
|
||||
/**
|
||||
* Notify of a new transport area
|
||||
*
|
||||
* The transport area is used to exchange real-time commands between
|
||||
* the client and the server.
|
||||
*
|
||||
* \param node_id the node id created for this client node
|
||||
* \param readfd fd for signal data can be read
|
||||
* \param writefd fd for signal data can be written
|
||||
* \param transport the shared transport area
|
||||
*/
|
||||
void (*transport) (void *object,
|
||||
uint32_t node_id,
|
||||
int readfd,
|
||||
int writefd,
|
||||
struct pw_client_node0_transport *transport);
|
||||
/**
|
||||
* Notify of a property change
|
||||
*
|
||||
* When the server configures the properties on the node
|
||||
* this event is sent
|
||||
*
|
||||
* \param seq a sequence number
|
||||
* \param id the id of the parameter
|
||||
* \param flags parameter flags
|
||||
* \param param the param to set
|
||||
*/
|
||||
void (*set_param) (void *object, uint32_t seq,
|
||||
uint32_t id, uint32_t flags,
|
||||
const struct spa_pod *param);
|
||||
/**
|
||||
* Receive an event from the client node
|
||||
* \param event the received event */
|
||||
void (*event) (void *object, const struct spa_event *event);
|
||||
/**
|
||||
* Notify of a new node command
|
||||
*
|
||||
* \param seq a sequence number
|
||||
* \param command the command
|
||||
*/
|
||||
void (*command) (void *object, uint32_t seq, const struct spa_command *command);
|
||||
/**
|
||||
* A new port was added to the node
|
||||
*
|
||||
* The server can at any time add a port to the node when there
|
||||
* are free ports available.
|
||||
*
|
||||
* \param seq a sequence number
|
||||
* \param direction the direction of the port
|
||||
* \param port_id the new port id
|
||||
*/
|
||||
void (*add_port) (void *object,
|
||||
uint32_t seq,
|
||||
enum spa_direction direction,
|
||||
uint32_t port_id);
|
||||
/**
|
||||
* A port was removed from the node
|
||||
*
|
||||
* \param seq a sequence number
|
||||
* \param direction a port direction
|
||||
* \param port_id the remove port id
|
||||
*/
|
||||
void (*remove_port) (void *object,
|
||||
uint32_t seq,
|
||||
enum spa_direction direction,
|
||||
uint32_t port_id);
|
||||
/**
|
||||
* A parameter was configured on the port
|
||||
*
|
||||
* \param seq a sequence number
|
||||
* \param direction a port direction
|
||||
* \param port_id the port id
|
||||
* \param id the id of the parameter
|
||||
* \param flags flags used when setting the param
|
||||
* \param param the new param
|
||||
*/
|
||||
void (*port_set_param) (void *object,
|
||||
uint32_t seq,
|
||||
enum spa_direction direction,
|
||||
uint32_t port_id,
|
||||
uint32_t id, uint32_t flags,
|
||||
const struct spa_pod *param);
|
||||
/**
|
||||
* Notify the port of buffers
|
||||
*
|
||||
* \param seq a sequence number
|
||||
* \param direction a port direction
|
||||
* \param port_id the port id
|
||||
* \param n_buffer the number of buffers
|
||||
* \param buffers and array of buffer descriptions
|
||||
*/
|
||||
void (*port_use_buffers) (void *object,
|
||||
uint32_t seq,
|
||||
enum spa_direction direction,
|
||||
uint32_t port_id,
|
||||
uint32_t n_buffers,
|
||||
struct pw_client_node0_buffer *buffers);
|
||||
/**
|
||||
* Notify of a new port command
|
||||
*
|
||||
* \param direction a port direction
|
||||
* \param port_id the port id
|
||||
* \param command the command
|
||||
*/
|
||||
void (*port_command) (void *object,
|
||||
enum spa_direction direction,
|
||||
uint32_t port_id,
|
||||
const struct spa_command *command);
|
||||
|
||||
/**
|
||||
* Configure the io area with \a id of \a port_id.
|
||||
*
|
||||
* \param seq a sequence number
|
||||
* \param direction the direction of the port
|
||||
* \param port_id the port id
|
||||
* \param id the id of the io area to set
|
||||
* \param mem_id the id of the memory to use
|
||||
* \param offset offset of io area in memory
|
||||
* \param size size of the io area
|
||||
*/
|
||||
void (*port_set_io) (void *object,
|
||||
uint32_t seq,
|
||||
enum spa_direction direction,
|
||||
uint32_t port_id,
|
||||
uint32_t id,
|
||||
uint32_t mem_id,
|
||||
uint32_t offset,
|
||||
uint32_t size);
|
||||
};
|
||||
#define pw_client_node0_resource(r,m,v,...) pw_resource_call(r, struct pw_client_node0_proxy_events, m, v, ##__VA_ARGS__)
|
||||
|
||||
#define pw_client_node0_resource_add_mem(r,...) pw_client_node0_resource(r,add_mem,0,__VA_ARGS__)
|
||||
#define pw_client_node0_resource_transport(r,...) pw_client_node0_resource(r,transport,0,__VA_ARGS__)
|
||||
#define pw_client_node0_resource_set_param(r,...) pw_client_node0_resource(r,set_param,0,__VA_ARGS__)
|
||||
#define pw_client_node0_resource_event(r,...) pw_client_node0_resource(r,event,0,__VA_ARGS__)
|
||||
#define pw_client_node0_resource_command(r,...) pw_client_node0_resource(r,command,0,__VA_ARGS__)
|
||||
#define pw_client_node0_resource_add_port(r,...) pw_client_node0_resource(r,add_port,0,__VA_ARGS__)
|
||||
#define pw_client_node0_resource_remove_port(r,...) pw_client_node0_resource(r,remove_port,0,__VA_ARGS__)
|
||||
#define pw_client_node0_resource_port_set_param(r,...) pw_client_node0_resource(r,port_set_param,0,__VA_ARGS__)
|
||||
#define pw_client_node0_resource_port_use_buffers(r,...) pw_client_node0_resource(r,port_use_buffers,0,__VA_ARGS__)
|
||||
#define pw_client_node0_resource_port_command(r,...) pw_client_node0_resource(r,port_command,0,__VA_ARGS__)
|
||||
#define pw_client_node0_resource_port_set_io(r,...) pw_client_node0_resource(r,port_set_io,0,__VA_ARGS__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* __PIPEWIRE_EXT_CLIENT_NODE0_H__ */
|
||||
517
src/modules/module-client-node/v0/protocol-native.c
Normal file
517
src/modules/module-client-node/v0/protocol-native.c
Normal file
|
|
@ -0,0 +1,517 @@
|
|||
/* 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 <errno.h>
|
||||
|
||||
#include <spa/pod/parser.h>
|
||||
|
||||
#include "pipewire/pipewire.h"
|
||||
#include "pipewire/interfaces.h"
|
||||
#include "pipewire/protocol.h"
|
||||
#include "pipewire/client.h"
|
||||
#include "pipewire/private.h"
|
||||
|
||||
#include "extensions/protocol-native.h"
|
||||
|
||||
#include "ext-client-node.h"
|
||||
|
||||
#include "transport.h"
|
||||
|
||||
#define PW_PROTOCOL_NATIVE_FLAG_REMAP (1<<0)
|
||||
|
||||
extern uint32_t pw_protocol_native0_find_type(struct pw_client *client, const char *type);
|
||||
extern int pw_protocol_native0_pod_to_v2(struct pw_client *client, const struct spa_pod *pod,
|
||||
struct spa_pod_builder *b);
|
||||
extern uint32_t pw_protocol_native0_type_to_v2(struct pw_client *client,
|
||||
const struct spa_type_info *info, uint32_t type);
|
||||
|
||||
static void
|
||||
client_node_marshal_add_mem(void *object,
|
||||
uint32_t mem_id,
|
||||
uint32_t type,
|
||||
int memfd, uint32_t flags)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct spa_pod_builder *b;
|
||||
const char *typename;
|
||||
|
||||
switch (type) {
|
||||
case SPA_DATA_MemFd:
|
||||
typename = "Spa:Enum:DataType:Fd:MemFd";
|
||||
break;
|
||||
case SPA_DATA_DmaBuf:
|
||||
typename = "Spa:Enum:DataType:Fd:DmaBuf";
|
||||
break;
|
||||
default:
|
||||
case SPA_DATA_MemPtr:
|
||||
return;
|
||||
|
||||
}
|
||||
b = pw_protocol_native_begin_resource(resource, PW_CLIENT_NODE0_PROXY_EVENT_ADD_MEM, NULL);
|
||||
|
||||
spa_pod_builder_add_struct(b,
|
||||
"i", mem_id,
|
||||
"I", pw_protocol_native0_find_type(resource->client, typename),
|
||||
"i", pw_protocol_native_add_resource_fd(resource, memfd),
|
||||
"i", flags);
|
||||
|
||||
pw_protocol_native_end_resource(resource, b);
|
||||
}
|
||||
|
||||
static void client_node_marshal_transport(void *object, uint32_t node_id, int readfd, int writefd,
|
||||
struct pw_client_node0_transport *transport)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct spa_pod_builder *b;
|
||||
struct pw_client_node0_transport_info info;
|
||||
|
||||
pw_client_node0_transport_get_info(transport, &info);
|
||||
|
||||
b = pw_protocol_native_begin_resource(resource, PW_CLIENT_NODE0_PROXY_EVENT_TRANSPORT, NULL);
|
||||
|
||||
spa_pod_builder_add_struct(b,
|
||||
"i", node_id,
|
||||
"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, info.memfd),
|
||||
"i", info.offset,
|
||||
"i", info.size);
|
||||
|
||||
pw_protocol_native_end_resource(resource, b);
|
||||
}
|
||||
|
||||
static void
|
||||
client_node_marshal_set_param(void *object, uint32_t seq, uint32_t id, uint32_t flags,
|
||||
const struct spa_pod *param)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct spa_pod_builder *b;
|
||||
|
||||
b = pw_protocol_native_begin_resource(resource, PW_CLIENT_NODE0_PROXY_EVENT_SET_PARAM, NULL);
|
||||
|
||||
spa_pod_builder_add_struct(b,
|
||||
"i", seq,
|
||||
"I", id,
|
||||
"i", flags,
|
||||
"P", param);
|
||||
|
||||
pw_protocol_native_end_resource(resource, b);
|
||||
}
|
||||
|
||||
static void client_node_marshal_event_event(void *object, const struct spa_event *event)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct spa_pod_builder *b;
|
||||
|
||||
b = pw_protocol_native_begin_resource(resource, PW_CLIENT_NODE0_PROXY_EVENT_EVENT, NULL);
|
||||
|
||||
spa_pod_builder_add_struct(b, "P", event);
|
||||
|
||||
pw_protocol_native_end_resource(resource, b);
|
||||
}
|
||||
|
||||
static void
|
||||
client_node_marshal_command(void *object, uint32_t seq, const struct spa_command *command)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_client *client = resource->client;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
b = pw_protocol_native_begin_resource(resource, PW_CLIENT_NODE0_PROXY_EVENT_COMMAND, NULL);
|
||||
|
||||
spa_pod_builder_push_struct(b, &f);
|
||||
spa_pod_builder_add(b, "i", seq, NULL);
|
||||
pw_protocol_native0_pod_to_v2(client, (struct spa_pod *)command, b);
|
||||
spa_pod_builder_pop(b, &f);
|
||||
|
||||
pw_protocol_native_end_resource(resource, b);
|
||||
}
|
||||
|
||||
static void
|
||||
client_node_marshal_add_port(void *object,
|
||||
uint32_t seq, enum spa_direction direction, uint32_t port_id)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct spa_pod_builder *b;
|
||||
|
||||
b = pw_protocol_native_begin_resource(resource, PW_CLIENT_NODE0_PROXY_EVENT_ADD_PORT, NULL);
|
||||
|
||||
spa_pod_builder_add_struct(b,
|
||||
"i", seq,
|
||||
"i", direction,
|
||||
"i", port_id);
|
||||
|
||||
pw_protocol_native_end_resource(resource, b);
|
||||
}
|
||||
|
||||
static void
|
||||
client_node_marshal_remove_port(void *object,
|
||||
uint32_t seq, enum spa_direction direction, uint32_t port_id)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct spa_pod_builder *b;
|
||||
|
||||
b = pw_protocol_native_begin_resource(resource, PW_CLIENT_NODE0_PROXY_EVENT_REMOVE_PORT, NULL);
|
||||
|
||||
spa_pod_builder_add_struct(b,
|
||||
"i", seq,
|
||||
"i", direction,
|
||||
"i", port_id);
|
||||
|
||||
pw_protocol_native_end_resource(resource, b);
|
||||
}
|
||||
|
||||
static void
|
||||
client_node_marshal_port_set_param(void *object,
|
||||
uint32_t seq,
|
||||
enum spa_direction direction,
|
||||
uint32_t port_id,
|
||||
uint32_t id,
|
||||
uint32_t flags,
|
||||
const struct spa_pod *param)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_client *client = resource->client;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
const char *typename;
|
||||
|
||||
b = pw_protocol_native_begin_resource(resource, PW_CLIENT_NODE0_PROXY_EVENT_PORT_SET_PARAM, NULL);
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_Props:
|
||||
typename = "Spa:Enum:ParamId:Props";
|
||||
break;
|
||||
case SPA_PARAM_Format:
|
||||
typename = "Spa:Enum:ParamId:Format";
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
spa_pod_builder_push_struct(b, &f);
|
||||
spa_pod_builder_add(b,
|
||||
"i", seq,
|
||||
"i", direction,
|
||||
"i", port_id,
|
||||
"I", pw_protocol_native0_find_type(client, typename),
|
||||
"i", flags, NULL);
|
||||
pw_protocol_native0_pod_to_v2(client, param, b);
|
||||
spa_pod_builder_pop(b, &f);
|
||||
|
||||
pw_protocol_native_end_resource(resource, b);
|
||||
}
|
||||
|
||||
static void
|
||||
client_node_marshal_port_use_buffers(void *object,
|
||||
uint32_t seq,
|
||||
enum spa_direction direction,
|
||||
uint32_t port_id,
|
||||
uint32_t n_buffers, struct pw_client_node0_buffer *buffers)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_client *client = resource->client;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
uint32_t i, j;
|
||||
|
||||
b = pw_protocol_native_begin_resource(resource, PW_CLIENT_NODE0_PROXY_EVENT_PORT_USE_BUFFERS, NULL);
|
||||
|
||||
spa_pod_builder_push_struct(b, &f);
|
||||
spa_pod_builder_add(b,
|
||||
"i", seq,
|
||||
"i", direction,
|
||||
"i", port_id,
|
||||
"i", n_buffers, NULL);
|
||||
|
||||
for (i = 0; i < n_buffers; i++) {
|
||||
struct spa_buffer *buf = buffers[i].buffer;
|
||||
|
||||
spa_pod_builder_add(b,
|
||||
"i", buffers[i].mem_id,
|
||||
"i", buffers[i].offset,
|
||||
"i", buffers[i].size,
|
||||
"i", i,
|
||||
"i", buf->n_metas, NULL);
|
||||
|
||||
for (j = 0; j < buf->n_metas; j++) {
|
||||
struct spa_meta *m = &buf->metas[j];
|
||||
spa_pod_builder_add(b,
|
||||
"I", pw_protocol_native0_type_to_v2(client, spa_type_meta_type, m->type),
|
||||
"i", m->size, NULL);
|
||||
}
|
||||
spa_pod_builder_add(b, "i", buf->n_datas, NULL);
|
||||
for (j = 0; j < buf->n_datas; j++) {
|
||||
struct spa_data *d = &buf->datas[j];
|
||||
spa_pod_builder_add(b,
|
||||
"I", pw_protocol_native0_type_to_v2(client, spa_type_data_type, d->type),
|
||||
"i", SPA_PTR_TO_UINT32(d->data),
|
||||
"i", d->flags,
|
||||
"i", d->mapoffset,
|
||||
"i", d->maxsize, NULL);
|
||||
}
|
||||
}
|
||||
spa_pod_builder_pop(b, &f);
|
||||
|
||||
pw_protocol_native_end_resource(resource, b);
|
||||
}
|
||||
|
||||
static void
|
||||
client_node_marshal_port_command(void *object,
|
||||
uint32_t direction,
|
||||
uint32_t port_id,
|
||||
const struct spa_command *command)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct pw_client *client = resource->client;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
b = pw_protocol_native_begin_resource(resource, PW_CLIENT_NODE0_PROXY_EVENT_PORT_COMMAND, NULL);
|
||||
|
||||
spa_pod_builder_push_struct(b, &f);
|
||||
spa_pod_builder_add(b,
|
||||
"i", direction,
|
||||
"i", port_id, NULL);
|
||||
pw_protocol_native0_pod_to_v2(client, (struct spa_pod *)command, b);
|
||||
spa_pod_builder_pop(b, &f);
|
||||
|
||||
pw_protocol_native_end_resource(resource, b);
|
||||
}
|
||||
|
||||
static void
|
||||
client_node_marshal_port_set_io(void *object,
|
||||
uint32_t seq,
|
||||
uint32_t direction,
|
||||
uint32_t port_id,
|
||||
uint32_t id,
|
||||
uint32_t memid,
|
||||
uint32_t offset,
|
||||
uint32_t size)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct spa_pod_builder *b;
|
||||
|
||||
b = pw_protocol_native_begin_resource(resource, PW_CLIENT_NODE0_PROXY_EVENT_PORT_SET_IO, NULL);
|
||||
|
||||
spa_pod_builder_add_struct(b,
|
||||
"i", seq,
|
||||
"i", direction,
|
||||
"i", port_id,
|
||||
"I", id,
|
||||
"i", memid,
|
||||
"i", offset,
|
||||
"i", size);
|
||||
|
||||
pw_protocol_native_end_resource(resource, b);
|
||||
}
|
||||
|
||||
|
||||
static int client_node_demarshal_done(void *object, const struct pw_protocol_native_message *msg)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct spa_pod_parser prs;
|
||||
uint32_t seq, res;
|
||||
|
||||
spa_pod_parser_init(&prs, msg->data, msg->size);
|
||||
if (spa_pod_parser_get_struct(&prs,
|
||||
"i", &seq,
|
||||
"i", &res) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return pw_resource_notify(resource, struct pw_client_node0_proxy_methods, done, 0, seq, res);
|
||||
}
|
||||
|
||||
static int client_node_demarshal_update(void *object, const struct pw_protocol_native_message *msg)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct spa_pod_parser prs;
|
||||
struct spa_pod_frame f;
|
||||
uint32_t change_mask, max_input_ports, max_output_ports, n_params;
|
||||
const struct spa_pod **params;
|
||||
uint32_t i;
|
||||
|
||||
spa_pod_parser_init(&prs, msg->data, msg->size);
|
||||
if (spa_pod_parser_push_struct(&prs, &f) < 0 ||
|
||||
spa_pod_parser_get(&prs,
|
||||
"i", &change_mask,
|
||||
"i", &max_input_ports,
|
||||
"i", &max_output_ports,
|
||||
"i", &n_params, NULL) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
params = alloca(n_params * sizeof(struct spa_pod *));
|
||||
for (i = 0; i < n_params; i++)
|
||||
if (spa_pod_parser_get(&prs, "O", ¶ms[i], NULL) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return pw_resource_notify(resource, struct pw_client_node0_proxy_methods, update, 0, change_mask,
|
||||
max_input_ports,
|
||||
max_output_ports,
|
||||
n_params,
|
||||
params);
|
||||
}
|
||||
|
||||
static int client_node_demarshal_port_update(void *object, const struct pw_protocol_native_message *msg)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct spa_pod_parser prs;
|
||||
struct spa_pod_frame f[2];
|
||||
uint32_t i, direction, port_id, change_mask, n_params;
|
||||
const struct spa_pod **params = NULL;
|
||||
struct spa_port_info info = { 0 }, *infop = NULL;
|
||||
struct spa_dict props;
|
||||
|
||||
spa_pod_parser_init(&prs, msg->data, msg->size);
|
||||
if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
|
||||
spa_pod_parser_get(&prs,
|
||||
"i", &direction,
|
||||
"i", &port_id,
|
||||
"i", &change_mask,
|
||||
"i", &n_params, NULL) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
params = alloca(n_params * sizeof(struct spa_pod *));
|
||||
for (i = 0; i < n_params; i++)
|
||||
if (spa_pod_parser_get(&prs, "O", ¶ms[i], NULL) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
if (spa_pod_parser_push_struct(&prs, &f[1]) >= 0) {
|
||||
infop = &info;
|
||||
|
||||
if (spa_pod_parser_get(&prs,
|
||||
"i", &info.flags,
|
||||
"i", &info.rate,
|
||||
"i", &props.n_items, NULL) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (props.n_items > 0) {
|
||||
info.props = &props;
|
||||
|
||||
props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
|
||||
for (i = 0; i < props.n_items; i++) {
|
||||
if (spa_pod_parser_get(&prs,
|
||||
"s", &props.items[i].key,
|
||||
"s", &props.items[i].value,
|
||||
NULL) < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pw_resource_notify(resource, struct pw_client_node0_proxy_methods, port_update, 0, direction,
|
||||
port_id,
|
||||
change_mask,
|
||||
n_params,
|
||||
params, infop);
|
||||
}
|
||||
|
||||
static int client_node_demarshal_set_active(void *object, const struct pw_protocol_native_message *msg)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct spa_pod_parser prs;
|
||||
int active;
|
||||
|
||||
spa_pod_parser_init(&prs, msg->data, msg->size);
|
||||
if (spa_pod_parser_get_struct(&prs,
|
||||
"b", &active) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return pw_resource_notify(resource, struct pw_client_node0_proxy_methods, set_active, 0, active);
|
||||
}
|
||||
|
||||
static int client_node_demarshal_event_method(void *object, const struct pw_protocol_native_message *msg)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct spa_pod_parser prs;
|
||||
struct spa_event *event;
|
||||
|
||||
spa_pod_parser_init(&prs, msg->data, msg->size);
|
||||
if (spa_pod_parser_get_struct(&prs,
|
||||
"O", &event) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return pw_resource_notify(resource, struct pw_client_node0_proxy_methods, event, 0, event);
|
||||
}
|
||||
|
||||
static int client_node_demarshal_destroy(void *object, const struct pw_protocol_native_message *msg)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct spa_pod_parser prs;
|
||||
int res;
|
||||
|
||||
spa_pod_parser_init(&prs, msg->data, msg->size);
|
||||
if (spa_pod_parser_get_struct(&prs, NULL) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
res = pw_resource_notify(resource, struct pw_client_node0_proxy_methods, destroy, 0);
|
||||
pw_resource_destroy(resource);
|
||||
return res;
|
||||
}
|
||||
|
||||
static const struct pw_protocol_native_demarshal pw_protocol_native_client_node_method_demarshal[] = {
|
||||
{ &client_node_demarshal_done, 0, 0 },
|
||||
{ &client_node_demarshal_update, 0, PW_PROTOCOL_NATIVE_FLAG_REMAP },
|
||||
{ &client_node_demarshal_port_update, 0, PW_PROTOCOL_NATIVE_FLAG_REMAP },
|
||||
{ &client_node_demarshal_set_active, 0, 0 },
|
||||
{ &client_node_demarshal_event_method, 0, PW_PROTOCOL_NATIVE_FLAG_REMAP },
|
||||
{ &client_node_demarshal_destroy, 0, 0 },
|
||||
};
|
||||
|
||||
static const struct pw_client_node0_proxy_events pw_protocol_native_client_node_event_marshal = {
|
||||
PW_VERSION_CLIENT_NODE0_PROXY_EVENTS,
|
||||
&client_node_marshal_add_mem,
|
||||
&client_node_marshal_transport,
|
||||
&client_node_marshal_set_param,
|
||||
&client_node_marshal_event_event,
|
||||
&client_node_marshal_command,
|
||||
&client_node_marshal_add_port,
|
||||
&client_node_marshal_remove_port,
|
||||
&client_node_marshal_port_set_param,
|
||||
&client_node_marshal_port_use_buffers,
|
||||
&client_node_marshal_port_command,
|
||||
&client_node_marshal_port_set_io,
|
||||
};
|
||||
|
||||
static const struct pw_protocol_marshal pw_protocol_native_client_node_marshal = {
|
||||
PW_TYPE_INTERFACE_ClientNode,
|
||||
PW_VERSION_CLIENT_NODE0,
|
||||
PW_CLIENT_NODE0_PROXY_METHOD_NUM,
|
||||
PW_CLIENT_NODE0_PROXY_EVENT_NUM,
|
||||
NULL,
|
||||
&pw_protocol_native_client_node_method_demarshal,
|
||||
&pw_protocol_native_client_node_event_marshal,
|
||||
NULL,
|
||||
};
|
||||
|
||||
struct pw_protocol *pw_protocol_native_ext_client_node0_init(struct pw_core *core)
|
||||
{
|
||||
struct pw_protocol *protocol;
|
||||
|
||||
protocol = pw_core_find_protocol(core, PW_TYPE_INFO_PROTOCOL_Native);
|
||||
|
||||
if (protocol == NULL)
|
||||
return NULL;
|
||||
|
||||
pw_protocol_add_marshal(protocol, &pw_protocol_native_client_node_marshal);
|
||||
|
||||
return protocol;
|
||||
}
|
||||
257
src/modules/module-client-node/v0/transport.c
Normal file
257
src/modules/module-client-node/v0/transport.c
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
/* 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 <pipewire/private.h>
|
||||
|
||||
#include "ext-client-node.h"
|
||||
|
||||
#include "transport.h"
|
||||
|
||||
/** \cond */
|
||||
|
||||
#define INPUT_BUFFER_SIZE (1<<12)
|
||||
#define OUTPUT_BUFFER_SIZE (1<<12)
|
||||
|
||||
struct transport {
|
||||
struct pw_client_node0_transport trans;
|
||||
|
||||
struct pw_memblock *mem;
|
||||
size_t offset;
|
||||
|
||||
struct pw_client_node0_message current;
|
||||
uint32_t current_index;
|
||||
};
|
||||
/** \endcond */
|
||||
|
||||
static size_t area_get_size(struct pw_client_node0_area *area)
|
||||
{
|
||||
size_t size;
|
||||
size = sizeof(struct pw_client_node0_area);
|
||||
size += area->max_input_ports * sizeof(struct spa_io_buffers);
|
||||
size += area->max_output_ports * sizeof(struct spa_io_buffers);
|
||||
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_node0_transport *trans)
|
||||
{
|
||||
struct pw_client_node0_area *a;
|
||||
|
||||
trans->area = a = p;
|
||||
p = SPA_MEMBER(p, sizeof(struct pw_client_node0_area), struct spa_io_buffers);
|
||||
|
||||
trans->inputs = p;
|
||||
p = SPA_MEMBER(p, a->max_input_ports * sizeof(struct spa_io_buffers), void);
|
||||
|
||||
trans->outputs = p;
|
||||
p = SPA_MEMBER(p, a->max_output_ports * sizeof(struct spa_io_buffers), void);
|
||||
|
||||
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_node0_transport *trans)
|
||||
{
|
||||
uint32_t i;
|
||||
struct pw_client_node0_area *a = trans->area;
|
||||
|
||||
for (i = 0; i < a->max_input_ports; i++) {
|
||||
trans->inputs[i].status = SPA_STATUS_OK;
|
||||
trans->inputs[i].buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
for (i = 0; i < a->max_output_ports; i++) {
|
||||
trans->outputs[i].status = SPA_STATUS_OK;
|
||||
trans->outputs[i].buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
spa_ringbuffer_init(trans->input_buffer);
|
||||
spa_ringbuffer_init(trans->output_buffer);
|
||||
}
|
||||
|
||||
static void destroy(struct pw_client_node0_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_node0_transport *trans, struct pw_client_node0_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 < (int)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_node0_transport *trans, struct pw_client_node0_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 < (int) sizeof(struct pw_client_node0_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_node0_message));
|
||||
|
||||
if (avail < (int) SPA_POD_SIZE(&impl->current))
|
||||
return 0;
|
||||
|
||||
*message = impl->current;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int parse_message(struct pw_client_node0_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
|
||||
* \param max_input_ports maximum number of input_ports
|
||||
* \param max_output_ports maximum number of output_ports
|
||||
* \return a newly allocated \ref pw_client_node0_transport
|
||||
* \memberof pw_client_node0_transport
|
||||
*/
|
||||
struct pw_client_node0_transport *
|
||||
pw_client_node0_transport_new(struct pw_core *core,
|
||||
uint32_t max_input_ports, uint32_t max_output_ports)
|
||||
{
|
||||
struct transport *impl;
|
||||
struct pw_client_node0_transport *trans;
|
||||
struct pw_client_node0_area area = { 0 };
|
||||
|
||||
area.max_input_ports = max_input_ports;
|
||||
area.n_input_ports = 0;
|
||||
area.max_output_ports = max_output_ports;
|
||||
area.n_output_ports = 0;
|
||||
|
||||
impl = calloc(1, sizeof(struct transport));
|
||||
if (impl == NULL)
|
||||
return NULL;
|
||||
|
||||
pw_log_debug("transport %p: new %d %d", impl, max_input_ports, max_output_ports);
|
||||
|
||||
trans = &impl->trans;
|
||||
impl->offset = 0;
|
||||
|
||||
impl->mem = pw_mempool_alloc(core->pool,
|
||||
PW_MEMBLOCK_FLAG_READWRITE |
|
||||
PW_MEMBLOCK_FLAG_MAP |
|
||||
PW_MEMBLOCK_FLAG_SEAL,
|
||||
SPA_DATA_MemFd, area_get_size(&area));
|
||||
if (impl->mem == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy(impl->mem->map->ptr, &area, sizeof(struct pw_client_node0_area));
|
||||
transport_setup_area(impl->mem->map->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_node0_transport *
|
||||
pw_client_node0_transport_new_from_info(struct pw_client_node0_transport_info *info)
|
||||
{
|
||||
errno = ENOTSUP;
|
||||
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_node0_transport
|
||||
*/
|
||||
int pw_client_node0_transport_get_info(struct pw_client_node0_transport *trans,
|
||||
struct pw_client_node0_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;
|
||||
}
|
||||
54
src/modules/module-client-node/v0/transport.h
Normal file
54
src/modules/module-client-node/v0/transport.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/* 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_NODE0_TRANSPORT_H__
|
||||
#define __PIPEWIRE_CLIENT_NODE0_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_node0_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_node0_transport *
|
||||
pw_client_node0_transport_new(struct pw_core *core, uint32_t max_input_ports, uint32_t max_output_ports);
|
||||
|
||||
struct pw_client_node0_transport *
|
||||
pw_client_node0_transport_new_from_info(struct pw_client_node0_transport_info *info);
|
||||
|
||||
int
|
||||
pw_client_node0_transport_get_info(struct pw_client_node0_transport *trans,
|
||||
struct pw_client_node0_transport_info *info);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* __PIPEWIRE_CLIENT_NODE0_TRANSPORT_H__ */
|
||||
Loading…
Add table
Add a link
Reference in a new issue