Comment 14 for bug 100114

Revision history for this message
TJ (tj) wrote :

Thanks for that report, it was just what I needed. I was already tracking the various code responsible for updating posbuf and your trace has confirmed some of what I was expecting. There are several reasons why posbuf/pos won't be updated so we should try eliminating possibilities.

In snd_pcm_update_hw_ptr_pos() it is possible that a buffer over-run (XRUN) could prevent pos being updated:

  pos = substream->ops->pointer(substream);
  if (pos == SNDRV_PCM_POS_XRUN)
   return pos; /* XRUN */

Because if the function didn't return at that point it would update pos:

  pos -= pos % runtime->min_align;

Using CONFIG_SND_PCM_XRUN_DEBUG, in snd_pcm_update_hw_ptr_interrupt() we might see something useful from:

 #ifdef CONFIG_SND_PCM_XRUN_DEBUG
  if (runtime->periods > 1 && substream->pstr->xrun_debug) {
   snd_printd(KERN_ERR "Unexpected hw_pointer value [1] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
   if (substream->pstr->xrun_debug > 1)
    dump_stack();
 }
 #endif

assuming that the function didn't return before it got to that point:

 pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
 if (pos == SNDRV_PCM_POS_XRUN) {
  xrun(substream);
  return -EPIPE;
 }

Alternatively, we need to watch snd_pcm_update_hw_ptr_interrupt() where control can branch:

 if (runtime->period_size == runtime->buffer_size)
  goto __next_buf;
 new_hw_ptr = runtime->hw_ptr_base + pos;
 hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size;