From 7e513ea2433482767358e50537eaa2783444dc64 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Oct 2018 10:02:10 +0200 Subject: [PATCH] alsa: clamp the period size to something sensible some clients (sweep) want to negotiate the smallest possible period size we can support, which is expressed in bytes and independent of samplerate, format and number of channels. For files with high samplerate and channelcount, this results in periods of 8 frames, which is too small to handle. Instead round up the period size to something we can likely handle, taking into account the samplerate and number of channels. --- alsa-plugins/pcm_pipewire.c | 44 ++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/alsa-plugins/pcm_pipewire.c b/alsa-plugins/pcm_pipewire.c index b56f2ae..56a78df 100644 --- a/alsa-plugins/pcm_pipewire.c +++ b/alsa-plugins/pcm_pipewire.c @@ -45,6 +45,8 @@ #define MAX_CHANNELS 32 #define MAX_RATE (48000*8) +#define MIN_PERIOD 64 + typedef struct { snd_pcm_ioplug_t io; @@ -189,9 +191,9 @@ snd_pcm_pipewire_process_playback(snd_pcm_pipewire_t *pw, struct pw_buffer *b) nbytes = SPA_MIN(avail, maxsize - offset); ptr = SPA_MEMBER(d[0].data, offset, void); - pw_log_trace("%d %d %d %d %p %d", nbytes, avail, filled, offset, ptr, io->state); nframes = nbytes / bpf; + pw_log_trace("%d %d %lu %d %d %p %d", nbytes, avail, nframes, filled, offset, ptr, io->state); for (channel = 0; channel < io->channels; channel++) { pwareas[channel].addr = ptr; @@ -317,10 +319,15 @@ static void on_stream_format_changed(void *data, const struct spa_pod *format) uint8_t buffer[4096]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); uint32_t stride = (io->channels * pw->sample_bits) / 8; - uint32_t buffers = SPA_CLAMP(io->buffer_size / io->period_size, MIN_BUFFERS, MAX_BUFFERS); - uint32_t size = io->period_size * stride; + uint32_t buffers; + uint32_t size; + + io->period_size = pw->min_avail; + buffers = SPA_CLAMP(io->buffer_size / io->period_size, MIN_BUFFERS, MAX_BUFFERS); + size = io->period_size * stride; - pw_log_info("buffers %lu %lu %u %u %u", io->buffer_size, io->period_size, buffers, stride, size); + pw_log_info("buffer_size:%lu period_size:%lu buffers:%u stride:%u size:%u min_avail:%lu", + io->buffer_size, io->period_size, buffers, stride, size, pw->min_avail); params[n_params++] = spa_pod_builder_object(&b, SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers, @@ -367,10 +374,20 @@ static int snd_pcm_pipewire_prepare(snd_pcm_ioplug_t *io) struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); struct pw_properties *props; int res; + uint32_t min_period; pw_thread_loop_lock(pw->main_loop); - pw_log_debug("prepare %d %p %lu", pw->error, pw->stream, io->period_size); + snd_pcm_sw_params_alloca(&swparams); + if ((res = snd_pcm_sw_params_current(io->pcm, swparams)) == 0) + snd_pcm_sw_params_get_avail_min(swparams, &pw->min_avail); + else + pw->min_avail = io->period_size; + + min_period = (MIN_PERIOD * io->rate / 48000); + pw->min_avail = SPA_MAX(pw->min_avail, min_period); + + pw_log_debug("prepare %d %p %lu %ld", pw->error, pw->stream, io->period_size, pw->min_avail); if (!pw->error && pw->stream != NULL) goto done; @@ -380,7 +397,8 @@ static int snd_pcm_pipewire_prepare(snd_pcm_ioplug_t *io) } props = pw_properties_new("client.api", "alsa", NULL); - pw_properties_setf(props, "node.latency", "%lu/%u", io->period_size, io->rate); + + pw_properties_setf(props, "node.latency", "%lu/%u", pw->min_avail, io->rate); pw_properties_set(props, PW_NODE_PROP_MEDIA, "Audio"); pw_properties_set(props, PW_NODE_PROP_CATEGORY, io->stream == SND_PCM_STREAM_PLAYBACK ? @@ -410,12 +428,6 @@ static int snd_pcm_pipewire_prepare(snd_pcm_ioplug_t *io) done: pw->hw_ptr = 0; - snd_pcm_sw_params_alloca(&swparams); - if ((res = snd_pcm_sw_params_current(io->pcm, swparams)) == 0) - snd_pcm_sw_params_get_avail_min(swparams, &pw->min_avail); - else - pw->min_avail = io->period_size; - pw_thread_loop_unlock(pw->main_loop); return 0; @@ -505,7 +517,7 @@ static int snd_pcm_pipewire_hw_params(snd_pcm_ioplug_t * io, snd_pcm_pipewire_t *pw = io->private_data; bool planar; - pw_log_debug("hw_params"); + pw_log_debug("hw_params %lu %lu", io->buffer_size, io->period_size); switch(io->access) { case SND_PCM_ACCESS_MMAP_INTERLEAVED: @@ -722,10 +734,12 @@ static int pipewire_set_hw_constraint(snd_pcm_pipewire_t *pw) 1, MAX_CHANNELS)) < 0 || (err = snd_pcm_ioplug_set_param_minmax(&pw->io, SND_PCM_IOPLUG_HW_RATE, 1, MAX_RATE)) < 0 || + (err = snd_pcm_ioplug_set_param_minmax(&pw->io, SND_PCM_IOPLUG_HW_BUFFER_BYTES, + 16*1024, 4*1024*1024)) < 0 || (err = snd_pcm_ioplug_set_param_minmax(&pw->io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, - 128, 64*1024)) < 0 || + 128, 2*1024*1024)) < 0 || (err = snd_pcm_ioplug_set_param_minmax(&pw->io, SND_PCM_IOPLUG_HW_PERIODS, - 2, 64)) < 0) + 3, 64)) < 0) return err; return 0;