aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2006-10-01 02:27:19 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-01 03:39:19 -0400
commit9442e691e4aec85eba43ac60a3e77c77fd2e73a4 (patch)
tree51314e5fcf6c023788df67a130cb6e692e5df496
parent5c87579e65ee4f419b2369407f82326d38b5d2d8 (diff)
[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>
-rw-r--r--include/sound/pcm.h1
-rw-r--r--sound/core/pcm.c3
-rw-r--r--sound/core/pcm_native.c23
3 files changed, 26 insertions, 1 deletions
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 {
347 int number; 347 int number;
348 char name[32]; /* substream name */ 348 char name[32]; /* substream name */
349 int stream; /* stream (direction) */ 349 int stream; /* stream (direction) */
350 char latency_id[20]; /* latency identifier */
350 size_t buffer_bytes_max; /* limit ring buffer size */ 351 size_t buffer_bytes_max; /* limit ring buffer size */
351 struct snd_dma_buffer dma_buffer; 352 struct snd_dma_buffer dma_buffer;
352 unsigned int dma_buf_id; 353 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)
629 substream->number = idx; 629 substream->number = idx;
630 substream->stream = stream; 630 substream->stream = stream;
631 sprintf(substream->name, "subdevice #%i", idx); 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 substream->buffer_bytes_max = UINT_MAX; 635 substream->buffer_bytes_max = UINT_MAX;
633 if (prev == NULL) 636 if (prev == NULL)
634 pstr->substream = substream; 637 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 @@
25#include <linux/file.h> 25#include <linux/file.h>
26#include <linux/slab.h> 26#include <linux/slab.h>
27#include <linux/time.h> 27#include <linux/time.h>
28#include <linux/latency.h>
28#include <linux/uio.h> 29#include <linux/uio.h>
29#include <sound/core.h> 30#include <sound/core.h>
30#include <sound/control.h> 31#include <sound/control.h>
@@ -347,11 +348,26 @@ out:
347 return err; 348 return err;
348} 349}
349 350
351static 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
350static int snd_pcm_hw_params(struct snd_pcm_substream *substream, 366static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
351 struct snd_pcm_hw_params *params) 367 struct snd_pcm_hw_params *params)
352{ 368{
353 struct snd_pcm_runtime *runtime; 369 struct snd_pcm_runtime *runtime;
354 int err; 370 int err, usecs;
355 unsigned int bits; 371 unsigned int bits;
356 snd_pcm_uframes_t frames; 372 snd_pcm_uframes_t frames;
357 373
@@ -431,6 +447,10 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
431 447
432 snd_pcm_timer_resolution_change(substream); 448 snd_pcm_timer_resolution_change(substream);
433 runtime->status->state = SNDRV_PCM_STATE_SETUP; 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 return 0; 454 return 0;
435 _error: 455 _error:
436 /* hardware might be unuseable from this time, 456 /* hardware might be unuseable from this time,
@@ -490,6 +510,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
490 if (substream->ops->hw_free) 510 if (substream->ops->hw_free)
491 result = substream->ops->hw_free(substream); 511 result = substream->ops->hw_free(substream);
492 runtime->status->state = SNDRV_PCM_STATE_OPEN; 512 runtime->status->state = SNDRV_PCM_STATE_OPEN;
513 remove_acceptable_latency(substream->latency_id);
493 return result; 514 return result;
494} 515}
495 516