mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
alsa: improve ringbuffer handling
Add max-latency property to configure the maximum amount we write to the device. Only try to pull after we consumed our current buffers.
This commit is contained in:
parent
f04b292d08
commit
af99c196c9
4 changed files with 34 additions and 20 deletions
|
|
@ -41,6 +41,7 @@ struct spa_props {
|
|||
#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__maxLatency SPA_TYPE_PROPS_BASE "maxLatency"
|
||||
#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"
|
||||
|
|
|
|||
|
|
@ -33,11 +33,13 @@
|
|||
|
||||
static const char default_device[] = "hw:0";
|
||||
static const uint32_t default_min_latency = 128;
|
||||
static const uint32_t default_max_latency = 1024;
|
||||
|
||||
static void reset_props(struct props *props)
|
||||
{
|
||||
strncpy(props->device, default_device, 64);
|
||||
props->min_latency = default_min_latency;
|
||||
props->max_latency = default_max_latency;
|
||||
}
|
||||
|
||||
static int impl_node_get_props(struct spa_node *node, struct spa_props **props)
|
||||
|
|
@ -58,6 +60,8 @@ static int impl_node_get_props(struct spa_node *node, struct spa_props **props)
|
|||
":", this->type.prop_device_name, "S", this->props.device_name, sizeof(this->props.device_name),
|
||||
":", this->type.prop_card_name, "S", this->props.card_name, sizeof(this->props.card_name),
|
||||
":", this->type.prop_min_latency, "ir", this->props.min_latency,
|
||||
2, 1, INT32_MAX,
|
||||
":", this->type.prop_max_latency, "ir", this->props.max_latency,
|
||||
2, 1, INT32_MAX);
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
|
|
@ -367,7 +371,7 @@ impl_node_port_enum_params(struct spa_node *node,
|
|||
INT32_MAX,
|
||||
":", t->param_alloc_buffers.stride, "i", 0,
|
||||
":", t->param_alloc_buffers.buffers, "ir", 2,
|
||||
2, 2, 32,
|
||||
2, 2, MAX_BUFFERS,
|
||||
":", t->param_alloc_buffers.align, "i", 16);
|
||||
break;
|
||||
|
||||
|
|
@ -381,9 +385,10 @@ impl_node_port_enum_params(struct spa_node *node,
|
|||
case 2:
|
||||
*param = spa_pod_builder_param(&b,
|
||||
t->param_alloc_meta_enable.MetaEnable,
|
||||
":", t->param_alloc_meta_enable.type, "I", t->meta.Ringbuffer,
|
||||
":", t->param_alloc_meta_enable.size, "i", sizeof(struct spa_meta_ringbuffer),
|
||||
":", t->param_alloc_meta_enable.ringbufferSize, "iru", this->props.min_latency * this->frame_size,
|
||||
":", t->param_alloc_meta_enable.type, "I", t->meta.Ringbuffer,
|
||||
":", t->param_alloc_meta_enable.size, "i", sizeof(struct spa_meta_ringbuffer),
|
||||
":", t->param_alloc_meta_enable.ringbufferSize, "iru",
|
||||
this->props.min_latency * this->frame_size,
|
||||
2, this->props.min_latency * this->frame_size,
|
||||
this->period_frames * this->frame_size,
|
||||
":", t->param_alloc_meta_enable.ringbufferStride, "i", 0,
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ pull_frames(struct state *state,
|
|||
snd_pcm_uframes_t frames,
|
||||
bool do_pull)
|
||||
{
|
||||
snd_pcm_uframes_t total_frames = 0, to_write = frames;
|
||||
snd_pcm_uframes_t total_frames = 0, to_write = SPA_MIN(frames, state->props.max_latency);
|
||||
bool underrun = false;
|
||||
|
||||
try_pull(state, frames, do_pull);
|
||||
|
|
@ -365,16 +365,17 @@ pull_frames(struct state *state,
|
|||
int32_t avail;
|
||||
|
||||
avail = spa_ringbuffer_get_read_index(ringbuffer, &index);
|
||||
avail /= state->frame_size;
|
||||
|
||||
n_bytes = SPA_MIN(avail, to_write * state->frame_size);
|
||||
n_frames = SPA_MIN(to_write, n_bytes / state->frame_size);
|
||||
n_frames = SPA_MIN(avail, to_write);
|
||||
n_bytes = n_frames * state->frame_size;
|
||||
|
||||
spa_ringbuffer_read_data(ringbuffer, d[0].data, index % ringbuffer->size, dst, n_bytes);
|
||||
|
||||
spa_ringbuffer_read_data(ringbuffer, d[0].data, index % ringbuffer->mask, dst, n_bytes);
|
||||
|
||||
spa_ringbuffer_read_update(ringbuffer, index + n_bytes);
|
||||
reuse = avail == n_bytes;
|
||||
spa_log_trace(state->log, "%d %d %ld %zd", avail, index, to_write, n_bytes);
|
||||
reuse = true;
|
||||
|
||||
reuse = avail == n_frames || state->n_buffers == 1;
|
||||
} else {
|
||||
offs = SPA_MIN(d[0].chunk->offset + state->ready_offset, d[0].maxsize);
|
||||
size = SPA_MIN(d[0].chunk->size + offs, d[0].maxsize) - offs;
|
||||
|
|
@ -394,12 +395,14 @@ pull_frames(struct state *state,
|
|||
spa_log_trace(state->log, "alsa-util %p: reuse buffer %u", state, b->outbuf->id);
|
||||
state->callbacks->reuse_buffer(state->callbacks_data, 0, b->outbuf->id);
|
||||
state->ready_offset = 0;
|
||||
|
||||
try_pull(state, frames, do_pull);
|
||||
}
|
||||
total_frames += n_frames;
|
||||
to_write -= n_frames;
|
||||
spa_log_trace(state->log, "alsa-util %p: written %lu frames, left %ld", state, total_frames, to_write);
|
||||
}
|
||||
|
||||
try_pull(state, frames, do_pull);
|
||||
|
||||
if (total_frames == 0 && do_pull) {
|
||||
total_frames = SPA_MIN(frames, state->threshold);
|
||||
snd_pcm_areas_silence(my_areas, offset, state->channels, total_frames, state->format);
|
||||
|
|
@ -454,12 +457,10 @@ push_frames(struct state *state,
|
|||
d[0].chunk->size = n_bytes;
|
||||
d[0].chunk->stride = 0;
|
||||
|
||||
{
|
||||
b->outstanding = true;
|
||||
io->buffer_id = b->outbuf->id;
|
||||
io->status = SPA_RESULT_HAVE_BUFFER;
|
||||
state->callbacks->have_output(state->callbacks_data);
|
||||
}
|
||||
b->outstanding = true;
|
||||
io->buffer_id = b->outbuf->id;
|
||||
io->status = SPA_RESULT_HAVE_BUFFER;
|
||||
state->callbacks->have_output(state->callbacks_data);
|
||||
}
|
||||
return total_frames;
|
||||
}
|
||||
|
|
@ -549,10 +550,13 @@ static void alsa_on_playback_timeout_event(struct spa_source *source)
|
|||
spa_log_error(state->log, "snd_pcm_mmap_begin error: %s", snd_strerror(res));
|
||||
return;
|
||||
}
|
||||
spa_log_trace(state->log, "begin %ld %ld", offset, frames);
|
||||
|
||||
written = pull_frames(state, my_areas, offset, frames, do_pull);
|
||||
if (written < frames)
|
||||
to_write = 0;
|
||||
|
||||
spa_log_trace(state->log, "commit %ld %ld", offset, written);
|
||||
if ((res = snd_pcm_mmap_commit(hndl, offset, written)) < 0) {
|
||||
spa_log_error(state->log, "snd_pcm_mmap_commit error: %s", snd_strerror(res));
|
||||
if (res != -EPIPE && res != -ESTRPIPE)
|
||||
|
|
|
|||
|
|
@ -44,9 +44,10 @@ struct props {
|
|||
char device_name[128];
|
||||
char card_name[128];
|
||||
uint32_t min_latency;
|
||||
uint32_t max_latency;
|
||||
};
|
||||
|
||||
#define MAX_BUFFERS 64
|
||||
#define MAX_BUFFERS 32
|
||||
|
||||
struct buffer {
|
||||
struct spa_buffer *outbuf;
|
||||
|
|
@ -65,6 +66,7 @@ struct type {
|
|||
uint32_t prop_device_name;
|
||||
uint32_t prop_card_name;
|
||||
uint32_t prop_min_latency;
|
||||
uint32_t prop_max_latency;
|
||||
struct spa_type_meta meta;
|
||||
struct spa_type_data data;
|
||||
struct spa_type_media_type media_type;
|
||||
|
|
@ -88,6 +90,7 @@ static inline void init_type(struct type *type, struct spa_type_map *map)
|
|||
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_min_latency = spa_type_map_get_id(map, SPA_TYPE_PROPS__minLatency);
|
||||
type->prop_max_latency = spa_type_map_get_id(map, SPA_TYPE_PROPS__maxLatency);
|
||||
|
||||
spa_type_meta_map(map, &type->meta);
|
||||
spa_type_data_map(map, &type->data);
|
||||
|
|
@ -148,6 +151,7 @@ struct state {
|
|||
|
||||
struct spa_list free;
|
||||
struct spa_list ready;
|
||||
|
||||
size_t ready_offset;
|
||||
|
||||
bool started;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue