From 9442e691e4aec85eba43ac60a3e77c77fd2e73a4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 30 Sep 2006 23:27:19 -0700 Subject: [PATCH] [PATCH] maximum latency tracking: ALSA support Add maximum latency tracking to the ALSA subsystem for PCM playback. In ALSA, the playback application controls the buffer size and thus indirectly the period of latency that it can deal with. This patch uses 75% of the total available latency as threshold to announce to the latency subsystem; While 75% is a crude heuristic it's a quite reasonable one; the remaining 25% can be used for all driver processing for the next samples which is also proportional to the size of the buffer. With ogg123 a latency setting of about 4msec was seen (at 44Khz), while with the "play" command a much longer maximum tolerable latency was seen. Other, more multimedia oriented players as well as games, will have a lot smaller buffers to allow better synchronization and those will actually get into the latency domains where there is impact on the power management rules. Signed-off-by: Takashi Iwai Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/sound/pcm.h | 1 + sound/core/pcm.c | 3 +++ sound/core/pcm_native.c | 23 ++++++++++++++++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 60d40b34efc0..afaf3e88e086 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -347,6 +347,7 @@ struct snd_pcm_substream { int number; char name[32]; /* substream name */ int stream; /* stream (direction) */ + char latency_id[20]; /* latency identifier */ size_t buffer_bytes_max; /* limit ring buffer size */ struct snd_dma_buffer dma_buffer; unsigned int dma_buf_id; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index bf8f412988b8..fbbbcd20c4cc 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -629,6 +629,9 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) substream->number = idx; substream->stream = stream; sprintf(substream->name, "subdevice #%i", idx); + snprintf(substream->latency_id, sizeof(substream->latency_id), + "ALSA-PCM%d-%d%c%d", pcm->card->number, pcm->device, + (stream ? 'c' : 'p'), idx); substream->buffer_bytes_max = UINT_MAX; if (prev == NULL) pstr->substream = substream; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 0224c70414f5..891d7140553c 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -347,11 +348,26 @@ out: return err; } +static int period_to_usecs(struct snd_pcm_runtime *runtime) +{ + int usecs; + + if (! runtime->rate) + return -1; /* invalid */ + + /* take 75% of period time as the deadline */ + usecs = (750000 / runtime->rate) * runtime->period_size; + usecs += ((750000 % runtime->rate) * runtime->period_size) / + runtime->rate; + + return usecs; +} + static int snd_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime; - int err; + int err, usecs; unsigned int bits; snd_pcm_uframes_t frames; @@ -431,6 +447,10 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, snd_pcm_timer_resolution_change(substream); runtime->status->state = SNDRV_PCM_STATE_SETUP; + + remove_acceptable_latency(substream->latency_id); + if ((usecs = period_to_usecs(runtime)) >= 0) + set_acceptable_latency(substream->latency_id, usecs); return 0; _error: /* hardware might be unuseable from this time, @@ -490,6 +510,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) if (substream->ops->hw_free) result = substream->ops->hw_free(substream); runtime->status->state = SNDRV_PCM_STATE_OPEN; + remove_acceptable_latency(substream->latency_id); return result; }