All of 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.