Alsa-Devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: mein_name@ist-einmalig.de
To: alsa-devel@alsa-project.org
Subject: playback delay and problems with simultaneous playback/capture
Date: Wed, 06 Jan 2010 15:51:31 +0100	[thread overview]
Message-ID: <20100106145131.24670@gmx.net> (raw)

I am currently testing my driver but I've got some problems with the "pcm machine"...as it is my first ALSA driver I am open for every hint. The code currently is not conform to linux kernel coding style, I will do all such cosmetically stuff after functionality is given.

1.
Playing a file works fine, but when the ALSA middle layer triggers stop command, the DSP still has data to play, so sending a stop signal to the DSP at this moment would result in breaking the playback. The strange thing here is, that it seems there are 6 frames missing, but the buffer of the DSP is only about 3 frames long. I am not sure if the problem here is, that I am not correctly "calculating" the pcm_pointer:

static snd_pcm_uframes_t
  snd_card_mychip_pcm_pointer(struct snd_pcm_substream *substream)
{
  struct snd_pcm_runtime *runtime = substream->runtime;
  struct snd_mychip_pcm *dpcm = runtime->private_data;


  /* get the current hardware pointer */
  // TODO: calc correct return value

  print_log(DEBUGC "pcm pointer: ret b=%lu\n",
     bytes_to_frames(runtime, dpcm->pcm_buf_pos));

  return bytes_to_frames(runtime, dpcm->pcm_buf_pos);
}


2.
when playing and capturing data simultaneously, I get troubles in both. Playback or Capture alone is working, but if both come togheter, troubles occur. The data-transfer from ALSA to DSP and DSP to ALSA I am doing in the timer function, I am not sure if this could be the problem...but to send data to the DSP I have to check a flag if the DSP is able to receive data, if so, I can send data, otherwise I have to wait until DSP is ready to receive data. That is done with dsp_sendstream. When capturing, the DSP is sending an interrupt every captured period that is available, so I store that in a buffer from where it got read frequently via the timer function (done by readbuf)...everytime when going through this function I think that this way may work, as it does normally, but I am absolutely n
 ot sure if this is a "right" way. I know that there are so called "copy" and "silence" callbacks, but using the copy callback for playback I lost frames, so I did it like it is now...

static void snd_card_mychip_pcm_timer_function(unsigned long data)
{
    struct snd_mychip_pcm *dpcm = (struct snd_mychip_pcm *)data;
    unsigned long flags;
    int count, pos, status;

    // disable interrupts
    spin_lock_irqsave(&dpcm->lock, flags);

    // restart the timer to be called again after one jiffie = 1 ms
    dpcm->timer.expires = 1 + jiffies;
    add_timer(&dpcm->timer);

    if (dpcm->substream->stream == 0) { // playback stream
        // increase counters by bytes per jiffie
        if (dpcm->sendingnotpossible == 0) {     
          dpcm->pcm_irq_pos += dpcm->pcm_jiffie;  //0..MAX_PERIOD_SIZE step=jiffie
          dpcm->pcm_buf_pos += dpcm->pcm_jiffie;  //0..MAX_BUFFER_SIZE step=jiffie
        }
        // if pcm_count has been reached, call snd_pcm_period_elapsed
        // to signal the end of one period (e.g. 288 for mpg or 768 for wav)
        if (dpcm->pcm_irq_pos >= dpcm->pcm_count) { // >= MAX_PERIOD_SIZE? 
            count=dpcm->pcm_count;        // number of bytes to be sent
            pos=dpcm->pcm_buf_pos-count;  // start offset in DMA buffer
            // try to send data to dsp
            status = dsp_sendstream(dpcm->substream->pcm->device, dpcm->substream->runtime->dma_area+pos, count);
            if (status != 0) {  // sending not possible
                dpcm->sendingnotpossible=1;
            } else {            // sending successful
                dpcm->sendingnotpossible=0;
                dpcm->sentframes++;
                if (dpcm->sentframes == 3) // 3 frames in buffer so we can start playback
                {
                  // start decoder playback
                  status=dsp_decod_action(dpcm->substream->pcm->device, DECOD_START);
                  print_log(DEBUGA "reply of dsp_decod_action = %i\n",status);
                }
                // wrap counter if end of buffer is reached
                dpcm->pcm_buf_pos %= dpcm->pcm_size;
                // wrap this counter too
                dpcm->pcm_irq_pos %= dpcm->pcm_count;    
                // tell the PCM middle layer when the buffer position goes across the prescribed period size
                snd_pcm_period_elapsed(dpcm->substream);
                print_log(DEBUGC "timer_function: Period elapsed (p) - pcm_count=%i - pcm_size=%i - src=%p - jiffie=%i\n",dpcm->pcm_count,dpcm->pcm_size,dpcm->substream->runtime->dma_area,dpcm->pcm_jiffie);
            }
            // enable interrupts
            spin_unlock_irqrestore(&dpcm->lock, flags);
        } else {  
            // wrap counter if end of buffer is reached
            dpcm->pcm_buf_pos %= dpcm->pcm_size;
            // enable interrupts
            spin_unlock_irqrestore(&dpcm->lock, flags);
        }
    } else if (dpcm->substream->stream == 1) { // capture stream
        count = dpcm->pcm_count;  // number of bytes to be captured
        pos = dpcm->pcm_buf_pos;  // start offset in DMA buffer
        // read from HIF buffer
        status = readbuf(dpcm->substream->pcm->device, dpcm->substream->runtime->dma_area+pos, count);
        if (status == 0) {  // we got new data from HIF buffer => increase pointers..
            dpcm->pcm_buf_pos += count;
            // wrap counter if end of buffer is reached
            dpcm->pcm_buf_pos %= dpcm->pcm_size;
            // wrap this counter too
            //dpcm->pcm_irq_pos %= dpcm->pcm_count;    
            // tell the PCM middle layer when the buffer position goes across the prescribed period size
            snd_pcm_period_elapsed(dpcm->substream);
            print_log(DEBUG "timer_function: Period elapsed (c) - pcm_count=%i - pcm_size=%i - src=%p - jiffie=%i\n",dpcm->pcm_count,dpcm->pcm_size,dpcm->substream->runtime->dma_area,dpcm->pcm_jiffie);
        }
        // enable interrupts
        spin_unlock_irqrestore(&dpcm->lock, flags);
    }
}

3.
Sometimes I am getting underruns with aplay or xruns with arecord. Currently I am not quite sure why they occur, but I guess this has to do with some of above problems?

-bash-3.2# aplay 20575_24k_100.wav
Playing WAVE '20575_24k_100.wav ' : Signed 16 bit Little Endian, Rate 24000 Hz, Mono
underrun!!! (at least 8.019 ms long)


As a reference I used the dummy driver and the tutorial Writing an ALSA Driver. If there are some other drivers that may be similar and I can look at, I am thankful for every hint! So far thanks for helping me!

Greetings,
Max

-- 
Jetzt kostenlos herunterladen: Internet Explorer 8 und Mozilla Firefox 3.5 -
sicherer, schneller und einfacher! http://portal.gmx.net/de/go/chbrowser

             reply	other threads:[~2010-01-06 14:51 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-01-06 14:51 mein_name [this message]
  -- strict thread matches above, loose matches on Subject: below --
2010-01-07 15:49 playback delay and problems with simultaneous playback/capture Max Klein

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20100106145131.24670@gmx.net \
    --to=mein_name@ist-einmalig.de \
    --cc=alsa-devel@alsa-project.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox