]> git.alsa-project.org Git - alsa-utils.git/commitdiff
axfer: add options for software parameters of PCM substream
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Tue, 13 Nov 2018 06:41:38 +0000 (15:41 +0900)
committerTakashi Iwai <tiwai@suse.de>
Tue, 13 Nov 2018 11:04:47 +0000 (12:04 +0100)
In ALSA PCM interface, some parameters are used to configure runtime of
PCM substream independently of actual hardware. These parameters are
mainly used to decide the detailed timing to start/stop PCM substream and
release I/O blocking state of application. These parameters are
represented and delivered by a structure.

In alsa-lib PCM API, the structure is hidden from userspace applications.
The applications can set/get actual parameters by helper functions.

In aplay, three of the parameters are configurable. This commit adds
support for them. When no options are given, default values are used.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
axfer/xfer-libasound.c
axfer/xfer-libasound.h

index a23021ef767ebc51f99ec0cf34a1f41cf89c35a9..1e709e0ed1f308f65eaf28909a17a0b8ff978708 100644 (file)
@@ -17,7 +17,7 @@ enum no_short_opts {
        OPT_TEST_NOWAIT,
 };
 
-#define S_OPTS "D:NMF:B:"
+#define S_OPTS "D:NMF:B:A:R:T:"
 static const struct option l_opts[] = {
        {"device",              1, 0, 'D'},
        {"nonblock",            0, 0, 'N'},
@@ -26,6 +26,9 @@ static const struct option l_opts[] = {
        {"buffer-time",         1, 0, 'B'},
        {"period-size",         1, 0, OPT_PERIOD_SIZE},
        {"buffer-size",         1, 0, OPT_BUFFER_SIZE},
+       {"avail-min",           1, 0, 'A'},
+       {"start-delay",         1, 0, 'R'},
+       {"stop-delay",          1, 0, 'T'},
        // For debugging.
        {"fatal-errors",        0, 0, OPT_FATAL_ERRORS},
        {"test-nowait",         0, 0, OPT_TEST_NOWAIT},
@@ -68,6 +71,12 @@ static int xfer_libasound_parse_opt(struct xfer_context *xfer, int key,
                state->frames_per_period = arg_parse_decimal_num(optarg, &err);
        else if (key == OPT_BUFFER_SIZE)
                state->frames_per_buffer = arg_parse_decimal_num(optarg, &err);
+       else if (key == 'A')
+               state->msec_for_avail_min = arg_parse_decimal_num(optarg, &err);
+       else if (key == 'R')
+               state->msec_for_start_threshold = arg_parse_decimal_num(optarg, &err);
+       else if (key == 'T')
+               state->msec_for_stop_threshold = arg_parse_decimal_num(optarg, &err);
        else if (key == OPT_FATAL_ERRORS)
                state->finish_at_xrun = true;
        else if (key == OPT_TEST_NOWAIT)
@@ -377,8 +386,76 @@ static int retrieve_actual_hw_params(snd_pcm_hw_params_t *hw_params,
 
 static int configure_sw_params(struct libasound_state *state,
                               unsigned int frames_per_second,
-                              unsigned int frames_per_buffer)
+                              unsigned int frames_per_buffer,
+                              unsigned int msec_for_avail_min,
+                              unsigned int msec_for_start_threshold,
+                              unsigned int msec_for_stop_threshold)
 {
+       snd_pcm_uframes_t frame_count;
+       int err;
+
+       if (msec_for_avail_min > 0) {
+               frame_count = msec_for_avail_min * frames_per_second / 1000000;
+               if (frame_count == 0 || frame_count > frames_per_buffer) {
+                       logging(state,
+                               "The msec for 'avail_min' is too %s: %u "
+                               "msec (%lu frames at %u).\n",
+                               frame_count == 0 ? "small" : "large",
+                               msec_for_avail_min, frame_count,
+                               frames_per_second);
+                       return -EINVAL;
+               }
+               err = snd_pcm_sw_params_set_avail_min(state->handle,
+                                               state->sw_params, frame_count);
+               if (err < 0) {
+                       logging(state,
+                               "Fail to configure 'avail-min'.\n");
+                       return -EINVAL;
+               }
+       }
+
+       if (msec_for_start_threshold > 0) {
+               frame_count = msec_for_start_threshold * frames_per_second /
+                             1000000;
+               if (frame_count == 0 || frame_count > frames_per_buffer) {
+                       logging(state,
+                               "The msec for 'start-delay' is too %s: %u "
+                               "msec (%lu frames at %u).\n",
+                               frame_count == 0 ? "small" : "large",
+                               msec_for_start_threshold, frame_count,
+                               frames_per_second);
+                       return -EINVAL;
+               }
+               err = snd_pcm_sw_params_set_start_threshold(state->handle,
+                                               state->sw_params, frame_count);
+               if (err < 0) {
+                       logging(state,
+                               "Fail to configure 'start-delay'.\n");
+                       return -EINVAL;
+               }
+       }
+
+       if (msec_for_stop_threshold > 0) {
+               frame_count = msec_for_stop_threshold * frames_per_second /
+                             1000000;
+               if (frame_count == 0 || frame_count > frames_per_buffer) {
+                       logging(state,
+                               "The msec for 'stop-delay' is too %s: %u "
+                               "msec (%lu frames at %u).\n",
+                               frame_count == 0 ? "small" : "large",
+                               msec_for_stop_threshold, frame_count,
+                               frames_per_second);
+                       return -EINVAL;
+               }
+               err = snd_pcm_sw_params_set_stop_threshold(state->handle,
+                                               state->sw_params, frame_count);
+               if (err < 0) {
+                       logging(state,
+                               "Fail to configure 'stop-delay'.\n");
+                       return -EINVAL;
+               }
+       }
+
        return snd_pcm_sw_params(state->handle, state->sw_params);
 }
 
@@ -444,7 +521,10 @@ static int xfer_libasound_pre_process(struct xfer_context *xfer,
                return err;
 
        err = configure_sw_params(state, *frames_per_second,
-                                 *frames_per_buffer);
+                                 *frames_per_buffer,
+                                 state->msec_for_avail_min,
+                                 state->msec_for_start_threshold,
+                                 state->msec_for_stop_threshold);
        if (err < 0) {
                logging(state, "Current software parameters:\n");
                snd_pcm_sw_params_dump(state->sw_params, state->log);
index 4456fabd453a4b835069d34422951f3bf0d5acf2..113c1b98f9894abde76d4e09bcd1e7fd82532506 100644 (file)
@@ -35,6 +35,10 @@ struct libasound_state {
        unsigned int frames_per_period;
        unsigned int frames_per_buffer;
 
+       unsigned int msec_for_avail_min;
+       unsigned int msec_for_start_threshold;
+       unsigned int msec_for_stop_threshold;
+
        bool finish_at_xrun:1;
        bool nonblock:1;
        bool mmap:1;