mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-12-17 08:56:49 -05: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__card SPA_TYPE_PROPS_BASE "card"
|
||||||
#define SPA_TYPE_PROPS__cardName SPA_TYPE_PROPS_BASE "cardName"
|
#define SPA_TYPE_PROPS__cardName SPA_TYPE_PROPS_BASE "cardName"
|
||||||
#define SPA_TYPE_PROPS__minLatency SPA_TYPE_PROPS_BASE "minLatency"
|
#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__periods SPA_TYPE_PROPS_BASE "periods"
|
||||||
#define SPA_TYPE_PROPS__periodSize SPA_TYPE_PROPS_BASE "periodSize"
|
#define SPA_TYPE_PROPS__periodSize SPA_TYPE_PROPS_BASE "periodSize"
|
||||||
#define SPA_TYPE_PROPS__periodEvent SPA_TYPE_PROPS_BASE "periodEvent"
|
#define SPA_TYPE_PROPS__periodEvent SPA_TYPE_PROPS_BASE "periodEvent"
|
||||||
|
|
|
||||||
|
|
@ -33,11 +33,13 @@
|
||||||
|
|
||||||
static const char default_device[] = "hw:0";
|
static const char default_device[] = "hw:0";
|
||||||
static const uint32_t default_min_latency = 128;
|
static const uint32_t default_min_latency = 128;
|
||||||
|
static const uint32_t default_max_latency = 1024;
|
||||||
|
|
||||||
static void reset_props(struct props *props)
|
static void reset_props(struct props *props)
|
||||||
{
|
{
|
||||||
strncpy(props->device, default_device, 64);
|
strncpy(props->device, default_device, 64);
|
||||||
props->min_latency = default_min_latency;
|
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)
|
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_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_card_name, "S", this->props.card_name, sizeof(this->props.card_name),
|
||||||
":", this->type.prop_min_latency, "ir", this->props.min_latency,
|
":", 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);
|
2, 1, INT32_MAX);
|
||||||
|
|
||||||
return SPA_RESULT_OK;
|
return SPA_RESULT_OK;
|
||||||
|
|
@ -367,7 +371,7 @@ impl_node_port_enum_params(struct spa_node *node,
|
||||||
INT32_MAX,
|
INT32_MAX,
|
||||||
":", t->param_alloc_buffers.stride, "i", 0,
|
":", t->param_alloc_buffers.stride, "i", 0,
|
||||||
":", t->param_alloc_buffers.buffers, "ir", 2,
|
":", t->param_alloc_buffers.buffers, "ir", 2,
|
||||||
2, 2, 32,
|
2, 2, MAX_BUFFERS,
|
||||||
":", t->param_alloc_buffers.align, "i", 16);
|
":", t->param_alloc_buffers.align, "i", 16);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -383,7 +387,8 @@ impl_node_port_enum_params(struct spa_node *node,
|
||||||
t->param_alloc_meta_enable.MetaEnable,
|
t->param_alloc_meta_enable.MetaEnable,
|
||||||
":", t->param_alloc_meta_enable.type, "I", t->meta.Ringbuffer,
|
":", 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.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.ringbufferSize, "iru",
|
||||||
|
this->props.min_latency * this->frame_size,
|
||||||
2, this->props.min_latency * this->frame_size,
|
2, this->props.min_latency * this->frame_size,
|
||||||
this->period_frames * this->frame_size,
|
this->period_frames * this->frame_size,
|
||||||
":", t->param_alloc_meta_enable.ringbufferStride, "i", 0,
|
":", t->param_alloc_meta_enable.ringbufferStride, "i", 0,
|
||||||
|
|
|
||||||
|
|
@ -341,7 +341,7 @@ pull_frames(struct state *state,
|
||||||
snd_pcm_uframes_t frames,
|
snd_pcm_uframes_t frames,
|
||||||
bool do_pull)
|
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;
|
bool underrun = false;
|
||||||
|
|
||||||
try_pull(state, frames, do_pull);
|
try_pull(state, frames, do_pull);
|
||||||
|
|
@ -365,16 +365,17 @@ pull_frames(struct state *state,
|
||||||
int32_t avail;
|
int32_t avail;
|
||||||
|
|
||||||
avail = spa_ringbuffer_get_read_index(ringbuffer, &index);
|
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(avail, to_write);
|
||||||
n_frames = SPA_MIN(to_write, n_bytes / state->frame_size);
|
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);
|
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 = avail == n_frames || state->n_buffers == 1;
|
||||||
reuse = true;
|
|
||||||
} else {
|
} else {
|
||||||
offs = SPA_MIN(d[0].chunk->offset + state->ready_offset, d[0].maxsize);
|
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;
|
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);
|
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->callbacks->reuse_buffer(state->callbacks_data, 0, b->outbuf->id);
|
||||||
state->ready_offset = 0;
|
state->ready_offset = 0;
|
||||||
|
|
||||||
try_pull(state, frames, do_pull);
|
|
||||||
}
|
}
|
||||||
total_frames += n_frames;
|
total_frames += n_frames;
|
||||||
to_write -= 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) {
|
if (total_frames == 0 && do_pull) {
|
||||||
total_frames = SPA_MIN(frames, state->threshold);
|
total_frames = SPA_MIN(frames, state->threshold);
|
||||||
snd_pcm_areas_silence(my_areas, offset, state->channels, total_frames, state->format);
|
snd_pcm_areas_silence(my_areas, offset, state->channels, total_frames, state->format);
|
||||||
|
|
@ -454,13 +457,11 @@ push_frames(struct state *state,
|
||||||
d[0].chunk->size = n_bytes;
|
d[0].chunk->size = n_bytes;
|
||||||
d[0].chunk->stride = 0;
|
d[0].chunk->stride = 0;
|
||||||
|
|
||||||
{
|
|
||||||
b->outstanding = true;
|
b->outstanding = true;
|
||||||
io->buffer_id = b->outbuf->id;
|
io->buffer_id = b->outbuf->id;
|
||||||
io->status = SPA_RESULT_HAVE_BUFFER;
|
io->status = SPA_RESULT_HAVE_BUFFER;
|
||||||
state->callbacks->have_output(state->callbacks_data);
|
state->callbacks->have_output(state->callbacks_data);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return total_frames;
|
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));
|
spa_log_error(state->log, "snd_pcm_mmap_begin error: %s", snd_strerror(res));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
spa_log_trace(state->log, "begin %ld %ld", offset, frames);
|
||||||
|
|
||||||
written = pull_frames(state, my_areas, offset, frames, do_pull);
|
written = pull_frames(state, my_areas, offset, frames, do_pull);
|
||||||
if (written < frames)
|
if (written < frames)
|
||||||
to_write = 0;
|
to_write = 0;
|
||||||
|
|
||||||
|
spa_log_trace(state->log, "commit %ld %ld", offset, written);
|
||||||
if ((res = snd_pcm_mmap_commit(hndl, offset, written)) < 0) {
|
if ((res = snd_pcm_mmap_commit(hndl, offset, written)) < 0) {
|
||||||
spa_log_error(state->log, "snd_pcm_mmap_commit error: %s", snd_strerror(res));
|
spa_log_error(state->log, "snd_pcm_mmap_commit error: %s", snd_strerror(res));
|
||||||
if (res != -EPIPE && res != -ESTRPIPE)
|
if (res != -EPIPE && res != -ESTRPIPE)
|
||||||
|
|
|
||||||
|
|
@ -44,9 +44,10 @@ struct props {
|
||||||
char device_name[128];
|
char device_name[128];
|
||||||
char card_name[128];
|
char card_name[128];
|
||||||
uint32_t min_latency;
|
uint32_t min_latency;
|
||||||
|
uint32_t max_latency;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_BUFFERS 64
|
#define MAX_BUFFERS 32
|
||||||
|
|
||||||
struct buffer {
|
struct buffer {
|
||||||
struct spa_buffer *outbuf;
|
struct spa_buffer *outbuf;
|
||||||
|
|
@ -65,6 +66,7 @@ struct type {
|
||||||
uint32_t prop_device_name;
|
uint32_t prop_device_name;
|
||||||
uint32_t prop_card_name;
|
uint32_t prop_card_name;
|
||||||
uint32_t prop_min_latency;
|
uint32_t prop_min_latency;
|
||||||
|
uint32_t prop_max_latency;
|
||||||
struct spa_type_meta meta;
|
struct spa_type_meta meta;
|
||||||
struct spa_type_data data;
|
struct spa_type_data data;
|
||||||
struct spa_type_media_type media_type;
|
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_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_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_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_meta_map(map, &type->meta);
|
||||||
spa_type_data_map(map, &type->data);
|
spa_type_data_map(map, &type->data);
|
||||||
|
|
@ -148,6 +151,7 @@ struct state {
|
||||||
|
|
||||||
struct spa_list free;
|
struct spa_list free;
|
||||||
struct spa_list ready;
|
struct spa_list ready;
|
||||||
|
|
||||||
size_t ready_offset;
|
size_t ready_offset;
|
||||||
|
|
||||||
bool started;
|
bool started;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue