Commit 9442e691e4aec85eba43ac60a3e77c77fd2e73a4

Authored by Takashi Iwai
Committed by Linus Torvalds
1 parent 5c87579e65

[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 <tiwai@suse.de>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 3 changed files with 26 additions and 1 deletions Side-by-side Diff

... ... @@ -347,6 +347,7 @@
347 347 int number;
348 348 char name[32]; /* substream name */
349 349 int stream; /* stream (direction) */
  350 + char latency_id[20]; /* latency identifier */
350 351 size_t buffer_bytes_max; /* limit ring buffer size */
351 352 struct snd_dma_buffer dma_buffer;
352 353 unsigned int dma_buf_id;
... ... @@ -629,6 +629,9 @@
629 629 substream->number = idx;
630 630 substream->stream = stream;
631 631 sprintf(substream->name, "subdevice #%i", idx);
  632 + snprintf(substream->latency_id, sizeof(substream->latency_id),
  633 + "ALSA-PCM%d-%d%c%d", pcm->card->number, pcm->device,
  634 + (stream ? 'c' : 'p'), idx);
632 635 substream->buffer_bytes_max = UINT_MAX;
633 636 if (prev == NULL)
634 637 pstr->substream = substream;
sound/core/pcm_native.c
... ... @@ -25,6 +25,7 @@
25 25 #include <linux/file.h>
26 26 #include <linux/slab.h>
27 27 #include <linux/time.h>
  28 +#include <linux/latency.h>
28 29 #include <linux/uio.h>
29 30 #include <sound/core.h>
30 31 #include <sound/control.h>
31 32  
... ... @@ -347,11 +348,26 @@
347 348 return err;
348 349 }
349 350  
  351 +static int period_to_usecs(struct snd_pcm_runtime *runtime)
  352 +{
  353 + int usecs;
  354 +
  355 + if (! runtime->rate)
  356 + return -1; /* invalid */
  357 +
  358 + /* take 75% of period time as the deadline */
  359 + usecs = (750000 / runtime->rate) * runtime->period_size;
  360 + usecs += ((750000 % runtime->rate) * runtime->period_size) /
  361 + runtime->rate;
  362 +
  363 + return usecs;
  364 +}
  365 +
350 366 static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
351 367 struct snd_pcm_hw_params *params)
352 368 {
353 369 struct snd_pcm_runtime *runtime;
354   - int err;
  370 + int err, usecs;
355 371 unsigned int bits;
356 372 snd_pcm_uframes_t frames;
357 373  
... ... @@ -431,6 +447,10 @@
431 447  
432 448 snd_pcm_timer_resolution_change(substream);
433 449 runtime->status->state = SNDRV_PCM_STATE_SETUP;
  450 +
  451 + remove_acceptable_latency(substream->latency_id);
  452 + if ((usecs = period_to_usecs(runtime)) >= 0)
  453 + set_acceptable_latency(substream->latency_id, usecs);
434 454 return 0;
435 455 _error:
436 456 /* hardware might be unuseable from this time,
... ... @@ -490,6 +510,7 @@
490 510 if (substream->ops->hw_free)
491 511 result = substream->ops->hw_free(substream);
492 512 runtime->status->state = SNDRV_PCM_STATE_OPEN;
  513 + remove_acceptable_latency(substream->latency_id);
493 514 return result;
494 515 }
495 516