At Thu, 4 Apr 2013 09:21:34 -0700, Dylan Reid wrote:
On Thu, Apr 4, 2013 at 12:10 AM, Takashi Iwai tiwai@suse.de wrote:
At Wed, 3 Apr 2013 08:30:03 -0700, Dylan Reid wrote:
Allow a codec to specify a delay in addition to the delay before samples are passed through DMA. Some codecs have large processing delays because of built-in DSPs that require codec-side buffers of many milliseconds. Default to zero delay if the codec doesn't specify a callback to get the processing delay.
Signed-off-by: Dylan Reid dgreid@chromium.org
sound/pci/hda/hda_codec.c | 17 +++++++++++++++++ sound/pci/hda/hda_codec.h | 4 ++++ sound/pci/hda/hda_intel.c | 2 ++ 3 files changed, 23 insertions(+)
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 17286b3..1d792dd 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3724,6 +3724,23 @@ void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, } EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all);
+/**
- snd_hda_codec_processing_delay - get the fixed delay through the codec
- @codec: HD-audio codec
- @stream: playback or capture
- This is needed for codecs that contain DSPs that cause long delays.
- */
+unsigned int snd_hda_codec_processing_delay(struct hda_codec *codec,
unsigned int stream)
+{
if (codec->patch_ops.get_processing_delay)
return codec->patch_ops.get_processing_delay(codec, stream);
return 0;
+} +EXPORT_SYMBOL_HDA(snd_hda_codec_processing_delay);
In the second thought, it would fit more better to pcm_ops than codec patch_ops. That is, the change would be like below.
Yes this looks better. I'll modify the subsequent patch and run our latency tests on it to make sure it works then resend based on this.
I found a missing substream->runtime check (the function may be called even without running the PCM). The revised patch below was committed to for-next branch in the end.
thanks,
Takashi
--- From: Takashi Iwai tiwai@suse.de Subject: [PATCH] ALSA: hda - Introduce get_delay codec PCM ops
Add a new codec PCM ops, get_delay(), to obtain the codec/stream- specific PCM delay count. When it's NULL, nothing changes.
This new feature was requested for CA0132, which has significant delays in the path depending on the running DSP code.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/hda_codec.h | 3 +++ sound/pci/hda/hda_intel.c | 18 ++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 23ca172..c93f902 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -757,6 +757,9 @@ struct hda_pcm_ops { struct snd_pcm_substream *substream); int (*cleanup)(struct hda_pcm_stream *info, struct hda_codec *codec, struct snd_pcm_substream *substream); + unsigned int (*get_delay)(struct hda_pcm_stream *info, + struct hda_codec *codec, + struct snd_pcm_substream *substream); };
/* PCM information for each substream */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 418bfc0..735567e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2349,8 +2349,11 @@ static unsigned int azx_get_position(struct azx *chip, struct azx_dev *azx_dev, bool with_check) { + struct snd_pcm_substream *substream = azx_dev->substream; + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); unsigned int pos; - int stream = azx_dev->substream->stream; + int stream = substream->stream; + struct hda_pcm_stream *hinfo = apcm->hinfo[stream]; int delay = 0;
switch (chip->position_fix[stream]) { @@ -2381,7 +2384,7 @@ static unsigned int azx_get_position(struct azx *chip, pos = 0;
/* calculate runtime delay from LPIB */ - if (azx_dev->substream->runtime && + if (substream->runtime && chip->position_fix[stream] == POS_FIX_POSBUF && (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) { unsigned int lpib_pos = azx_sd_readl(azx_dev, SD_LPIB); @@ -2399,9 +2402,16 @@ static unsigned int azx_get_position(struct azx *chip, delay = 0; chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY; } - azx_dev->substream->runtime->delay = - bytes_to_frames(azx_dev->substream->runtime, delay); + delay = bytes_to_frames(substream->runtime, delay); } + + if (substream->runtime) { + if (hinfo->ops.get_delay) + delay += hinfo->ops.get_delay(hinfo, apcm->codec, + substream); + substream->runtime->delay = delay; + } + trace_azx_get_position(chip, azx_dev, pos, delay); return pos; }