From 85827fbb642463ab724a9471a7a88f93fa2a217d Mon Sep 17 00:00:00 2001 From: David Fries Date: Wed, 13 Apr 2016 23:32:46 -0500 Subject: [PATCH 1/4] aplay: fix lurking capture file overwrite bug If -d was given to arecord while commit 8aa13eec80eac312e4b99423909387660fb99b8f (now reverted) was in effect, the last read would be shorter than the chunk size, but pcm_read would read and return the chunk size, the samples were discarded, and capture() continued in a loop because count never reached 0. arecord opens a new file each loop iteration, if arecord is dynamically naming files, --use-strftime option or beyond the wave 2GB limit, this will generate a series of header only wave files. If the file is unique the originally recorded data is lost and it will continue overwriting the same file with a header only wave file. While the current pcm_read can't fail (it can exit), it is better to just fix this lurking bug in case it is "fixed" again. Signed-off-by: Takashi Iwai --- aplay/aplay.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/aplay/aplay.c b/aplay/aplay.c index 7acaa83..2da7dda 100644 --- a/aplay/aplay.c +++ b/aplay/aplay.c @@ -3067,11 +3067,14 @@ static void capture(char *orig_name) size_t c = (rest <= (off64_t)chunk_bytes) ? (size_t)rest : chunk_bytes; size_t f = c * 8 / bits_per_frame; - if (pcm_read(audiobuf, f) != f) + if (pcm_read(audiobuf, f) != f) { + in_aborting = 1; break; + } if (write(fd, audiobuf, c) != c) { perror(name); - prg_exit(EXIT_FAILURE); + in_aborting = 1; + break; } count -= c; rest -= c; @@ -3091,7 +3094,7 @@ static void capture(char *orig_name) } if (in_aborting) - break; + prg_exit(EXIT_FAILURE); /* repeat the loop when format is raw without timelimit or * requested counts of data are recorded -- 2.5.5 From 569f2c116ee30de8a16fef0822e13dd33a41f33e Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Sun, 17 Apr 2016 09:26:45 +0800 Subject: [PATCH 2/4] alsabat: add terminate status check for capture thread In loopback test, alsabat use pthread_join(pthread_t thread, **retval) to wait for the capture thread to terminate. If the capture thread was canceled, PTHREAD_CANCELED is placed in *retval, and the access to the **retval will fail. Add status check to prevent illegal access to the **retval. Signed-off-by: Lu, Han Signed-off-by: Takashi Iwai --- bat/bat.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bat/bat.c b/bat/bat.c index e824065..1afdcb4 100644 --- a/bat/bat.c +++ b/bat/bat.c @@ -192,6 +192,12 @@ static void test_loopback(struct bat *bat) exit(EXIT_FAILURE); } + /* check if capture thread is canceled or not */ + if (thread_result_capture == PTHREAD_CANCELED) { + fprintf(bat->log, _("Capture canceled.\n")); + return; + } + /* check capture status */ if (*thread_result_capture != 0) { fprintf(bat->err, _("Exit capture thread fail: %d\n"), -- 2.5.5 From 9e196efda4463452db51e295cd57bbf0bdaa4715 Mon Sep 17 00:00:00 2001 From: "vivian,zhang" Date: Tue, 31 May 2016 15:31:32 +0800 Subject: [PATCH 3/4] alsabat: add buffer size and period size settings Add buffer size and period size settings in alsabat. With -E and -B options, alsabat performs the test with specified buffer size and period size Signed-off-by: Zhang Vivian Acked-by: Liam Girdwood Signed-off-by: Takashi Iwai --- bat/alsa.c | 95 ++++++++++++++++++++++++++++++++++++++++------------------ bat/bat.c | 18 +++++++++-- bat/common.h | 8 +++++ bat/tinyalsa.c | 5 +++- 4 files changed, 94 insertions(+), 32 deletions(-) diff --git a/bat/alsa.c b/bat/alsa.c index 75158cb..0a37714 100644 --- a/bat/alsa.c +++ b/bat/alsa.c @@ -74,6 +74,8 @@ static int set_snd_pcm_params(struct bat *bat, struct pcm_container *sndpcm) snd_pcm_format_t format; unsigned int buffer_time = 0; unsigned int period_time = 0; + snd_pcm_uframes_t buffer_size = 0; + snd_pcm_uframes_t period_size = 0; unsigned int rate; int err; const char *device_name = snd_pcm_name(sndpcm->handle); @@ -145,39 +147,71 @@ static int set_snd_pcm_params(struct bat *bat, struct pcm_container *sndpcm) return -EINVAL; } - if (snd_pcm_hw_params_get_buffer_time_max(params, - &buffer_time, 0) < 0) { - fprintf(bat->err, _("Get parameter from device error: ")); - fprintf(bat->err, _("buffer time: %d %s: %s(%d)\n"), - buffer_time, - device_name, snd_strerror(err), err); - return -EINVAL; - } + if (bat->buffer_size > 0 && bat->period_size == 0) + bat->period_size = bat->buffer_size / DIV_BUFFERTIME; - if (buffer_time > MAX_BUFFERTIME) - buffer_time = MAX_BUFFERTIME; + if (bat->buffer_size > 0) { + buffer_size = bat->buffer_size; + period_size = bat->period_size; - period_time = buffer_time / DIV_BUFFERTIME; + fprintf(bat->log, _("Set period size: %d buffer size: %d\n"), + (int) period_size, (int) buffer_size); - /* Set buffer time and period time */ - err = snd_pcm_hw_params_set_buffer_time_near(sndpcm->handle, params, - &buffer_time, 0); - if (err < 0) { - fprintf(bat->err, _("Set parameter to device error: ")); - fprintf(bat->err, _("buffer time: %d %s: %s(%d)\n"), - buffer_time, - device_name, snd_strerror(err), err); - return err; - } + err = snd_pcm_hw_params_set_buffer_size_near(sndpcm->handle, + params, &buffer_size); + if (err < 0) { + fprintf(bat->err, _("Set parameter to device error: ")); + fprintf(bat->err, _("buffer size: %d %s: %s(%d)\n"), + (int) buffer_size, + device_name, snd_strerror(err), err); + return err; + } - err = snd_pcm_hw_params_set_period_time_near(sndpcm->handle, params, - &period_time, 0); - if (err < 0) { - fprintf(bat->err, _("Set parameter to device error: ")); - fprintf(bat->err, _("period time: %d %s: %s(%d)\n"), - period_time, - device_name, snd_strerror(err), err); - return err; + err = snd_pcm_hw_params_set_period_size_near(sndpcm->handle, + params, &period_size, 0); + if (err < 0) { + fprintf(bat->err, _("Set parameter to device error: ")); + fprintf(bat->err, _("period size: %d %s: %s(%d)\n"), + (int) period_size, + device_name, snd_strerror(err), err); + return err; + } + } else { + if (snd_pcm_hw_params_get_buffer_time_max(params, + &buffer_time, 0) < 0) { + fprintf(bat->err, + _("Get parameter from device error: ")); + fprintf(bat->err, _("buffer time: %d %s: %s(%d)\n"), + buffer_time, + device_name, snd_strerror(err), err); + return -EINVAL; + } + + if (buffer_time > MAX_BUFFERTIME) + buffer_time = MAX_BUFFERTIME; + + period_time = buffer_time / DIV_BUFFERTIME; + + /* Set buffer time and period time */ + err = snd_pcm_hw_params_set_buffer_time_near(sndpcm->handle, + params, &buffer_time, 0); + if (err < 0) { + fprintf(bat->err, _("Set parameter to device error: ")); + fprintf(bat->err, _("buffer time: %d %s: %s(%d)\n"), + buffer_time, + device_name, snd_strerror(err), err); + return err; + } + + err = snd_pcm_hw_params_set_period_time_near(sndpcm->handle, + params, &period_time, 0); + if (err < 0) { + fprintf(bat->err, _("Set parameter to device error: ")); + fprintf(bat->err, _("period time: %d %s: %s(%d)\n"), + period_time, + device_name, snd_strerror(err), err); + return err; + } } /* Write the parameters to the driver */ @@ -214,6 +248,9 @@ static int set_snd_pcm_params(struct bat *bat, struct pcm_container *sndpcm) return -EINVAL; } + fprintf(bat->log, _("Get period size: %d buffer size: %d\n"), + (int) sndpcm->period_size, (int) sndpcm->buffer_size); + err = snd_pcm_format_physical_width(format); if (err < 0) { fprintf(bat->err, _("Invalid parameters: ")); diff --git a/bat/bat.c b/bat/bat.c index 1afdcb4..cd4ea2d 100644 --- a/bat/bat.c +++ b/bat/bat.c @@ -292,6 +292,8 @@ _("Usage: alsabat [-options]...\n" " -k parameter for frequency detecting threshold\n" " -F target frequency\n" " -p total number of periods to play/capture\n" +" -B buffer size in frames\n" +" -E period size in frames\n" " --log=# file that both stdout and strerr redirecting to\n" " --file=# file for playback\n" " --saveplay=# file that storing playback content, for debug\n" @@ -324,6 +326,8 @@ static void set_defaults(struct bat *bat) bat->capture.device = NULL; bat->buf = NULL; bat->local = false; + bat->buffer_size = 0; + bat->period_size = 0; #ifdef HAVE_LIBTINYALSA bat->channels = 2; bat->playback.fct = &playback_tinyalsa; @@ -342,8 +346,8 @@ static void set_defaults(struct bat *bat) static void parse_arguments(struct bat *bat, int argc, char *argv[]) { - int c, option_index; - static const char short_options[] = "D:P:C:f:n:F:c:r:s:k:p:lth"; + int c, option_index, err; + static const char short_options[] = "D:P:C:f:n:F:c:r:s:k:p:B:E:lth"; static const struct option long_options[] = { {"help", 0, 0, 'h'}, {"log", 1, 0, OPT_LOG}, @@ -414,6 +418,16 @@ static void parse_arguments(struct bat *bat, int argc, char *argv[]) bat->periods_total = atoi(optarg); bat->period_is_limited = true; break; + case 'B': + err = atoi(optarg); + bat->buffer_size = err >= MIN_BUFFERSIZE + && err < MAX_BUFFERSIZE ? err : 0; + break; + case 'E': + err = atoi(optarg); + bat->period_size = err >= MIN_PERIODSIZE + && err < MAX_PERIODSIZE ? err : 0; + break; case 'h': default: usage(bat); diff --git a/bat/common.h b/bat/common.h index b789af5..ad02a5a 100644 --- a/bat/common.h +++ b/bat/common.h @@ -46,6 +46,12 @@ #define DIV_BUFFERTIME 8 /* margin to avoid sign inversion when generate sine wav */ #define RANGE_FACTOR 0.95 +#define MAX_BUFFERSIZE 200000 +#define MIN_BUFFERSIZE 32 +#define MAX_PERIODSIZE 200000 +#define MIN_PERIODSIZE 32 +/* default period size for tinyalsa */ +#define TINYALSA_PERIODSIZE 1024 #define EBATBASE 1000 #define ENOPEAK (EBATBASE + 1) @@ -152,6 +158,8 @@ struct bat { int frame_size; /* size of frame */ int sample_size; /* size of sample */ enum _bat_pcm_format format; /* PCM format */ + int buffer_size; /* buffer size in frames */ + int period_size; /* period size in frames */ float sigma_k; /* threshold for peak detection */ float target_freq[MAX_CHANNELS]; diff --git a/bat/tinyalsa.c b/bat/tinyalsa.c index ea5f848..a19dd90 100644 --- a/bat/tinyalsa.c +++ b/bat/tinyalsa.c @@ -57,7 +57,10 @@ static int init_config(struct bat *bat, struct pcm_config *config) { config->channels = bat->channels; config->rate = bat->rate; - config->period_size = 1024; + if (bat->period_size > 0) + config->period_size = bat->period_size; + else + config->period_size = TINYALSA_PERIODSIZE; config->period_count = 4; config->start_threshold = 0; config->stop_threshold = 0; -- 2.5.5 From 2b3adf8668ab4e0e57168725f2562006bb5472ef Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Wed, 1 Jun 2016 16:54:28 +0800 Subject: [PATCH 4/4] alsabat: fix a possible memory leak Fix a possible memory leak in generate_sine_wave(). Memory free was ignored when the function return an error. Signed-off-by: Lu, Han Signed-off-by: Takashi Iwai --- bat/signal.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bat/signal.c b/bat/signal.c index a47ba97..61d2824 100644 --- a/bat/signal.c +++ b/bat/signal.c @@ -168,16 +168,17 @@ int generate_sine_wave(struct bat *bat, int frames, void *buf) /* reorder samples to interleaved mode */ err = reorder(bat, sinus_f, frames); if (err != 0) - return err; + goto exit; /* adjust amplitude and offset of waveform */ err = adjust_waveform(bat, sinus_f, frames); if (err != 0) - return err; + goto exit; bat->convert_float_to_sample(sinus_f, buf, frames, bat->channels); +exit: free(sinus_f); - return 0; + return err; } -- 2.5.5