From 73896bfa83902e7de28f2e3f1e9bf600ff5a96e7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 21 Jan 2021 17:10:48 +0100 Subject: [PATCH] alsa: rework batch handling a bit By default, use a 512 period for batch and use 512 headroom Add a property to disable special batch handling. --- spa/plugins/alsa/alsa-pcm-sink.c | 14 ++++++---- spa/plugins/alsa/alsa-pcm-source.c | 14 ++++++---- spa/plugins/alsa/alsa-pcm.c | 29 +++++++------------- spa/plugins/alsa/alsa-pcm.h | 1 + src/daemon/media-session.d/alsa-monitor.conf | 1 + 5 files changed, 28 insertions(+), 31 deletions(-) diff --git a/spa/plugins/alsa/alsa-pcm-sink.c b/spa/plugins/alsa/alsa-pcm-sink.c index 89b5a735c..d75c4a6ec 100644 --- a/spa/plugins/alsa/alsa-pcm-sink.c +++ b/spa/plugins/alsa/alsa-pcm-sink.c @@ -776,6 +776,7 @@ impl_init(const struct spa_handle_factory *factory, snd_config_update_free_global(); for (i = 0; info && i < info->n_items; i++) { + const char *s = info->items[i].value; if (!strcmp(info->items[i].key, SPA_KEY_API_ALSA_PATH)) { snprintf(this->props.device, 63, "%s", info->items[i].value); } else if (!strcmp(info->items[i].key, SPA_KEY_AUDIO_CHANNELS)) { @@ -786,20 +787,21 @@ impl_init(const struct spa_handle_factory *factory, this->default_format = spa_alsa_format_from_name(info->items[i].value, 128); } else if (!strcmp(info->items[i].key, SPA_KEY_AUDIO_POSITION)) { size_t len; - const char *p = info->items[i].value; - while (*p && this->default_pos.channels < SPA_AUDIO_MAX_CHANNELS) { - if ((len = strcspn(p, ",")) == 0) + while (*s && this->default_pos.channels < SPA_AUDIO_MAX_CHANNELS) { + if ((len = strcspn(s, ",")) == 0) break; this->default_pos.pos[this->default_pos.channels++] = - spa_alsa_channel_from_name(p, len); - p += len + strspn(p+len, ","); + spa_alsa_channel_from_name(s, len); + s += len + strspn(s+len, ","); } } else if (!strcmp(info->items[i].key, "api.alsa.period-size")) { this->default_period_size = atoi(info->items[i].value); } else if (!strcmp(info->items[i].key, "api.alsa.headroom")) { this->default_headroom = atoi(info->items[i].value); } else if (!strcmp(info->items[i].key, "api.alsa.disable-mmap")) { - this->disable_mmap = atoi(info->items[i].value); + this->disable_mmap = (strcmp(s, "true") == 0 || atoi(s) == 1); + } else if (!strcmp(info->items[i].key, "api.alsa.disable-batch")) { + this->disable_batch = (strcmp(s, "true") == 0 || atoi(s) == 1); } } return 0; diff --git a/spa/plugins/alsa/alsa-pcm-source.c b/spa/plugins/alsa/alsa-pcm-source.c index 9535fa1b3..17b12e789 100644 --- a/spa/plugins/alsa/alsa-pcm-source.c +++ b/spa/plugins/alsa/alsa-pcm-source.c @@ -797,6 +797,7 @@ impl_init(const struct spa_handle_factory *factory, snd_config_update_free_global(); for (i = 0; info && i < info->n_items; i++) { + const char *s = info->items[i].value; if (!strcmp(info->items[i].key, SPA_KEY_API_ALSA_PATH)) { snprintf(this->props.device, 63, "%s", info->items[i].value); } else if (!strcmp(info->items[i].key, SPA_KEY_AUDIO_CHANNELS)) { @@ -807,20 +808,21 @@ impl_init(const struct spa_handle_factory *factory, this->default_format = spa_alsa_format_from_name(info->items[i].value, 128); } else if (!strcmp(info->items[i].key, SPA_KEY_AUDIO_POSITION)) { size_t len; - const char *p = info->items[i].value; - while (*p && this->default_pos.channels < SPA_AUDIO_MAX_CHANNELS) { - if ((len = strcspn(p, ",")) == 0) + while (*s && this->default_pos.channels < SPA_AUDIO_MAX_CHANNELS) { + if ((len = strcspn(s, ",")) == 0) break; this->default_pos.pos[this->default_pos.channels++] = - spa_alsa_channel_from_name(p, len); - p += len + strspn(p+len, ","); + spa_alsa_channel_from_name(s, len); + s += len + strspn(s+len, ","); } } else if (!strcmp(info->items[i].key, "api.alsa.period-size")) { this->default_period_size = atoi(info->items[i].value); } else if (!strcmp(info->items[i].key, "api.alsa.headroom")) { this->default_headroom = atoi(info->items[i].value); } else if (!strcmp(info->items[i].key, "api.alsa.disable-mmap")) { - this->disable_mmap = atoi(info->items[i].value); + this->disable_mmap = (strcmp(s, "true") == 0 || atoi(s) == 1); + } else if (!strcmp(info->items[i].key, "api.alsa.disable-batch")) { + this->disable_batch = (strcmp(s, "true") == 0 || atoi(s) == 1); } } return 0; diff --git a/spa/plugins/alsa/alsa-pcm.c b/spa/plugins/alsa/alsa-pcm.c index 07b3b8185..76c6158b0 100644 --- a/spa/plugins/alsa/alsa-pcm.c +++ b/spa/plugins/alsa/alsa-pcm.c @@ -584,47 +584,38 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_ dir = 0; period_size = state->default_period_size ? state->default_period_size : 1024; - is_batch = snd_pcm_hw_params_is_batch(params); - if (is_batch) { - const char *id; - snd_pcm_info_t* pcm_info; - snd_pcm_info_alloca(&pcm_info); - if (snd_pcm_info(hndl, pcm_info) == 0 && - (id = snd_pcm_info_get_id(pcm_info)) != NULL) { - /* usb devices have low enough transfer size */ - if (strcmp(id, "USB Audio") == 0) - is_batch = false; - } - } + is_batch = snd_pcm_hw_params_is_batch(params) && + !state->disable_batch; + if (is_batch) { /* batch devices get their hw pointers updated every period. Make * the period smaller and add one period of headroom */ period_size /= 2; spa_log_info(state->log, NAME" %s: batch mode, period_size:%ld", - state->props.device, period_size); + state->props.device, period_size); } CHECK(snd_pcm_hw_params_set_period_size_near(hndl, params, &period_size, &dir), "set_period_size_near"); CHECK(snd_pcm_hw_params_get_buffer_size_max(params, &state->buffer_frames), "get_buffer_size_max"); CHECK(snd_pcm_hw_params_set_buffer_size_near(hndl, params, &state->buffer_frames), "set_buffer_size_near"); - if (state->default_headroom == 0) - state->headroom = is_batch ? period_size : 0; - else - state->headroom = state->default_headroom; + state->headroom = state->default_headroom; + if (is_batch) + state->headroom += period_size; state->period_frames = period_size; periods = state->buffer_frames / state->period_frames; spa_log_info(state->log, NAME" %s (%s): format:%s access:%s-%s rate:%d channels:%d " - "buffer frames %lu, period frames %lu, periods %u, frame_size %zd", + "buffer frames %lu, period frames %lu, periods %u, frame_size %zd" + "headroom %u", state->props.device, state->stream == SND_PCM_STREAM_CAPTURE ? "capture" : "playback", snd_pcm_format_name(state->format), state->use_mmap ? "mmap" : "rw", planar ? "planar" : "interleaved", state->rate, state->channels, state->buffer_frames, state->period_frames, - periods, state->frame_size); + periods, state->frame_size, state->headroom); /* write the parameters to device */ CHECK(snd_pcm_hw_params(hndl, params), "set_hw_params"); diff --git a/spa/plugins/alsa/alsa-pcm.h b/spa/plugins/alsa/alsa-pcm.h index 69ab6f690..7b949029f 100644 --- a/spa/plugins/alsa/alsa-pcm.h +++ b/spa/plugins/alsa/alsa-pcm.h @@ -117,6 +117,7 @@ struct state { unsigned int default_rate; struct channel_map default_pos; unsigned int disable_mmap; + unsigned int disable_batch; snd_pcm_uframes_t buffer_frames; snd_pcm_uframes_t period_frames; diff --git a/src/daemon/media-session.d/alsa-monitor.conf b/src/daemon/media-session.d/alsa-monitor.conf index 62aead16c..47c58e951 100644 --- a/src/daemon/media-session.d/alsa-monitor.conf +++ b/src/daemon/media-session.d/alsa-monitor.conf @@ -58,6 +58,7 @@ rules = [ #api.alsa.period-size = 1024 #api.alsa.headroom = 0 #api.alsa.disable-mmap = false + #api.alsa.disable-batch = false } } }