]> git.alsa-project.org Git - alsa-utils.git/commitdiff
alsaloop: fixes, added -W/--wake option
authorJaroslav Kysela <perex@perex.cz>
Thu, 14 Oct 2010 09:17:25 +0000 (11:17 +0200)
committerJaroslav Kysela <perex@perex.cz>
Thu, 14 Oct 2010 09:17:25 +0000 (11:17 +0200)
- added -W/--wake option to reduce poll time
- another try to fix the avail_min parameter for playback
- fixed initial silence fill

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
alsaloop/alsaloop.1
alsaloop/alsaloop.c
alsaloop/alsaloop.h
alsaloop/pcmjob.c
alsaloop/test.sh

index 65edba1df3e561848a97b2f4e3cfaf44d003f81c..048d1e048c771c493f5b5e3675583947fdcf0a66 100644 (file)
@@ -189,6 +189,10 @@ Verbose mode. Use multiple times to increase verbosity.
 
 Verbose xrun profiling.
 
+.TP
+\fI\-W <timeout>\fP | \fI\-\-wake=<timeout>\fP
+
+Set process wake timeout.
 
 .SH EXAMPLES
 
index 561fdd7bb9f818541d2e5946f94ad88369c4d479..8710dd19d083d4f4becd240bf0651141190696dc 100644 (file)
@@ -56,6 +56,7 @@ struct loopback_thread *threads;
 int threads_count = 0;
 pthread_t main_job;
 int arg_default_xrun = 0;
+int arg_default_wake = 0;
 
 static void my_exit(struct loopback_thread *thread, int exitcode)
 {
@@ -193,6 +194,7 @@ void help(void)
 "-v,--verbose   verbose mode (more -v means more verbose)\n"
 "-w,--workaround use workaround (serialopen)\n"
 "-U,--xrun      xrun profiling\n"
+"-W,--wake      process wake timeout in ms\n"
 );
        printf("\nRecognized sample formats are:");
        for (k = 0; k < SND_PCM_FORMAT_LAST; ++k) {
@@ -395,12 +397,13 @@ static int parse_config(int argc, char *argv[], snd_output_t *output,
        char *arg_ossmixers[MAX_MIXERS];
        int arg_ossmixers_count = 0;
        int arg_xrun = arg_default_xrun;
+       int arg_wake = arg_default_wake;
 
        morehelp = 0;
        while (1) {
                int c;
                if ((c = getopt_long(argc, argv,
-                               "hdg:P:C:X:Y:l:t:F:f:c:r:s:benvA:S:a:m:T:O:w:U",
+                               "hdg:P:C:X:Y:l:t:F:f:c:r:s:benvA:S:a:m:T:O:w:UW:",
                                long_option, NULL)) < 0)
                        break;
                switch (c) {
@@ -549,6 +552,11 @@ static int parse_config(int argc, char *argv[], snd_output_t *output,
                        if (cmdline)
                                arg_default_xrun = 1;
                        break;
+               case 'W':
+                       arg_wake = atoi(optarg);
+                       if (cmdline)
+                               arg_default_wake = arg_wake;
+                       break;
                }
        }
 
@@ -587,6 +595,7 @@ static int parse_config(int argc, char *argv[], snd_output_t *output,
                loop->slave = arg_slave;
                loop->thread = arg_thread;
                loop->xrun = arg_xrun;
+               loop->wake = arg_wake;
                err = add_mixers(loop, arg_mixers, arg_mixers_count);
                if (err < 0) {
                        logit(LOG_CRIT, "Unable to add mixer controls.\n");
@@ -691,7 +700,7 @@ static void thread_job1(void *_data)
        snd_output_t *output = thread->output;
        struct pollfd *pfds = NULL;
        int pfds_count = 0;
-       int i, j, err;
+       int i, j, err, wake = 1000000;
 
        setscheduler();
 
@@ -709,7 +718,12 @@ static void thread_job1(void *_data)
                        my_exit(thread, EXIT_FAILURE);
                }
                pfds_count += thread->loopbacks[i]->pollfd_count;
+               j = thread->loopbacks[i]->wake;
+               if (j > 0 && j < wake)
+                       wake = j;
        }
+       if (wake >= 1000000)
+               wake = -1;
        pfds = calloc(pfds_count, sizeof(struct pollfd));
        if (pfds == NULL || pfds_count <= 0) {
                logit(LOG_CRIT, "Poll FDs allocation failed.\n");
@@ -727,7 +741,7 @@ static void thread_job1(void *_data)
                }
                if (verbose > 10)
                        gettimeofday(&tv1, NULL);
-               err = poll(pfds, j, -1);
+               err = poll(pfds, j, wake);
                if (err < 0)
                        err = -errno;
                if (verbose > 10) {
index 839fc6d74ec3bda0a0d68c644ce94c2e4d358661..e506427e9112dc295c72e16e97716e76e3523adb 100644 (file)
@@ -146,6 +146,7 @@ struct loopback {
        sync_type_t sync;               /* type of sync */
        slave_type_t slave;
        int thread;                     /* thread number */
+       unsigned int wake;
        /* statistics */
        double pitch;
        double pitch_delta;
@@ -164,6 +165,9 @@ struct loopback {
        snd_timestamp_t xrun_last_check;
        snd_pcm_sframes_t xrun_last_pdelay;
        snd_pcm_sframes_t xrun_last_cdelay;
+       snd_pcm_uframes_t xrun_buf_pcount;
+       snd_pcm_uframes_t xrun_buf_ccount;
+       unsigned int xrun_out_frames;
        long xrun_max_proctime;
        double xrun_max_missing;
        /* control mixer */
index 0f1a8538f26e65747bae6e2085df6e9f75c9773d..6aa8bfe1222aa450fd6312375c2c1caa9b21a14c 100644 (file)
@@ -83,16 +83,16 @@ static inline snd_pcm_uframes_t get_whole_latency(struct loopback *loop)
 }
 
 static inline unsigned long long
-                       frames_to_time(struct loopback_handle *lhandle,
+                       frames_to_time(unsigned int rate,
                                       snd_pcm_uframes_t frames)
 {
-       return (frames * 1000000ULL) / lhandle->rate;
+       return (frames * 1000000ULL) / rate;
 }
 
-static inline snd_pcm_uframes_t time_to_frames(struct loopback_handle *lhandle,
+static inline snd_pcm_uframes_t time_to_frames(unsigned int rate,
                                               unsigned long long time)
 {
-       return (time * lhandle->rate) / 1000000ULL;
+       return (time * rate) / 1000000ULL;
 }
 
 static int setparams_stream(struct loopback_handle *lhandle,
@@ -245,12 +245,16 @@ static int setparams_set(struct loopback_handle *lhandle,
                        snd_output_printf(lhandle->loopback->output, "%s: avail_min1=%li\n", lhandle->id, val);
        } else {
                if (lhandle == lhandle->loopback->play) {
-                       val = bufsize / 2 + bufsize / 4 + bufsize / 8;
-                       if (val > buffer_size / 4)
-                               val = buffer_size / 4;
+                       val = bufsize + bufsize / 2;
+                       if (val < (period_size * 3) / 4)
+                               val = (period_size * 3) / 4;
+                       if (val > (buffer_size * 3) / 4)
+                               val = (buffer_size * 3) / 4;
                        val = buffer_size - val;
                } else {
                        val = bufsize / 2;
+                       if (val < period_size / 2)
+                               val = period_size / 2;
                        if (val > buffer_size / 4)
                                val = buffer_size / 4;
                }
@@ -372,6 +376,11 @@ static void xrun_profile0(struct loopback *loop)
                getcurtimestamp(&loop->xrun_last_update);
                loop->xrun_last_pdelay = pdelay;
                loop->xrun_last_cdelay = cdelay;
+               loop->xrun_buf_pcount = loop->play->buf_count;
+               loop->xrun_buf_ccount = loop->capt->buf_count;
+#ifdef USE_SAMPLERATE
+               loop->xrun_out_frames = loop->src_out_frames;
+#endif
        }
 }
 
@@ -384,27 +393,45 @@ static inline void xrun_profile(struct loopback *loop)
 static void xrun_stats0(struct loopback *loop)
 {
        snd_timestamp_t t;
-       double expected, last, wake, check, queued = -1, proc, missing;
+       double expected, last, wake, check, queued = -1, proc, missing = -1;
+       double maxbuf, pfilled, cfilled, cqueued = -1, avail_min;
+       double sincejob;
 
        expected = ((double)loop->latency /
-                               (double)loop->play->rate) * 1000;
+                               (double)loop->play->rate_req) * 1000;
        getcurtimestamp(&t);
        last = (double)timediff(t, loop->xrun_last_update) / 1000;
        wake = (double)timediff(t, loop->xrun_last_wake) / 1000;
        check = (double)timediff(t, loop->xrun_last_check) / 1000;
+       sincejob = (double)timediff(t, loop->tstamp_start) / 1000;
        if (loop->xrun_last_pdelay != XRUN_PROFILE_UNKNOWN)
-               queued = (((double)loop->xrun_last_pdelay *
-                                               loop->play->pitch) /
+               queued = ((double)loop->xrun_last_pdelay /
+                               (double)loop->play->rate) * 1000;
+       if (loop->xrun_last_cdelay != XRUN_PROFILE_UNKNOWN)
+               cqueued = ((double)loop->xrun_last_cdelay /
+                               (double)loop->capt->rate) * 1000;
+       maxbuf = ((double)loop->play->buffer_size /
                                (double)loop->play->rate) * 1000;
        proc = (double)loop->xrun_max_proctime / 1000;
-       missing = last - queued;
-       if (loop->xrun_max_missing < missing)
+       pfilled = ((double)(loop->xrun_buf_pcount + loop->xrun_out_frames) /
+                               (double)loop->play->rate) * 1000;
+       cfilled = ((double)loop->xrun_buf_ccount /
+                               (double)loop->capt->rate) * 1000;
+       avail_min = (((double)loop->play->buffer_size - 
+                               (double)loop->play->avail_min ) / 
+                               (double)loop->play->rate) * 1000;
+       avail_min = expected - avail_min;
+       if (queued >= 0)
+               missing = last - queued;
+       if (missing >= 0 && loop->xrun_max_missing < missing)
                loop->xrun_max_missing = missing;
        loop->xrun_max_proctime = 0;
        getcurtimestamp(&t);
-       logit(LOG_INFO, "  last write before %.4fms, queued %.4fms -> missing %.4fms\n", last, queued, missing);
+       logit(LOG_INFO, "  last write before %.4fms, queued %.4fms/%.4fms -> missing %.4fms\n", last, queued, cqueued, missing);
        logit(LOG_INFO, "  expected %.4fms, processing %.4fms, max missing %.4fms\n", expected, proc, loop->xrun_max_missing);
-       logit(LOG_INFO, "  last wake before %.4fms, last check before %.4fms\n", wake, check);
+       logit(LOG_INFO, "  last wake %.4fms, last check %.4fms, avail_min %.4fms\n", wake, check, avail_min);
+       logit(LOG_INFO, "  max buf %.4fms, pfilled %.4fms, cfilled %.4fms\n", maxbuf, pfilled, cfilled);
+       logit(LOG_INFO, "  job started before %.4fms\n", sincejob);
 }
 
 static inline void xrun_stats(struct loopback *loop)
@@ -483,7 +510,14 @@ static void buf_add_src(struct loopback *loop)
                count1 = count;
                if (count1 + pos1 > capt->buf_size)
                        count1 = capt->buf_size - pos1;
-               src_short_to_float_array((short *)(capt->buf +
+               if (capt->format == SND_PCM_FORMAT_S32)
+                       src_int_to_float_array((int *)(capt->buf +
+                                               pos1 * capt->frame_size),
+                                        loop->src_data.data_in +
+                                          pos * capt->channels,
+                                        count1 * capt->channels);
+               else
+                       src_short_to_float_array((short *)(capt->buf +
                                                pos1 * capt->frame_size),
                                         loop->src_data.data_in +
                                           pos * capt->channels,
@@ -514,7 +548,14 @@ static void buf_add_src(struct loopback *loop)
                        count1 = buf_avail(play);
                if (count1 == 0)
                        break;
-               src_float_to_short_array(loop->src_data.data_out +
+               if (capt->format == SND_PCM_FORMAT_S32)
+                       src_float_to_int_array(loop->src_data.data_out +
+                                          pos * play->channels,
+                                        (int *)(play->buf +
+                                          pos1 * play->frame_size),
+                                        count1 * play->channels);
+               else
+                       src_float_to_short_array(loop->src_data.data_out +
                                           pos * play->channels,
                                         (short *)(play->buf +
                                           pos1 * play->frame_size),
@@ -691,12 +732,12 @@ static int writeit(struct loopback_handle *lhandle)
                        fwrite(lhandle->buf + lhandle->buf_pos * lhandle->frame_size,
                               r, lhandle->frame_size, lhandle->loopback->pfile);
 #endif
-               xrun_profile(lhandle->loopback);
                res += r;
                lhandle->counter += r;
                lhandle->buf_count -= r;
                lhandle->buf_pos += r;
                lhandle->buf_pos %= lhandle->buf_size;
+               xrun_profile(lhandle->loopback);
        }
        return res;
 }
@@ -919,6 +960,7 @@ static int xrun_sync(struct loopback *loop)
                        snd_output_printf(loop->output, "%s: sync verify: %li\n", loop->id, delay1);
                }
        }
+       loop->xrun_max_proctime = 0;
        return 0;
 }
 
@@ -1344,11 +1386,11 @@ int pcmjob_start(struct loopback *loop)
        loop->reinit = 0;
        loop->use_samplerate = 0;
        if (loop->latency_req) {
-               loop->latency_reqtime = frames_to_time(loop->play,
+               loop->latency_reqtime = frames_to_time(loop->play->rate_req,
                                                       loop->latency_req);
                loop->latency_req = 0;
        }
-       loop->latency = time_to_frames(loop->play, loop->latency_reqtime);
+       loop->latency = time_to_frames(loop->play->rate_req, loop->latency_reqtime);
        if ((err = setparams(loop, loop->latency/2)) < 0)
                goto __error;
        if (verbose)
@@ -1406,9 +1448,11 @@ int pcmjob_start(struct loopback *loop)
                goto __error;           
        }
        if (loop->use_samplerate) {
-               if (loop->capt->format != SND_PCM_FORMAT_S16 ||
-                   loop->play->format != SND_PCM_FORMAT_S16) {
-                       logit(LOG_CRIT, "samplerate conversion supports only %s format (play=%s, capt=%s)\n", snd_pcm_format_name(SND_PCM_FORMAT_S16), snd_pcm_format_name(loop->play->format), snd_pcm_format_name(loop->capt->format));
+               if ((loop->capt->format != SND_PCM_FORMAT_S16 ||
+                   loop->play->format != SND_PCM_FORMAT_S16) &&
+                   (loop->capt->format != SND_PCM_FORMAT_S32 ||
+                    loop->play->format != SND_PCM_FORMAT_S32)) {
+                       logit(LOG_CRIT, "samplerate conversion supports only %s or %s formats (play=%s, capt=%s)\n", snd_pcm_format_name(SND_PCM_FORMAT_S16), snd_pcm_format_name(SND_PCM_FORMAT_S32), snd_pcm_format_name(loop->play->format), snd_pcm_format_name(loop->capt->format));
                        loop->use_samplerate = 0;
                        err = -EIO;
                        goto __error;           
index ff9aa4ed033bc4b491dc3cd91956c1b771ca3961..fac72b91251e34e2bc52f0e171d1ed3378b7a727 100755 (executable)
@@ -34,19 +34,20 @@ EOF
 
 test3() {
   echo "TEST3"
+  LATENCY=180000
 cat > $CFGFILE <<EOF
--C hw:1,0,0 -P plug:dmix:0 --tlatency 30000 --thread 0 \
+-C hw:1,0,0 -P plug:dmix:0 --tlatency $LATENCY --thread 0 \
     --mixer "name='Master Playback Volume'@name='Master Playback Volume'" \
     --mixer "name='Master Playback Switch'@name='Master Playback Switch'" \
     --mixer "name='PCM Playback Volume'" \
     --ossmixer "name=Master@VOLUME"
--C hw:1,0,1 -P plug:dmix:0 --tlatency 30000 --thread 1
--C hw:1,0,2 -P plug:dmix:0 --tlatency 30000 --thread 2
--C hw:1,0,3 -P plug:dmix:0 --tlatency 30000 --thread 3
--C hw:1,0,4 -P plug:dmix:0 --tlatency 30000 --thread 4
--C hw:1,0,5 -P plug:dmix:0 --tlatency 30000 --thread 5
--C hw:1,0,6 -P plug:dmix:0 --tlatency 30000 --thread 6
--C hw:1,0,7 -P plug:dmix:0 --tlatency 30000 --thread 7
+-C hw:1,0,1 -P plug:dmix:0 --tlatency $LATENCY --thread 1
+-C hw:1,0,2 -P plug:dmix:0 --tlatency $LATENCY --thread 2
+-C hw:1,0,3 -P plug:dmix:0 --tlatency $LATENCY --thread 3
+-C hw:1,0,4 -P plug:dmix:0 --tlatency $LATENCY --thread 4
+-C hw:1,0,5 -P plug:dmix:0 --tlatency $LATENCY --thread 5
+-C hw:1,0,6 -P plug:dmix:0 --tlatency $LATENCY --thread 6
+-C hw:1,0,7 -P plug:dmix:0 --tlatency $LATENCY --thread 7
 EOF
   $DBG ./alsaloop --config $CFGFILE $ARGS
 }