<html>
    <head>
      <base href="https://bugs.freedesktop.org/" />
    </head>
    <body>
      <p>
        <div>
            <b><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - periodic audio skips with Intel HDA"
   href="https://bugs.freedesktop.org/show_bug.cgi?id=49608#c53">Comment # 53</a>
              on <a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - periodic audio skips with Intel HDA"
   href="https://bugs.freedesktop.org/show_bug.cgi?id=49608">bug 49608</a>
              from <span class="vcard"><a class="email" href="mailto:superquad.vortex2@gmail.com" title="Raymond <superquad.vortex2@gmail.com>"> <span class="fn">Raymond</span></a>
</span></b>
        <pre>as pulseaudio use snd_pcm_rewind() which require the sound card report accurate
hwptr position than those sound card which report hwptr position at period
bounary when interrupt occur 


the difference between hda-intel and your ca0106 is the granularity of the
pointer callback 


<a href="https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/tree/include/linux/dmaengine.h">https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/tree/include/linux/dmaengine.h</a>


/**
 * enum dma_residue_granularity - Granularity of the reported transfer residue
 * @DMA_RESIDUE_GRANULARITY_DESCRIPTOR: Residue reporting is not support. The
 *  DMA channel is only able to tell whether a descriptor has been completed or
 *  not, which means residue reporting is not supported by this channel. The
 *  residue field of the dma_tx_state field will always be 0.
 * @DMA_RESIDUE_GRANULARITY_SEGMENT: Residue is updated after each successfully
 *  completed segment of the transfer (For cyclic transfers this is after each
 *  period). This is typically implemented by having the hardware generate an
 *  interrupt after each transferred segment and then the drivers updates the
 *  outstanding residue by the size of the segment. Another possibility is if
 *  the hardware supports scatter-gather and the segment descriptor has a field
 *  which gets set after the segment has been completed. The driver then counts
 *  the number of segments without the flag set to compute the residue.
 * @DMA_RESIDUE_GRANULARITY_BURST: Residue is updated after each transferred
 *  burst. This is typically only supported if the hardware has a progress
 *  register of some sort (E.g. a register with the current read/write address
 *  or a register with the amount of bursts/beats/bytes that have been
 *  transferred or still need to be transferred).
 */

hda-intel  can report DMA_RESIDUE_GRANULARITY_BURST  

seem both read hwptr from hardware register

can your ca0106 report DMA_RESIDUE_GRANULARITY_SEGMENT or
DMA_RESIDUE_GRANULARITY_BURST ?



<a href="https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/tree/sound/pci/ca0106/ca0106_main.c">https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/tree/sound/pci/ca0106/ca0106_main.c</a>


static snd_pcm_uframes_t
snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream)
{
    struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
    struct snd_pcm_runtime *runtime = substream->runtime;
    struct snd_ca0106_pcm *epcm = runtime->private_data;
    unsigned int ptr, prev_ptr;
    int channel = epcm->channel_id;
    int timeout = 10;

    if (!epcm->running)
        return 0;

    prev_ptr = -1;
    do {
        ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
        ptr = (ptr >> 3) * runtime->period_size;
        ptr += bytes_to_frames(runtime,
            snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel));
        if (ptr >= runtime->buffer_size)
            ptr -= runtime->buffer_size;
        if (prev_ptr == ptr)
            return ptr;
        prev_ptr = ptr;
    } while (--timeout);
    dev_warn(emu->card->dev, "ca0106: unstable DMA pointer!\n");
    return 0;
}


<a href="https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/tree/sound/pci/hda/hda_controller.c">https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/tree/sound/pci/hda/hda_controller.c</a>

static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
{
    struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
    struct azx *chip = apcm->chip;
    struct azx_dev *azx_dev = get_azx_dev(substream);
    return bytes_to_frames(substream->runtime,
                   azx_get_position(chip, azx_dev));
}</pre>
        </div>
      </p>
      <hr>
      <span>You are receiving this mail because:</span>
      
      <ul>
          <li>You are the QA Contact for the bug.</li>
          <li>You are the assignee for the bug.</li>
      </ul>
    </body>
</html>