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