Add sync and async support in *testsrc

Make minumum alsa latency configurable.
This commit is contained in:
Wim Taymans 2017-04-03 16:54:44 +02:00
parent 01c13adab5
commit 5c32690cc8
13 changed files with 186 additions and 153 deletions

View file

@ -500,7 +500,6 @@ handle_rtnode_event (PinosStream *stream,
}
else if (SPA_EVENT_TYPE (event) == context->type.event_node.NeedInput) {
int i;
BufferId *bid;
for (i = 0; i < impl->trans->area->n_outputs; i++) {
SpaPortIO *output = &impl->trans->outputs[i];
@ -516,7 +515,6 @@ handle_rtnode_event (PinosStream *stream,
}
else if (SPA_EVENT_TYPE (event) == context->type.event_node.ReuseBuffer) {
SpaEventNodeReuseBuffer *p = (SpaEventNodeReuseBuffer *) event;
BufferId *bid;
if (p->body.port_id.value != impl->port_id)
return;

View file

@ -51,6 +51,8 @@ pinos_spa_node_load (PinosCore *core,
SpaEnumHandleFactoryFunc enum_func;
const SpaHandleFactory *factory;
void *iface;
SpaDictItem items[1];
SpaDict dict = SPA_DICT_INIT (1, items);
if ((hnd = dlopen (lib, RTLD_NOW)) == NULL) {
pinos_log_error ("can't load %s: %s", lib, dlerror());
@ -71,10 +73,13 @@ pinos_spa_node_load (PinosCore *core,
break;
}
items[0].key = "asynchronous";
items[0].value = "1";
handle = calloc (1, factory->size);
if ((res = spa_handle_factory_init (factory,
handle,
NULL,
&dict,
core->support,
core->n_support)) < 0) {
pinos_log_error ("can't make factory instance: %d", res);

View file

@ -798,14 +798,11 @@ 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);

View file

@ -37,6 +37,7 @@ typedef SpaPODObject SpaProps;
#define SPA_TYPE_PROPS__deviceFd SPA_TYPE_PROPS_BASE "deviceFd"
#define SPA_TYPE_PROPS__card SPA_TYPE_PROPS_BASE "card"
#define SPA_TYPE_PROPS__cardName SPA_TYPE_PROPS_BASE "cardName"
#define SPA_TYPE_PROPS__minLatency SPA_TYPE_PROPS_BASE "minLatency"
#define SPA_TYPE_PROPS__periods SPA_TYPE_PROPS_BASE "periods"
#define SPA_TYPE_PROPS__periodSize SPA_TYPE_PROPS_BASE "periodSize"
#define SPA_TYPE_PROPS__periodEvent SPA_TYPE_PROPS_BASE "periodEvent"

View file

@ -474,7 +474,7 @@ spa_debug_dict (const SpaDict *dict)
}
#define DEFAULT_LOG_LEVEL SPA_LOG_LEVEL_TRACE
#define DEFAULT_LOG_LEVEL SPA_LOG_LEVEL_DEBUG
static void
do_logv (SpaLog *log,

View file

@ -32,17 +32,13 @@
typedef struct _SpaALSAState SpaALSASink;
static const char default_device[] = "default";
static const uint32_t default_period_size = 128;
static const uint32_t default_periods = 2;
static const bool default_period_event = 0;
static const uint32_t default_min_latency = 1024;
static void
reset_alsa_sink_props (SpaALSAProps *props)
{
strncpy (props->device, default_device, 64);
props->period_size = default_period_size;
props->periods = default_periods;
props->period_event = default_period_event;
props->min_latency = default_min_latency;
}
static void
@ -83,9 +79,7 @@ spa_alsa_sink_node_get_props (SpaNode *node,
PROP (&f[1], this->type.prop_device, -SPA_POD_TYPE_STRING, this->props.device, sizeof (this->props.device)),
PROP (&f[1], this->type.prop_device_name, -SPA_POD_TYPE_STRING, this->props.device_name, sizeof (this->props.device_name)),
PROP (&f[1], this->type.prop_card_name, -SPA_POD_TYPE_STRING, this->props.card_name, sizeof (this->props.card_name)),
PROP_MM (&f[1], this->type.prop_period_size, SPA_POD_TYPE_INT, this->props.period_size, 1, INT32_MAX),
PROP_MM (&f[1], this->type.prop_periods, SPA_POD_TYPE_INT, this->props.periods, 1, INT32_MAX),
PROP (&f[1], this->type.prop_period_event, SPA_POD_TYPE_BOOL, this->props.period_event));
PROP_MM (&f[1], this->type.prop_min_latency, SPA_POD_TYPE_INT, this->props.min_latency, 1, INT32_MAX));
*props = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaProps);
@ -109,9 +103,7 @@ spa_alsa_sink_node_set_props (SpaNode *node,
} else {
spa_props_query (props,
this->type.prop_device, -SPA_POD_TYPE_STRING, this->props.device, sizeof (this->props.device),
this->type.prop_period_size, SPA_POD_TYPE_INT, &this->props.period_size,
this->type.prop_periods, SPA_POD_TYPE_INT, &this->props.periods,
this->type.prop_period_event, SPA_POD_TYPE_BOOL, &this->props.period_event,
this->type.prop_min_latency, SPA_POD_TYPE_INT, &this->props.min_latency,
0);
}
return SPA_RESULT_OK;

View file

@ -39,17 +39,13 @@ update_state (SpaALSASource *this, SpaNodeState state)
}
static const char default_device[] = "hw:0";
static const uint32_t default_period_size = 32;
static const uint32_t default_periods = 2;
static const bool default_period_event = 0;
static const uint32_t default_min_latency = 1024;
static void
reset_alsa_props (SpaALSAProps *props)
{
strncpy (props->device, default_device, 64);
props->period_size = default_period_size;
props->periods = default_periods;
props->period_event = default_period_event;
props->min_latency = default_min_latency;
}
#define PROP(f,key,type,...) \
@ -84,9 +80,7 @@ spa_alsa_source_node_get_props (SpaNode *node,
PROP (&f[1], this->type.prop_device, -SPA_POD_TYPE_STRING, this->props.device, sizeof (this->props.device)),
PROP (&f[1], this->type.prop_device_name, -SPA_POD_TYPE_STRING, this->props.device_name, sizeof (this->props.device_name)),
PROP (&f[1], this->type.prop_card_name, -SPA_POD_TYPE_STRING, this->props.card_name, sizeof (this->props.card_name)),
PROP_MM (&f[1], this->type.prop_period_size, SPA_POD_TYPE_INT, this->props.period_size, 1, INT32_MAX),
PROP_MM (&f[1], this->type.prop_periods, SPA_POD_TYPE_INT, this->props.periods, 1, INT32_MAX),
PROP (&f[1], this->type.prop_period_event, SPA_POD_TYPE_BOOL, this->props.period_event));
PROP_MM (&f[1], this->type.prop_min_latency, SPA_POD_TYPE_INT, this->props.min_latency, 1, INT32_MAX));
*props = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaProps);
@ -110,9 +104,7 @@ spa_alsa_source_node_set_props (SpaNode *node,
} else {
spa_props_query (props,
this->type.prop_device, -SPA_POD_TYPE_STRING, this->props.device, sizeof (this->props.device),
this->type.prop_period_size, SPA_POD_TYPE_INT, &this->props.period_size,
this->type.prop_periods, SPA_POD_TYPE_INT, &this->props.periods,
this->type.prop_period_event, SPA_POD_TYPE_BOOL, &this->props.period_event,
this->type.prop_min_latency, SPA_POD_TYPE_INT, &this->props.min_latency,
0);
}

View file

@ -117,7 +117,6 @@ spa_alsa_set_format (SpaALSAState *state, SpaAudioInfo *fmt, SpaPortFormatFlags
SpaAudioInfoRaw *info = &fmt->info.raw;
snd_pcm_t *hndl;
unsigned int periods;
SpaALSAProps *props = &state->props;
if ((err = spa_alsa_open (state)) < 0)
return err;
@ -195,8 +194,6 @@ set_swparams (SpaALSAState *state)
snd_pcm_sw_params_t *params;
snd_pcm_uframes_t boundary;
SpaALSAProps *props = &state->props;
snd_pcm_sw_params_alloca (&params);
/* get the current params */
@ -618,7 +615,7 @@ spa_alsa_start (SpaALSAState *state, bool xrun_recover)
state->source.rmask = 0;
spa_loop_add_source (state->data_loop, &state->source);
state->threshold = 1024;
state->threshold = state->props.min_latency;
if (state->stream == SND_PCM_STREAM_PLAYBACK) {
state->alsa_started = false;

View file

@ -45,9 +45,7 @@ typedef struct {
char device[64];
char device_name[128];
char card_name[128];
uint32_t period_size;
uint32_t periods;
bool period_event;
uint32_t min_latency;
} SpaALSAProps;
#define MAX_BUFFERS 64
@ -68,9 +66,7 @@ typedef struct {
uint32_t prop_device;
uint32_t prop_device_name;
uint32_t prop_card_name;
uint32_t prop_period_size;
uint32_t prop_periods;
uint32_t prop_period_event;
uint32_t prop_min_latency;
SpaTypeMediaType media_type;
SpaTypeMediaSubtype media_subtype;
SpaTypeMediaSubtypeAudio media_subtype_audio;
@ -92,9 +88,7 @@ init_type (Type *type, SpaTypeMap *map)
type->prop_device = spa_type_map_get_id (map, SPA_TYPE_PROPS__device);
type->prop_device_name = spa_type_map_get_id (map, SPA_TYPE_PROPS__deviceName);
type->prop_card_name = spa_type_map_get_id (map, SPA_TYPE_PROPS__cardName);
type->prop_period_size = spa_type_map_get_id (map, SPA_TYPE_PROPS__periodSize);
type->prop_periods = spa_type_map_get_id (map, SPA_TYPE_PROPS__periods);
type->prop_period_event = spa_type_map_get_id (map, SPA_TYPE_PROPS__periodEvent);
type->prop_min_latency = spa_type_map_get_id (map, SPA_TYPE_PROPS__minLatency);
spa_type_media_type_map (map, &type->media_type);
spa_type_media_subtype_map (map, &type->media_subtype);

View file

@ -452,7 +452,7 @@ spa_audiomixer_node_port_use_buffers (SpaNode *node,
b = &port->buffers[i];
b->outbuf = buffers[i];
b->outstanding = true;
b->outstanding = direction == SPA_DIRECTION_INPUT ? true : false;
b->h = spa_buffer_find_meta (buffers[i], SPA_META_TYPE_HEADER);
switch (d[0].type) {
@ -516,11 +516,34 @@ spa_audiomixer_node_port_set_io (SpaNode *node,
return SPA_RESULT_OK;
}
static void
recycle_buffer (SpaAudioMixer *this, uint32_t id)
{
SpaAudioMixerPort *port = &this->out_ports[0];
MixerBuffer *b = &port->buffers[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, id);
}
}
static SpaResult
spa_audiomixer_node_port_reuse_buffer (SpaNode *node,
uint32_t port_id,
uint32_t buffer_id)
{
SpaAudioMixer *this;
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, SPA_DIRECTION_OUTPUT, port_id), SPA_RESULT_INVALID_PORT);
recycle_buffer (this, buffer_id);
return SPA_RESULT_NOT_IMPLEMENTED;
}
@ -664,15 +687,11 @@ spa_audiomixer_node_process_output (SpaNode *node)
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);
}
recycle_buffer (this, output->buffer_id);
output->buffer_id = SPA_ID_INVALID;
}
this->state = STATE_IN;
return SPA_RESULT_NEED_INPUT;
}

View file

@ -112,6 +112,7 @@ struct _SpaAudioTestSrc {
SpaTypeMap *map;
SpaLog *log;
SpaLoop *data_loop;
bool async;
uint8_t props_buffer[512];
SpaAudioTestSrcProps props;
@ -239,7 +240,6 @@ send_have_output (SpaAudioTestSrc *this)
SpaEvent event = SPA_EVENT_INIT (this->type.event_node.HaveOutput);
this->event_cb (&this->node, &event, this->user_data);
}
return SPA_RESULT_OK;
}
@ -280,6 +280,10 @@ audiotestsrc_make_buffer (SpaAudioTestSrc *this)
{
ATSBuffer *b;
SpaPortIO *io;
uint64_t expirations;
if (read (this->timer_source.fd, &expirations, sizeof (uint64_t)) < sizeof (uint64_t))
perror ("read timerfd");
if (spa_list_is_empty (&this->empty)) {
set_timer (this, false);
@ -306,21 +310,19 @@ audiotestsrc_make_buffer (SpaAudioTestSrc *this)
io->buffer_id = b->outbuf->id;
io->status = SPA_RESULT_OK;
}
return SPA_RESULT_OK;
return SPA_RESULT_HAVE_OUTPUT;
}
static void
audiotestsrc_on_output (SpaSource *source)
{
SpaAudioTestSrc *this = source->data;
uint64_t expirations;
SpaResult res;
if (read (this->timer_source.fd, &expirations, sizeof (uint64_t)) < sizeof (uint64_t))
perror ("read timerfd");
res = audiotestsrc_make_buffer (this);
audiotestsrc_make_buffer (this);
send_have_output (this);
if (res == SPA_RESULT_HAVE_OUTPUT)
send_have_output (this);
}
static void
@ -396,15 +398,9 @@ spa_audiotestsrc_node_set_event_callback (SpaNode *node,
this = SPA_CONTAINER_OF (node, SpaAudioTestSrc, node);
if (event_cb == NULL && this->event_cb)
spa_loop_remove_source (this->data_loop, &this->timer_source);
this->event_cb = event_cb;
this->user_data = user_data;
if (this->event_cb) {
spa_loop_add_source (this->data_loop, &this->timer_source);
}
return SPA_RESULT_OK;
}
@ -768,13 +764,27 @@ spa_audiotestsrc_node_port_set_io (SpaNode *node,
return SPA_RESULT_OK;
}
static inline void
reuse_buffer (SpaAudioTestSrc *this, uint32_t id)
{
ATSBuffer *b = &this->buffers[id];
spa_return_if_fail (b->outstanding);
spa_log_trace (this->log, "audiotestsrc %p: reuse buffer %d", this, id);
b->outstanding = false;
spa_list_insert (this->empty.prev, &b->link);
if (!this->props.live)
set_timer (this, true);
}
static SpaResult
spa_audiotestsrc_node_port_reuse_buffer (SpaNode *node,
uint32_t port_id,
uint32_t buffer_id)
{
SpaAudioTestSrc *this;
ATSBuffer *b;
spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS);
@ -784,16 +794,7 @@ spa_audiotestsrc_node_port_reuse_buffer (SpaNode *node,
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];
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);
if (!this->props.live)
set_timer (this, true);
reuse_buffer (this, buffer_id);
return SPA_RESULT_OK;
}
@ -816,29 +817,21 @@ spa_audiotestsrc_node_process_input (SpaNode *node)
static SpaResult
spa_audiotestsrc_node_process_output (SpaNode *node)
{
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);
}
reuse_buffer (this, this->io->buffer_id);
this->io->buffer_id = SPA_ID_INVALID;
}
if ((res = audiotestsrc_make_buffer (this)) < 0)
return res;
return SPA_RESULT_HAVE_OUTPUT;
if (!this->async)
return audiotestsrc_make_buffer (this);
else
return SPA_RESULT_OK;
}
static const SpaNode audiotestsrc_node = {
@ -949,6 +942,7 @@ audiotestsrc_clear (SpaHandle *handle)
this = (SpaAudioTestSrc *) handle;
spa_loop_remove_source (this->data_loop, &this->timer_source);
close (this->timer_source.fd);
return SPA_RESULT_OK;
@ -963,6 +957,7 @@ audiotestsrc_init (const SpaHandleFactory *factory,
{
SpaAudioTestSrc *this;
uint32_t i;
const char *str;
if (factory == NULL || handle == NULL)
return SPA_RESULT_INVALID_ARGUMENTS;
@ -972,6 +967,11 @@ audiotestsrc_init (const SpaHandleFactory *factory,
this = (SpaAudioTestSrc *) handle;
if (info && (str = spa_dict_lookup (info, "asynchronous")))
this->async = atoi (str) == 1;
else
this->async = false;
for (i = 0; i < n_support; i++) {
if (strcmp (support[i].type, SPA_TYPE__TypeMap) == 0)
this->map = support[i].data;
@ -984,7 +984,7 @@ audiotestsrc_init (const SpaHandleFactory *factory,
spa_log_error (this->log, "a type-map is needed");
return SPA_RESULT_ERROR;
}
if (this->data_loop == NULL) {
if (this->data_loop == NULL && this->async) {
spa_log_error (this->log, "a data_loop is needed");
return SPA_RESULT_ERROR;
}
@ -998,7 +998,7 @@ audiotestsrc_init (const SpaHandleFactory *factory,
this->timer_source.func = audiotestsrc_on_output;
this->timer_source.data = this;
this->timer_source.fd = timerfd_create (CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
this->timer_source.fd = timerfd_create (CLOCK_MONOTONIC, TFD_CLOEXEC);
this->timer_source.mask = SPA_IO_IN;
this->timer_source.rmask = 0;
this->timerspec.it_value.tv_sec = 0;
@ -1006,6 +1006,9 @@ audiotestsrc_init (const SpaHandleFactory *factory,
this->timerspec.it_interval.tv_sec = 0;
this->timerspec.it_interval.tv_nsec = 0;
if (this->data_loop && this->async)
spa_loop_add_source (this->data_loop, &this->timer_source);
this->info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS |
SPA_PORT_INFO_FLAG_NO_REF;
if (this->props.live)
@ -1013,6 +1016,8 @@ audiotestsrc_init (const SpaHandleFactory *factory,
this->node.state = SPA_NODE_STATE_CONFIGURE;
spa_log_info (this->log, "audiotestsrc %p: initialized, async=%d", this, this->async);
return SPA_RESULT_OK;
}

View file

@ -106,6 +106,7 @@ struct _SpaVideoTestSrc {
SpaTypeMap *map;
SpaLog *log;
SpaLoop *data_loop;
bool async;
uint8_t props_buffer[512];
SpaVideoTestSrcProps props;
@ -177,7 +178,6 @@ spa_videotestsrc_node_get_props (SpaNode *node,
this = SPA_CONTAINER_OF (node, SpaVideoTestSrc, node);
spa_pod_builder_init (&b, this->props_buffer, sizeof (this->props_buffer));
spa_pod_builder_props (&b, &f[0], this->type.props,
PROP (&f[1], this->type.prop_live, SPA_POD_TYPE_BOOL, this->props.live),
PROP_EN (&f[1], this->type.prop_pattern, SPA_POD_TYPE_ID, 3,
@ -256,10 +256,9 @@ set_timer (SpaVideoTestSrc *this, bool enabled)
timerfd_settime (this->timer_source.fd, TFD_TIMER_ABSTIME, &this->timerspec, NULL);
}
static void
videotestsrc_on_output (SpaSource *source)
static SpaResult
videotestsrc_make_buffer (SpaVideoTestSrc *this)
{
SpaVideoTestSrc *this = source->data;
VTSBuffer *b;
SpaPortIO *io;
uint64_t expirations;
@ -269,10 +268,12 @@ videotestsrc_on_output (SpaSource *source)
if (spa_list_is_empty (&this->empty)) {
set_timer (this, false);
return;
return SPA_RESULT_OUT_OF_BUFFERS;
}
b = spa_list_first (&this->empty, VTSBuffer, link);
spa_list_remove (&b->link);
b->outstanding = true;
spa_log_trace (this->log, "videotestsrc %p: dequeue buffer %d", this, b->outbuf->id);
fill_buffer (this, b);
@ -287,11 +288,22 @@ videotestsrc_on_output (SpaSource *source)
set_timer (this, true);
if ((io = this->io)) {
b->outstanding = true;
io->buffer_id = b->outbuf->id;
io->status = SPA_RESULT_OK;
send_have_output (this);
}
return SPA_RESULT_HAVE_OUTPUT;
}
static void
videotestsrc_on_output (SpaSource *source)
{
SpaVideoTestSrc *this = source->data;
SpaResult res;
res = videotestsrc_make_buffer (this);
if (res == SPA_RESULT_HAVE_OUTPUT)
send_have_output (this);
}
static void
@ -367,15 +379,9 @@ spa_videotestsrc_node_set_event_callback (SpaNode *node,
this = SPA_CONTAINER_OF (node, SpaVideoTestSrc, node);
if (event_cb == NULL && this->event_cb)
spa_loop_remove_source (this->data_loop, &this->timer_source);
this->event_cb = event_cb;
this->user_data = user_data;
if (this->event_cb) {
spa_loop_add_source (this->data_loop, &this->timer_source);
}
return SPA_RESULT_OK;
}
@ -479,7 +485,6 @@ next:
default:
return SPA_RESULT_ENUM_END;
}
fmt = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaFormat);
spa_pod_builder_init (&b, this->format_buffer, sizeof (this->format_buffer));
@ -605,7 +610,6 @@ spa_videotestsrc_node_port_get_format (SpaNode *node,
return SPA_RESULT_NO_FORMAT;
spa_pod_builder_init (&b, this->format_buffer, sizeof (this->format_buffer));
spa_pod_builder_format (&b, &f[0], this->type.format,
this->type.media_type.video, this->type.media_subtype.raw,
PROP (&f[1], this->type.format_video.format, SPA_POD_TYPE_ID, this->current_format.info.raw.format),
@ -747,50 +751,48 @@ spa_videotestsrc_node_port_set_io (SpaNode *node,
{
SpaVideoTestSrc *this;
if (node == NULL)
return SPA_RESULT_INVALID_ARGUMENTS;
spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS);
this = SPA_CONTAINER_OF (node, SpaVideoTestSrc, node);
if (!CHECK_PORT (this, direction, port_id))
return SPA_RESULT_INVALID_PORT;
spa_return_val_if_fail (CHECK_PORT (this, direction, port_id), SPA_RESULT_INVALID_PORT);
this->io = io;
return SPA_RESULT_OK;
}
static inline void
reuse_buffer (SpaVideoTestSrc *this, uint32_t id)
{
VTSBuffer *b = &this->buffers[id];
spa_return_if_fail (b->outstanding);
spa_log_trace (this->log, "videotestsrc %p: reuse buffer %d", this, id);
b->outstanding = false;
spa_list_insert (this->empty.prev, &b->link);
if (!this->props.live)
set_timer (this, true);
}
static SpaResult
spa_videotestsrc_node_port_reuse_buffer (SpaNode *node,
uint32_t port_id,
uint32_t buffer_id)
{
SpaVideoTestSrc *this;
VTSBuffer *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, SpaVideoTestSrc, node);
if (port_id != 0)
return SPA_RESULT_INVALID_PORT;
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);
if (this->n_buffers == 0)
return SPA_RESULT_NO_BUFFERS;
if (buffer_id >= this->n_buffers)
return SPA_RESULT_INVALID_BUFFER_ID;
b = &this->buffers[buffer_id];
if (!b->outstanding)
return SPA_RESULT_OK;
b->outstanding = false;
spa_list_insert (this->empty.prev, &b->link);
if (!this->props.live)
set_timer (this, true);
reuse_buffer (this, buffer_id);
return SPA_RESULT_OK;
}
@ -814,24 +816,20 @@ static SpaResult
spa_videotestsrc_node_process_output (SpaNode *node)
{
SpaVideoTestSrc *this;
VTSBuffer *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, 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);
}
reuse_buffer (this, this->io->buffer_id);
this->io->buffer_id = SPA_ID_INVALID;
}
return SPA_RESULT_OK;
if (!this->async)
return videotestsrc_make_buffer (this);
else
return SPA_RESULT_OK;
}
static const SpaNode videotestsrc_node = {
@ -942,6 +940,7 @@ videotestsrc_clear (SpaHandle *handle)
this = (SpaVideoTestSrc *) handle;
spa_loop_remove_source (this->data_loop, &this->timer_source);
close (this->timer_source.fd);
return SPA_RESULT_OK;
@ -956,6 +955,7 @@ videotestsrc_init (const SpaHandleFactory *factory,
{
SpaVideoTestSrc *this;
uint32_t i;
const char *str;
if (factory == NULL || handle == NULL)
return SPA_RESULT_INVALID_ARGUMENTS;
@ -965,6 +965,11 @@ videotestsrc_init (const SpaHandleFactory *factory,
this = (SpaVideoTestSrc *) handle;
if (info && (str = spa_dict_lookup (info, "asynchronous")))
this->async = atoi (str) == 1;
else
this->async = false;
for (i = 0; i < n_support; i++) {
if (strcmp (support[i].type, SPA_TYPE__TypeMap) == 0)
this->map = support[i].data;
@ -974,10 +979,10 @@ videotestsrc_init (const SpaHandleFactory *factory,
this->data_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) {
if (this->data_loop == NULL && this->async) {
spa_log_error (this->log, "a data_loop is needed");
return SPA_RESULT_ERROR;
}
@ -991,7 +996,7 @@ videotestsrc_init (const SpaHandleFactory *factory,
this->timer_source.func = videotestsrc_on_output;
this->timer_source.data = this;
this->timer_source.fd = timerfd_create (CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
this->timer_source.fd = timerfd_create (CLOCK_MONOTONIC, TFD_CLOEXEC);
this->timer_source.mask = SPA_IO_IN;
this->timer_source.rmask = 0;
this->timerspec.it_value.tv_sec = 0;
@ -999,6 +1004,9 @@ videotestsrc_init (const SpaHandleFactory *factory,
this->timerspec.it_interval.tv_sec = 0;
this->timerspec.it_interval.tv_nsec = 0;
if (this->data_loop && this->async)
spa_loop_add_source (this->data_loop, &this->timer_source);
this->info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS |
SPA_PORT_INFO_FLAG_NO_REF;
if (this->props.live)
@ -1006,6 +1014,8 @@ videotestsrc_init (const SpaHandleFactory *factory,
this->node.state = SPA_NODE_STATE_CONFIGURE;
spa_log_info (this->log, "videotestsrc %p: initialized, async=%d", this, this->async);
return SPA_RESULT_OK;
}

View file

@ -141,7 +141,7 @@ init_buffer (AppData *data, Buffer *b, void *ptr, size_t size)
}
static SpaResult
make_node (AppData *data, SpaNode **node, const char *lib, const char *name)
make_node (AppData *data, SpaNode **node, const char *lib, const char *name, bool async)
{
SpaHandle *handle;
SpaResult res;
@ -149,6 +149,8 @@ make_node (AppData *data, SpaNode **node, const char *lib, const char *name)
SpaEnumHandleFactoryFunc enum_func;
unsigned int i;
uint32_t state = 0;
SpaDictItem items[1];
SpaDict dict = SPA_DICT_INIT (1, items);
if ((hnd = dlopen (lib, RTLD_NOW)) == NULL) {
printf ("can't load %s: %s\n", lib, dlerror());
@ -159,6 +161,9 @@ make_node (AppData *data, SpaNode **node, const char *lib, const char *name)
return SPA_RESULT_ERROR;
}
items[0].key = "asynchronous";
items[0].value = async ? "1" : "0";
for (i = 0; ;i++) {
const SpaHandleFactory *factory;
void *iface;
@ -172,7 +177,7 @@ make_node (AppData *data, SpaNode **node, const char *lib, const char *name)
continue;
handle = calloc (1, factory->size);
if ((res = spa_handle_factory_init (factory, handle, NULL, data->support, data->n_support)) < 0) {
if ((res = spa_handle_factory_init (factory, handle, &dict, data->support, data->n_support)) < 0) {
printf ("can't make factory instance: %d\n", res);
return res;
}
@ -194,7 +199,6 @@ on_sink_event (SpaNode *node, SpaEvent *event, void *user_data)
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) {
@ -226,7 +230,6 @@ push:
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 {
@ -278,7 +281,9 @@ make_nodes (AppData *data)
SpaPODFrame f[2];
uint8_t buffer[128];
if ((res = make_node (data, &data->sink, "build/spa/plugins/alsa/libspa-alsa.so", "alsa-sink")) < 0) {
if ((res = make_node (data, &data->sink,
"build/spa/plugins/alsa/libspa-alsa.so",
"alsa-sink", true)) < 0) {
printf ("can't create alsa-sink: %d\n", res);
return res;
}
@ -293,15 +298,21 @@ make_nodes (AppData *data)
if ((res = spa_node_set_props (data->sink, props)) < 0)
printf ("got set_props error %d\n", res);
if ((res = make_node (data, &data->mix, "build/spa/plugins/audiomixer/libspa-audiomixer.so", "audiomixer")) < 0) {
if ((res = make_node (data, &data->mix,
"build/spa/plugins/audiomixer/libspa-audiomixer.so",
"audiomixer", false)) < 0) {
printf ("can't create audiomixer: %d\n", res);
return res;
}
if ((res = make_node (data, &data->source1, "build/spa/plugins/audiotestsrc/libspa-audiotestsrc.so", "audiotestsrc")) < 0) {
if ((res = make_node (data, &data->source1,
"build/spa/plugins/audiotestsrc/libspa-audiotestsrc.so",
"audiotestsrc", false)) < 0) {
printf ("can't create audiotestsrc: %d\n", res);
return res;
}
if ((res = make_node (data, &data->source2, "build/spa/plugins/audiotestsrc/libspa-audiotestsrc.so", "audiotestsrc")) < 0) {
if ((res = make_node (data, &data->source2,
"build/spa/plugins/audiotestsrc/libspa-audiotestsrc.so",
"audiotestsrc", false)) < 0) {
printf ("can't create audiotestsrc: %d\n", res);
return res;
}
@ -462,8 +473,14 @@ run_async_sink (AppData *data)
{
SpaCommand cmd = SPA_COMMAND_INIT (data->type.command_node.Start);
if ((res = spa_node_send_command (data->source1, &cmd)) < 0)
printf ("got source1 error %d\n", res);
if ((res = spa_node_send_command (data->source2, &cmd)) < 0)
printf ("got source2 error %d\n", res);
if ((res = spa_node_send_command (data->mix, &cmd)) < 0)
printf ("got mix error %d\n", res);
if ((res = spa_node_send_command (data->sink, &cmd)) < 0)
printf ("got error %d\n", res);
printf ("got sink error %d\n", res);
}
data->running = true;
@ -484,6 +501,12 @@ run_async_sink (AppData *data)
SpaCommand cmd = SPA_COMMAND_INIT (data->type.command_node.Pause);
if ((res = spa_node_send_command (data->sink, &cmd)) < 0)
printf ("got error %d\n", res);
if ((res = spa_node_send_command (data->mix, &cmd)) < 0)
printf ("got mix error %d\n", res);
if ((res = spa_node_send_command (data->source1, &cmd)) < 0)
printf ("got source1 error %d\n", res);
if ((res = spa_node_send_command (data->source2, &cmd)) < 0)
printf ("got source2 error %d\n", res);
}
}