[alsa-devel] [RFCv3][PATCH 34/39] axfer: add a unit test for vumeter calculation

Takashi Sakamoto o-takashi at sakamocchi.jp
Mon Oct 2 02:19:35 CEST 2017


In a previous commit, vumeter is implemented. This commit adds a simple
unit test for the feature. This tests positive cases only.

Signed-off-by: Takashi Sakamoto <o-takashi at sakamocchi.jp>
---
 axfer/test/Makefile.am        |  14 +++-
 axfer/test/vumeter-test.c     | 184 ++++++++++++++++++++++++++++++++++++++++++
 axfer/xfer-libasound-irq-rw.c |   2 +-
 3 files changed, 196 insertions(+), 4 deletions(-)
 create mode 100644 axfer/test/vumeter-test.c

diff --git a/axfer/test/Makefile.am b/axfer/test/Makefile.am
index 76a93bfc..0e48b9f2 100644
--- a/axfer/test/Makefile.am
+++ b/axfer/test/Makefile.am
@@ -1,10 +1,12 @@
 TESTS = \
-	container-test  \
-	mapper-test
+	container-test \
+	mapper-test \
+	vumeter-test
 
 check_PROGRAMS = \
 	container-test \
-	mapper-test
+	mapper-test \
+	vumeter-test
 
 container_test_SOURCES = \
 	../container.h \
@@ -29,3 +31,9 @@ mapper_test_SOURCES = \
 	../mapper-multiple.c \
 	generator.c \
 	mapper-test.c
+
+vumeter_test_SOURCES = \
+	../vumeter.h \
+	../vumeter.c \
+	generator.c \
+	vumeter-test.c
diff --git a/axfer/test/vumeter-test.c b/axfer/test/vumeter-test.c
new file mode 100644
index 00000000..6df7c067
--- /dev/null
+++ b/axfer/test/vumeter-test.c
@@ -0,0 +1,184 @@
+/*
+ * test-vumeter.c - A unit test for Volume Unit meter.
+ *
+ * Copyright (c) 2017 Takashi Sakamoto <o-takashi at sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "../vumeter.h"
+#include "../misc.h"
+
+#include "generator.h"
+
+#include <stdlib.h>
+
+static bool verbose;
+
+static int callback(struct test_generator *gen, snd_pcm_access_t access,
+		    snd_pcm_format_t sample_format,
+		    unsigned int samples_per_frame, void *frame_buffer,
+		    unsigned int frame_count)
+{
+	static const enum vumeter_mode modes[] = {
+		[0] = VUMETER_MODE_MONO,
+		[1] = VUMETER_MODE_STEREO,
+	};
+	struct vumeter_context *vu = gen->private_data;
+	int i;
+	int err;
+
+	char **vector = NULL;
+
+	if (access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED) {
+		char *buf;
+		unsigned int size;
+
+		vector = calloc(samples_per_frame, sizeof(*vector));
+		if (vector == NULL)
+			return -ENOMEM;
+
+		buf = frame_buffer;
+		size = snd_pcm_format_physical_width(sample_format) *
+		       frame_count / 8;
+
+		for (i = 0; i < samples_per_frame; ++i)
+			vector[i] = buf + size * i;
+
+		frame_buffer = vector;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(modes); ++i) {
+		int j;
+
+		if (verbose) {
+			printf("%d %s %s %d %d\n",
+			       modes[i], snd_pcm_access_name(access),
+			       snd_pcm_format_name(sample_format),
+			       samples_per_frame, frame_count);
+		}
+
+		memset(vu, 0, sizeof(*vu));
+		err = vumeter_context_init(vu, modes[i], access, sample_format,
+					   samples_per_frame, 4000);
+		if (err < 0)
+			break;
+		assert(vu->significant_bits_per_sample >= 0);
+		assert(vu->bytes_per_sample >= 0);
+		assert(vu->samples_per_frame >= 0);
+		assert(vu->frames_per_second >= 0);
+		assert(vu->max > 0);
+		assert(vu->peaks != NULL);
+		assert(vu->ratios != NULL);
+		assert(vu->max_ratios_in_second != NULL);
+		assert(vu->printer != NULL);
+		assert(vu->calculator != NULL);
+
+		vumeter_context_prepare(vu);
+		for (j = 0; j < samples_per_frame; ++j) {
+			assert(vu->ratios[j] == 0);
+			assert(vu->max_ratios_in_second[j] == 0);
+		}
+
+		vumeter_context_calculate(vu, frame_buffer, frame_count);
+		for (j = 0; j < samples_per_frame; ++j) {
+			assert(vu->peaks[j] <= vu->max);
+			assert(vu->max_ratios_in_second[j] <= vu->max);
+			assert(vu->max_ratios_in_second[j] <= 100);
+		}
+
+		vumeter_context_destroy(vu);
+		assert(vu->ratios == NULL);
+		assert(vu->max_ratios_in_second == NULL);
+		assert(vu->peaks == NULL);
+	}
+
+	if (vector != NULL)
+		free(vector);
+
+	return err;
+}
+
+int main(int argc, const char *argv[])
+{
+	const uint64_t sample_format_mask =
+		(1ul << SND_PCM_FORMAT_S8) |
+		(1ul << SND_PCM_FORMAT_U8) |
+		(1ul << SND_PCM_FORMAT_S16_LE) |
+		(1ul << SND_PCM_FORMAT_S16_BE) |
+		(1ul << SND_PCM_FORMAT_U16_LE) |
+		(1ul << SND_PCM_FORMAT_U16_BE) |
+		(1ul << SND_PCM_FORMAT_S24_LE) |
+		(1ul << SND_PCM_FORMAT_S24_BE) |
+		(1ul << SND_PCM_FORMAT_U24_LE) |
+		(1ul << SND_PCM_FORMAT_U24_BE) |
+		(1ul << SND_PCM_FORMAT_S32_LE) |
+		(1ul << SND_PCM_FORMAT_S32_BE) |
+		(1ul << SND_PCM_FORMAT_U32_LE) |
+		(1ul << SND_PCM_FORMAT_U32_BE) |
+		(1ul << SND_PCM_FORMAT_S24_3LE) |
+		(1ul << SND_PCM_FORMAT_S24_3BE) |
+		(1ul << SND_PCM_FORMAT_U24_3LE) |
+		(1ul << SND_PCM_FORMAT_U24_3BE) |
+		(1ul << SND_PCM_FORMAT_S24_3LE) |
+		(1ul << SND_PCM_FORMAT_S24_3BE) |
+		(1ul << SND_PCM_FORMAT_U24_3LE) |
+		(1ul << SND_PCM_FORMAT_U24_3BE) |
+		(1ul << SND_PCM_FORMAT_S20_3LE) |
+		(1ul << SND_PCM_FORMAT_S20_3BE) |
+		(1ul << SND_PCM_FORMAT_U20_3LE) |
+		(1ul << SND_PCM_FORMAT_U20_3BE) |
+		(1ul << SND_PCM_FORMAT_S18_3LE) |
+		(1ul << SND_PCM_FORMAT_S18_3BE) |
+		(1ul << SND_PCM_FORMAT_U18_3LE) |
+		(1ul << SND_PCM_FORMAT_U18_3BE);
+	uint64_t access_mask;
+	struct test_generator gen = {0};
+	snd_pcm_access_t access;
+	int err;
+
+	if (argc > 1) {
+		char *term;
+
+		access = strtol(argv[1], &term, 10);
+		if (errno != 0 || *term != '\0') {
+			err = -EINVAL;
+			goto end;
+		}
+		if (access < SND_PCM_ACCESS_MMAP_INTERLEAVED &&
+		    access > SND_PCM_ACCESS_RW_NONINTERLEAVED) {
+			err = -EINVAL;
+			goto end;
+		}
+		if (access == SND_PCM_ACCESS_MMAP_COMPLEX) {
+			err = -EINVAL;
+			goto end;
+		}
+		access_mask = 1ul << access;
+		verbose = true;
+	} else {
+		access_mask = (1ul << SND_PCM_ACCESS_MMAP_INTERLEAVED) |
+			      (1ul << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) |
+			      (1ul << SND_PCM_ACCESS_RW_INTERLEAVED) |
+			      (1ul << SND_PCM_ACCESS_RW_NONINTERLEAVED);
+		verbose = false;
+	}
+
+
+	err = generator_context_init(&gen, access_mask, sample_format_mask,
+				     1, 128, 23, 4500, 1024,
+				     sizeof(struct vumeter_context));
+	if (err < 0)
+		return EXIT_FAILURE;
+
+	err = generator_context_run(&gen, callback);
+
+	generator_context_destroy(&gen);
+end:
+	if (err < 0) {
+		printf("%s\n", strerror(-err));
+		return EXIT_FAILURE;
+	}
+
+	return EXIT_SUCCESS;
+}
diff --git a/axfer/xfer-libasound-irq-rw.c b/axfer/xfer-libasound-irq-rw.c
index ee5ce801..a2152d92 100644
--- a/axfer/xfer-libasound-irq-rw.c
+++ b/axfer/xfer-libasound-irq-rw.c
@@ -261,11 +261,11 @@ static int write_frames(struct libasound_state *state,
 		err = snd_pcm_writen(state->handle, cache->buf, consumed_count);
 	if (err < 0)
 		return err;
+	consumed_count = (unsigned int)err;
 
 	if (vu)
 		vumeter_context_calculate(vu, cache->buf, consumed_count);
 
-	consumed_count = (unsigned int)err;
 	cache->align_frames(cache, consumed_count, cache->bytes_per_sample,
 			    cache->samples_per_frame);
 
-- 
2.11.0



More information about the Alsa-devel mailing list