mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
improve node io
Unify input and output io areas. Add support for ranges in the io area. Automatically recycle buffers in the output areas in process_output Improve the mixer, add use_buffer support, use a queue of input buffers, fix mixing, add support for ranges. Fix mixer and v4l2 tests
This commit is contained in:
parent
29fbf2e841
commit
01c13adab5
28 changed files with 983 additions and 747 deletions
|
|
@ -418,6 +418,8 @@ on_context_data (SpaSource *source,
|
|||
PinosProxy *proxy;
|
||||
const PinosDemarshalFunc *demarshal;
|
||||
|
||||
pinos_log_trace ("context %p: got message %d from %u", this, opcode, id);
|
||||
|
||||
proxy = pinos_map_lookup (&this->objects, id);
|
||||
if (proxy == NULL) {
|
||||
pinos_log_error ("context %p: could not find proxy %u", this, id);
|
||||
|
|
@ -428,8 +430,6 @@ on_context_data (SpaSource *source,
|
|||
continue;
|
||||
}
|
||||
|
||||
pinos_log_debug ("context %p: object demarshal %u, %u", this, id, opcode);
|
||||
|
||||
demarshal = proxy->iface->events;
|
||||
if (demarshal[opcode]) {
|
||||
if (!demarshal[opcode] (proxy, message, size))
|
||||
|
|
|
|||
|
|
@ -54,12 +54,12 @@ pinos_proxy_new (PinosContext *context,
|
|||
|
||||
spa_list_insert (&this->context->proxy_list, &this->link);
|
||||
|
||||
pinos_log_debug ("proxy %p: new %u", this, this->id);
|
||||
pinos_log_trace ("proxy %p: new %u", this, this->id);
|
||||
|
||||
return this;
|
||||
|
||||
in_use:
|
||||
pinos_log_debug ("proxy %p: id %u in use for context %p", this, id, context);
|
||||
pinos_log_error ("proxy %p: id %u in use for context %p", this, id, context);
|
||||
free (impl);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -69,12 +69,11 @@ pinos_proxy_destroy (PinosProxy *proxy)
|
|||
{
|
||||
PinosProxyImpl *impl = SPA_CONTAINER_OF (proxy, PinosProxyImpl, this);
|
||||
|
||||
pinos_log_debug ("proxy %p: destroy %u", proxy, proxy->id);
|
||||
pinos_log_trace ("proxy %p: destroy %u", proxy, proxy->id);
|
||||
pinos_signal_emit (&proxy->destroy_signal, proxy);
|
||||
|
||||
pinos_map_remove (&proxy->context->objects, proxy->id);
|
||||
spa_list_remove (&proxy->link);
|
||||
|
||||
pinos_log_debug ("proxy %p: free", proxy);
|
||||
free (impl);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -463,6 +463,18 @@ find_buffer (PinosStream *stream, uint32_t id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
reuse_buffer (PinosStream *stream, uint32_t id)
|
||||
{
|
||||
BufferId *bid;
|
||||
|
||||
if ((bid = find_buffer (stream, id)) && bid->used) {
|
||||
pinos_log_trace ("stream %p: reuse buffer %u", stream, id);
|
||||
bid->used = false;
|
||||
pinos_signal_emit (&stream->new_buffer, stream, id);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_rtnode_event (PinosStream *stream,
|
||||
SpaEvent *event)
|
||||
|
|
@ -473,10 +485,10 @@ handle_rtnode_event (PinosStream *stream,
|
|||
if (SPA_EVENT_TYPE (event) == context->type.event_node.HaveOutput) {
|
||||
int i;
|
||||
|
||||
//pinos_log_debug ("stream %p: have output", stream);
|
||||
pinos_log_trace ("stream %p: have output", stream);
|
||||
|
||||
for (i = 0; i < impl->trans->area->n_inputs; i++) {
|
||||
SpaPortInput *input = &impl->trans->inputs[i];
|
||||
SpaPortIO *input = &impl->trans->inputs[i];
|
||||
|
||||
if (input->buffer_id == SPA_ID_INVALID)
|
||||
continue;
|
||||
|
|
@ -487,7 +499,19 @@ handle_rtnode_event (PinosStream *stream,
|
|||
send_need_input (stream);
|
||||
}
|
||||
else if (SPA_EVENT_TYPE (event) == context->type.event_node.NeedInput) {
|
||||
//pinos_log_debug ("stream %p: need input", stream);
|
||||
int i;
|
||||
BufferId *bid;
|
||||
|
||||
for (i = 0; i < impl->trans->area->n_outputs; i++) {
|
||||
SpaPortIO *output = &impl->trans->outputs[i];
|
||||
|
||||
if (output->buffer_id == SPA_ID_INVALID)
|
||||
continue;
|
||||
|
||||
reuse_buffer (stream, output->buffer_id);
|
||||
output->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
pinos_log_trace ("stream %p: need input", stream);
|
||||
pinos_signal_emit (&stream->need_buffer, stream);
|
||||
}
|
||||
else if (SPA_EVENT_TYPE (event) == context->type.event_node.ReuseBuffer) {
|
||||
|
|
@ -499,10 +523,7 @@ handle_rtnode_event (PinosStream *stream,
|
|||
if (impl->direction != SPA_DIRECTION_OUTPUT)
|
||||
return;
|
||||
|
||||
if ((bid = find_buffer (stream, p->body.buffer_id.value)) && bid->used) {
|
||||
bid->used = false;
|
||||
pinos_signal_emit (&stream->new_buffer, stream, p->body.buffer_id.value);
|
||||
}
|
||||
reuse_buffer (stream, p->body.buffer_id.value);
|
||||
}
|
||||
else {
|
||||
pinos_log_warn ("unexpected node event %d", SPA_EVENT_TYPE (event));
|
||||
|
|
@ -547,7 +568,7 @@ handle_socket (PinosStream *stream, int rtfd)
|
|||
impl->rtfd = rtfd;
|
||||
impl->rtsocket_source = pinos_loop_add_io (stream->context->loop,
|
||||
impl->rtfd,
|
||||
SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP,
|
||||
SPA_IO_ERR | SPA_IO_HUP,
|
||||
true,
|
||||
on_rtsocket_condition,
|
||||
stream);
|
||||
|
|
@ -583,17 +604,27 @@ handle_node_command (PinosStream *stream,
|
|||
if (SPA_COMMAND_TYPE (command) == context->type.command_node.Pause) {
|
||||
pinos_log_debug ("stream %p: pause %d", stream, seq);
|
||||
|
||||
pinos_loop_update_io (stream->context->loop,
|
||||
impl->rtsocket_source,
|
||||
SPA_IO_ERR | SPA_IO_HUP);
|
||||
|
||||
add_state_change (stream, SPA_NODE_STATE_PAUSED, false);
|
||||
add_async_complete (stream, seq, SPA_RESULT_OK, true);
|
||||
stream_set_state (stream, PINOS_STREAM_STATE_PAUSED, NULL);
|
||||
}
|
||||
else if (SPA_COMMAND_TYPE (command) == context->type.command_node.Start) {
|
||||
pinos_log_debug ("stream %p: start %d", stream, seq);
|
||||
pinos_log_debug ("stream %p: start %d %d", stream, seq, impl->direction);
|
||||
add_state_change (stream, SPA_NODE_STATE_STREAMING, false);
|
||||
add_async_complete (stream, seq, SPA_RESULT_OK, true);
|
||||
|
||||
pinos_loop_update_io (stream->context->loop,
|
||||
impl->rtsocket_source,
|
||||
SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP);
|
||||
|
||||
if (impl->direction == SPA_DIRECTION_INPUT)
|
||||
send_need_input (stream);
|
||||
else
|
||||
pinos_signal_emit (&stream->need_buffer, stream);
|
||||
|
||||
stream_set_state (stream, PINOS_STREAM_STATE_STREAMING, NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ transport_area_get_size (PinosTransportArea *area)
|
|||
{
|
||||
size_t size;
|
||||
size = sizeof (PinosTransportArea);
|
||||
size += area->max_inputs * sizeof (SpaPortInput);
|
||||
size += area->max_outputs * sizeof (SpaPortOutput);
|
||||
size += area->max_inputs * sizeof (SpaPortIO);
|
||||
size += area->max_outputs * sizeof (SpaPortIO);
|
||||
size += sizeof (SpaRingbuffer);
|
||||
size += INPUT_BUFFER_SIZE;
|
||||
size += sizeof (SpaRingbuffer);
|
||||
|
|
@ -63,25 +63,25 @@ transport_setup_area (void *p, PinosTransport *trans)
|
|||
int i;
|
||||
|
||||
trans->area = a = p;
|
||||
p = SPA_MEMBER (p, sizeof (PinosTransportArea), SpaPortInput);
|
||||
p = SPA_MEMBER (p, sizeof (PinosTransportArea), SpaPortIO);
|
||||
|
||||
trans->inputs = p;
|
||||
for (i = 0; i < a->max_inputs; i++) {
|
||||
trans->inputs[i].state = SPA_PORT_STATE_FLAG_NONE;
|
||||
trans->inputs[i].flags = SPA_PORT_INPUT_FLAG_NONE;
|
||||
trans->inputs[i].flags = SPA_PORT_IO_FLAG_NONE;
|
||||
trans->inputs[i].buffer_id = SPA_ID_INVALID;
|
||||
trans->inputs[i].status = SPA_RESULT_OK;
|
||||
}
|
||||
p = SPA_MEMBER (p, a->max_inputs * sizeof (SpaPortInput), void);
|
||||
p = SPA_MEMBER (p, a->max_inputs * sizeof (SpaPortIO), void);
|
||||
|
||||
trans->outputs = p;
|
||||
for (i = 0; i < a->max_outputs; i++) {
|
||||
trans->outputs[i].state = SPA_PORT_STATE_FLAG_NONE;
|
||||
trans->outputs[i].flags = SPA_PORT_OUTPUT_FLAG_NONE;
|
||||
trans->outputs[i].flags = SPA_PORT_IO_FLAG_NONE;
|
||||
trans->outputs[i].buffer_id = SPA_ID_INVALID;
|
||||
trans->outputs[i].status = SPA_RESULT_OK;
|
||||
}
|
||||
p = SPA_MEMBER (p, a->max_outputs * sizeof (SpaPortOutput), void);
|
||||
p = SPA_MEMBER (p, a->max_outputs * sizeof (SpaPortIO), void);
|
||||
|
||||
trans->input_buffer = p;
|
||||
spa_ringbuffer_init (trans->input_buffer, INPUT_BUFFER_SIZE);
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ struct _PinosTransport {
|
|||
PinosTransport *trans));
|
||||
|
||||
PinosTransportArea *area;
|
||||
SpaPortInput *inputs;
|
||||
SpaPortOutput *outputs;
|
||||
SpaPortIO *inputs;
|
||||
SpaPortIO *outputs;
|
||||
void *input_data;
|
||||
SpaRingbuffer *input_buffer;
|
||||
void *output_data;
|
||||
|
|
|
|||
|
|
@ -565,41 +565,24 @@ spa_proxy_node_port_set_props (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_proxy_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
spa_proxy_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaProxy *this;
|
||||
SpaProxyPort *port;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaProxy, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_INPUT, port_id))
|
||||
if (!CHECK_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->in_ports[port_id].io = input;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_proxy_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
{
|
||||
SpaProxy *this;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaProxy, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->out_ports[port_id].io = output;
|
||||
port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id];
|
||||
port->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -815,11 +798,14 @@ static SpaResult
|
|||
spa_proxy_node_process_output (SpaNode *node)
|
||||
{
|
||||
SpaProxy *this;
|
||||
PinosNode *pnode;
|
||||
int i;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaProxy, node);
|
||||
pnode = this->pnode;
|
||||
|
||||
send_need_input (this);
|
||||
|
||||
|
|
@ -982,8 +968,7 @@ static const SpaNode proxy_node = {
|
|||
spa_proxy_node_port_set_props,
|
||||
spa_proxy_node_port_use_buffers,
|
||||
spa_proxy_node_port_alloc_buffers,
|
||||
spa_proxy_node_port_set_input,
|
||||
spa_proxy_node_port_set_output,
|
||||
spa_proxy_node_port_set_io,
|
||||
spa_proxy_node_port_reuse_buffer,
|
||||
spa_proxy_node_port_send_command,
|
||||
spa_proxy_node_process_input,
|
||||
|
|
|
|||
|
|
@ -150,9 +150,9 @@ update_port_ids (PinosNode *node, bool create)
|
|||
node->transport->area->n_outputs = n_output_ports;
|
||||
|
||||
for (i = 0; i < max_input_ports; i++)
|
||||
spa_node_port_set_input (node->node, i, &node->transport->inputs[i]);
|
||||
spa_node_port_set_io (node->node, SPA_DIRECTION_INPUT, i, &node->transport->inputs[i]);
|
||||
for (i = 0; i < max_output_ports; i++)
|
||||
spa_node_port_set_output (node->node, i, &node->transport->outputs[i]);
|
||||
spa_node_port_set_io (node->node, SPA_DIRECTION_OUTPUT, i, &node->transport->outputs[i]);
|
||||
|
||||
pinos_signal_emit (&node->transport_changed, node);
|
||||
}
|
||||
|
|
@ -272,8 +272,8 @@ on_node_event (SpaNode *node, SpaEvent *event, void *user_data)
|
|||
for (i = 0; i < this->transport->area->n_inputs; i++) {
|
||||
PinosLink *link;
|
||||
PinosPort *inport, *outport;
|
||||
SpaPortInput *pi;
|
||||
SpaPortOutput *po;
|
||||
SpaPortIO *pi;
|
||||
SpaPortIO *po;
|
||||
|
||||
pi = &this->transport->inputs[i];
|
||||
if (pi->buffer_id != SPA_ID_INVALID)
|
||||
|
|
@ -289,16 +289,8 @@ on_node_event (SpaNode *node, SpaEvent *event, void *user_data)
|
|||
|
||||
if (po->buffer_id != SPA_ID_INVALID) {
|
||||
processed = true;
|
||||
|
||||
pi->buffer_id = po->buffer_id;
|
||||
if ((res = spa_node_port_reuse_buffer (outport->node->node,
|
||||
outport->port_id,
|
||||
po->buffer_id)) < 0)
|
||||
pinos_log_warn ("node %p: error reuse buffer: %d", outport->node, res);
|
||||
|
||||
po->buffer_id = SPA_ID_INVALID;
|
||||
*pi = *po;
|
||||
}
|
||||
|
||||
if ((res = spa_node_process_output (outport->node->node)) < 0)
|
||||
pinos_log_warn ("node %p: got process output %d", outport->node, res);
|
||||
}
|
||||
|
|
@ -316,8 +308,7 @@ on_node_event (SpaNode *node, SpaEvent *event, void *user_data)
|
|||
for (i = 0; i < this->transport->area->n_outputs; i++) {
|
||||
PinosLink *link;
|
||||
PinosPort *inport, *outport;
|
||||
SpaPortInput *pi;
|
||||
SpaPortOutput *po;
|
||||
SpaPortIO *po;
|
||||
|
||||
po = &this->transport->outputs[i];
|
||||
if (po->buffer_id == SPA_ID_INVALID)
|
||||
|
|
@ -331,22 +322,12 @@ on_node_event (SpaNode *node, SpaEvent *event, void *user_data)
|
|||
continue;
|
||||
|
||||
inport = link->rt.input;
|
||||
pi = &inport->node->transport->inputs[inport->port_id];
|
||||
|
||||
|
||||
pi->buffer_id = po->buffer_id;
|
||||
inport->node->transport->inputs[inport->port_id] = *po;
|
||||
|
||||
if ((res = spa_node_process_input (inport->node->node)) < 0)
|
||||
pinos_log_warn ("node %p: got process input %d", inport->node, res);
|
||||
}
|
||||
|
||||
if ((res = spa_node_port_reuse_buffer (this->node,
|
||||
outport->port_id,
|
||||
po->buffer_id)) < 0)
|
||||
pinos_log_warn ("node %p: error reuse buffer: %d", this, res);
|
||||
|
||||
processed = true;
|
||||
po->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
if (processed) {
|
||||
if ((res = spa_node_process_output (this->node)) < 0)
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ pinos_resource_destroy (PinosResource *resource)
|
|||
{
|
||||
PinosClient *client = resource->client;
|
||||
|
||||
pinos_log_debug ("resource %p: destroy %u", resource, resource->id);
|
||||
pinos_log_trace ("resource %p: destroy %u", resource, resource->id);
|
||||
pinos_signal_emit (&resource->destroy_signal, resource);
|
||||
|
||||
pinos_map_insert_at (&client->objects, resource->id, NULL);
|
||||
|
|
@ -84,6 +84,5 @@ pinos_resource_destroy (PinosResource *resource)
|
|||
if (client->core_resource)
|
||||
pinos_core_notify_remove_id (client->core_resource, resource->id);
|
||||
|
||||
pinos_log_debug ("resource %p: free", resource);
|
||||
free (resource);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,30 +76,19 @@ typedef enum {
|
|||
#define SPA_PORT_STATE_FLAG_HAVE_FORMAT (1 << 0)
|
||||
#define SPA_PORT_STATE_FLAG_HAVE_BUFFERS (1 << 1)
|
||||
|
||||
/**
|
||||
* SpaPortInput:
|
||||
* @state: the port state
|
||||
* @flags: extra flags
|
||||
* @buffer_id: a buffer id
|
||||
* @status: status
|
||||
*
|
||||
* Input information for a node.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t state;
|
||||
#define SPA_PORT_INPUT_FLAG_NONE 0
|
||||
uint32_t flags;
|
||||
uint32_t buffer_id;
|
||||
uint32_t status;
|
||||
} SpaPortInput;
|
||||
uint64_t offset;
|
||||
uint32_t min_size;
|
||||
uint32_t max_size;
|
||||
} SpaRange;
|
||||
|
||||
/**
|
||||
* SpaPortOutput:
|
||||
* SpaPortIO:
|
||||
* @state: the port state
|
||||
* @flags: extra flags
|
||||
* @buffer_id: a buffer id will be set
|
||||
* @status: the status
|
||||
* @latency: current port latency
|
||||
* @range: requested output range
|
||||
* @event: output event
|
||||
*
|
||||
* Output information for a port on a node. This is allocated
|
||||
|
|
@ -108,13 +97,14 @@ typedef struct {
|
|||
*/
|
||||
typedef struct {
|
||||
uint32_t state;
|
||||
#define SPA_PORT_OUTPUT_FLAG_NONE 0
|
||||
#define SPA_PORT_IO_FLAG_NONE 0
|
||||
#define SPA_PORT_IO_FLAG_RANGE (1 << 0)
|
||||
uint32_t flags;
|
||||
uint32_t buffer_id;
|
||||
uint32_t status;
|
||||
uint64_t latency;
|
||||
SpaRange range;
|
||||
SpaEvent *event;
|
||||
} SpaPortOutput;
|
||||
} SpaPortIO;
|
||||
|
||||
/**
|
||||
* SpaPortInfoFlags:
|
||||
|
|
@ -533,38 +523,23 @@ struct _SpaNode {
|
|||
uint32_t *n_buffers);
|
||||
|
||||
/**
|
||||
* SpaNode::port_set_input:
|
||||
* @port_id: an input port id
|
||||
* @input: a #SpaPortInput
|
||||
* SpaNode::port_set_io:
|
||||
* @direction: a #SpaDirection
|
||||
* @port_id: a port id
|
||||
* @io: a #SpaPortIO
|
||||
*
|
||||
* Configure the given input structure on the input @port_id. This
|
||||
* Configure the given io structure on @port_id. This
|
||||
* structure is allocated by the host and is used to query the state
|
||||
* of the port and transfer buffers into the port.
|
||||
* of the port and exchange buffers with the port.
|
||||
*
|
||||
* Setting an @input of %NULL will disable the port.
|
||||
* Setting an @io of %NULL will disable the port.
|
||||
*
|
||||
* Returns: #SPA_RESULT_OK on success
|
||||
*/
|
||||
SpaResult (*port_set_input) (SpaNode *node,
|
||||
SpaResult (*port_set_io) (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input);
|
||||
|
||||
/**
|
||||
* SpaNode::port_set_output:
|
||||
* @port_id: an output port id
|
||||
* @output: a #SpaPortOutput
|
||||
*
|
||||
* Configure the given output structure on the output @port_id. This
|
||||
* structure is allocated by the host and is used to query the state
|
||||
* of the port and transfer buffers and events into the port.
|
||||
*
|
||||
* Setting an @output of %NULL will disable the port.
|
||||
*
|
||||
* Returns: #SPA_RESULT_OK on success
|
||||
*/
|
||||
SpaResult (*port_set_output) (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output);
|
||||
SpaPortIO *io);
|
||||
|
||||
/**
|
||||
* SpaNode::port_reuse_buffer:
|
||||
|
|
@ -665,8 +640,7 @@ struct _SpaNode {
|
|||
#define spa_node_port_set_props(n,...) (n)->port_set_props((n),__VA_ARGS__)
|
||||
#define spa_node_port_use_buffers(n,...) (n)->port_use_buffers((n),__VA_ARGS__)
|
||||
#define spa_node_port_alloc_buffers(n,...) (n)->port_alloc_buffers((n),__VA_ARGS__)
|
||||
#define spa_node_port_set_input(n,...) (n)->port_set_input((n),__VA_ARGS__)
|
||||
#define spa_node_port_set_output(n,...) (n)->port_set_output((n),__VA_ARGS__)
|
||||
#define spa_node_port_set_io(n,...) (n)->port_set_io((n),__VA_ARGS__)
|
||||
#define spa_node_port_reuse_buffer(n,...) (n)->port_reuse_buffer((n),__VA_ARGS__)
|
||||
#define spa_node_port_send_command(n,...) (n)->port_send_command((n),__VA_ARGS__)
|
||||
#define spa_node_process_input(n) (n)->process_input((n))
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ typedef struct _SpaPODBuilder {
|
|||
bool first;
|
||||
} SpaPODBuilder;
|
||||
|
||||
#define SPA_POD_BUILDER_INIT(buffer,size) { buffer, size, }
|
||||
|
||||
#define SPA_POD_BUILDER_DEREF(b,ref,type) SPA_MEMBER ((b)->data, (ref), type)
|
||||
|
||||
static inline void
|
||||
|
|
|
|||
|
|
@ -472,3 +472,61 @@ spa_debug_dict (const SpaDict *dict)
|
|||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
|
||||
#define DEFAULT_LOG_LEVEL SPA_LOG_LEVEL_TRACE
|
||||
|
||||
static void
|
||||
do_logv (SpaLog *log,
|
||||
SpaLogLevel level,
|
||||
const char *file,
|
||||
int line,
|
||||
const char *func,
|
||||
const char *fmt,
|
||||
va_list args)
|
||||
{
|
||||
char text[16*1024], location[128];
|
||||
static const char *levels[] = {
|
||||
"-",
|
||||
"E",
|
||||
"W",
|
||||
"I",
|
||||
"D",
|
||||
"T",
|
||||
};
|
||||
vsnprintf (text, sizeof(text), fmt, args);
|
||||
if (1) {
|
||||
snprintf (location, sizeof(location), "%s:%i %s()", strrchr (file, '/')+1, line, func);
|
||||
fprintf(stderr, "[%s][%s] %s\n", levels[level], location, text);
|
||||
} else {
|
||||
fprintf(stderr, "[%s] %s\n", levels[level], text);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_log (SpaLog *log,
|
||||
SpaLogLevel level,
|
||||
const char *file,
|
||||
int line,
|
||||
const char *func,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, fmt);
|
||||
do_logv (log, level, file, line, func, fmt, args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
static SpaLog log = {
|
||||
sizeof (SpaLog),
|
||||
NULL,
|
||||
DEFAULT_LOG_LEVEL,
|
||||
do_log,
|
||||
do_logv,
|
||||
};
|
||||
|
||||
SpaLog *
|
||||
spa_log_get_default (void)
|
||||
{
|
||||
return &log;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ extern "C" {
|
|||
#include <spa/props.h>
|
||||
#include <spa/format.h>
|
||||
#include <spa/dict.h>
|
||||
#include <spa/log.h>
|
||||
|
||||
SpaResult spa_debug_port_info (const SpaPortInfo *info, const SpaTypeMap *map);
|
||||
SpaResult spa_debug_buffer (const SpaBuffer *buffer);
|
||||
|
|
@ -40,6 +41,8 @@ SpaResult spa_debug_format (const SpaFormat *format, const SpaTypeMap *map);
|
|||
SpaResult spa_debug_dump_mem (const void *data, size_t size);
|
||||
SpaResult spa_debug_dict (const SpaDict *dict);
|
||||
|
||||
SpaLog * spa_log_get_default (void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -576,9 +576,10 @@ spa_alsa_sink_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_alsa_sink_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
spa_alsa_sink_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaALSASink *this;
|
||||
|
||||
|
|
@ -587,22 +588,14 @@ spa_alsa_sink_node_port_set_input (SpaNode *node,
|
|||
|
||||
this = SPA_CONTAINER_OF (node, SpaALSASink, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_INPUT, port_id))
|
||||
if (!CHECK_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->io = input;
|
||||
this->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_alsa_sink_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_alsa_sink_node_port_reuse_buffer (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
|
|
@ -648,7 +641,7 @@ static SpaResult
|
|||
spa_alsa_sink_node_process_input (SpaNode *node)
|
||||
{
|
||||
SpaALSASink *this;
|
||||
SpaPortInput *input;
|
||||
SpaPortIO *input;
|
||||
SpaALSABuffer *b;
|
||||
|
||||
if (node == NULL)
|
||||
|
|
@ -680,8 +673,8 @@ spa_alsa_sink_node_process_input (SpaNode *node)
|
|||
this->ringbuffer = b;
|
||||
} else {
|
||||
spa_list_insert (this->ready.prev, &b->link);
|
||||
spa_log_trace (this->log, "alsa-sink %p: queue buffer %u", this, input->buffer_id);
|
||||
}
|
||||
//spa_log_debug (this->log, "alsa-source: got buffer %u", input->buffer_id);
|
||||
b->outstanding = false;
|
||||
input->buffer_id = SPA_ID_INVALID;
|
||||
input->status = SPA_RESULT_OK;
|
||||
|
|
@ -716,8 +709,7 @@ static const SpaNode alsasink_node = {
|
|||
spa_alsa_sink_node_port_set_props,
|
||||
spa_alsa_sink_node_port_use_buffers,
|
||||
spa_alsa_sink_node_port_alloc_buffers,
|
||||
spa_alsa_sink_node_port_set_input,
|
||||
spa_alsa_sink_node_port_set_output,
|
||||
spa_alsa_sink_node_port_set_io,
|
||||
spa_alsa_sink_node_port_reuse_buffer,
|
||||
spa_alsa_sink_node_port_send_command,
|
||||
spa_alsa_sink_node_process_input,
|
||||
|
|
@ -779,7 +771,15 @@ alsa_sink_init (const SpaHandleFactory *factory,
|
|||
this->main_loop = support[i].data;
|
||||
}
|
||||
if (this->map == NULL) {
|
||||
spa_log_error (this->log, "an id-map is needed");
|
||||
spa_log_error (this->log, "a type-map is needed");
|
||||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
if (this->data_loop == NULL) {
|
||||
spa_log_error (this->log, "a data loop is needed");
|
||||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
if (this->main_loop == NULL) {
|
||||
spa_log_error (this->log, "a main loop is needed");
|
||||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
init_type (&this->type, this->map);
|
||||
|
|
|
|||
|
|
@ -369,8 +369,7 @@ recycle_buffer (SpaALSASource *this, uint32_t buffer_id)
|
|||
SpaALSABuffer *b;
|
||||
|
||||
b = &this->buffers[buffer_id];
|
||||
if (!b->outstanding)
|
||||
return;
|
||||
spa_return_if_fail (b->outstanding);
|
||||
|
||||
b->outstanding = false;
|
||||
spa_list_insert (this->free.prev, &b->link);
|
||||
|
|
@ -616,17 +615,10 @@ spa_alsa_source_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_alsa_source_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_alsa_source_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
spa_alsa_source_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaALSASource *this;
|
||||
|
||||
|
|
@ -635,10 +627,10 @@ spa_alsa_source_node_port_set_output (SpaNode *node,
|
|||
|
||||
this = SPA_CONTAINER_OF (node, SpaALSASource, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
if (!CHECK_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->io = output;
|
||||
this->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -710,6 +702,17 @@ spa_alsa_source_node_process_input (SpaNode *node)
|
|||
static SpaResult
|
||||
spa_alsa_source_node_process_output (SpaNode *node)
|
||||
{
|
||||
SpaALSASource *this;
|
||||
SpaPortIO *io;
|
||||
|
||||
spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS);
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaALSASource, node);
|
||||
|
||||
if ((io = this->io) && io->buffer_id != SPA_ID_INVALID) {
|
||||
recycle_buffer (this, io->buffer_id);
|
||||
io->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
|
|
@ -733,8 +736,7 @@ static const SpaNode alsasource_node = {
|
|||
spa_alsa_source_node_port_set_props,
|
||||
spa_alsa_source_node_port_use_buffers,
|
||||
spa_alsa_source_node_port_alloc_buffers,
|
||||
spa_alsa_source_node_port_set_input,
|
||||
spa_alsa_source_node_port_set_output,
|
||||
spa_alsa_source_node_port_set_io,
|
||||
spa_alsa_source_node_port_reuse_buffer,
|
||||
spa_alsa_source_node_port_send_command,
|
||||
spa_alsa_source_node_process_input,
|
||||
|
|
@ -847,6 +849,14 @@ alsa_source_init (const SpaHandleFactory *factory,
|
|||
spa_log_error (this->log, "an id-map is needed");
|
||||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
if (this->data_loop == NULL) {
|
||||
spa_log_error (this->log, "a data loop is needed");
|
||||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
if (this->main_loop == NULL) {
|
||||
spa_log_error (this->log, "a main loop is needed");
|
||||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
init_type (&this->type, this->map);
|
||||
|
||||
this->node = alsasource_node;
|
||||
|
|
|
|||
|
|
@ -228,6 +228,15 @@ pull_frames_queue (SpaALSAState *state,
|
|||
|
||||
if (spa_list_is_empty (&state->ready)) {
|
||||
SpaEvent event = SPA_EVENT_INIT (state->type.event_node.NeedInput);
|
||||
SpaPortIO *io;
|
||||
|
||||
if ((io = state->io)) {
|
||||
io->flags = SPA_PORT_IO_FLAG_RANGE;
|
||||
io->status = SPA_RESULT_OK;
|
||||
io->range.offset = state->sample_count;
|
||||
io->range.min_size = state->threshold;
|
||||
io->range.max_size = frames;
|
||||
}
|
||||
state->event_cb (&state->node, &event, state->user_data);
|
||||
}
|
||||
while (!spa_list_is_empty (&state->ready) && to_write > 0) {
|
||||
|
|
@ -334,7 +343,7 @@ push_frames_queue (SpaALSAState *state,
|
|||
size_t n_bytes;
|
||||
SpaALSABuffer *b;
|
||||
SpaData *d;
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *io;
|
||||
|
||||
b = spa_list_first (&state->free, SpaALSABuffer, link);
|
||||
spa_list_remove (&b->link);
|
||||
|
|
@ -357,13 +366,13 @@ push_frames_queue (SpaALSAState *state,
|
|||
d[0].chunk->size = n_bytes;
|
||||
d[0].chunk->stride = 0;
|
||||
|
||||
if ((output = state->io)) {
|
||||
b->outstanding = true;
|
||||
output->buffer_id = b->outbuf->id;
|
||||
output->status = SPA_RESULT_OK;
|
||||
}
|
||||
{
|
||||
if ((io = state->io)) {
|
||||
SpaEvent event = SPA_EVENT_INIT (state->type.event_node.HaveOutput);
|
||||
|
||||
b->outstanding = true;
|
||||
io->buffer_id = b->outbuf->id;
|
||||
io->status = SPA_RESULT_OK;
|
||||
|
||||
state->event_cb (&state->node, &event, state->user_data);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ struct _SpaALSAState {
|
|||
SpaPortInfo info;
|
||||
SpaAllocParam *params[3];
|
||||
uint8_t params_buffer[1024];
|
||||
void *io;
|
||||
SpaPortIO *io;
|
||||
|
||||
SpaALSABuffer buffers[MAX_BUFFERS];
|
||||
unsigned int n_buffers;
|
||||
|
|
|
|||
|
|
@ -21,39 +21,38 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include <spa/log.h>
|
||||
#include <spa/list.h>
|
||||
#include <spa/type-map.h>
|
||||
#include <spa/node.h>
|
||||
#include <spa/audio/format-utils.h>
|
||||
#include <lib/props.h>
|
||||
|
||||
#define MAX_BUFFERS 64
|
||||
#define MAX_PORTS 128
|
||||
|
||||
typedef struct _SpaAudioMixer SpaAudioMixer;
|
||||
|
||||
typedef struct _MixerBuffer MixerBuffer;
|
||||
|
||||
struct _MixerBuffer {
|
||||
SpaBuffer buffer;
|
||||
SpaMeta meta[1];
|
||||
SpaMetaHeader header;
|
||||
SpaData data[1];
|
||||
uint16_t samples[4096];
|
||||
};
|
||||
typedef struct {
|
||||
SpaBuffer *outbuf;
|
||||
bool outstanding;
|
||||
SpaMetaHeader *h;
|
||||
void *ptr;
|
||||
size_t size;
|
||||
SpaList link;
|
||||
} MixerBuffer;
|
||||
|
||||
typedef struct {
|
||||
bool valid;
|
||||
bool have_format;
|
||||
SpaAudioInfo format;
|
||||
SpaPortInfo info;
|
||||
size_t buffer_index;
|
||||
size_t buffer_offset;
|
||||
size_t buffer_queued;
|
||||
MixerBuffer mix;
|
||||
|
||||
SpaBuffer **buffers;
|
||||
uint32_t n_buffers;
|
||||
SpaBuffer *buffer;
|
||||
void *io;
|
||||
SpaPortIO *io;
|
||||
MixerBuffer buffers[MAX_BUFFERS];
|
||||
uint32_t n_buffers;
|
||||
SpaList queue;
|
||||
size_t queued_offset;
|
||||
size_t queued_bytes;
|
||||
} SpaAudioMixerPort;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -89,6 +88,11 @@ struct _SpaAudioMixer {
|
|||
int port_queued;
|
||||
SpaAudioMixerPort in_ports[MAX_PORTS];
|
||||
SpaAudioMixerPort out_ports[1];
|
||||
|
||||
#define STATE_ERROR 0
|
||||
#define STATE_IN 1
|
||||
#define STATE_OUT 2
|
||||
int state;
|
||||
};
|
||||
|
||||
#define CHECK_FREE_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS && !this->in_ports[(p)].valid)
|
||||
|
|
@ -227,6 +231,7 @@ spa_audiomixer_node_add_port (SpaNode *node,
|
|||
|
||||
this->in_ports[port_id].valid = true;
|
||||
this->port_count++;
|
||||
spa_list_init (&this->in_ports[port_id].queue);
|
||||
|
||||
this->in_ports[port_id].info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS |
|
||||
SPA_PORT_INFO_FLAG_REMOVABLE |
|
||||
|
|
@ -241,7 +246,7 @@ spa_audiomixer_node_remove_port (SpaNode *node,
|
|||
uint32_t port_id)
|
||||
{
|
||||
SpaAudioMixer *this;
|
||||
SpaPortInput *input;
|
||||
SpaPortIO *io;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
|
@ -254,8 +259,8 @@ spa_audiomixer_node_remove_port (SpaNode *node,
|
|||
this->in_ports[port_id].valid = false;
|
||||
this->port_count--;
|
||||
|
||||
input = this->in_ports[port_id].io;
|
||||
if (input && input->buffer_id) {
|
||||
io = this->in_ports[port_id].io;
|
||||
if (io && io->buffer_id) {
|
||||
this->port_queued--;
|
||||
}
|
||||
|
||||
|
|
@ -292,6 +297,17 @@ spa_audiomixer_node_port_enum_formats (SpaNode *node,
|
|||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
clear_buffers (SpaAudioMixer *this, SpaAudioMixerPort *port)
|
||||
{
|
||||
if (port->n_buffers > 0) {
|
||||
spa_log_info (this->log, "audio-mixer %p: clear buffers", this);
|
||||
port->n_buffers = 0;
|
||||
spa_list_init (&port->queue);
|
||||
}
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_audiomixer_node_port_set_format (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
|
|
@ -314,6 +330,7 @@ spa_audiomixer_node_port_set_format (SpaNode *node,
|
|||
|
||||
if (format == NULL) {
|
||||
port->have_format = false;
|
||||
clear_buffers (this, port);
|
||||
} else {
|
||||
SpaAudioInfo info = { SPA_FORMAT_MEDIA_TYPE (format),
|
||||
SPA_FORMAT_MEDIA_SUBTYPE (format), };
|
||||
|
|
@ -328,6 +345,13 @@ spa_audiomixer_node_port_set_format (SpaNode *node,
|
|||
port->format = info;
|
||||
port->have_format = true;
|
||||
}
|
||||
|
||||
if (port->have_format) {
|
||||
update_state (this, SPA_NODE_STATE_READY);
|
||||
}
|
||||
else
|
||||
update_state (this, SPA_NODE_STATE_CONFIGURE);
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
|
|
@ -406,7 +430,55 @@ spa_audiomixer_node_port_use_buffers (SpaNode *node,
|
|||
SpaBuffer **buffers,
|
||||
uint32_t n_buffers)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
SpaAudioMixer *this;
|
||||
SpaAudioMixerPort *port;
|
||||
uint32_t i;
|
||||
|
||||
spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS);
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaAudioMixer, node);
|
||||
|
||||
spa_return_val_if_fail (CHECK_PORT (this, direction, port_id), SPA_RESULT_INVALID_PORT);
|
||||
|
||||
port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id];
|
||||
|
||||
spa_return_val_if_fail (port->have_format, SPA_RESULT_NO_FORMAT);
|
||||
|
||||
clear_buffers (this, port);
|
||||
|
||||
for (i = 0; i < n_buffers; i++) {
|
||||
MixerBuffer *b;
|
||||
SpaData *d = buffers[i]->datas;
|
||||
|
||||
b = &port->buffers[i];
|
||||
b->outbuf = buffers[i];
|
||||
b->outstanding = true;
|
||||
b->h = spa_buffer_find_meta (buffers[i], SPA_META_TYPE_HEADER);
|
||||
|
||||
switch (d[0].type) {
|
||||
case SPA_DATA_TYPE_MEMPTR:
|
||||
case SPA_DATA_TYPE_MEMFD:
|
||||
case SPA_DATA_TYPE_DMABUF:
|
||||
if (d[0].data == NULL) {
|
||||
spa_log_error (this->log, "volume %p: invalid memory on buffer %p", this, buffers[i]);
|
||||
continue;
|
||||
}
|
||||
b->ptr = d[0].data;
|
||||
b->size = d[0].maxsize;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
spa_list_insert (port->queue.prev, &b->link);
|
||||
}
|
||||
port->n_buffers = n_buffers;
|
||||
|
||||
if (port->n_buffers > 0) {
|
||||
update_state (this, SPA_NODE_STATE_PAUSED);
|
||||
} else {
|
||||
update_state (this, SPA_NODE_STATE_READY);
|
||||
}
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
|
|
@ -422,41 +494,24 @@ spa_audiomixer_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_audiomixer_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
spa_audiomixer_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaAudioMixer *this;
|
||||
SpaAudioMixerPort *port;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaAudioMixer, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_INPUT, port_id))
|
||||
if (!CHECK_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->in_ports[port_id].io = input;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_audiomixer_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
{
|
||||
SpaAudioMixer *this;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaAudioMixer, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->out_ports[port_id].io = output;
|
||||
port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id];
|
||||
port->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -478,131 +533,107 @@ spa_audiomixer_node_port_send_command (SpaNode *node,
|
|||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static void
|
||||
add_port_data (SpaAudioMixer *this, MixerBuffer *out, SpaAudioMixerPort *port)
|
||||
{
|
||||
int i;
|
||||
uint8_t *op, *ip;
|
||||
size_t os, is, chunk;
|
||||
MixerBuffer *b = spa_list_first (&port->queue, MixerBuffer, link);
|
||||
|
||||
op = out->ptr;
|
||||
os = out->size;
|
||||
ip = SPA_MEMBER (b->ptr, port->queued_offset + b->outbuf->datas[0].chunk->offset, void);
|
||||
is = b->outbuf->datas[0].chunk->size - port->queued_offset;
|
||||
|
||||
chunk = SPA_MIN (os, is);
|
||||
|
||||
for (i = 0; i < chunk; i++)
|
||||
op[i] += ip[i];
|
||||
|
||||
port->queued_offset += chunk;
|
||||
port->queued_bytes -= chunk;
|
||||
|
||||
if (chunk == is) {
|
||||
spa_log_trace (this->log, "audiomixer %p: return buffer %d on port %p", this, b->outbuf->id, port);
|
||||
port->io->buffer_id = b->outbuf->id;
|
||||
spa_list_remove (&b->link);
|
||||
b->outstanding = true;
|
||||
port->queued_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_audiomixer_node_process_input (SpaNode *node)
|
||||
{
|
||||
SpaAudioMixer *this;
|
||||
uint32_t i;
|
||||
bool have_error = false;
|
||||
SpaPortOutput *output;
|
||||
SpaAudioMixerPort *outport;
|
||||
size_t min_queued = -1;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS);
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaAudioMixer, node);
|
||||
|
||||
if ((output = this->out_ports[0].io) == NULL)
|
||||
return SPA_RESULT_OK;
|
||||
if (this->state == STATE_OUT)
|
||||
return SPA_RESULT_HAVE_OUTPUT;
|
||||
|
||||
this->port_queued = 0;
|
||||
outport = &this->out_ports[0];
|
||||
spa_return_val_if_fail (outport->io != NULL, SPA_RESULT_ERROR);
|
||||
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
SpaAudioMixerPort *port = &this->in_ports[i];
|
||||
SpaPortInput *input;
|
||||
SpaPortIO *input;
|
||||
|
||||
if ((input = port->io) == NULL)
|
||||
if (!port->valid || (input = port->io) == NULL)
|
||||
continue;
|
||||
|
||||
if (input->buffer_id >= port->n_buffers) {
|
||||
input->status = SPA_RESULT_INVALID_BUFFER_ID;
|
||||
have_error = true;
|
||||
continue;
|
||||
}
|
||||
if (port->buffer == NULL) {
|
||||
port->buffer = port->buffers[input->buffer_id];
|
||||
if (input->buffer_id != SPA_ID_INVALID) {
|
||||
MixerBuffer *b = &port->buffers[input->buffer_id];
|
||||
|
||||
if (spa_list_is_empty (&port->queue)) {
|
||||
port->queued_bytes = 0;
|
||||
port->queued_offset = 0;
|
||||
}
|
||||
spa_log_trace (this->log, "audiomixer %p: queue buffer %d on port %p", this, b->outbuf->id, port);
|
||||
spa_list_insert (port->queue.prev, &b->link);
|
||||
b->outstanding = false;
|
||||
port->queued_bytes += b->size;
|
||||
input->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
if (min_queued == -1 || port->queued_bytes < min_queued)
|
||||
min_queued = port->queued_bytes;
|
||||
|
||||
input->status = SPA_RESULT_OK;
|
||||
this->port_queued++;
|
||||
}
|
||||
if (have_error)
|
||||
return SPA_RESULT_ERROR;
|
||||
|
||||
return this->port_queued == this->port_count ? SPA_RESULT_HAVE_OUTPUT : SPA_RESULT_OK;
|
||||
}
|
||||
if (min_queued != -1) {
|
||||
MixerBuffer *outbuf;
|
||||
SpaPortIO *output;
|
||||
|
||||
static void
|
||||
add_port_data (SpaAudioMixer *this, SpaBuffer *out, SpaAudioMixerPort *port)
|
||||
{
|
||||
int i, oi = 0;
|
||||
uint8_t *op, *ip;
|
||||
size_t os, is, chunk;
|
||||
SpaData *odatas = out->datas;
|
||||
SpaData *idatas = port->buffer->datas;
|
||||
if (spa_list_is_empty (&outport->queue))
|
||||
return SPA_RESULT_OUT_OF_BUFFERS;
|
||||
|
||||
op = ip = NULL;
|
||||
outbuf = spa_list_first (&outport->queue, MixerBuffer, link);
|
||||
spa_list_remove (&outbuf->link);
|
||||
spa_log_trace (this->log, "audiomixer %p: dequeue output buffer %d", this, outbuf->outbuf->id);
|
||||
outbuf->outstanding = true;
|
||||
|
||||
while (true) {
|
||||
if (op == NULL) {
|
||||
op = (uint8_t*)odatas[oi].data + odatas[oi].chunk->offset;
|
||||
os = odatas[oi].chunk->size;
|
||||
}
|
||||
if (ip == NULL) {
|
||||
ip = (uint8_t*)idatas[port->buffer_index].data + idatas[port->buffer_index].chunk->offset;
|
||||
is = idatas[port->buffer_index].chunk->size;
|
||||
ip += port->buffer_offset;
|
||||
is -= port->buffer_offset;
|
||||
}
|
||||
|
||||
chunk = os < is ? os : is;
|
||||
|
||||
for (i = 0; i < chunk; i++)
|
||||
op[i] += ip[i];
|
||||
|
||||
if ((is -= chunk) == 0) {
|
||||
if (++port->buffer_index == port->buffer->n_datas) {
|
||||
port->buffer = NULL;
|
||||
break;
|
||||
}
|
||||
port->buffer_offset = 0;
|
||||
ip = NULL;
|
||||
} else {
|
||||
port->buffer_offset += chunk;
|
||||
}
|
||||
port->buffer_queued -= chunk;
|
||||
|
||||
if ((os -= chunk) == 0) {
|
||||
if (++oi == out->n_datas)
|
||||
break;
|
||||
op = NULL;
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
SpaAudioMixerPort *port = &this->in_ports[i];
|
||||
|
||||
if (!port->valid || port->io == NULL ||
|
||||
spa_list_is_empty (&port->queue))
|
||||
continue;
|
||||
|
||||
add_port_data (this, outbuf, port);
|
||||
}
|
||||
output = outport->io;
|
||||
output->buffer_id = outbuf->outbuf->id;
|
||||
output->state = SPA_RESULT_OK;
|
||||
this->state = STATE_OUT;
|
||||
}
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
mix_data (SpaAudioMixer *this, SpaPortOutput *output)
|
||||
{
|
||||
int i, min_size, min_port;
|
||||
SpaBuffer *buf;
|
||||
|
||||
min_size = 0;
|
||||
min_port = 0;
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
if (!this->in_ports[i].valid)
|
||||
continue;
|
||||
|
||||
if (this->in_ports[i].buffer == NULL)
|
||||
return SPA_RESULT_NEED_INPUT;
|
||||
|
||||
if (min_size == 0 || this->in_ports[i].buffer_queued < min_size) {
|
||||
min_size = this->in_ports[i].buffer_queued;
|
||||
min_port = i;
|
||||
}
|
||||
}
|
||||
if (min_port == 0)
|
||||
return SPA_RESULT_NEED_INPUT;
|
||||
|
||||
buf = this->in_ports[min_port].buffer;
|
||||
output->buffer_id = buf->id;
|
||||
this->in_ports[min_port].buffer = NULL;
|
||||
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
if (!this->in_ports[i].valid || this->in_ports[i].buffer == NULL)
|
||||
continue;
|
||||
|
||||
add_port_data (this, buf, &this->in_ports[i]);
|
||||
}
|
||||
return SPA_RESULT_OK;
|
||||
return this->state == STATE_IN ? SPA_RESULT_NEED_INPUT : SPA_RESULT_HAVE_OUTPUT;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
|
|
@ -610,24 +641,39 @@ spa_audiomixer_node_process_output (SpaNode *node)
|
|||
{
|
||||
SpaAudioMixer *this;
|
||||
SpaAudioMixerPort *port;
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *output;
|
||||
int i;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS);
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaAudioMixer, node);
|
||||
|
||||
port = &this->out_ports[0];
|
||||
if ((output = port->io) == NULL)
|
||||
return SPA_RESULT_ERROR;
|
||||
spa_return_val_if_fail (port->io != NULL, SPA_RESULT_ERROR);
|
||||
output = port->io;
|
||||
|
||||
if (!port->have_format)
|
||||
return SPA_RESULT_NO_FORMAT;
|
||||
spa_return_val_if_fail (port->have_format, SPA_RESULT_NO_FORMAT);
|
||||
|
||||
if ((output->status = mix_data (this, output)) < 0)
|
||||
return SPA_RESULT_ERROR;
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
SpaPortIO *input;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
if (!this->in_ports[i].valid || (input = this->in_ports[i].io) == NULL)
|
||||
continue;
|
||||
|
||||
input->flags = output->flags;
|
||||
input->range = output->range;
|
||||
}
|
||||
if (output->buffer_id != SPA_ID_INVALID) {
|
||||
MixerBuffer *b = &port->buffers[output->buffer_id];
|
||||
if (b->outstanding) {
|
||||
spa_list_insert (port->queue.prev, &b->link);
|
||||
b->outstanding = false;
|
||||
spa_log_trace (this->log, "audiomixer %p: recycle buffer %d", this, b->outbuf->id);
|
||||
}
|
||||
output->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
this->state = STATE_IN;
|
||||
return SPA_RESULT_NEED_INPUT;
|
||||
}
|
||||
|
||||
static const SpaNode audiomixer_node = {
|
||||
|
|
@ -650,8 +696,7 @@ static const SpaNode audiomixer_node = {
|
|||
spa_audiomixer_node_port_set_props,
|
||||
spa_audiomixer_node_port_use_buffers,
|
||||
spa_audiomixer_node_port_alloc_buffers,
|
||||
spa_audiomixer_node_port_set_input,
|
||||
spa_audiomixer_node_port_set_output,
|
||||
spa_audiomixer_node_port_set_io,
|
||||
spa_audiomixer_node_port_reuse_buffer,
|
||||
spa_audiomixer_node_port_send_command,
|
||||
spa_audiomixer_node_process_input,
|
||||
|
|
@ -717,9 +762,10 @@ spa_audiomixer_init (const SpaHandleFactory *factory,
|
|||
this->node = audiomixer_node;
|
||||
|
||||
this->out_ports[0].valid = true;
|
||||
this->out_ports[0].info.flags = SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS |
|
||||
SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS |
|
||||
this->out_ports[0].info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS |
|
||||
SPA_PORT_INFO_FLAG_NO_REF;
|
||||
spa_list_init (&this->out_ports[0].queue);
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ struct _SpaAudioTestSrc {
|
|||
SpaPortInfo info;
|
||||
SpaAllocParam *params[2];
|
||||
uint8_t params_buffer[1024];
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *io;
|
||||
|
||||
bool have_format;
|
||||
SpaAudioInfo current_format;
|
||||
|
|
@ -275,23 +275,20 @@ set_timer (SpaAudioTestSrc *this, bool enabled)
|
|||
timerfd_settime (this->timer_source.fd, TFD_TIMER_ABSTIME, &this->timerspec, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
audiotestsrc_on_output (SpaSource *source)
|
||||
static SpaResult
|
||||
audiotestsrc_make_buffer (SpaAudioTestSrc *this)
|
||||
{
|
||||
SpaAudioTestSrc *this = source->data;
|
||||
ATSBuffer *b;
|
||||
SpaPortOutput *output;
|
||||
uint64_t expirations;
|
||||
|
||||
if (read (this->timer_source.fd, &expirations, sizeof (uint64_t)) < sizeof (uint64_t))
|
||||
perror ("read timerfd");
|
||||
SpaPortIO *io;
|
||||
|
||||
if (spa_list_is_empty (&this->empty)) {
|
||||
set_timer (this, false);
|
||||
return;
|
||||
return SPA_RESULT_OUT_OF_BUFFERS;
|
||||
}
|
||||
b = spa_list_first (&this->empty, ATSBuffer, link);
|
||||
spa_list_remove (&b->link);
|
||||
b->outstanding = true;
|
||||
spa_log_trace (this->log, "audiotestsrc %p: dequeue buffer %d", this, b->outbuf->id);
|
||||
|
||||
fill_buffer (this, b);
|
||||
|
||||
|
|
@ -305,12 +302,25 @@ audiotestsrc_on_output (SpaSource *source)
|
|||
this->elapsed_time = SAMPLES_TO_TIME (this, this->sample_count);
|
||||
set_timer (this, true);
|
||||
|
||||
if ((output = this->output)) {
|
||||
b->outstanding = true;
|
||||
output->buffer_id = b->outbuf->id;
|
||||
output->status = SPA_RESULT_OK;
|
||||
send_have_output (this);
|
||||
if ((io = this->io)) {
|
||||
io->buffer_id = b->outbuf->id;
|
||||
io->status = SPA_RESULT_OK;
|
||||
}
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
audiotestsrc_on_output (SpaSource *source)
|
||||
{
|
||||
SpaAudioTestSrc *this = source->data;
|
||||
uint64_t expirations;
|
||||
|
||||
if (read (this->timer_source.fd, &expirations, sizeof (uint64_t)) < sizeof (uint64_t))
|
||||
perror ("read timerfd");
|
||||
|
||||
audiotestsrc_make_buffer (this);
|
||||
|
||||
send_have_output (this);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -684,7 +694,7 @@ spa_audiotestsrc_node_port_use_buffers (SpaNode *node,
|
|||
|
||||
b = &this->buffers[i];
|
||||
b->outbuf = buffers[i];
|
||||
b->outstanding = true;
|
||||
b->outstanding = false;
|
||||
b->h = spa_buffer_find_meta (buffers[i], SPA_META_TYPE_HEADER);
|
||||
|
||||
switch (d[0].type) {
|
||||
|
|
@ -740,29 +750,20 @@ spa_audiotestsrc_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_audiotestsrc_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_audiotestsrc_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
spa_audiotestsrc_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaAudioTestSrc *this;
|
||||
|
||||
if (node == NULL || output == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS);
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaAudioTestSrc, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
spa_return_val_if_fail (CHECK_PORT (this, direction, port_id), SPA_RESULT_INVALID_PORT);
|
||||
|
||||
this->output = output;
|
||||
this->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -775,23 +776,18 @@ spa_audiotestsrc_node_port_reuse_buffer (SpaNode *node,
|
|||
SpaAudioTestSrc *this;
|
||||
ATSBuffer *b;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS);
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaAudioTestSrc, node);
|
||||
|
||||
if (port_id != 0)
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
if (this->n_buffers == 0)
|
||||
return SPA_RESULT_NO_BUFFERS;
|
||||
|
||||
if (buffer_id >= this->n_buffers)
|
||||
return SPA_RESULT_INVALID_BUFFER_ID;
|
||||
spa_return_val_if_fail (port_id == 0, SPA_RESULT_INVALID_PORT);
|
||||
spa_return_val_if_fail (this->n_buffers > 0, SPA_RESULT_NO_BUFFERS);
|
||||
spa_return_val_if_fail (buffer_id < this->n_buffers, SPA_RESULT_INVALID_BUFFER_ID);
|
||||
|
||||
b = &this->buffers[buffer_id];
|
||||
if (!b->outstanding)
|
||||
return SPA_RESULT_OK;
|
||||
spa_return_val_if_fail (b->outstanding, SPA_RESULT_INVALID_BUFFER_ID);
|
||||
|
||||
spa_log_trace (this->log, "audiotestsrc %p: reuse buffer %d", this, b->outbuf->id);
|
||||
|
||||
b->outstanding = false;
|
||||
spa_list_insert (this->empty.prev, &b->link);
|
||||
|
|
@ -820,7 +816,29 @@ spa_audiotestsrc_node_process_input (SpaNode *node)
|
|||
static SpaResult
|
||||
spa_audiotestsrc_node_process_output (SpaNode *node)
|
||||
{
|
||||
return SPA_RESULT_OK;
|
||||
SpaResult res;
|
||||
SpaAudioTestSrc *this;
|
||||
ATSBuffer *b;
|
||||
|
||||
spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS);
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaAudioTestSrc, node);
|
||||
|
||||
if (this->io && this->io->buffer_id != SPA_ID_INVALID) {
|
||||
b = &this->buffers[this->io->buffer_id];
|
||||
if (b->outstanding) {
|
||||
b->outstanding = false;
|
||||
spa_log_trace (this->log, "audiotestsrc %p: recycle buffer %d", this, b->outbuf->id);
|
||||
spa_list_insert (this->empty.prev, &b->link);
|
||||
if (!this->props.live)
|
||||
set_timer (this, true);
|
||||
}
|
||||
this->io->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
if ((res = audiotestsrc_make_buffer (this)) < 0)
|
||||
return res;
|
||||
|
||||
return SPA_RESULT_HAVE_OUTPUT;
|
||||
}
|
||||
|
||||
static const SpaNode audiotestsrc_node = {
|
||||
|
|
@ -843,8 +861,7 @@ static const SpaNode audiotestsrc_node = {
|
|||
spa_audiotestsrc_node_port_set_props,
|
||||
spa_audiotestsrc_node_port_use_buffers,
|
||||
spa_audiotestsrc_node_port_alloc_buffers,
|
||||
spa_audiotestsrc_node_port_set_input,
|
||||
spa_audiotestsrc_node_port_set_output,
|
||||
spa_audiotestsrc_node_port_set_io,
|
||||
spa_audiotestsrc_node_port_reuse_buffer,
|
||||
spa_audiotestsrc_node_port_send_command,
|
||||
spa_audiotestsrc_node_process_input,
|
||||
|
|
|
|||
|
|
@ -373,41 +373,24 @@ spa_ffmpeg_dec_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_ffmpeg_dec_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
spa_ffmpeg_dec_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaFFMpegDec *this;
|
||||
SpaFFMpegPort *port;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaFFMpegDec, node);
|
||||
|
||||
if (!IS_VALID_PORT (this, SPA_DIRECTION_INPUT, port_id))
|
||||
if (!IS_VALID_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->in_ports[port_id].io = input;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_ffmpeg_dec_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
{
|
||||
SpaFFMpegDec *this;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaFFMpegDec, node);
|
||||
|
||||
if (!IS_VALID_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->out_ports[port_id].io = output;
|
||||
port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id];
|
||||
port->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -423,7 +406,7 @@ spa_ffmpeg_dec_node_process_output (SpaNode *node)
|
|||
{
|
||||
SpaFFMpegDec *this;
|
||||
SpaFFMpegPort *port;
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *output;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
|
@ -488,8 +471,7 @@ static const SpaNode ffmpeg_dec_node = {
|
|||
spa_ffmpeg_dec_node_port_set_props,
|
||||
spa_ffmpeg_dec_node_port_use_buffers,
|
||||
spa_ffmpeg_dec_node_port_alloc_buffers,
|
||||
spa_ffmpeg_dec_node_port_set_input,
|
||||
spa_ffmpeg_dec_node_port_set_output,
|
||||
spa_ffmpeg_dec_node_port_set_io,
|
||||
spa_ffmpeg_dec_node_port_reuse_buffer,
|
||||
spa_ffmpeg_dec_node_port_send_command,
|
||||
spa_ffmpeg_dec_node_process_input,
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ typedef struct {
|
|||
bool have_buffers;
|
||||
FFMpegBuffer buffers[MAX_BUFFERS];
|
||||
SpaPortInfo info;
|
||||
void *io;
|
||||
SpaPortIO *io;
|
||||
} SpaFFMpegPort;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -381,41 +381,24 @@ spa_ffmpeg_enc_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_ffmpeg_enc_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
spa_ffmpeg_enc_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaFFMpegEnc *this;
|
||||
SpaFFMpegPort *port;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaFFMpegEnc, node);
|
||||
|
||||
if (!IS_VALID_PORT (this, SPA_DIRECTION_INPUT, port_id))
|
||||
if (!IS_VALID_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->in_ports[port_id].io = input;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_ffmpeg_enc_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
{
|
||||
SpaFFMpegEnc *this;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaFFMpegEnc, node);
|
||||
|
||||
if (!IS_VALID_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->out_ports[port_id].io = output;
|
||||
port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id];
|
||||
port->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -454,7 +437,7 @@ spa_ffmpeg_enc_node_process_output (SpaNode *node)
|
|||
{
|
||||
SpaFFMpegEnc *this;
|
||||
SpaFFMpegPort *port;
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *output;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
|
@ -495,8 +478,7 @@ static const SpaNode ffmpeg_enc_node = {
|
|||
spa_ffmpeg_enc_node_port_set_props,
|
||||
spa_ffmpeg_enc_node_port_use_buffers,
|
||||
spa_ffmpeg_enc_node_port_alloc_buffers,
|
||||
spa_ffmpeg_enc_node_port_set_input,
|
||||
spa_ffmpeg_enc_node_port_set_output,
|
||||
spa_ffmpeg_enc_node_port_set_io,
|
||||
spa_ffmpeg_enc_node_port_reuse_buffer,
|
||||
spa_ffmpeg_enc_node_port_send_command,
|
||||
spa_ffmpeg_enc_node_process_input,
|
||||
|
|
|
|||
|
|
@ -528,12 +528,16 @@ spa_v4l2_source_node_port_set_format (SpaNode *node,
|
|||
info.media_type = SPA_FORMAT_MEDIA_TYPE (format);
|
||||
info.media_subtype = SPA_FORMAT_MEDIA_SUBTYPE (format);
|
||||
|
||||
if (info.media_type != this->type.media_type.video)
|
||||
if (info.media_type != this->type.media_type.video) {
|
||||
spa_log_error (this->log, "media type must be video");
|
||||
return SPA_RESULT_INVALID_MEDIA_TYPE;
|
||||
}
|
||||
|
||||
if (info.media_subtype == this->type.media_subtype.raw) {
|
||||
if (!spa_format_video_raw_parse (format, &info.info.raw, &this->type.format_video))
|
||||
if (!spa_format_video_raw_parse (format, &info.info.raw, &this->type.format_video)) {
|
||||
spa_log_error (this->log, "can't parse video raw");
|
||||
return SPA_RESULT_INVALID_MEDIA_TYPE;
|
||||
}
|
||||
|
||||
if (state->have_format && info.media_type == state->current_format.media_type &&
|
||||
info.media_subtype == state->current_format.media_subtype &&
|
||||
|
|
@ -761,17 +765,10 @@ spa_v4l2_source_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_v4l2_source_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_v4l2_source_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
spa_v4l2_source_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaV4l2Source *this;
|
||||
|
||||
|
|
@ -780,15 +777,14 @@ spa_v4l2_source_node_port_set_output (SpaNode *node,
|
|||
|
||||
this = SPA_CONTAINER_OF (node, SpaV4l2Source, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
if (!CHECK_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->state[port_id].io = output;
|
||||
this->state[port_id].io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
|
||||
static SpaResult
|
||||
spa_v4l2_source_node_port_reuse_buffer (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
|
|
@ -834,7 +830,8 @@ spa_v4l2_source_node_port_send_command (SpaNode *node,
|
|||
}
|
||||
else if (SPA_COMMAND_TYPE (command) == this->type.command_node.Start) {
|
||||
res = spa_v4l2_port_set_enabled (this, true);
|
||||
} else
|
||||
}
|
||||
else
|
||||
res = SPA_RESULT_NOT_IMPLEMENTED;
|
||||
|
||||
return res;
|
||||
|
|
@ -849,7 +846,22 @@ spa_v4l2_source_node_process_input (SpaNode *node)
|
|||
static SpaResult
|
||||
spa_v4l2_source_node_process_output (SpaNode *node)
|
||||
{
|
||||
return SPA_RESULT_OK;
|
||||
SpaV4l2Source *this;
|
||||
SpaResult res = SPA_RESULT_OK;
|
||||
SpaPortIO *io;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaV4l2Source, node);
|
||||
|
||||
if ((io = this->state[0].io)) {
|
||||
if (io->buffer_id != SPA_ID_INVALID) {
|
||||
res = spa_v4l2_buffer_recycle (this, io->buffer_id);
|
||||
io->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static const SpaNode v4l2source_node = {
|
||||
|
|
@ -872,8 +884,7 @@ static const SpaNode v4l2source_node = {
|
|||
spa_v4l2_source_node_port_set_props,
|
||||
spa_v4l2_source_node_port_use_buffers,
|
||||
spa_v4l2_source_node_port_alloc_buffers,
|
||||
spa_v4l2_source_node_port_set_input,
|
||||
spa_v4l2_source_node_port_set_output,
|
||||
spa_v4l2_source_node_port_set_io,
|
||||
spa_v4l2_source_node_port_reuse_buffer,
|
||||
spa_v4l2_source_node_port_send_command,
|
||||
spa_v4l2_source_node_process_input,
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ spa_v4l2_buffer_recycle (SpaV4l2Source *this, uint32_t buffer_id)
|
|||
return SPA_RESULT_OK;
|
||||
|
||||
b->outstanding = false;
|
||||
spa_log_trace (state->log, "v4l2 %p: recycle buffer %d", this, buffer_id);
|
||||
|
||||
if (xioctl (state->fd, VIDIOC_QBUF, &b->v4l2_buffer) < 0) {
|
||||
perror ("VIDIOC_QBUF");
|
||||
|
|
@ -916,7 +917,7 @@ mmap_read (SpaV4l2Source *this)
|
|||
V4l2Buffer *b;
|
||||
SpaData *d;
|
||||
int64_t pts;
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *io;
|
||||
|
||||
CLEAR(buf);
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
|
|
@ -955,10 +956,14 @@ mmap_read (SpaV4l2Source *this)
|
|||
d[0].chunk->size = buf.bytesused;
|
||||
d[0].chunk->stride = state->fmt.fmt.pix.bytesperline;
|
||||
|
||||
if ((output = state->io)) {
|
||||
if ((io = state->io)) {
|
||||
SpaEvent event = SPA_EVENT_INIT (this->type.event_node.HaveOutput);
|
||||
|
||||
b->outstanding = true;
|
||||
output->buffer_id = b->outbuf->id;
|
||||
output->status = SPA_RESULT_OK;
|
||||
io->buffer_id = b->outbuf->id;
|
||||
io->status = SPA_RESULT_OK;
|
||||
|
||||
this->event_cb (&this->node, &event, this->user_data);
|
||||
}
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -976,11 +981,6 @@ v4l2_on_fd_events (SpaSource *source)
|
|||
|
||||
if (mmap_read (this) < 0)
|
||||
return;
|
||||
|
||||
{
|
||||
SpaEvent event = SPA_EVENT_INIT (this->type.event_node.HaveOutput);
|
||||
this->event_cb (&this->node, &event, this->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ struct _SpaVideoTestSrc {
|
|||
SpaAllocParam *params[2];
|
||||
uint8_t params_buffer[1024];
|
||||
int stride;
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *io;
|
||||
|
||||
bool have_format;
|
||||
SpaVideoInfo current_format;
|
||||
|
|
@ -261,7 +261,7 @@ videotestsrc_on_output (SpaSource *source)
|
|||
{
|
||||
SpaVideoTestSrc *this = source->data;
|
||||
VTSBuffer *b;
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *io;
|
||||
uint64_t expirations;
|
||||
|
||||
if (read (this->timer_source.fd, &expirations, sizeof (uint64_t)) < sizeof (uint64_t))
|
||||
|
|
@ -286,10 +286,10 @@ videotestsrc_on_output (SpaSource *source)
|
|||
this->elapsed_time = FRAMES_TO_TIME (this, this->frame_count);
|
||||
set_timer (this, true);
|
||||
|
||||
if ((output = this->output)) {
|
||||
if ((io = this->io)) {
|
||||
b->outstanding = true;
|
||||
output->buffer_id = b->outbuf->id;
|
||||
output->status = SPA_RESULT_OK;
|
||||
io->buffer_id = b->outbuf->id;
|
||||
io->status = SPA_RESULT_OK;
|
||||
send_have_output (this);
|
||||
}
|
||||
}
|
||||
|
|
@ -684,7 +684,7 @@ spa_videotestsrc_node_port_use_buffers (SpaNode *node,
|
|||
|
||||
b = &this->buffers[i];
|
||||
b->outbuf = buffers[i];
|
||||
b->outstanding = true;
|
||||
b->outstanding = false;
|
||||
b->h = spa_buffer_find_meta (buffers[i], SPA_META_TYPE_HEADER);
|
||||
|
||||
switch (d[0].type) {
|
||||
|
|
@ -740,17 +740,10 @@ spa_videotestsrc_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_videotestsrc_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_videotestsrc_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
spa_videotestsrc_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaVideoTestSrc *this;
|
||||
|
||||
|
|
@ -759,10 +752,10 @@ spa_videotestsrc_node_port_set_output (SpaNode *node,
|
|||
|
||||
this = SPA_CONTAINER_OF (node, SpaVideoTestSrc, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
if (!CHECK_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->output = output;
|
||||
this->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -814,12 +807,30 @@ spa_videotestsrc_node_port_send_command (SpaNode *node,
|
|||
static SpaResult
|
||||
spa_videotestsrc_node_process_input (SpaNode *node)
|
||||
{
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_videotestsrc_node_process_output (SpaNode *node)
|
||||
{
|
||||
SpaVideoTestSrc *this;
|
||||
VTSBuffer *b;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaVideoTestSrc, node);
|
||||
|
||||
if (this->io && this->io->buffer_id != SPA_ID_INVALID) {
|
||||
b = &this->buffers[this->io->buffer_id];
|
||||
if (b->outstanding) {
|
||||
b->outstanding = false;
|
||||
spa_list_insert (this->empty.prev, &b->link);
|
||||
if (!this->props.live)
|
||||
set_timer (this, true);
|
||||
}
|
||||
this->io->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
|
|
@ -843,8 +854,7 @@ static const SpaNode videotestsrc_node = {
|
|||
spa_videotestsrc_node_port_set_props,
|
||||
spa_videotestsrc_node_port_use_buffers,
|
||||
spa_videotestsrc_node_port_alloc_buffers,
|
||||
spa_videotestsrc_node_port_set_input,
|
||||
spa_videotestsrc_node_port_set_output,
|
||||
spa_videotestsrc_node_port_set_io,
|
||||
spa_videotestsrc_node_port_reuse_buffer,
|
||||
spa_videotestsrc_node_port_send_command,
|
||||
spa_videotestsrc_node_process_input,
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ typedef struct {
|
|||
|
||||
SpaVolumeBuffer buffers[MAX_BUFFERS];
|
||||
uint32_t n_buffers;
|
||||
|
||||
void *io;
|
||||
|
||||
SpaList empty;
|
||||
|
|
@ -565,41 +564,24 @@ spa_volume_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_volume_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
spa_volume_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaVolume *this;
|
||||
SpaVolumePort *port;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaVolume, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_INPUT, port_id))
|
||||
if (!CHECK_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->in_ports[port_id].io = input;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_volume_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
{
|
||||
SpaVolume *this;
|
||||
|
||||
if (node == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
||||
this = SPA_CONTAINER_OF (node, SpaVolume, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_OUTPUT, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->in_ports[port_id].io = output;
|
||||
port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id];
|
||||
port->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -718,8 +700,8 @@ static SpaResult
|
|||
spa_volume_node_process_input (SpaNode *node)
|
||||
{
|
||||
SpaVolume *this;
|
||||
SpaPortInput *input;
|
||||
SpaPortOutput *output;
|
||||
SpaPortIO *input;
|
||||
SpaPortIO *output;
|
||||
SpaVolumePort *in_port, *out_port;
|
||||
SpaBuffer *dbuf, *sbuf;
|
||||
|
||||
|
|
@ -795,8 +777,7 @@ static const SpaNode volume_node = {
|
|||
spa_volume_node_port_set_props,
|
||||
spa_volume_node_port_use_buffers,
|
||||
spa_volume_node_port_alloc_buffers,
|
||||
spa_volume_node_port_set_input,
|
||||
spa_volume_node_port_set_output,
|
||||
spa_volume_node_port_set_io,
|
||||
spa_volume_node_port_reuse_buffer,
|
||||
spa_volume_node_port_send_command,
|
||||
spa_volume_node_process_input,
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ struct _SpaXvSink {
|
|||
SpaPortInfo info;
|
||||
SpaXvState state;
|
||||
|
||||
SpaPortInput *input;
|
||||
SpaPortIO *io;
|
||||
};
|
||||
|
||||
#define CHECK_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) == 0)
|
||||
|
|
@ -437,9 +437,10 @@ spa_xv_sink_node_port_alloc_buffers (SpaNode *node,
|
|||
}
|
||||
|
||||
static SpaResult
|
||||
spa_xv_sink_node_port_set_input (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortInput *input)
|
||||
spa_xv_sink_node_port_set_io (SpaNode *node,
|
||||
SpaDirection direction,
|
||||
uint32_t port_id,
|
||||
SpaPortIO *io)
|
||||
{
|
||||
SpaXvSink *this;
|
||||
|
||||
|
|
@ -448,22 +449,14 @@ spa_xv_sink_node_port_set_input (SpaNode *node,
|
|||
|
||||
this = SPA_CONTAINER_OF (node, SpaXvSink, node);
|
||||
|
||||
if (!CHECK_PORT (this, SPA_DIRECTION_INPUT, port_id))
|
||||
if (!CHECK_PORT (this, direction, port_id))
|
||||
return SPA_RESULT_INVALID_PORT;
|
||||
|
||||
this->input = input;
|
||||
this->io = io;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_xv_sink_node_port_set_output (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
SpaPortOutput *output)
|
||||
{
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
spa_xv_sink_node_port_reuse_buffer (SpaNode *node,
|
||||
uint32_t port_id,
|
||||
|
|
@ -513,8 +506,7 @@ static const SpaNode xvsink_node = {
|
|||
spa_xv_sink_node_port_set_props,
|
||||
spa_xv_sink_node_port_use_buffers,
|
||||
spa_xv_sink_node_port_alloc_buffers,
|
||||
spa_xv_sink_node_port_set_input,
|
||||
spa_xv_sink_node_port_set_output,
|
||||
spa_xv_sink_node_port_set_io,
|
||||
spa_xv_sink_node_port_reuse_buffer,
|
||||
spa_xv_sink_node_port_send_command,
|
||||
spa_xv_sink_node_process_input,
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ executable('test-mixer', 'test-mixer.c',
|
|||
link_with : spalib,
|
||||
install : false)
|
||||
|
||||
#executable('test-v4l2', 'test-v4l2.c',
|
||||
# include_directories : [spa_inc, spa_libinc ],
|
||||
# dependencies : [dl_lib, sdl_dep, pthread_lib],
|
||||
# link_with : spalib,
|
||||
# install : false)
|
||||
executable('test-v4l2', 'test-v4l2.c',
|
||||
include_directories : [spa_inc, spa_libinc ],
|
||||
dependencies : [dl_lib, sdl_dep, pthread_lib],
|
||||
link_with : spalib,
|
||||
install : false)
|
||||
executable('test-props', 'test-props.c',
|
||||
include_directories : [spa_inc, spa_libinc ],
|
||||
dependencies : [],
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <spa/format-utils.h>
|
||||
#include <spa/format-builder.h>
|
||||
#include <lib/mapper.h>
|
||||
#include <lib/debug.h>
|
||||
#include <lib/props.h>
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -64,28 +65,40 @@ init_type (Type *type, SpaTypeMap *map)
|
|||
spa_type_command_node_map (map, &type->command_node);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
SpaBuffer buffer;
|
||||
SpaMeta metas[1];
|
||||
SpaMetaHeader header;
|
||||
SpaData datas[1];
|
||||
SpaChunk chunks[1];
|
||||
} Buffer;
|
||||
|
||||
typedef struct {
|
||||
SpaTypeMap *map;
|
||||
SpaLog *log;
|
||||
SpaLoop data_loop;
|
||||
Type type;
|
||||
|
||||
SpaSupport support[2];
|
||||
SpaSupport support[4];
|
||||
uint32_t n_support;
|
||||
|
||||
SpaNode *sink;
|
||||
SpaPortInput sink_input[1];
|
||||
SpaPortIO mix_sink_io[1];
|
||||
|
||||
SpaNode *mix;
|
||||
uint32_t mix_ports[2];
|
||||
SpaPortInput mix_input[2];
|
||||
SpaPortOutput mix_output[1];
|
||||
SpaBuffer *mix_buffers[1];
|
||||
Buffer mix_buffer[1];
|
||||
|
||||
SpaNode *source1;
|
||||
SpaPortOutput source1_output[1];
|
||||
SpaPortIO source1_mix_io[1];
|
||||
SpaBuffer *source1_buffers[1];
|
||||
Buffer source1_buffer[1];
|
||||
|
||||
SpaNode *source2;
|
||||
SpaPortOutput source2_output[1];
|
||||
SpaPortIO source2_mix_io[1];
|
||||
SpaBuffer *source2_buffers[1];
|
||||
Buffer source2_buffer[1];
|
||||
|
||||
bool running;
|
||||
pthread_t thread;
|
||||
|
|
@ -98,6 +111,35 @@ typedef struct {
|
|||
unsigned int n_fds;
|
||||
} AppData;
|
||||
|
||||
static void
|
||||
init_buffer (AppData *data, Buffer *b, void *ptr, size_t size)
|
||||
{
|
||||
b->buffer.id = 0;
|
||||
b->buffer.n_metas = 1;
|
||||
b->buffer.metas = b->metas;
|
||||
b->buffer.n_datas = 1;
|
||||
b->buffer.datas = b->datas;
|
||||
|
||||
b->header.flags = 0;
|
||||
b->header.seq = 0;
|
||||
b->header.pts = 0;
|
||||
b->header.dts_offset = 0;
|
||||
b->metas[0].type = SPA_META_TYPE_HEADER;
|
||||
b->metas[0].data = &b->header;
|
||||
b->metas[0].size = sizeof (b->header);
|
||||
|
||||
b->datas[0].type = SPA_DATA_TYPE_MEMPTR;
|
||||
b->datas[0].flags = 0;
|
||||
b->datas[0].fd = -1;
|
||||
b->datas[0].mapoffset = 0;
|
||||
b->datas[0].maxsize = size;
|
||||
b->datas[0].data = ptr;
|
||||
b->datas[0].chunk = &b->chunks[0];
|
||||
b->datas[0].chunk->offset = 0;
|
||||
b->datas[0].chunk->size = size;
|
||||
b->datas[0].chunk->stride = 0;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
make_node (AppData *data, SpaNode **node, const char *lib, const char *name)
|
||||
{
|
||||
|
|
@ -144,46 +186,48 @@ make_node (AppData *data, SpaNode **node, const char *lib, const char *name)
|
|||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
|
||||
static void
|
||||
on_mix_event (SpaNode *node, SpaEvent *event, void *user_data)
|
||||
{
|
||||
/*
|
||||
AppData *data = user_data;
|
||||
|
||||
if (SPA_EVENT_TYPE (event) == data->type.event_node.NeedInput) {
|
||||
SpaPortInput pi = { 0, };
|
||||
SpaPortOutput po = { 0, };
|
||||
SpaResult res;
|
||||
SpaNodeEventNeedInput *ni = (SpaNodeEventNeedInput *) event;
|
||||
SpaNode *peer;
|
||||
|
||||
if (ni->port_id == data->mix_ports[0])
|
||||
peer = data->source1;
|
||||
else
|
||||
peer = data->source2;
|
||||
|
||||
spa_node_port_set_output (peer, 0, &po);
|
||||
if ((res = spa_node_process_output (peer)) < 0)
|
||||
printf ("got error %d\n", res);
|
||||
|
||||
pi.buffer_id = po.buffer_id;
|
||||
|
||||
spa_node_port_set_input (data->mix, ni->port_id, &pi);
|
||||
if ((res = spa_node_process_input (data->mix)) < 0)
|
||||
printf ("got error from mixer %d\n", res);
|
||||
}
|
||||
else {
|
||||
printf ("got event %d\n", SPA_EVENT_TYPE (event));
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
static void
|
||||
on_sink_event (SpaNode *node, SpaEvent *event, void *user_data)
|
||||
{
|
||||
AppData *data = user_data;
|
||||
SpaResult res;
|
||||
|
||||
if (SPA_EVENT_TYPE (event) == data->type.event_node.NeedInput) {
|
||||
|
||||
printf ("need input event\n");
|
||||
res = spa_node_process_output (data->mix);
|
||||
|
||||
if (res == SPA_RESULT_NEED_INPUT) {
|
||||
|
||||
res = spa_node_process_output (data->source1);
|
||||
|
||||
if (res != SPA_RESULT_HAVE_OUTPUT)
|
||||
printf ("got process_output error from source1 %d\n", res);
|
||||
|
||||
res = spa_node_process_output (data->source2);
|
||||
|
||||
if (res != SPA_RESULT_HAVE_OUTPUT)
|
||||
printf ("got process_output error from source2 %d\n", res);
|
||||
|
||||
res = spa_node_process_input (data->mix);
|
||||
if (res == SPA_RESULT_HAVE_OUTPUT)
|
||||
goto push;
|
||||
else
|
||||
printf ("got process_input error from mixer %d\n", res);
|
||||
|
||||
} else if (res == SPA_RESULT_HAVE_OUTPUT) {
|
||||
push:
|
||||
if ((res = spa_node_process_input (data->sink)) < 0)
|
||||
printf ("got process_input error from sink %d\n", res);
|
||||
} else {
|
||||
printf ("got process_output error from mixer %d\n", res);
|
||||
}
|
||||
}
|
||||
else if (SPA_EVENT_TYPE (event) == data->type.event_node.ReuseBuffer) {
|
||||
SpaEventNodeReuseBuffer *rb = (SpaEventNodeReuseBuffer *) event;
|
||||
|
||||
printf ("got recycle event %d\n", rb->body.buffer_id.value);
|
||||
data->mix_sink_io[0].buffer_id = rb->body.buffer_id.value;
|
||||
}
|
||||
else {
|
||||
printf ("got event %d\n", SPA_EVENT_TYPE (event));
|
||||
|
|
@ -214,6 +258,17 @@ do_remove_source (SpaSource *source)
|
|||
{
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
do_invoke (SpaLoop *loop,
|
||||
SpaInvokeFunc func,
|
||||
uint32_t seq,
|
||||
size_t size,
|
||||
void *data,
|
||||
void *user_data)
|
||||
{
|
||||
return func (loop, false, seq, size, data, user_data);
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
make_nodes (AppData *data)
|
||||
{
|
||||
|
|
@ -232,7 +287,7 @@ make_nodes (AppData *data)
|
|||
spa_pod_builder_init (&b, buffer, sizeof (buffer));
|
||||
spa_pod_builder_props (&b, &f[0], data->type.props,
|
||||
SPA_POD_PROP (&f[1], data->type.props_device, 0,
|
||||
SPA_POD_TYPE_STRING, 1, "hw:1"));
|
||||
SPA_POD_TYPE_STRING, 1, "hw:0"));
|
||||
props = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaProps);
|
||||
|
||||
if ((res = spa_node_set_props (data->sink, props)) < 0)
|
||||
|
|
@ -242,8 +297,6 @@ make_nodes (AppData *data)
|
|||
printf ("can't create audiomixer: %d\n", res);
|
||||
return res;
|
||||
}
|
||||
spa_node_set_event_callback (data->mix, on_mix_event, data);
|
||||
|
||||
if ((res = make_node (data, &data->source1, "build/spa/plugins/audiotestsrc/libspa-audiotestsrc.so", "audiotestsrc")) < 0) {
|
||||
printf ("can't create audiotestsrc: %d\n", res);
|
||||
return res;
|
||||
|
|
@ -285,22 +338,44 @@ negotiate_formats (AppData *data)
|
|||
if ((res = spa_node_port_enum_formats (data->sink, SPA_DIRECTION_INPUT, 0, &format, filter, state)) < 0)
|
||||
return res;
|
||||
|
||||
|
||||
if ((res = spa_node_port_set_format (data->sink, SPA_DIRECTION_INPUT, 0, 0, format)) < 0)
|
||||
return res;
|
||||
|
||||
spa_node_port_set_io (data->mix, SPA_DIRECTION_OUTPUT, 0, &data->mix_sink_io[0]);
|
||||
spa_node_port_set_io (data->sink, SPA_DIRECTION_INPUT, 0, &data->mix_sink_io[0]);
|
||||
|
||||
if ((res = spa_node_port_set_format (data->mix, SPA_DIRECTION_OUTPUT, 0, 0, format)) < 0)
|
||||
return res;
|
||||
|
||||
init_buffer (data, &data->mix_buffer[0], malloc (1024), 1024);
|
||||
data->mix_buffers[0] = &data->mix_buffer[0].buffer;
|
||||
if ((res = spa_node_port_use_buffers (data->sink, SPA_DIRECTION_INPUT, 0, data->mix_buffers, 1)) < 0)
|
||||
return res;
|
||||
if ((res = spa_node_port_use_buffers (data->mix, SPA_DIRECTION_OUTPUT, 0, data->mix_buffers, 1)) < 0)
|
||||
return res;
|
||||
|
||||
data->mix_ports[0] = 0;
|
||||
if ((res = spa_node_add_port (data->mix, SPA_DIRECTION_INPUT, 0)) < 0)
|
||||
return res;
|
||||
|
||||
|
||||
if ((res = spa_node_port_set_format (data->mix, SPA_DIRECTION_INPUT, data->mix_ports[0], 0, format)) < 0)
|
||||
return res;
|
||||
|
||||
spa_node_port_set_io (data->source1, SPA_DIRECTION_OUTPUT, 0, &data->source1_mix_io[0]);
|
||||
spa_node_port_set_io (data->mix, SPA_DIRECTION_INPUT, 0, &data->source1_mix_io[0]);
|
||||
|
||||
if ((res = spa_node_port_set_format (data->source1, SPA_DIRECTION_OUTPUT, 0, 0, format)) < 0)
|
||||
return res;
|
||||
|
||||
init_buffer (data, &data->source1_buffer[0], malloc (1024), 1024);
|
||||
data->source1_buffers[0] = &data->source1_buffer[0].buffer;
|
||||
if ((res = spa_node_port_use_buffers (data->mix, SPA_DIRECTION_INPUT, data->mix_ports[0], data->source1_buffers, 1)) < 0)
|
||||
return res;
|
||||
if ((res = spa_node_port_use_buffers (data->source1, SPA_DIRECTION_OUTPUT, 0, data->source1_buffers, 1)) < 0)
|
||||
return res;
|
||||
|
||||
data->mix_ports[1] = 1;
|
||||
if ((res = spa_node_add_port (data->mix, SPA_DIRECTION_INPUT, 1)) < 0)
|
||||
return res;
|
||||
|
|
@ -308,9 +383,19 @@ negotiate_formats (AppData *data)
|
|||
if ((res = spa_node_port_set_format (data->mix, SPA_DIRECTION_INPUT, data->mix_ports[1], 0, format)) < 0)
|
||||
return res;
|
||||
|
||||
spa_node_port_set_io (data->source2, SPA_DIRECTION_OUTPUT, 0, &data->source2_mix_io[0]);
|
||||
spa_node_port_set_io (data->mix, SPA_DIRECTION_INPUT, 1, &data->source2_mix_io[0]);
|
||||
|
||||
if ((res = spa_node_port_set_format (data->source2, SPA_DIRECTION_OUTPUT, 0, 0, format)) < 0)
|
||||
return res;
|
||||
|
||||
init_buffer (data, &data->source2_buffer[0], malloc (1024), 1024);
|
||||
data->source2_buffers[0] = &data->source2_buffer[0].buffer;
|
||||
if ((res = spa_node_port_use_buffers (data->mix, SPA_DIRECTION_INPUT, data->mix_ports[1], data->source2_buffers, 1)) < 0)
|
||||
return res;
|
||||
if ((res = spa_node_port_use_buffers (data->source2, SPA_DIRECTION_OUTPUT, 0, data->source2_buffers, 1)) < 0)
|
||||
return res;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
|
|
@ -348,7 +433,20 @@ loop (void *user_data)
|
|||
/* after */
|
||||
for (i = 0; i < data->n_sources; i++) {
|
||||
SpaSource *p = &data->sources[i];
|
||||
p->func (p);
|
||||
p->rmask = 0;
|
||||
if (data->fds[i].revents & POLLIN)
|
||||
p->rmask |= SPA_IO_IN;
|
||||
if (data->fds[i].revents & POLLOUT)
|
||||
p->rmask |= SPA_IO_OUT;
|
||||
if (data->fds[i].revents & POLLHUP)
|
||||
p->rmask |= SPA_IO_HUP;
|
||||
if (data->fds[i].revents & POLLERR)
|
||||
p->rmask |= SPA_IO_ERR;
|
||||
}
|
||||
for (i = 0; i < data->n_sources; i++) {
|
||||
SpaSource *p = &data->sources[i];
|
||||
if (p->rmask)
|
||||
p->func (p);
|
||||
}
|
||||
}
|
||||
printf ("leave thread\n");
|
||||
|
|
@ -396,16 +494,22 @@ main (int argc, char *argv[])
|
|||
SpaResult res;
|
||||
|
||||
data.map = spa_type_map_get_default();
|
||||
data.log = spa_log_get_default();
|
||||
data.data_loop.size = sizeof (SpaLoop);
|
||||
data.data_loop.add_source = do_add_source;
|
||||
data.data_loop.update_source = do_update_source;
|
||||
data.data_loop.remove_source = do_remove_source;
|
||||
data.data_loop.invoke = do_invoke;
|
||||
|
||||
data.support[0].type = SPA_TYPE__TypeMap;
|
||||
data.support[0].data = data.map;
|
||||
data.support[1].type = SPA_TYPE_LOOP__DataLoop;
|
||||
data.support[1].data = &data.data_loop;
|
||||
data.n_support = 2;
|
||||
data.support[1].type = SPA_TYPE__Log;
|
||||
data.support[1].data = data.log;
|
||||
data.support[2].type = SPA_TYPE_LOOP__DataLoop;
|
||||
data.support[2].data = &data.data_loop;
|
||||
data.support[3].type = SPA_TYPE_LOOP__MainLoop;
|
||||
data.support[3].data = &data.data_loop;
|
||||
data.n_support = 4;
|
||||
|
||||
init_type (&data.type, data.map);
|
||||
|
||||
|
|
|
|||
|
|
@ -28,15 +28,44 @@
|
|||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include <spa/id-map.h>
|
||||
#include <spa/type-map.h>
|
||||
#include <spa/log.h>
|
||||
#include <spa/node.h>
|
||||
#include <spa/loop.h>
|
||||
#include <spa/video/format.h>
|
||||
#include <spa/video/format-utils.h>
|
||||
#include <spa/format-builder.h>
|
||||
#include <lib/debug.h>
|
||||
#include <lib/props.h>
|
||||
#include <lib/mapper.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t node;
|
||||
uint32_t props;
|
||||
uint32_t format;
|
||||
uint32_t props_device;
|
||||
SpaTypeMediaType media_type;
|
||||
SpaTypeMediaSubtype media_subtype;
|
||||
SpaTypeFormatVideo format_video;
|
||||
SpaTypeVideoFormat video_format;
|
||||
SpaTypeEventNode event_node;
|
||||
SpaTypeCommandNode command_node;
|
||||
} Type;
|
||||
|
||||
static inline void
|
||||
init_type (Type *type, SpaTypeMap *map)
|
||||
{
|
||||
type->node = spa_type_map_get_id (map, SPA_TYPE__Node);
|
||||
type->props = spa_type_map_get_id (map, SPA_TYPE__Props);
|
||||
type->format = spa_type_map_get_id (map, SPA_TYPE__Format);
|
||||
type->props_device = spa_type_map_get_id (map, SPA_TYPE_PROPS__device);
|
||||
spa_type_media_type_map (map, &type->media_type);
|
||||
spa_type_media_subtype_map (map, &type->media_subtype);
|
||||
spa_type_format_video_map (map, &type->format_video);
|
||||
spa_type_video_format_map (map, &type->video_format);
|
||||
spa_type_event_node_map (map, &type->event_node);
|
||||
spa_type_command_node_map (map, &type->command_node);
|
||||
}
|
||||
|
||||
#define MAX_BUFFERS 8
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -45,14 +74,21 @@ typedef struct {
|
|||
SpaMetaHeader header;
|
||||
SpaMetaPointer ptr;
|
||||
SpaData datas[1];
|
||||
SpaChunk chunks[1];
|
||||
} SDLBuffer;
|
||||
|
||||
typedef struct {
|
||||
uint32_t node;
|
||||
} Type;
|
||||
Type type;
|
||||
|
||||
SpaTypeMap *map;
|
||||
SpaLog *log;
|
||||
SpaLoop data_loop;
|
||||
|
||||
SpaSupport support[4];
|
||||
uint32_t n_support;
|
||||
|
||||
typedef struct {
|
||||
SpaNode *source;
|
||||
SpaPortIO source_output[1];
|
||||
|
||||
SDL_Renderer *renderer;
|
||||
SDL_Window *window;
|
||||
|
|
@ -62,20 +98,17 @@ typedef struct {
|
|||
|
||||
bool running;
|
||||
pthread_t thread;
|
||||
SpaPollFd fds[16];
|
||||
|
||||
SpaSource sources[16];
|
||||
unsigned int n_sources;
|
||||
|
||||
bool rebuild_fds;
|
||||
struct pollfd fds[16];
|
||||
unsigned int n_fds;
|
||||
SpaPollItem poll;
|
||||
|
||||
SpaBuffer *bp[MAX_BUFFERS];
|
||||
SDLBuffer buffers[MAX_BUFFERS];
|
||||
unsigned int n_buffers;
|
||||
|
||||
SpaSupport support[2];
|
||||
uint32_t n_support;
|
||||
SpaTypeMap *map;
|
||||
SpaLog *log;
|
||||
SpaPoll data_loop;
|
||||
Type type;
|
||||
} AppData;
|
||||
|
||||
static SpaResult
|
||||
|
|
@ -86,7 +119,7 @@ make_node (AppData *data, SpaNode **node, const char *lib, const char *name)
|
|||
void *hnd;
|
||||
SpaEnumHandleFactoryFunc enum_func;
|
||||
unsigned int i;
|
||||
void *state = NULL;
|
||||
uint32_t state = 0;
|
||||
|
||||
if ((hnd = dlopen (lib, RTLD_NOW)) == NULL) {
|
||||
printf ("can't load %s: %s\n", lib, dlerror());
|
||||
|
|
@ -101,7 +134,7 @@ make_node (AppData *data, SpaNode **node, const char *lib, const char *name)
|
|||
const SpaHandleFactory *factory;
|
||||
void *iface;
|
||||
|
||||
if ((res = enum_func (&factory, &state)) < 0) {
|
||||
if ((res = enum_func (&factory, state)) < 0) {
|
||||
if (res != SPA_RESULT_ENUM_END)
|
||||
printf ("can't enumerate factories: %d\n", res);
|
||||
break;
|
||||
|
|
@ -125,109 +158,110 @@ make_node (AppData *data, SpaNode **node, const char *lib, const char *name)
|
|||
}
|
||||
|
||||
static void
|
||||
on_source_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
|
||||
on_source_event (SpaNode *node, SpaEvent *event, void *user_data)
|
||||
{
|
||||
AppData *data = user_data;
|
||||
|
||||
switch (event->type) {
|
||||
case SPA_NODE_EVENT_TYPE_HAVE_OUTPUT:
|
||||
{
|
||||
SpaPortOutput po = { 0, };
|
||||
SpaResult res;
|
||||
SpaBuffer *b;
|
||||
void *sdata, *ddata;
|
||||
int sstride, dstride;
|
||||
int i;
|
||||
uint8_t *src, *dst;
|
||||
SpaMeta *metas;
|
||||
SpaData *datas;
|
||||
if (SPA_EVENT_TYPE (event) == data->type.event_node.HaveOutput) {
|
||||
SpaResult res;
|
||||
SpaBuffer *b;
|
||||
void *sdata, *ddata;
|
||||
int sstride, dstride;
|
||||
int i;
|
||||
uint8_t *src, *dst;
|
||||
SpaMeta *metas;
|
||||
SpaData *datas;
|
||||
|
||||
spa_node_port_set_output (data->source, 0, &po);
|
||||
if ((res = spa_node_process_output (data->source)) < 0)
|
||||
printf ("got pull error %d\n", res);
|
||||
b = data->bp[data->source_output[0].buffer_id];
|
||||
|
||||
b = data->bp[po.buffer_id];
|
||||
metas = b->metas;
|
||||
datas = b->datas;
|
||||
metas = b->metas;
|
||||
datas = b->datas;
|
||||
|
||||
if (metas[1].type == SPA_META_TYPE_POINTER &&
|
||||
strcmp (((SpaMetaPointer *)metas[1].data)->ptr_type, "SDL_Texture") == 0) {
|
||||
SDL_Texture *texture;
|
||||
texture = ((SpaMetaPointer *)metas[1].data)->ptr;
|
||||
if (metas[1].type == SPA_META_TYPE_POINTER &&
|
||||
strcmp (((SpaMetaPointer *)metas[1].data)->ptr_type, "SDL_Texture") == 0) {
|
||||
SDL_Texture *texture;
|
||||
texture = ((SpaMetaPointer *)metas[1].data)->ptr;
|
||||
|
||||
SDL_UnlockTexture(texture);
|
||||
SDL_UnlockTexture(texture);
|
||||
|
||||
SDL_RenderClear (data->renderer);
|
||||
SDL_RenderCopy (data->renderer, texture, NULL, NULL);
|
||||
SDL_RenderPresent (data->renderer);
|
||||
SDL_RenderClear (data->renderer);
|
||||
SDL_RenderCopy (data->renderer, texture, NULL, NULL);
|
||||
SDL_RenderPresent (data->renderer);
|
||||
|
||||
if (SDL_LockTexture (texture, NULL, &sdata, &sstride) < 0) {
|
||||
fprintf (stderr, "Couldn't lock texture: %s\n", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
datas[0].type = SPA_DATA_TYPE_MEMPTR;
|
||||
datas[0].data = sdata;
|
||||
datas[0].offset = 0;
|
||||
datas[0].size = sstride * 240;
|
||||
datas[0].maxsize = sstride * 240;
|
||||
datas[0].stride = sstride;
|
||||
} else {
|
||||
if (SDL_LockTexture (data->texture, NULL, &ddata, &dstride) < 0) {
|
||||
fprintf (stderr, "Couldn't lock texture: %s\n", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
sdata = datas[0].data;
|
||||
sstride = datas[0].stride;
|
||||
|
||||
for (i = 0; i < 240; i++) {
|
||||
src = ((uint8_t*)sdata + i * sstride);
|
||||
dst = ((uint8_t*)ddata + i * dstride);
|
||||
memcpy (dst, src, SPA_MIN (sstride, dstride));
|
||||
}
|
||||
SDL_UnlockTexture(data->texture);
|
||||
|
||||
SDL_RenderClear (data->renderer);
|
||||
SDL_RenderCopy (data->renderer, data->texture, NULL, NULL);
|
||||
SDL_RenderPresent (data->renderer);
|
||||
if (SDL_LockTexture (texture, NULL, &sdata, &sstride) < 0) {
|
||||
fprintf (stderr, "Couldn't lock texture: %s\n", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
spa_node_port_reuse_buffer (data->source, 0, po.buffer_id);
|
||||
break;
|
||||
datas[0].type = SPA_DATA_TYPE_MEMPTR;
|
||||
datas[0].flags = 0;
|
||||
datas[0].fd = -1;
|
||||
datas[0].mapoffset = 0;
|
||||
datas[0].maxsize = sstride * 240;
|
||||
datas[0].data = sdata;
|
||||
datas[0].chunk->offset = 0;
|
||||
datas[0].chunk->size = sstride * 240;
|
||||
datas[0].chunk->stride = sstride;
|
||||
} else {
|
||||
if (SDL_LockTexture (data->texture, NULL, &ddata, &dstride) < 0) {
|
||||
fprintf (stderr, "Couldn't lock texture: %s\n", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
sdata = datas[0].data;
|
||||
sstride = datas[0].chunk->stride;
|
||||
|
||||
for (i = 0; i < 240; i++) {
|
||||
src = ((uint8_t*)sdata + i * sstride);
|
||||
dst = ((uint8_t*)ddata + i * dstride);
|
||||
memcpy (dst, src, SPA_MIN (sstride, dstride));
|
||||
}
|
||||
SDL_UnlockTexture(data->texture);
|
||||
|
||||
SDL_RenderClear (data->renderer);
|
||||
SDL_RenderCopy (data->renderer, data->texture, NULL, NULL);
|
||||
SDL_RenderPresent (data->renderer);
|
||||
}
|
||||
default:
|
||||
printf ("got event %d\n", event->type);
|
||||
break;
|
||||
|
||||
if ((res = spa_node_process_output (data->source)) < 0)
|
||||
printf ("got pull error %d\n", res);
|
||||
}
|
||||
else {
|
||||
printf ("got event %d\n", SPA_EVENT_TYPE (event));
|
||||
}
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
do_add_item (SpaPoll *poll,
|
||||
SpaPollItem *item)
|
||||
do_add_source (SpaLoop *loop,
|
||||
SpaSource *source)
|
||||
{
|
||||
AppData *data = SPA_CONTAINER_OF (poll, AppData, data_loop);
|
||||
int i;
|
||||
AppData *data = SPA_CONTAINER_OF (loop, AppData, data_loop);
|
||||
|
||||
data->poll = *item;
|
||||
for (i = 0; i < data->poll.n_fds; i++) {
|
||||
data->fds[i] = item->fds[i];
|
||||
}
|
||||
data->n_fds = data->poll.n_fds;
|
||||
data->poll.fds = data->fds;
|
||||
data->sources[data->n_sources] = *source;
|
||||
data->n_sources++;
|
||||
data->rebuild_fds = true;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
do_update_item (SpaPoll *poll,
|
||||
SpaPollItem *item)
|
||||
do_update_source (SpaSource *source)
|
||||
{
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
do_remove_item (SpaPoll *poll,
|
||||
SpaPollItem *item)
|
||||
static void
|
||||
do_remove_source (SpaSource *source)
|
||||
{
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
do_invoke (SpaLoop *loop,
|
||||
SpaInvokeFunc func,
|
||||
uint32_t seq,
|
||||
size_t size,
|
||||
void *data,
|
||||
void *user_data)
|
||||
{
|
||||
return func (loop, false, seq, size, data, user_data);
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
|
|
@ -235,20 +269,22 @@ make_nodes (AppData *data, const char *device)
|
|||
{
|
||||
SpaResult res;
|
||||
SpaProps *props;
|
||||
SpaPropValue value;
|
||||
SpaPODBuilder b = { 0 };
|
||||
SpaPODFrame f[2];
|
||||
uint8_t buffer[256];
|
||||
|
||||
if ((res = make_node (data, &data->source, "spa/plugins/v4l2/libspa-v4l2.so", "v4l2-source")) < 0) {
|
||||
if ((res = make_node (data, &data->source, "build/spa/plugins/v4l2/libspa-v4l2.so", "v4l2-source")) < 0) {
|
||||
printf ("can't create v4l2-source: %d\n", res);
|
||||
return res;
|
||||
}
|
||||
spa_node_set_event_callback (data->source, on_source_event, data);
|
||||
|
||||
if ((res = spa_node_get_props (data->source, &props)) < 0)
|
||||
printf ("got get_props error %d\n", res);
|
||||
|
||||
value.value = device ? device : "/dev/video7";
|
||||
value.size = strlen (value.value)+1;
|
||||
spa_props_set_value (props, spa_props_index_for_name (props, "device"), &value);
|
||||
spa_pod_builder_init (&b, buffer, sizeof (buffer));
|
||||
spa_pod_builder_props (&b, &f[0], data->type.props,
|
||||
SPA_POD_PROP (&f[1], data->type.props_device, 0,
|
||||
SPA_POD_TYPE_STRING, 1,
|
||||
device ? device : "/dev/video0"));
|
||||
props = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaProps);
|
||||
|
||||
if ((res = spa_node_set_props (data->source, props)) < 0)
|
||||
printf ("got set_props error %d\n", res);
|
||||
|
|
@ -256,7 +292,7 @@ make_nodes (AppData *data, const char *device)
|
|||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
static SpaResult
|
||||
alloc_buffers (AppData *data)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -275,11 +311,11 @@ alloc_buffers (AppData *data)
|
|||
320, 240);
|
||||
if (!texture) {
|
||||
printf ("can't create texture: %s\n", SDL_GetError ());
|
||||
return;
|
||||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
if (SDL_LockTexture (texture, NULL, &ptr, &stride) < 0) {
|
||||
fprintf (stderr, "Couldn't lock texture: %s\n", SDL_GetError());
|
||||
return;
|
||||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
|
||||
b->buffer.id = i;
|
||||
|
|
@ -303,31 +339,33 @@ alloc_buffers (AppData *data)
|
|||
b->metas[1].size = sizeof (b->ptr);
|
||||
|
||||
b->datas[0].type = SPA_DATA_TYPE_MEMPTR;
|
||||
b->datas[0].data = ptr;
|
||||
b->datas[0].offset = 0;
|
||||
b->datas[0].size = stride * 240;
|
||||
b->datas[0].flags = 0;
|
||||
b->datas[0].fd = -1;
|
||||
b->datas[0].mapoffset = 0;
|
||||
b->datas[0].maxsize = stride * 240;
|
||||
b->datas[0].stride = stride;
|
||||
b->datas[0].data = ptr;
|
||||
b->datas[0].chunk = &b->chunks[0];
|
||||
b->datas[0].chunk->offset = 0;
|
||||
b->datas[0].chunk->size = stride * 240;
|
||||
b->datas[0].chunk->stride = stride;
|
||||
}
|
||||
data->n_buffers = MAX_BUFFERS;
|
||||
|
||||
spa_node_port_use_buffers (data->source, SPA_DIRECTION_OUTPUT, 0, data->bp, MAX_BUFFERS);
|
||||
return spa_node_port_use_buffers (data->source, SPA_DIRECTION_OUTPUT, 0, data->bp, data->n_buffers);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
SpaFormat fmt;
|
||||
SpaPropInfo infos[3];
|
||||
SpaVideoFormat format;
|
||||
SpaRectangle size;
|
||||
SpaFraction framerate;
|
||||
} VideoFormat;
|
||||
|
||||
static SpaResult
|
||||
negotiate_formats (AppData *data)
|
||||
{
|
||||
SpaResult res;
|
||||
const SpaPortInfo *info;
|
||||
VideoFormat f;
|
||||
SpaFormat *format;
|
||||
SpaPODFrame f[2];
|
||||
uint8_t buffer[256];
|
||||
SpaPODBuilder b = SPA_POD_BUILDER_INIT (buffer, sizeof (buffer));
|
||||
|
||||
if ((res = spa_node_port_set_io (data->source, SPA_DIRECTION_OUTPUT, 0, &data->source_output[0])) < 0)
|
||||
return res;
|
||||
|
||||
#if 0
|
||||
void *state = NULL;
|
||||
|
|
@ -335,39 +373,30 @@ negotiate_formats (AppData *data)
|
|||
if ((res = spa_node_port_enum_formats (data->source, 0, &format, NULL, &state)) < 0)
|
||||
return res;
|
||||
#else
|
||||
f.fmt.media_type = SPA_MEDIA_TYPE_VIDEO;
|
||||
f.fmt.media_subtype = SPA_MEDIA_SUBTYPE_RAW;
|
||||
f.fmt.props.n_prop_info = 3;
|
||||
f.fmt.props.prop_info = f.infos;
|
||||
|
||||
spa_prop_info_fill_video (&f.infos[0],
|
||||
SPA_PROP_ID_VIDEO_FORMAT,
|
||||
offsetof (VideoFormat, format));
|
||||
f.format = SPA_VIDEO_FORMAT_YUY2;
|
||||
|
||||
spa_prop_info_fill_video (&f.infos[1],
|
||||
SPA_PROP_ID_VIDEO_SIZE,
|
||||
offsetof (VideoFormat, size));
|
||||
f.size.width = 320;
|
||||
f.size.height = 240;
|
||||
|
||||
spa_prop_info_fill_video (&f.infos[2],
|
||||
SPA_PROP_ID_VIDEO_FRAMERATE,
|
||||
offsetof (VideoFormat, framerate));
|
||||
f.framerate.num = 25;
|
||||
f.framerate.denom = 1;
|
||||
spa_pod_builder_format (&b, &f[0], data->type.format,
|
||||
data->type.media_type.video, data->type.media_subtype.raw,
|
||||
SPA_POD_PROP (&f[1], data->type.format_video.format, 0,
|
||||
SPA_POD_TYPE_ID, 1,
|
||||
data->type.video_format.YUY2),
|
||||
SPA_POD_PROP (&f[1], data->type.format_video.size, 0,
|
||||
SPA_POD_TYPE_RECTANGLE, 1,
|
||||
320, 240),
|
||||
SPA_POD_PROP (&f[1], data->type.format_video.framerate, 0,
|
||||
SPA_POD_TYPE_FRACTION, 1,
|
||||
25, 1));
|
||||
format = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaFormat);
|
||||
#endif
|
||||
|
||||
if ((res = spa_node_port_set_format (data->source, SPA_DIRECTION_OUTPUT, 0, false, &f.fmt)) < 0)
|
||||
if ((res = spa_node_port_set_format (data->source, SPA_DIRECTION_OUTPUT, 0, 0, format)) < 0)
|
||||
return res;
|
||||
|
||||
if ((res = spa_node_port_get_info (data->source, SPA_DIRECTION_OUTPUT, 0, &info)) < 0)
|
||||
return res;
|
||||
|
||||
spa_debug_port_info (info);
|
||||
|
||||
if (data->use_buffer) {
|
||||
alloc_buffers (data);
|
||||
if ((res = alloc_buffers (data)) < 0)
|
||||
return res;
|
||||
} else {
|
||||
unsigned int n_buffers;
|
||||
|
||||
|
|
@ -393,11 +422,21 @@ static void *
|
|||
loop (void *user_data)
|
||||
{
|
||||
AppData *data = user_data;
|
||||
int r;
|
||||
|
||||
printf ("enter thread\n");
|
||||
while (data->running) {
|
||||
SpaPollNotifyData ndata;
|
||||
int i, r;
|
||||
|
||||
/* rebuild */
|
||||
if (data->rebuild_fds) {
|
||||
for (i = 0; i < data->n_sources; i++) {
|
||||
SpaSource *p = &data->sources[i];
|
||||
data->fds[i].fd = p->fd;
|
||||
data->fds[i].events = p->mask;
|
||||
}
|
||||
data->n_fds = data->n_sources;
|
||||
data->rebuild_fds = false;
|
||||
}
|
||||
|
||||
r = poll ((struct pollfd *) data->fds, data->n_fds, -1);
|
||||
if (r < 0) {
|
||||
|
|
@ -406,14 +445,27 @@ loop (void *user_data)
|
|||
break;
|
||||
}
|
||||
if (r == 0) {
|
||||
fprintf (stderr, "select timeout\n");
|
||||
fprintf (stderr, "select timeout");
|
||||
break;
|
||||
}
|
||||
if (data->poll.after_cb) {
|
||||
ndata.fds = data->poll.fds;
|
||||
ndata.n_fds = data->poll.n_fds;
|
||||
ndata.user_data = data->poll.user_data;
|
||||
data->poll.after_cb (&ndata);
|
||||
|
||||
/* after */
|
||||
for (i = 0; i < data->n_sources; i++) {
|
||||
SpaSource *p = &data->sources[i];
|
||||
p->rmask = 0;
|
||||
if (data->fds[i].revents & POLLIN)
|
||||
p->rmask |= SPA_IO_IN;
|
||||
if (data->fds[i].revents & POLLOUT)
|
||||
p->rmask |= SPA_IO_OUT;
|
||||
if (data->fds[i].revents & POLLHUP)
|
||||
p->rmask |= SPA_IO_HUP;
|
||||
if (data->fds[i].revents & POLLERR)
|
||||
p->rmask |= SPA_IO_ERR;
|
||||
}
|
||||
for (i = 0; i < data->n_sources; i++) {
|
||||
SpaSource *p = &data->sources[i];
|
||||
if (p->rmask)
|
||||
p->func (p);
|
||||
}
|
||||
}
|
||||
printf ("leave thread\n");
|
||||
|
|
@ -424,12 +476,13 @@ static void
|
|||
run_async_source (AppData *data)
|
||||
{
|
||||
SpaResult res;
|
||||
SpaNodeCommand cmd;
|
||||
int err;
|
||||
|
||||
cmd.type = SPA_NODE_COMMAND_START;
|
||||
if ((res = spa_node_send_command (data->source, &cmd)) < 0)
|
||||
printf ("got error %d\n", res);
|
||||
{
|
||||
SpaCommand cmd = SPA_COMMAND_INIT (data->type.command_node.Start);
|
||||
if ((res = spa_node_send_command (data->source, &cmd)) < 0)
|
||||
printf ("got error %d\n", res);
|
||||
}
|
||||
|
||||
data->running = true;
|
||||
if ((err = pthread_create (&data->thread, NULL, loop, data)) != 0) {
|
||||
|
|
@ -444,34 +497,41 @@ run_async_source (AppData *data)
|
|||
pthread_join (data->thread, NULL);
|
||||
}
|
||||
|
||||
cmd.type = SPA_NODE_COMMAND_PAUSE;
|
||||
if ((res = spa_node_send_command (data->source, &cmd)) < 0)
|
||||
printf ("got error %d\n", res);
|
||||
{
|
||||
SpaCommand cmd = SPA_COMMAND_INIT (data->type.command_node.Pause);
|
||||
if ((res = spa_node_send_command (data->source, &cmd)) < 0)
|
||||
printf ("got error %d\n", res);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
AppData data;
|
||||
AppData data = { 0 };
|
||||
SpaResult res;
|
||||
|
||||
data.use_buffer = true;
|
||||
|
||||
data.map = spa_type_map_get_default ();
|
||||
data.log = spa_log_get_default ();
|
||||
|
||||
data.data_loop.size = sizeof (SpaPoll);
|
||||
data.data_loop.info = NULL;
|
||||
data.data_loop.add_item = do_add_item;
|
||||
data.data_loop.update_item = do_update_item;
|
||||
data.data_loop.remove_item = do_remove_item;
|
||||
data.data_loop.size = sizeof (SpaLoop);
|
||||
data.data_loop.add_source = do_add_source;
|
||||
data.data_loop.update_source = do_update_source;
|
||||
data.data_loop.remove_source = do_remove_source;
|
||||
data.data_loop.invoke = do_invoke;
|
||||
|
||||
data.support[0].type = SPA_TYPE__TypeMap;
|
||||
data.support[0].data = data.map;
|
||||
data.support[1].type = SPA_TYPE_LOOP__DataLoop;
|
||||
data.support[1].data = &data.data_loop;
|
||||
data.n_support = 2;
|
||||
data.support[1].type = SPA_TYPE__Log;
|
||||
data.support[1].data = data.log;
|
||||
data.support[2].type = SPA_TYPE_LOOP__DataLoop;
|
||||
data.support[2].data = &data.data_loop;
|
||||
data.support[3].type = SPA_TYPE_LOOP__MainLoop;
|
||||
data.support[3].data = &data.data_loop;
|
||||
data.n_support = 4;
|
||||
|
||||
data.type.node = spa_type_map_get_id (data.map, SPA_TYPE__Node);
|
||||
init_type (&data.type, data.map);
|
||||
|
||||
if (SDL_Init (SDL_INIT_VIDEO) < 0) {
|
||||
printf ("can't initialize SDL: %s\n", SDL_GetError ());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue