mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
Add sync and async support in *testsrc
Make minumum alsa latency configurable.
This commit is contained in:
parent
01c13adab5
commit
5c32690cc8
13 changed files with 186 additions and 153 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 (¶ms);
|
||||
|
||||
/* 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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue