mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
Enable header metadata
Enable the header metadata so that we have timestamps again. Rework allocation in the link a little. Reuse previously allocated buffers when possible. Keep track of where the buffers was allocated. Make some more convenience functions to initialize buffer headers. Make it so that we move allocations to the app. Make some helpers to make memfd memory in pinos now that we will be able to do all allocation there.
This commit is contained in:
parent
24108e01c1
commit
9d4048e73a
15 changed files with 504 additions and 157 deletions
|
|
@ -28,6 +28,7 @@
|
|||
#include "pinos/client/enumtypes.h"
|
||||
|
||||
#include "pinos/server/link.h"
|
||||
#include "pinos/server/utils.h"
|
||||
|
||||
#include "pinos/dbus/org-pinos.h"
|
||||
|
||||
|
|
@ -51,7 +52,8 @@ struct _PinosLinkPrivate
|
|||
uint32_t async_busy;
|
||||
|
||||
gboolean allocated;
|
||||
SpaBuffer *buffers[MAX_BUFFERS];
|
||||
PinosMemblock buffer_mem;
|
||||
SpaBuffer **buffers;
|
||||
unsigned int n_buffers;
|
||||
};
|
||||
|
||||
|
|
@ -417,10 +419,10 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
|
|||
spa_debug_port_info (oinfo);
|
||||
spa_debug_port_info (iinfo);
|
||||
|
||||
if (!priv->allocated) {
|
||||
if (priv->buffers == NULL) {
|
||||
SpaAllocParamBuffers *in_alloc, *out_alloc;
|
||||
guint max_buffers = MAX_BUFFERS;
|
||||
SpaBufferAllocFlags flags = 0;
|
||||
gboolean alloc_data = TRUE;
|
||||
|
||||
max_buffers = MAX_BUFFERS;
|
||||
in_alloc = find_param (iinfo, SPA_ALLOC_PARAM_TYPE_BUFFERS);
|
||||
|
|
@ -432,21 +434,49 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
|
|||
|
||||
if ((in_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) ||
|
||||
(out_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS))
|
||||
flags |= SPA_BUFFER_ALLOC_FLAG_NO_MEM;
|
||||
alloc_data = FALSE;
|
||||
|
||||
priv->n_buffers = max_buffers;
|
||||
if ((res = spa_buffer_alloc (flags,
|
||||
oinfo->params, oinfo->n_params,
|
||||
priv->buffers,
|
||||
&priv->n_buffers)) < 0) {
|
||||
g_set_error (&error,
|
||||
PINOS_ERROR,
|
||||
PINOS_ERROR_BUFFER_ALLOCATION,
|
||||
"error buffer alloc: %d", res);
|
||||
goto error;
|
||||
if (this->output->allocated) {
|
||||
out_flags = 0;
|
||||
in_flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS;
|
||||
priv->n_buffers = this->output->n_buffers;
|
||||
priv->buffers = this->output->buffers;
|
||||
priv->allocated = FALSE;
|
||||
g_debug ("reusing %d output buffers %p", priv->n_buffers, priv->buffers);
|
||||
} else {
|
||||
guint i;
|
||||
size_t hdr_size;
|
||||
void *p;
|
||||
|
||||
spa_alloc_params_get_header_size (oinfo->params, oinfo->n_params, 1, &hdr_size);
|
||||
|
||||
priv->n_buffers = max_buffers;
|
||||
|
||||
pinos_memblock_alloc (PINOS_MEMBLOCK_FLAG_WITH_FD |
|
||||
PINOS_MEMBLOCK_FLAG_MAP_READWRITE |
|
||||
PINOS_MEMBLOCK_FLAG_SEAL,
|
||||
priv->n_buffers * (sizeof (SpaBuffer*) + hdr_size),
|
||||
&priv->buffer_mem);
|
||||
|
||||
priv->buffers = p = priv->buffer_mem.ptr;
|
||||
p = SPA_MEMBER (p, priv->n_buffers * sizeof (SpaBuffer*), void);
|
||||
for (i = 0; i < priv->n_buffers; i++)
|
||||
priv->buffers[i] = SPA_MEMBER (p, hdr_size * i, SpaBuffer);
|
||||
|
||||
if ((res = spa_buffer_init_headers (oinfo->params,
|
||||
oinfo->n_params,
|
||||
1,
|
||||
priv->buffers,
|
||||
priv->n_buffers)) < 0) {
|
||||
g_set_error (&error,
|
||||
PINOS_ERROR,
|
||||
PINOS_ERROR_BUFFER_ALLOCATION,
|
||||
"error buffer alloc: %d", res);
|
||||
goto error;
|
||||
}
|
||||
g_debug ("allocated %d buffers %p", priv->n_buffers, priv->buffers);
|
||||
priv->allocated = TRUE;
|
||||
}
|
||||
g_debug ("allocated %d buffers %p", priv->n_buffers, priv->buffers);
|
||||
priv->allocated = TRUE;
|
||||
|
||||
if (in_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) {
|
||||
if ((res = spa_node_port_alloc_buffers (this->input->node->node, this->input->port,
|
||||
|
|
@ -458,7 +488,10 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
|
|||
"error alloc input buffers: %d", res);
|
||||
goto error;
|
||||
}
|
||||
this->input->buffers = priv->buffers;
|
||||
this->input->n_buffers = priv->n_buffers;
|
||||
this->input->allocated = TRUE;
|
||||
priv->allocated = FALSE;
|
||||
g_debug ("allocated %d buffers %p from input port", priv->n_buffers, priv->buffers);
|
||||
}
|
||||
else if (out_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) {
|
||||
|
|
@ -471,10 +504,14 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
|
|||
"error alloc output buffers: %d", res);
|
||||
goto error;
|
||||
}
|
||||
this->output->buffers = priv->buffers;
|
||||
this->output->n_buffers = priv->n_buffers;
|
||||
this->output->allocated = TRUE;
|
||||
priv->allocated = FALSE;
|
||||
g_debug ("allocated %d buffers %p from output port", priv->n_buffers, priv->buffers);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_flags & SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS) {
|
||||
g_debug ("using %d buffers %p on input port", priv->n_buffers, priv->buffers);
|
||||
if ((res = spa_node_port_use_buffers (this->input->node->node, this->input->port,
|
||||
|
|
@ -485,6 +522,8 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
|
|||
"error use input buffers: %d", res);
|
||||
goto error;
|
||||
}
|
||||
this->input->buffers = priv->buffers;
|
||||
this->input->n_buffers = priv->n_buffers;
|
||||
this->input->allocated = FALSE;
|
||||
}
|
||||
else if (out_flags & SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS) {
|
||||
|
|
@ -497,21 +536,27 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
|
|||
"error use output buffers: %d", res);
|
||||
goto error;
|
||||
}
|
||||
this->output->buffers = priv->buffers;
|
||||
this->output->n_buffers = priv->n_buffers;
|
||||
this->output->allocated = FALSE;
|
||||
} else {
|
||||
g_set_error (&error,
|
||||
PINOS_ERROR,
|
||||
PINOS_ERROR_BUFFER_ALLOCATION,
|
||||
"no common buffer alloc found");
|
||||
goto error;
|
||||
this->input->allocated = FALSE;
|
||||
this->output->allocated = FALSE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
error:
|
||||
{
|
||||
this->output->buffers = NULL;
|
||||
this->output->n_buffers = 0;
|
||||
this->output->allocated = FALSE;
|
||||
this->input->buffers = NULL;
|
||||
this->input->n_buffers = 0;
|
||||
this->input->allocated = FALSE;
|
||||
pinos_link_report_error (this, error);
|
||||
return res;
|
||||
}
|
||||
|
|
@ -624,11 +669,22 @@ on_property_notify (GObject *obj,
|
|||
static void
|
||||
on_node_remove (PinosNode *node, PinosLink *this)
|
||||
{
|
||||
PinosLinkPrivate *priv = this->priv;
|
||||
|
||||
g_signal_handlers_disconnect_by_data (node, this);
|
||||
if (node == this->input->node)
|
||||
if (node == this->input->node) {
|
||||
if (this->input->allocated) {
|
||||
priv->buffers = NULL;
|
||||
priv->n_buffers = 0;
|
||||
}
|
||||
this->input = NULL;
|
||||
else
|
||||
} else {
|
||||
if (this->output->allocated) {
|
||||
priv->buffers = NULL;
|
||||
priv->n_buffers = 0;
|
||||
}
|
||||
this->output = NULL;
|
||||
}
|
||||
|
||||
pinos_link_update_state (this, PINOS_LINK_STATE_UNLINKED);
|
||||
}
|
||||
|
|
@ -688,6 +744,9 @@ pinos_link_finalize (GObject * object)
|
|||
g_clear_object (&priv->iface);
|
||||
g_free (priv->object_path);
|
||||
|
||||
if (priv->allocated)
|
||||
pinos_memblock_free (&priv->buffer_mem);
|
||||
|
||||
G_OBJECT_CLASS (pinos_link_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ typedef struct {
|
|||
PinosNode *node;
|
||||
uint32_t port;
|
||||
gboolean allocated;
|
||||
SpaBuffer **buffers;
|
||||
guint n_buffers;
|
||||
} PinosPort;
|
||||
|
||||
/**
|
||||
|
|
|
|||
59
pinos/server/memfd-wrappers.h
Normal file
59
pinos/server/memfd-wrappers.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* Simple Plugin API
|
||||
* 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 <sys/syscall.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/*
|
||||
* No glibc wrappers exist for memfd_create(2), so provide our own.
|
||||
*
|
||||
* Also define memfd fcntl sealing macros. While they are already
|
||||
* defined in the kernel header file <linux/fcntl.h>, that file as
|
||||
* a whole conflicts with the original glibc header <fnctl.h>.
|
||||
*/
|
||||
|
||||
static inline int memfd_create(const char *name, unsigned int flags) {
|
||||
return syscall(SYS_memfd_create, name, flags);
|
||||
}
|
||||
|
||||
/* memfd_create(2) flags */
|
||||
|
||||
#ifndef MFD_CLOEXEC
|
||||
#define MFD_CLOEXEC 0x0001U
|
||||
#endif
|
||||
|
||||
#ifndef MFD_ALLOW_SEALING
|
||||
#define MFD_ALLOW_SEALING 0x0002U
|
||||
#endif
|
||||
|
||||
/* fcntl() seals-related flags */
|
||||
|
||||
#ifndef F_LINUX_SPECIFIC_BASE
|
||||
#define F_LINUX_SPECIFIC_BASE 1024
|
||||
#endif
|
||||
|
||||
#ifndef F_ADD_SEALS
|
||||
#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
|
||||
#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
|
||||
|
||||
#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
|
||||
#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
|
||||
#define F_SEAL_GROW 0x0004 /* prevent file from growing */
|
||||
#define F_SEAL_WRITE 0x0008 /* prevent writes */
|
||||
#endif
|
||||
|
|
@ -8,6 +8,7 @@ pinoscore_headers = [
|
|||
'node.h',
|
||||
'node-factory.h',
|
||||
'rt-loop.h',
|
||||
'utils.h',
|
||||
]
|
||||
|
||||
pinoscore_sources = [
|
||||
|
|
@ -20,6 +21,7 @@ pinoscore_sources = [
|
|||
'node.c',
|
||||
'node-factory.c',
|
||||
'rt-loop.c',
|
||||
'utils.c',
|
||||
]
|
||||
|
||||
libpinoscore_c_args = [
|
||||
|
|
|
|||
|
|
@ -283,12 +283,16 @@ suspend_node (PinosNode *this)
|
|||
NodePort *p = walk->data;
|
||||
if ((res = spa_node_port_set_format (this->node, p->port.port, 0, NULL)) < 0)
|
||||
g_warning ("error unset format output: %d", res);
|
||||
p->port.buffers = NULL;
|
||||
p->port.n_buffers = 0;
|
||||
p->port.allocated = FALSE;
|
||||
}
|
||||
for (walk = priv->output_ports; walk; walk = g_list_next (walk)) {
|
||||
NodePort *p = walk->data;
|
||||
if ((res = spa_node_port_set_format (this->node, p->port.port, 0, NULL)) < 0)
|
||||
g_warning ("error unset format output: %d", res);
|
||||
p->port.buffers = NULL;
|
||||
p->port.n_buffers = 0;
|
||||
p->port.allocated = FALSE;
|
||||
}
|
||||
return res;
|
||||
|
|
|
|||
91
pinos/server/utils.c
Normal file
91
pinos/server/utils.c
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/* Pinos
|
||||
* 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 <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "memfd-wrappers.h"
|
||||
|
||||
#include <pinos/server/utils.h>
|
||||
|
||||
gboolean
|
||||
pinos_memblock_alloc (PinosMemblockFlags flags,
|
||||
gsize size,
|
||||
PinosMemblock *mem)
|
||||
{
|
||||
g_return_val_if_fail (mem != NULL, FALSE);
|
||||
g_return_val_if_fail (size > 0, FALSE);
|
||||
|
||||
mem->flags = flags;
|
||||
mem->size = size;
|
||||
|
||||
if (flags & PINOS_MEMBLOCK_FLAG_WITH_FD) {
|
||||
mem->fd = memfd_create ("pinos-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING);
|
||||
|
||||
if (ftruncate (mem->fd, size) < 0) {
|
||||
g_warning ("Failed to truncate temporary file: %s", strerror (errno));
|
||||
close (mem->fd);
|
||||
return FALSE;
|
||||
}
|
||||
if (flags & PINOS_MEMBLOCK_FLAG_SEAL) {
|
||||
unsigned int seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL;
|
||||
if (fcntl (mem->fd, F_ADD_SEALS, seals) == -1) {
|
||||
g_warning ("Failed to add seals: %s", strerror (errno));
|
||||
}
|
||||
}
|
||||
if (flags & PINOS_MEMBLOCK_FLAG_MAP_READWRITE) {
|
||||
int prot = 0;
|
||||
|
||||
if (flags & PINOS_MEMBLOCK_FLAG_MAP_READ)
|
||||
prot |= PROT_READ;
|
||||
if (flags & PINOS_MEMBLOCK_FLAG_MAP_WRITE)
|
||||
prot |= PROT_WRITE;
|
||||
|
||||
mem->ptr = mmap (NULL, size, prot, MAP_SHARED, mem->fd, 0);
|
||||
} else {
|
||||
mem->ptr = NULL;
|
||||
}
|
||||
} else {
|
||||
mem->ptr = g_malloc (size);
|
||||
mem->fd = -1;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
pinos_memblock_free (PinosMemblock *mem)
|
||||
{
|
||||
g_return_if_fail (mem != NULL);
|
||||
|
||||
if (mem->flags & PINOS_MEMBLOCK_FLAG_WITH_FD) {
|
||||
if (mem->ptr)
|
||||
munmap (mem->ptr, mem->size);
|
||||
if (mem->fd != -1)
|
||||
close (mem->fd);
|
||||
} else {
|
||||
g_free (mem->ptr);
|
||||
}
|
||||
mem->ptr = NULL;
|
||||
mem->fd = -1;
|
||||
}
|
||||
55
pinos/server/utils.h
Normal file
55
pinos/server/utils.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/* Pinos
|
||||
* 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 __PINOS_UTILS_H__
|
||||
#define __PINOS_UTILS_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _PinosMemblock PinosMemblock;
|
||||
|
||||
#include <pinos/server/daemon.h>
|
||||
|
||||
typedef enum {
|
||||
PINOS_MEMBLOCK_FLAG_NONE = 0,
|
||||
PINOS_MEMBLOCK_FLAG_WITH_FD = (1 << 0),
|
||||
PINOS_MEMBLOCK_FLAG_MAP_READ = (1 << 1),
|
||||
PINOS_MEMBLOCK_FLAG_MAP_WRITE = (1 << 2),
|
||||
PINOS_MEMBLOCK_FLAG_SEAL = (1 << 3),
|
||||
} PinosMemblockFlags;
|
||||
|
||||
#define PINOS_MEMBLOCK_FLAG_MAP_READWRITE (PINOS_MEMBLOCK_FLAG_MAP_READ | PINOS_MEMBLOCK_FLAG_MAP_WRITE)
|
||||
|
||||
struct _PinosMemblock {
|
||||
PinosMemblockFlags flags;
|
||||
int fd;
|
||||
gpointer *ptr;
|
||||
gsize size;
|
||||
};
|
||||
|
||||
gboolean pinos_memblock_alloc (PinosMemblockFlags flags,
|
||||
gsize size,
|
||||
PinosMemblock *mem);
|
||||
void pinos_memblock_free (PinosMemblock *mem);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PINOS_UTILS_H__ */
|
||||
Loading…
Add table
Add a link
Reference in a new issue