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:
Wim Taymans 2017-04-03 14:56:04 +02:00
parent 29fbf2e841
commit 01c13adab5
28 changed files with 983 additions and 747 deletions

View file

@ -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))

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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;

View file

@ -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,

View file

@ -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)

View file

@ -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);
}

View file

@ -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))

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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 : [],

View file

@ -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);

View file

@ -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 ());