[alsa-devel] period time vs. buffer time

Joël Krähemann jkraehemann at gmail.com
Mon Jun 27 17:27:24 CEST 2016


Hi all

Do I need to call both functions in order to get good performance?

snd_pcm_hw_params_set_period_time()
snd_pcm_hw_params_set_buffer_time()

Or is one enough? Since I call:

snd_pcm_hw_params_set_buffer_size()

I have developed an application called gsequencer I experience good
throughput but playback collapses after a specified amount of time.
The application is unusable after 60 seconds of playback.

http://www.nongnu.org/gsequencer/
http://www.nongnu.org/gsequencer/api/ags/AgsThread.html - does the JIFFIEs
http://www.nongnu.org/gsequencer/api/ags/AgsDevout.html - does setup audio HW
http://www.nongnu.org/gsequencer/api/ags/AgsSoundcardThread.html -
calls ags_soundcard_play()

I do some kind of overclocking within thread frequency. I ceil() the
frequency of the thread in Hertz jiffies and add one. Within this
thread I call:

snd_pcm_writei()

In numbers:

2 audio channels
44100 samplerate
944 buffer size in samples = 2 * 944 frames = 2 * 944 * sizeof(signed short)
48 times per second call:  snd_pcm_writei()

I use the soundcard in non-blocking mode because I need the time to
compute the rest of the tree within time. The question is how to
handle lost precision? As I round values and do some overclocking to
ensure alsa has enough frames to do the playback. What do I have to do
in order to get great performance and throughput? Do I need to drop
frames? Or even buffers? And what is alsa's job?

So playback gets delay by nanosleep() as following:

  if(g_atomic_pointer_get(&(thread->parent)) == NULL){
    gdouble time_spent, relative_time_spent;
    gdouble time_cycle;

    static const gdouble nsec_per_jiffie = NSEC_PER_SEC /
AGS_THREAD_HERTZ_JIFFIE;
    static const gdouble lost_per_jiffie = nsec_per_jiffie /
AGS_THREAD_MAX_PRECISION;
    gdouble lost_precision;

    if(thread->tic_delay == thread->delay){
      struct timespec timed_sleep = {
        0,
        0,
      };

      clock_gettime(CLOCK_MONOTONIC, &time_now);

      if(time_now.tv_sec == thread->computing_time->tv_sec + 1){
        time_spent = (time_now.tv_nsec) + (NSEC_PER_SEC -
thread->computing_time->tv_nsec);
      }else if(time_now.tv_sec > thread->computing_time->tv_sec + 1){
        time_spent = (time_now.tv_sec -
thread->computing_time->tv_sec) * NSEC_PER_SEC;
        time_spent += (time_now.tv_nsec - thread->computing_time->tv_nsec);
      }else{
        time_spent = time_now.tv_nsec - thread->computing_time->tv_nsec;
      }

      //FIXME:JK: do optimization
      time_cycle = ((gdouble) NSEC_PER_SEC / thread->freq);

      relative_time_spent = time_cycle - time_spent;

      if(relative_time_spent > 0.0 &&
         relative_time_spent < time_cycle){
        timed_sleep.tv_nsec = (long) relative_time_spent;

        /* lost precision */
        //NOTE:JK: this is experimental
        lost_precision = lost_per_jiffie / (1.0 + (1.0 / thread->freq));

        if(relative_time_spent - lost_precision > 0.0){
          timed_sleep.tv_nsec = (long) (relative_time_spent - lost_precision);
        }else{
          g_warning("ags_thread-posix.c - not optimized tree\0");
        }

        /* sleep the rest of available time of the period */
        nanosleep(&timed_sleep, NULL);
      }

      clock_gettime(CLOCK_MONOTONIC, thread->computing_time);
    }

Here's a piece of soundcard initialization:

  /* set the period time */
  period_time = (USEC_PER_SEC / (devout->samplerate));
  dir = -1;
  err = snd_pcm_hw_params_set_period_time_near(handle, hwparams,
&period_time, &dir);
  if (err < 0) {
    pthread_mutex_unlock(mutex);

    str = snd_strerror(err);
    g_warning("Unable to set period time %i for playback: %s\n",
period_time, str);

    free(str);

    return;
  }

My problem with alsa is that as I don't tell the exact values I get
good throughput but playback collapses. When I do exact values the
sound is soften and loses volume.

Strange is I can sometimes hear some crackling and I'm unsure what to
set as period time. Does it need the time to do periodic things or
should it be reduced or overloaded to have accurate time?

Bests,
Joël
--
To unsubscribe from this list: send the line "unsubscribe alsa-devel" in



More information about the Alsa-devel mailing list