* [PATCH i-g-t 1/3] lib: Add audio library with dedicated helpers
@ 2017-08-17 16:05 Paul Kocialkowski
2017-08-17 16:05 ` [PATCH i-g-t 2/3] lib: Add ALSA " Paul Kocialkowski
` (3 more replies)
0 siblings, 4 replies; 16+ messages in thread
From: Paul Kocialkowski @ 2017-08-17 16:05 UTC (permalink / raw)
To: intel-gfx
This introduces an audio library, with dedicated helpers for both
generating signals and detecting peak frequencies in a signal.
This library paves the way for testing audio going through display
connectors, such as HDMI.
Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
.../intel-gpu-tools/intel-gpu-tools-docs.xml | 1 +
lib/Makefile.am | 2 +
lib/igt.h | 1 +
lib/igt_audio.c | 326 +++++++++++++++++++++
lib/igt_audio.h | 47 +++
5 files changed, 377 insertions(+)
create mode 100644 lib/igt_audio.c
create mode 100644 lib/igt_audio.h
diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
index f88afd2a..c77159cf 100644
--- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
+++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
@@ -16,6 +16,7 @@
<chapter>
<title>API Reference</title>
<xi:include href="xml/drmtest.xml"/>
+ <xi:include href="xml/igt_audio.xml"/>
<xi:include href="xml/igt_aux.xml"/>
<xi:include href="xml/igt_chamelium.xml"/>
<xi:include href="xml/igt_core.xml"/>
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 9c932d6f..5ea08314 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -33,6 +33,8 @@ if HAVE_GSL
lib_source_list += \
igt_frame.c \
igt_frame.h \
+ igt_audio.c \
+ igt_audio.h \
$(NULL)
endif
diff --git a/lib/igt.h b/lib/igt.h
index d16a4991..a75d2db7 100644
--- a/lib/igt.h
+++ b/lib/igt.h
@@ -35,6 +35,7 @@
#include "igt_dummyload.h"
#include "igt_fb.h"
#include "igt_frame.h"
+#include "igt_audio.h"
#include "igt_gt.h"
#include "igt_kms.h"
#include "igt_pm.h"
diff --git a/lib/igt_audio.c b/lib/igt_audio.c
new file mode 100644
index 00000000..527a4930
--- /dev/null
+++ b/lib/igt_audio.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright © 2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <gsl/gsl_fft_real.h>
+
+#include "igt.h"
+
+#define FREQS_MAX 8
+
+/**
+ * SECTION:igt_audio
+ * @short_description: Library for audio-related tests
+ * @title: Audio
+ * @include: igt_audio.h
+ *
+ * This library contains helpers for audio-related tests. More specifically,
+ * it allows generating additions of sine signals as well as detecting them.
+ */
+
+struct audio_signal_freq {
+ int freq;
+
+ short *period;
+ int frames;
+ int offset;
+};
+
+struct audio_signal {
+ int channels;
+ int sampling_rate;
+
+ struct audio_signal_freq freqs[FREQS_MAX];
+ int freqs_count;
+};
+
+/**
+ * audio_signal_init:
+ * @channels: The number of channels to use for the signal
+ * @sampling_rate: The sampling rate to use for the signal
+ *
+ * Allocate and initialize an audio signal structure with the given parameters.
+ *
+ * Returns: A newly-allocated audio signal structure
+ */
+struct audio_signal *audio_signal_init(int channels, int sampling_rate)
+{
+ struct audio_signal *signal;
+
+ signal = malloc(sizeof(struct audio_signal));
+ memset(signal, 0, sizeof(struct audio_signal));
+
+ signal->sampling_rate = sampling_rate;
+ signal->channels = channels;
+
+ return signal;
+}
+
+/**
+ * audio_signal_add_frequency:
+ * @signal: The target signal structure
+ * @frequency: The frequency to add to the signal
+ *
+ * Add a frequency to the signal.
+ *
+ * Returns: An integer equal to zero for success and negative for failure
+ */
+int audio_signal_add_frequency(struct audio_signal *signal, int frequency)
+{
+ int index = signal->freqs_count;
+
+ if (index == FREQS_MAX)
+ return -1;
+
+ /* Stay within the Nyquist–Shannon sampling theorem. */
+ if (frequency > signal->sampling_rate / 2)
+ return -1;
+
+ /* Clip the frequency to an integer multiple of the sampling rate.
+ * This to be able to store a full period of it and use that for
+ * signal generation, instead of recurrent calls to sin().
+ */
+ frequency = signal->sampling_rate / (signal->sampling_rate / frequency);
+
+ igt_debug("Adding test frequency %d\n", frequency);
+
+ signal->freqs[index].freq = frequency;
+ signal->freqs[index].frames = 0;
+ signal->freqs[index].offset = 0;
+ signal->freqs_count++;
+
+ return 0;
+}
+
+/**
+ * audio_signal_synthesize:
+ * @signal: The target signal structure
+ *
+ * Synthesize the data tables for the audio signal, that can later be used
+ * to fill audio buffers. The resources allocated by this function must be
+ * freed with a call to audio_signal_clean when the signal is no longer used.
+ */
+void audio_signal_synthesize(struct audio_signal *signal)
+{
+ short *period;
+ double value;
+ int frames;
+ int freq;
+ int i, j;
+
+ if (signal->freqs_count == 0)
+ return;
+
+ for (i = 0; i < signal->freqs_count; i++) {
+ freq = signal->freqs[i].freq;
+ frames = signal->sampling_rate / freq;
+
+ period = calloc(1, frames * sizeof(short));
+
+ for (j = 0; j < frames; j++) {
+ value = 2.0 * M_PI * freq / signal->sampling_rate * j;
+ value = sin(value) * SHRT_MAX / signal->freqs_count;
+
+ period[j] = (short) value;
+ }
+
+ signal->freqs[i].period = period;
+ signal->freqs[i].frames = frames;
+ }
+}
+
+/**
+ * audio_signal_synthesize:
+ * @signal: The target signal structure
+ *
+ * Free the resources allocated by audio_signal_synthesize and remove
+ * the previously-added frequencies.
+ */
+void audio_signal_clean(struct audio_signal *signal)
+{
+ int i;
+
+ for (i = 0; i < signal->freqs_count; i++) {
+ if (signal->freqs[i].period)
+ free(signal->freqs[i].period);
+
+ memset(&signal->freqs[i], 0, sizeof(struct audio_signal_freq));
+ }
+
+ signal->freqs_count = 0;
+}
+
+/**
+ * audio_signal_fill:
+ * @signal: The target signal structure
+ * @buffer: The target buffer to fill
+ * @frames: The number of frames to fill
+ *
+ * Fill the requested number of frames to the target buffer with the audio
+ * signal data (in interleaved S16_LE format), at the requested sampling rate
+ * and number of channels.
+ */
+void audio_signal_fill(struct audio_signal *signal, short *buffer, int frames)
+{
+ short *destination;
+ short *source;
+ int total;
+ int freq_frames;
+ int freq_offset;
+ int count;
+ int i, j, k;
+
+ memset(buffer, 0, sizeof(short) * signal->channels * frames);
+
+ for (i = 0; i < signal->freqs_count; i++) {
+ total = 0;
+
+ while (total < frames) {
+ freq_frames = signal->freqs[i].frames;
+ freq_offset = signal->freqs[i].offset;
+
+ source = signal->freqs[i].period + freq_offset;
+ destination = buffer + total * signal->channels;
+
+ count = freq_frames - freq_offset;
+ if (count > (frames - total))
+ count = frames - total;
+
+ freq_offset += count;
+ freq_offset %= freq_frames;
+
+ signal->freqs[i].offset = freq_offset;
+
+ for (j = 0; j < count; j++) {
+ for (k = 0; k < signal->channels; k++) {
+ destination[j * signal->channels + k] += source[j];
+ }
+ }
+
+ total += count;
+ }
+ }
+}
+
+/**
+ * audio_signal_detect:
+ * @signal: The target signal structure
+ * @channels: The input data's number of channels
+ * @sampling_rate: The input data's sampling rate
+ * @buffer: The input data's buffer
+ * @frames: The input data's number of frames
+ *
+ * Detect that the frequencies specified in @signal, and only those, are
+ * present in the input data. The input data's format is required to be S16_LE.
+ *
+ * Returns: A boolean indicating whether the detection was successful
+ */
+bool audio_signal_detect(struct audio_signal *signal, int channels,
+ int sampling_rate, short *buffer, int frames)
+{
+ double data[frames];
+ int amplitude[frames / 2];
+ bool detected[signal->freqs_count];
+ int threshold;
+ bool above;
+ int error;
+ int freq;
+ int max;
+ int c, i, j;
+
+ /* Allowed error in Hz due to FFT step. */
+ error = sampling_rate / frames;
+
+ for (c = 0; c < channels; c++) {
+ for (i = 0; i < frames; i++)
+ data[i] = (double) buffer[i * channels + c];
+
+ gsl_fft_real_radix2_transform(data, 1, frames);
+
+ max = 0;
+
+ for (i = 0; i < frames / 2; i++) {
+ amplitude[i] = sqrt(data[i] * data[i] +
+ data[frames - i] *
+ data[frames - i]);
+ if (amplitude[i] > max)
+ max = amplitude[i];
+ }
+
+ for (i = 0; i < signal->freqs_count; i++)
+ detected[i] = false;
+
+ threshold = max / 2;
+ above = false;
+ max = 0;
+
+ for (i = 0; i < frames / 2; i++) {
+ if (amplitude[i] > threshold)
+ above = true;
+
+ if (above) {
+ if (amplitude[i] < threshold) {
+ above = false;
+ max = 0;
+
+ for (j = 0; j < signal->freqs_count; j++) {
+ if (signal->freqs[j].freq >
+ freq - error &&
+ signal->freqs[j].freq <
+ freq + error) {
+ detected[j] = true;
+ break;
+ }
+ }
+
+ /* Detected frequency was not generated. */
+ if (j == signal->freqs_count) {
+ igt_debug("Detected additional frequency: %d\n",
+ freq);
+ return false;
+ }
+ }
+
+ if (amplitude[i] > max) {
+ max = amplitude[i];
+ freq = sampling_rate * i / frames;
+ }
+ }
+ }
+
+ for (i = 0; i < signal->freqs_count; i++) {
+ if (!detected[i]) {
+ igt_debug("Missing frequency: %d\n",
+ signal->freqs[i].freq);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
diff --git a/lib/igt_audio.h b/lib/igt_audio.h
new file mode 100644
index 00000000..507e7ab9
--- /dev/null
+++ b/lib/igt_audio.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright © 2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
+ */
+
+#ifndef IGT_AUDIO_H
+#define IGT_AUDIO_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "igt.h"
+#include <stdbool.h>
+
+struct audio_signal;
+
+struct audio_signal *audio_signal_init(int channels, int sampling_rate);
+int audio_signal_add_frequency(struct audio_signal *signal, int frequency);
+void audio_signal_synthesize(struct audio_signal *signal);
+void audio_signal_clean(struct audio_signal *signal);
+void audio_signal_fill(struct audio_signal *signal, short *buffer, int frames);
+bool audio_signal_detect(struct audio_signal *signal, int channels,
+ int sampling_rate, short *buffer, int frames);
+
+#endif
--
2.14.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH i-g-t 2/3] lib: Add ALSA library with dedicated helpers
2017-08-17 16:05 [PATCH i-g-t 1/3] lib: Add audio library with dedicated helpers Paul Kocialkowski
@ 2017-08-17 16:05 ` Paul Kocialkowski
2017-08-18 9:46 ` Arkadiusz Hiler
2017-08-18 16:20 ` Lyude Paul
2017-08-17 16:05 ` [PATCH i-g-t 3/3] tests: Introduce audio tests, starting with HDMI signal integrity Paul Kocialkowski
` (2 subsequent siblings)
3 siblings, 2 replies; 16+ messages in thread
From: Paul Kocialkowski @ 2017-08-17 16:05 UTC (permalink / raw)
To: intel-gfx
This introduces an ALSA library, with dedicated helpers for handling
playback and capture. It handles ALSA device identification and
configuration as well as a run loop with callback mechanisms for feeding
output data and handling input data.
This library paves the way for testing audio going through display
connectors, such as HDMI.
Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
configure.ac | 3 +
.../intel-gpu-tools/intel-gpu-tools-docs.xml | 1 +
lib/Makefile.am | 7 +
lib/igt.h | 1 +
lib/igt_alsa.c | 624 +++++++++++++++++++++
lib/igt_alsa.h | 60 ++
6 files changed, 696 insertions(+)
create mode 100644 lib/igt_alsa.c
create mode 100644 lib/igt_alsa.h
diff --git a/configure.ac b/configure.ac
index 50aa86b5..e66273a4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -219,6 +219,9 @@ if test "x$enable_chamelium" = xyes; then
AC_DEFINE(HAVE_CHAMELIUM, 1, [Enable Chamelium support])
fi
+PKG_CHECK_MODULES(ALSA, [alsa], [alsa=yes], [alsa=no])
+AM_CONDITIONAL(HAVE_ALSA, [test "x$alsa" = xyes])
+
# -----------------------------------------------------------------------------
# Configuration options
# -----------------------------------------------------------------------------
diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
index c77159cf..0c34e4a5 100644
--- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
+++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
@@ -16,6 +16,7 @@
<chapter>
<title>API Reference</title>
<xi:include href="xml/drmtest.xml"/>
+ <xi:include href="xml/igt_alsa.xml"/>
<xi:include href="xml/igt_audio.xml"/>
<xi:include href="xml/igt_aux.xml"/>
<xi:include href="xml/igt_chamelium.xml"/>
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 5ea08314..3ff14f66 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -38,6 +38,13 @@ lib_source_list += \
$(NULL)
endif
+if HAVE_ALSA
+lib_source_list += \
+ igt_alsa.c \
+ igt_alsa.h \
+ $(NULL)
+endif
+
AM_CPPFLAGS = -I$(top_srcdir)
AM_CFLAGS = \
$(CWARNFLAGS) \
diff --git a/lib/igt.h b/lib/igt.h
index a75d2db7..ebf92349 100644
--- a/lib/igt.h
+++ b/lib/igt.h
@@ -35,6 +35,7 @@
#include "igt_dummyload.h"
#include "igt_fb.h"
#include "igt_frame.h"
+#include "igt_alsa.h"
#include "igt_audio.h"
#include "igt_gt.h"
#include "igt_kms.h"
diff --git a/lib/igt_alsa.c b/lib/igt_alsa.c
new file mode 100644
index 00000000..d8bd0873
--- /dev/null
+++ b/lib/igt_alsa.c
@@ -0,0 +1,624 @@
+/*
+ * Copyright © 2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
+ */
+
+#include "config.h"
+
+#include <alsa/asoundlib.h>
+
+#include "igt.h"
+
+#define HANDLES_MAX 8
+
+/**
+ * SECTION:igt_alsa
+ * @short_description: Library with ALSA helpers
+ * @title: ALSA
+ * @include: igt_alsa.h
+ *
+ * This library contains helpers for ALSA playback and capture.
+ */
+
+struct alsa {
+ snd_pcm_t *output_handles[HANDLES_MAX];
+ int output_handles_count;
+ int output_sampling_rate;
+ int output_channels;
+
+ int (*output_callback)(void *data, short *buffer, int samples);
+ void *output_callback_data;
+ int output_samples_trigger;
+
+ snd_pcm_t *input_handle;
+ int input_sampling_rate;
+ int input_channels;
+
+ int (*input_callback)(void *data, short *buffer, int samples);
+ void *input_callback_data;
+ int input_samples_trigger;
+};
+
+static void alsa_error_handler(const char *file, int line, const char *function,
+ int err, const char *fmt, ...)
+{
+ if (err)
+ igt_debug("[ALSA] %s: %s\n", function, snd_strerror(err));
+}
+
+/**
+ * alsa_init:
+ * Allocate and initialize an alsa structure and configure the error handler.
+ *
+ * Returns: A newly-allocated alsa structure
+ */
+struct alsa *alsa_init(void)
+{
+ struct alsa *alsa;
+
+ alsa = malloc(sizeof(struct alsa));
+ memset(alsa, 0, sizeof(struct alsa));
+
+ /* Redirect errors to igt_debug instead of stderr. */
+ snd_lib_error_set_handler(alsa_error_handler);
+
+ return alsa;
+}
+
+static char *alsa_resolve_indentifier(const char *device_name, int skip)
+{
+ snd_ctl_card_info_t *card_info;
+ snd_pcm_info_t *pcm_info;
+ snd_ctl_t *handle = NULL;
+ const char *pcm_name;
+ char *identifier = NULL;
+ char name[32];
+ int card;
+ int dev;
+ int ret;
+
+ snd_ctl_card_info_alloca(&card_info);
+ snd_pcm_info_alloca(&pcm_info);
+
+ card = -1;
+
+ /* First try to open the device as-is. */
+ if (!skip) {
+ ret = snd_ctl_open(&handle, device_name, 0);
+ if (!ret) {
+ identifier = strdup(device_name);
+ goto resolved;
+ }
+ }
+
+ do {
+ ret = snd_card_next(&card);
+ if (ret < 0 || card < 0)
+ break;
+
+ snprintf(name, sizeof(name), "hw:%d", card);
+
+ ret = snd_ctl_open(&handle, name, 0);
+ if (ret < 0)
+ continue;
+
+ ret = snd_ctl_card_info(handle, card_info);
+ if (ret < 0) {
+ snd_ctl_close(handle);
+ handle = NULL;
+ continue;
+ }
+
+ dev = -1;
+
+ do {
+ ret = snd_ctl_pcm_next_device(handle, &dev);
+ if (ret < 0 || dev < 0)
+ break;
+
+ snd_pcm_info_set_device(pcm_info, dev);
+ snd_pcm_info_set_subdevice(pcm_info, 0);
+
+ ret = snd_ctl_pcm_info(handle, pcm_info);
+ if (ret < 0)
+ continue;
+
+ pcm_name = snd_pcm_info_get_name(pcm_info);
+ if (!pcm_name)
+ continue;
+
+ ret = strncmp(device_name, pcm_name,
+ strlen(device_name));
+
+ if (ret == 0) {
+ if (skip > 0) {
+ skip--;
+ continue;
+ }
+
+ snprintf(name, sizeof(name), "hw:%d,%d", card,
+ dev);
+
+ identifier = strdup(name);
+ goto resolved;
+ }
+ } while (dev >= 0);
+
+ snd_ctl_close(handle);
+ handle = NULL;
+ } while (card >= 0);
+
+resolved:
+ if (handle)
+ snd_ctl_close(handle);
+
+ return identifier;
+}
+
+/**
+ * alsa_open_output:
+ * @alsa: The target alsa structure
+ * @device_name: The name prefix of the output device(s) to open
+ *
+ * Open ALSA output devices whose name prefixes match the provided name prefix.
+ *
+ * Returns: An integer equal to zero for success and negative for failure
+ */
+int alsa_open_output(struct alsa *alsa, const char *device_name)
+{
+ snd_pcm_t *handle;
+ char *identifier;
+ int skip;
+ int index;
+ int ret;
+
+ skip = alsa->output_handles_count;
+ index = alsa->output_handles_count;
+
+ while (index < HANDLES_MAX) {
+ identifier = alsa_resolve_indentifier(device_name, skip++);
+ if (!identifier)
+ break;
+
+ ret = snd_pcm_open(&handle, identifier, SND_PCM_STREAM_PLAYBACK,
+ SND_PCM_NONBLOCK);
+ if (ret < 0) {
+ free(identifier);
+ continue;
+ }
+
+ igt_debug("Opened output %s\n", identifier);
+
+ alsa->output_handles[index++] = handle;
+ free(identifier);
+ }
+
+ if (index == 0)
+ return -1;
+
+ alsa->output_handles_count = index;
+
+ return 0;
+}
+
+/**
+ * alsa_open_input:
+ * @alsa: The target alsa structure
+ * @device_name: The name of the input device to open
+ *
+ * Open the ALSA input device whose name matches the provided name prefix.
+ *
+ * Returns: An integer equal to zero for success and negative for failure
+ */
+int alsa_open_input(struct alsa *alsa, const char *device_name)
+{
+ snd_pcm_t *handle;
+ char *identifier;
+ int ret;
+
+ identifier = alsa_resolve_indentifier(device_name, 0);
+
+ ret = snd_pcm_open(&handle, device_name, SND_PCM_STREAM_CAPTURE,
+ SND_PCM_NONBLOCK);
+ if (ret < 0)
+ goto complete;
+
+ igt_debug("Opened input %s\n", identifier);
+
+ alsa->input_handle = handle;
+
+ ret = 0;
+
+complete:
+ free(identifier);
+
+ return ret;
+}
+
+/**
+ * alsa_close_output:
+ * @alsa: The target alsa structure
+ *
+ * Close all the open ALSA outputs.
+ */
+void alsa_close_output(struct alsa *alsa)
+{
+ snd_pcm_t *handle;
+ int i;
+
+ for (i = 0; i < alsa->output_handles_count; i++) {
+ handle = alsa->output_handles[i];
+ if (!handle)
+ continue;
+
+ snd_pcm_close(handle);
+ alsa->output_handles[i] = NULL;
+ }
+
+ alsa->output_handles_count = 0;
+}
+
+/**
+ * alsa_close_output:
+ * @alsa: The target alsa structure
+ *
+ * Close the open ALSA input.
+ */
+void alsa_close_input(struct alsa *alsa)
+{
+ snd_pcm_t *handle = alsa->input_handle;
+ if (!handle)
+ return;
+
+ snd_pcm_close(handle);
+ alsa->input_handle = NULL;
+}
+
+static bool alsa_test_configuration(snd_pcm_t *handle, int channels,
+ int sampling_rate)
+{
+ snd_pcm_hw_params_t *params;
+ int ret;
+
+ snd_pcm_hw_params_alloca(¶ms);
+
+ ret = snd_pcm_hw_params_any(handle, params);
+ if (ret < 0)
+ return false;
+
+ ret = snd_pcm_hw_params_test_rate(handle, params, sampling_rate, 0);
+ if (ret < 0)
+ return false;
+
+ ret = snd_pcm_hw_params_test_channels(handle, params, channels);
+ if (ret < 0)
+ return false;
+
+ return true;
+}
+
+/**
+ * alsa_test_output_configuration:
+ * @alsa: The target alsa structure
+ * @channels: The number of channels to test
+ * @sampling_rate: The sampling rate to test
+ *
+ * Test the output configuration specified by @channels and @sampling_rate
+ * for the output devices.
+ *
+ * Returns: A boolean indicating whether the test succeeded
+ */
+bool alsa_test_output_configuration(struct alsa *alsa, int channels,
+ int sampling_rate)
+{
+ snd_pcm_t *handle;
+ bool ret;
+ int i;
+
+ for (i = 0; i < alsa->output_handles_count; i++) {
+ handle = alsa->output_handles[i];
+
+ ret = alsa_test_configuration(handle, channels, sampling_rate);
+ if (!ret)
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * alsa_test_input_configuration:
+ * @alsa: The target alsa structure
+ * @channels: The number of channels to test
+ * @sampling_rate: The sampling rate to test
+ *
+ * Test the input configuration specified by @channels and @sampling_rate
+ * for the input device.
+ *
+ * Returns: A boolean indicating whether the test succeeded
+ */
+bool alsa_test_input_configuration(struct alsa *alsa, int channels,
+ int sampling_rate)
+{
+ return alsa_test_configuration(alsa->input_handle, channels,
+ sampling_rate);
+}
+
+/**
+ * alsa_configure_output:
+ * @alsa: The target alsa structure
+ * @channels: The number of channels to test
+ * @sampling_rate: The sampling rate to test
+ *
+ * Configure the output devices with the configuration specified by @channels
+ * and @sampling_rate.
+ */
+void alsa_configure_output(struct alsa *alsa, int channels,
+ int sampling_rate)
+{
+ snd_pcm_t *handle;
+ int ret;
+ int i;
+
+ for (i = 0; i < alsa->output_handles_count; i++) {
+ handle = alsa->output_handles[i];
+
+ ret = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE,
+ SND_PCM_ACCESS_RW_INTERLEAVED,
+ channels, sampling_rate, 0, 0);
+ igt_assert(ret >= 0);
+ }
+
+ alsa->output_channels = channels;
+ alsa->output_sampling_rate = sampling_rate;
+}
+
+/**
+ * alsa_configure_input:
+ * @alsa: The target alsa structure
+ * @channels: The number of channels to test
+ * @sampling_rate: The sampling rate to test
+ *
+ * Configure the input device with the configuration specified by @channels
+ * and @sampling_rate.
+ */
+void alsa_configure_input(struct alsa *alsa, int channels,
+ int sampling_rate)
+{
+ snd_pcm_t *handle;
+ int ret;
+
+ handle = alsa->input_handle;
+
+ ret = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE,
+ SND_PCM_ACCESS_RW_INTERLEAVED, channels,
+ sampling_rate, 0, 0);
+ igt_assert(ret >= 0);
+
+ alsa->input_channels = channels;
+ alsa->input_sampling_rate = sampling_rate;
+
+}
+
+/**
+ * alsa_register_output_callback:
+ * @alsa: The target alsa structure
+ * @callback: The callback function to call to fill output data
+ * @callback_data: The data pointer to pass to the callback function
+ * @samples_trigger: The required number of samples to trigger the callback
+ *
+ * Register a callback function to be called to fill output data during a run.
+ * The callback is called when @samples_trigger samples are required.
+ *
+ * The callback should return an integer equal to zero for success and negative
+ * for failure.
+ */
+void alsa_register_output_callback(struct alsa *alsa,
+ int (*callback)(void *data, short *buffer, int samples),
+ void *callback_data, int samples_trigger)
+{
+ alsa->output_callback = callback;
+ alsa->output_callback_data = callback_data;
+ alsa->output_samples_trigger = samples_trigger;
+}
+
+/**
+ * alsa_register_input_callback:
+ * @alsa: The target alsa structure
+ * @callback: The callback function to call when input data is available
+ * @callback_data: The data pointer to pass to the callback function
+ * @samples_trigger: The required number of samples to trigger the callback
+ *
+ * Register a callback function to be called when input data is available during
+ * a run. The callback is called when @samples_trigger samples are available.
+ *
+ * The callback should return an integer equal to zero for success, negative for
+ * failure and positive to indicate that the run should stop.
+ */
+void alsa_register_input_callback(struct alsa *alsa,
+ int (*callback)(void *data, short *buffer, int samples),
+ void *callback_data, int samples_trigger)
+{
+ alsa->input_callback = callback;
+ alsa->input_callback_data = callback_data;
+ alsa->input_samples_trigger = samples_trigger;
+}
+
+/**
+ * alsa_run:
+ * @alsa: The target alsa structure
+ * @duration_ms: The maximum duration of the run in milliseconds
+ *
+ * Run ALSA playback and capture on the input and output devices for at
+ * most @duration_ms milliseconds, calling the registered callbacks when needed.
+ *
+ * Returns: An integer equal to zero for success, positive for a stop caused
+ * by the input callback and negative for failure
+ */
+int alsa_run(struct alsa *alsa, int duration_ms)
+{
+ snd_pcm_t *handle;
+ short *output_buffer = NULL;
+ short *input_buffer = NULL;
+ int output_limit;
+ int output_total = 0;
+ int output_counts[alsa->output_handles_count];
+ bool output_ready = false;
+ int output_channels;
+ int output_trigger;
+ int input_limit;
+ int input_total = 0;
+ int input_count = 0;
+ int input_channels;
+ int input_trigger;
+ bool reached;
+ int index;
+ int count;
+ int avail;
+ int i;
+ int ret;
+
+ output_limit = alsa->output_sampling_rate * duration_ms / 1000;
+ output_channels = alsa->output_channels;
+ output_trigger = alsa->output_samples_trigger;
+ output_buffer = malloc(sizeof(short) * output_channels *
+ output_trigger);
+
+ if (alsa->input_callback) {
+ input_limit = alsa->input_sampling_rate * duration_ms / 1000;
+ input_trigger = alsa->input_samples_trigger;
+ input_channels = alsa->input_channels;
+ input_buffer = malloc(sizeof(short) * input_channels *
+ input_trigger);
+ }
+
+ do {
+ reached = true;
+
+ if (output_total < output_limit) {
+ reached = false;
+
+ if (!output_ready) {
+ output_ready = true;
+
+ for (i = 0; i < alsa->output_handles_count; i++)
+ output_counts[i] = 0;
+
+ ret = alsa->output_callback(alsa->output_callback_data,
+ output_buffer,
+ output_trigger);
+ if (ret < 0)
+ goto complete;
+ }
+
+ for (i = 0; i < alsa->output_handles_count; i++) {
+ handle = alsa->output_handles[i];
+
+ if (output_counts[i] < output_trigger &&
+ snd_pcm_avail(handle) > 0) {
+ index = output_counts[i] *
+ output_channels;
+ count = output_trigger -
+ output_counts[i];
+ avail = snd_pcm_avail(handle);
+
+ count = avail < count ? avail : count;
+
+ ret = snd_pcm_writei(handle,
+ &output_buffer[index],
+ count);
+ if (ret < 0) {
+ ret = snd_pcm_recover(handle,
+ count, 0);
+ if (ret < 0)
+ goto complete;
+ }
+
+ output_counts[i] += ret;
+ }
+ }
+
+ output_ready = false;
+
+ for (i = 0; i < alsa->output_handles_count; i++)
+ if (output_counts[i] < output_trigger)
+ output_ready = true;
+
+ if (!output_ready)
+ output_total += output_trigger;
+
+ }
+
+ if (alsa->input_callback && input_total < input_limit) {
+ reached = false;
+
+ if (input_count == input_trigger) {
+ input_count = 0;
+
+ ret = alsa->input_callback(alsa->input_callback_data,
+ input_buffer,
+ input_trigger);
+ if (ret != 0)
+ goto complete;
+ }
+
+ handle = alsa->input_handle;
+
+ if (input_count < input_trigger &&
+ (snd_pcm_avail(handle) > 0 || input_total == 0)) {
+ index = input_count * input_channels;
+ count = input_trigger - input_count;
+ avail = snd_pcm_avail(handle);
+
+ count = avail > 0 && avail < count ? avail :
+ count;
+
+ ret = snd_pcm_readi(handle,
+ &input_buffer[index],
+ count);
+ if (ret == -EAGAIN) {
+ ret = 0;
+ } else if (ret < 0) {
+ ret = snd_pcm_recover(handle, count, 0);
+ if (ret < 0)
+ goto complete;
+ }
+
+ input_count += ret;
+ input_total += ret;
+ }
+ }
+ } while (!reached);
+
+ ret = 0;
+
+complete:
+ if (output_buffer)
+ free(output_buffer);
+
+ if (input_buffer)
+ free(input_buffer);
+
+ return ret;
+}
diff --git a/lib/igt_alsa.h b/lib/igt_alsa.h
new file mode 100644
index 00000000..9911ddde
--- /dev/null
+++ b/lib/igt_alsa.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
+ */
+
+#ifndef IGT_ALSA_H
+#define IGT_ALSA_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "igt.h"
+#include <stdbool.h>
+
+struct alsa;
+
+struct alsa *alsa_init(void);
+int alsa_open_output(struct alsa *alsa, const char *device_name);
+int alsa_open_input(struct alsa *alsa, const char *device_name);
+void alsa_close_output(struct alsa *alsa);
+void alsa_close_input(struct alsa *alsa);
+bool alsa_test_output_configuration(struct alsa *alsa, int channels,
+ int sampling_rate);
+bool alsa_test_input_configuration(struct alsa *alsa, int channels,
+ int sampling_rate);
+void alsa_configure_output(struct alsa *alsa, int channels,
+ int sampling_rate);
+void alsa_configure_input(struct alsa *alsa, int channels,
+ int sampling_rate);
+void alsa_register_output_callback(struct alsa *alsa,
+ int (*callback)(void *data, short *buffer, int samples),
+ void *callback_data, int samples_trigger);
+void alsa_register_input_callback(struct alsa *alsa,
+ int (*callback)(void *data, short *buffer, int samples),
+ void *callback_data, int samples_trigger);
+int alsa_run(struct alsa *alsa, int duration_ms);
+
+#endif
--
2.14.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH i-g-t 3/3] tests: Introduce audio tests, starting with HDMI signal integrity
2017-08-17 16:05 [PATCH i-g-t 1/3] lib: Add audio library with dedicated helpers Paul Kocialkowski
2017-08-17 16:05 ` [PATCH i-g-t 2/3] lib: Add ALSA " Paul Kocialkowski
@ 2017-08-17 16:05 ` Paul Kocialkowski
2017-08-18 16:15 ` Lyude Paul
2017-08-17 16:24 ` ✓ Fi.CI.BAT: success for series starting with [1/3] lib: Add audio library with dedicated helpers Patchwork
2017-08-18 16:16 ` [PATCH i-g-t 1/3] " Lyude Paul
3 siblings, 1 reply; 16+ messages in thread
From: Paul Kocialkowski @ 2017-08-17 16:05 UTC (permalink / raw)
To: intel-gfx
This introduces a new test for audio going through display connectors.
It currently contains a single subtest for HDMI signal integrity, but
other test cases will be added later on.
The test setup consists in using an HDMI-VGA bridge that separates the
audio out (via a 3.5 mm jack) and feeding this back to the DUT's line-in
where it can be recorded by ALSA with controls correctly configured.
The audio test makes use of the audio and ALSA igt libraries helpers.
Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
tests/Makefile.am | 12 ++++
tests/audio.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 182 insertions(+)
create mode 100644 tests/audio.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f9d11e6c..471f3818 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -20,6 +20,15 @@ TESTS_progs += \
$(NULL)
endif
+if HAVE_ALSA
+if HAVE_GSL
+TESTS_progs += \
+ audio \
+ $(NULL)
+endif
+endif
+
+
if BUILD_TESTS
test-list.txt: Makefile.sources
@echo TESTLIST > $@
@@ -134,6 +143,9 @@ vc4_wait_seqno_LDADD = $(LDADD) $(DRM_VC4_LIBS)
chamelium_CFLAGS = $(AM_CFLAGS) $(XMLRPC_CFLAGS) $(LIBUDEV_CFLAGS)
chamelium_LDADD = $(LDADD) $(XMLRPC_LIBS) $(LIBUDEV_LIBS)
+audio_CFLAGS = $(AM_CFLAGS) $(ALSA_CFLAGS)
+audio_LDADD = $(LDADD) $(ALSA_LIBS)
+
amdgpu_amd_basic_CFLAGS = $(AM_CFLAGS) $(DRM_AMDGPU_CFLAGS)
amdgpu_amd_basic_LDADD = $(LDADD) $(DRM_AMDGPU_LIBS)
amdgpu_amd_cs_nop_CFLAGS = $(AM_CFLAGS) $(DRM_AMDGPU_CFLAGS)
diff --git a/tests/audio.c b/tests/audio.c
new file mode 100644
index 00000000..7099dd99
--- /dev/null
+++ b/tests/audio.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright © 2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
+ */
+
+#include "config.h"
+#include "igt.h"
+
+#define PLAYBACK_CHANNELS 2
+#define PLAYBACK_FRAMES 1024
+
+#define CAPTURE_SAMPLE_RATE 48000
+#define CAPTURE_CHANNELS 2
+#define CAPTURE_DEVICE_NAME "default"
+#define CAPTURE_FRAMES 2048
+
+#define RUN_TIMEOUT 2000
+
+struct test_data {
+ struct alsa *alsa;
+ struct audio_signal *signal;
+
+ int streak;
+};
+
+static int sampling_rates[] = {
+ 32000,
+ 44100,
+ 48000,
+ 88200,
+ 96000,
+ 176400,
+ 192000,
+};
+
+static int sampling_rates_count = sizeof(sampling_rates) / sizeof(int);
+
+static int test_frequencies[] = {
+ 300,
+ 600,
+ 1200,
+ 80000,
+ 10000,
+};
+
+static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
+
+static int output_callback(void *data, short *buffer, int frames)
+{
+ struct test_data *test_data = (struct test_data *) data;
+
+ audio_signal_fill(test_data->signal, buffer, frames);
+
+ return 0;
+}
+
+static int input_callback(void *data, short *buffer, int frames)
+{
+ struct test_data *test_data = (struct test_data *) data;
+ bool detect;
+
+ detect = audio_signal_detect(test_data->signal, CAPTURE_CHANNELS,
+ CAPTURE_SAMPLE_RATE, buffer, frames);
+ if (detect)
+ test_data->streak++;
+ else
+ test_data->streak = 0;
+
+ /* A streak of 3 gives confidence that the signal is good. */
+ if (test_data->streak == 3)
+ return 1;
+
+ return 0;
+}
+
+static void test_integrity(const char *device_name)
+{
+ struct test_data data;
+ int sampling_rate;
+ bool run = false;
+ bool test;
+ int i, j;
+ int ret;
+
+ data.alsa = alsa_init();
+ igt_assert(data.alsa);
+
+ ret = alsa_open_output(data.alsa, device_name);
+ igt_assert(ret >= 0);
+
+ ret = alsa_open_input(data.alsa, CAPTURE_DEVICE_NAME);
+ igt_assert(ret >= 0);
+
+ alsa_configure_input(data.alsa, CAPTURE_CHANNELS,
+ CAPTURE_SAMPLE_RATE);
+
+ for (i = 0; i < sampling_rates_count; i++) {
+ sampling_rate = sampling_rates[i];
+
+ test = alsa_test_output_configuration(data.alsa,
+ PLAYBACK_CHANNELS,
+ sampling_rate);
+ if (!test)
+ continue;
+
+ igt_debug("Testing with sampling rate %d\n", sampling_rate);
+
+ alsa_configure_output(data.alsa, PLAYBACK_CHANNELS,
+ sampling_rate);
+
+ data.signal = audio_signal_init(PLAYBACK_CHANNELS,
+ sampling_rate);
+ igt_assert(data.signal);
+
+ for (j = 0; j < test_frequencies_count; j++)
+ audio_signal_add_frequency(data.signal,
+ test_frequencies[j]);
+
+ audio_signal_synthesize(data.signal);
+
+ alsa_register_output_callback(data.alsa, output_callback,
+ &data, PLAYBACK_FRAMES);
+ alsa_register_input_callback(data.alsa, input_callback, &data,
+ CAPTURE_FRAMES);
+
+ data.streak = 0;
+
+ ret = alsa_run(data.alsa, RUN_TIMEOUT);
+ igt_assert(ret > 0);
+
+ audio_signal_clean(data.signal);
+ free(data.signal);
+
+ run = true;
+ }
+
+ /* Make sure we tested at least one frequency */
+ igt_assert(run);
+
+ alsa_close_input(data.alsa);
+ alsa_close_output(data.alsa);
+ free(data.alsa);
+}
+
+igt_main
+{
+ igt_subtest("hdmi-integrity")
+ test_integrity("HDMI");
+}
--
2.14.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 16+ messages in thread
* ✓ Fi.CI.BAT: success for series starting with [1/3] lib: Add audio library with dedicated helpers
2017-08-17 16:05 [PATCH i-g-t 1/3] lib: Add audio library with dedicated helpers Paul Kocialkowski
2017-08-17 16:05 ` [PATCH i-g-t 2/3] lib: Add ALSA " Paul Kocialkowski
2017-08-17 16:05 ` [PATCH i-g-t 3/3] tests: Introduce audio tests, starting with HDMI signal integrity Paul Kocialkowski
@ 2017-08-17 16:24 ` Patchwork
2017-08-18 9:59 ` Petri Latvala
2017-08-18 16:16 ` [PATCH i-g-t 1/3] " Lyude Paul
3 siblings, 1 reply; 16+ messages in thread
From: Patchwork @ 2017-08-17 16:24 UTC (permalink / raw)
To: Paul Kocialkowski; +Cc: intel-gfx
== Series Details ==
Series: series starting with [1/3] lib: Add audio library with dedicated helpers
URL : https://patchwork.freedesktop.org/series/28929/
State : success
== Summary ==
IGT patchset tested on top of latest successful build
5a17ee2c8f9013f5db852d27564b837f9f2c5a9f tools/intel_vbt_decode: Fix decoding of child device structure
with latest DRM-Tip kernel build CI_DRM_2971
e1b18fbd4dae drm-tip: 2017y-08m-17d-14h-58m-23s UTC integration manifest
Test gem_exec_flush:
Subgroup basic-batch-kernel-default-uc:
pass -> FAIL (fi-snb-2600) fdo#100007
Test kms_flip:
Subgroup basic-flip-vs-modeset:
skip -> PASS (fi-skl-x1585l) fdo#101781
fdo#100007 https://bugs.freedesktop.org/show_bug.cgi?id=100007
fdo#101781 https://bugs.freedesktop.org/show_bug.cgi?id=101781
fi-bdw-5557u total:279 pass:268 dwarn:0 dfail:0 fail:0 skip:11 time:451s
fi-bdw-gvtdvm total:279 pass:265 dwarn:0 dfail:0 fail:0 skip:14 time:440s
fi-blb-e6850 total:279 pass:224 dwarn:1 dfail:0 fail:0 skip:54 time:357s
fi-bsw-n3050 total:279 pass:243 dwarn:0 dfail:0 fail:0 skip:36 time:555s
fi-bxt-j4205 total:279 pass:260 dwarn:0 dfail:0 fail:0 skip:19 time:533s
fi-byt-j1900 total:279 pass:254 dwarn:1 dfail:0 fail:0 skip:24 time:527s
fi-byt-n2820 total:279 pass:251 dwarn:0 dfail:0 fail:0 skip:28 time:516s
fi-glk-2a total:279 pass:260 dwarn:0 dfail:0 fail:0 skip:19 time:610s
fi-hsw-4770 total:279 pass:263 dwarn:0 dfail:0 fail:0 skip:16 time:443s
fi-hsw-4770r total:279 pass:263 dwarn:0 dfail:0 fail:0 skip:16 time:420s
fi-ilk-650 total:279 pass:229 dwarn:0 dfail:0 fail:0 skip:50 time:419s
fi-ivb-3520m total:279 pass:261 dwarn:0 dfail:0 fail:0 skip:18 time:498s
fi-ivb-3770 total:279 pass:261 dwarn:0 dfail:0 fail:0 skip:18 time:480s
fi-kbl-7500u total:279 pass:261 dwarn:0 dfail:0 fail:0 skip:18 time:477s
fi-kbl-7560u total:279 pass:269 dwarn:0 dfail:0 fail:0 skip:10 time:595s
fi-kbl-r total:279 pass:261 dwarn:0 dfail:0 fail:0 skip:18 time:604s
fi-skl-6260u total:279 pass:269 dwarn:0 dfail:0 fail:0 skip:10 time:463s
fi-skl-6700k total:279 pass:261 dwarn:0 dfail:0 fail:0 skip:18 time:473s
fi-skl-6770hq total:279 pass:269 dwarn:0 dfail:0 fail:0 skip:10 time:487s
fi-skl-gvtdvm total:279 pass:266 dwarn:0 dfail:0 fail:0 skip:13 time:445s
fi-skl-x1585l total:279 pass:269 dwarn:0 dfail:0 fail:0 skip:10 time:508s
fi-snb-2520m total:279 pass:251 dwarn:0 dfail:0 fail:0 skip:28 time:546s
fi-snb-2600 total:279 pass:249 dwarn:0 dfail:0 fail:1 skip:29 time:414s
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_72/
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH i-g-t 2/3] lib: Add ALSA library with dedicated helpers
2017-08-17 16:05 ` [PATCH i-g-t 2/3] lib: Add ALSA " Paul Kocialkowski
@ 2017-08-18 9:46 ` Arkadiusz Hiler
2017-08-21 7:25 ` Arkadiusz Hiler
2017-08-18 16:20 ` Lyude Paul
1 sibling, 1 reply; 16+ messages in thread
From: Arkadiusz Hiler @ 2017-08-18 9:46 UTC (permalink / raw)
To: Paul Kocialkowski; +Cc: intel-gfx
On Thu, Aug 17, 2017 at 07:05:56PM +0300, Paul Kocialkowski wrote:
> This introduces an ALSA library, with dedicated helpers for handling
> playback and capture. It handles ALSA device identification and
> configuration as well as a run loop with callback mechanisms for feeding
> output data and handling input data.
>
> This library paves the way for testing audio going through display
> connectors, such as HDMI.
>
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> ---
> configure.ac | 3 +
> .../intel-gpu-tools/intel-gpu-tools-docs.xml | 1 +
> lib/Makefile.am | 7 +
> lib/igt.h | 1 +
> lib/igt_alsa.c | 624 +++++++++++++++++++++
> lib/igt_alsa.h | 60 ++
> 6 files changed, 696 insertions(+)
> create mode 100644 lib/igt_alsa.c
> create mode 100644 lib/igt_alsa.h
>
> diff --git a/configure.ac b/configure.ac
> index 50aa86b5..e66273a4 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -219,6 +219,9 @@ if test "x$enable_chamelium" = xyes; then
> AC_DEFINE(HAVE_CHAMELIUM, 1, [Enable Chamelium support])
> fi
>
> +PKG_CHECK_MODULES(ALSA, [alsa], [alsa=yes], [alsa=no])
> +AM_CONDITIONAL(HAVE_ALSA, [test "x$alsa" = xyes])
please mention the new dependency in the README
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: ✓ Fi.CI.BAT: success for series starting with [1/3] lib: Add audio library with dedicated helpers
2017-08-17 16:24 ` ✓ Fi.CI.BAT: success for series starting with [1/3] lib: Add audio library with dedicated helpers Patchwork
@ 2017-08-18 9:59 ` Petri Latvala
0 siblings, 0 replies; 16+ messages in thread
From: Petri Latvala @ 2017-08-18 9:59 UTC (permalink / raw)
To: intel-gfx
Note: Alsa libraries are not installed in CI atm so this series wasn't
quite tested.
--
Petri Latvala
On Thu, Aug 17, 2017 at 04:24:21PM +0000, Patchwork wrote:
> == Series Details ==
>
> Series: series starting with [1/3] lib: Add audio library with dedicated helpers
> URL : https://patchwork.freedesktop.org/series/28929/
> State : success
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH i-g-t 3/3] tests: Introduce audio tests, starting with HDMI signal integrity
2017-08-17 16:05 ` [PATCH i-g-t 3/3] tests: Introduce audio tests, starting with HDMI signal integrity Paul Kocialkowski
@ 2017-08-18 16:15 ` Lyude Paul
2017-08-21 15:14 ` Paul Kocialkowski
0 siblings, 1 reply; 16+ messages in thread
From: Lyude Paul @ 2017-08-18 16:15 UTC (permalink / raw)
To: Paul Kocialkowski, intel-gfx
Nice job! Only one small formatting change
On Thu, 2017-08-17 at 19:05 +0300, Paul Kocialkowski wrote:
> This introduces a new test for audio going through display
> connectors.
> It currently contains a single subtest for HDMI signal integrity, but
> other test cases will be added later on.
>
> The test setup consists in using an HDMI-VGA bridge that separates
> the
> audio out (via a 3.5 mm jack) and feeding this back to the DUT's
> line-in
> where it can be recorded by ALSA with controls correctly configured.
>
> The audio test makes use of the audio and ALSA igt libraries helpers.
>
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> ---
> tests/Makefile.am | 12 ++++
> tests/audio.c | 170
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 182 insertions(+)
> create mode 100644 tests/audio.c
>
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index f9d11e6c..471f3818 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -20,6 +20,15 @@ TESTS_progs += \
> $(NULL)
> endif
>
> +if HAVE_ALSA
> +if HAVE_GSL
> +TESTS_progs += \
> + audio \
> + $(NULL)
> +endif
> +endif
> +
> +
> if BUILD_TESTS
> test-list.txt: Makefile.sources
> @echo TESTLIST > $@
> @@ -134,6 +143,9 @@ vc4_wait_seqno_LDADD = $(LDADD) $(DRM_VC4_LIBS)
> chamelium_CFLAGS = $(AM_CFLAGS) $(XMLRPC_CFLAGS) $(LIBUDEV_CFLAGS)
> chamelium_LDADD = $(LDADD) $(XMLRPC_LIBS) $(LIBUDEV_LIBS)
>
> +audio_CFLAGS = $(AM_CFLAGS) $(ALSA_CFLAGS)
> +audio_LDADD = $(LDADD) $(ALSA_LIBS)
> +
> amdgpu_amd_basic_CFLAGS = $(AM_CFLAGS) $(DRM_AMDGPU_CFLAGS)
> amdgpu_amd_basic_LDADD = $(LDADD) $(DRM_AMDGPU_LIBS)
> amdgpu_amd_cs_nop_CFLAGS = $(AM_CFLAGS) $(DRM_AMDGPU_CFLAGS)
> diff --git a/tests/audio.c b/tests/audio.c
> new file mode 100644
> index 00000000..7099dd99
> --- /dev/null
> +++ b/tests/audio.c
> @@ -0,0 +1,170 @@
> +/*
> + * Copyright © 2017 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person
> obtaining a
> + * copy of this software and associated documentation files (the
> "Software"),
> + * to deal in the Software without restriction, including without
> limitation
> + * the rights to use, copy, modify, merge, publish, distribute,
> sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom
> the
> + * Software is furnished to do so, subject to the following
> conditions:
> + *
> + * The above copyright notice and this permission notice (including
> the next
> + * paragraph) shall be included in all copies or substantial
> portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
> OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + * Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> + */
> +
> +#include "config.h"
> +#include "igt.h"
> +
> +#define PLAYBACK_CHANNELS 2
> +#define PLAYBACK_FRAMES 1024
> +
> +#define CAPTURE_SAMPLE_RATE 48000
> +#define CAPTURE_CHANNELS 2
> +#define CAPTURE_DEVICE_NAME "default"
> +#define CAPTURE_FRAMES 2048
Might want to fix the indenting here
> +
> +#define RUN_TIMEOUT 2000
> +
> +struct test_data {
> + struct alsa *alsa;
> + struct audio_signal *signal;
> +
> + int streak;
> +};
> +
> +static int sampling_rates[] = {
> + 32000,
> + 44100,
> + 48000,
> + 88200,
> + 96000,
> + 176400,
> + 192000,
> +};
> +
> +static int sampling_rates_count = sizeof(sampling_rates) /
> sizeof(int);
> +
> +static int test_frequencies[] = {
> + 300,
> + 600,
> + 1200,
> + 80000,
> + 10000,
> +};
> +
> +static int test_frequencies_count = sizeof(test_frequencies) /
> sizeof(int);
> +
> +static int output_callback(void *data, short *buffer, int frames)
> +{
> + struct test_data *test_data = (struct test_data *) data;
> +
> + audio_signal_fill(test_data->signal, buffer, frames);
> +
> + return 0;
> +}
> +
> +static int input_callback(void *data, short *buffer, int frames)
> +{
> + struct test_data *test_data = (struct test_data *) data;
> + bool detect;
> +
> + detect = audio_signal_detect(test_data->signal,
> CAPTURE_CHANNELS,
> + CAPTURE_SAMPLE_RATE, buffer,
> frames);
> + if (detect)
> + test_data->streak++;
> + else
> + test_data->streak = 0;
> +
> + /* A streak of 3 gives confidence that the signal is good.
> */
> + if (test_data->streak == 3)
> + return 1;
> +
> + return 0;
> +}
> +
> +static void test_integrity(const char *device_name)
> +{
> + struct test_data data;
> + int sampling_rate;
> + bool run = false;
> + bool test;
> + int i, j;
> + int ret;
> +
> + data.alsa = alsa_init();
> + igt_assert(data.alsa);
> +
> + ret = alsa_open_output(data.alsa, device_name);
> + igt_assert(ret >= 0);
> +
> + ret = alsa_open_input(data.alsa, CAPTURE_DEVICE_NAME);
> + igt_assert(ret >= 0);
> +
> + alsa_configure_input(data.alsa, CAPTURE_CHANNELS,
> + CAPTURE_SAMPLE_RATE);
> +
> + for (i = 0; i < sampling_rates_count; i++) {
> + sampling_rate = sampling_rates[i];
> +
> + test = alsa_test_output_configuration(data.alsa,
> + PLAYBACK_CHANN
> ELS,
> + sampling_rate)
> ;
> + if (!test)
> + continue;
> +
> + igt_debug("Testing with sampling rate %d\n",
> sampling_rate);
> +
> + alsa_configure_output(data.alsa, PLAYBACK_CHANNELS,
> + sampling_rate);
> +
> + data.signal = audio_signal_init(PLAYBACK_CHANNELS,
> + sampling_rate);
> + igt_assert(data.signal);
> +
> + for (j = 0; j < test_frequencies_count; j++)
> + audio_signal_add_frequency(data.signal,
> + test_frequencies[
> j]);
> +
> + audio_signal_synthesize(data.signal);
> +
> + alsa_register_output_callback(data.alsa,
> output_callback,
> + &data,
> PLAYBACK_FRAMES);
> + alsa_register_input_callback(data.alsa,
> input_callback, &data,
> + CAPTURE_FRAMES);
> +
> + data.streak = 0;
> +
> + ret = alsa_run(data.alsa, RUN_TIMEOUT);
> + igt_assert(ret > 0);
> +
> + audio_signal_clean(data.signal);
> + free(data.signal);
> +
> + run = true;
> + }
> +
> + /* Make sure we tested at least one frequency */
> + igt_assert(run);
> +
> + alsa_close_input(data.alsa);
> + alsa_close_output(data.alsa);
> + free(data.alsa);
> +}
> +
> +igt_main
> +{
> + igt_subtest("hdmi-integrity")
> + test_integrity("HDMI");
> +}
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH i-g-t 1/3] lib: Add audio library with dedicated helpers
2017-08-17 16:05 [PATCH i-g-t 1/3] lib: Add audio library with dedicated helpers Paul Kocialkowski
` (2 preceding siblings ...)
2017-08-17 16:24 ` ✓ Fi.CI.BAT: success for series starting with [1/3] lib: Add audio library with dedicated helpers Patchwork
@ 2017-08-18 16:16 ` Lyude Paul
2017-08-21 15:27 ` Paul Kocialkowski
3 siblings, 1 reply; 16+ messages in thread
From: Lyude Paul @ 2017-08-18 16:16 UTC (permalink / raw)
To: Paul Kocialkowski, intel-gfx
One more small formatting change
On Thu, 2017-08-17 at 19:05 +0300, Paul Kocialkowski wrote:
> This introduces an audio library, with dedicated helpers for both
> generating signals and detecting peak frequencies in a signal.
>
> This library paves the way for testing audio going through display
> connectors, such as HDMI.
>
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> ---
> .../intel-gpu-tools/intel-gpu-tools-docs.xml | 1 +
> lib/Makefile.am | 2 +
> lib/igt.h | 1 +
> lib/igt_audio.c | 326
> +++++++++++++++++++++
> lib/igt_audio.h | 47 +++
> 5 files changed, 377 insertions(+)
> create mode 100644 lib/igt_audio.c
> create mode 100644 lib/igt_audio.h
>
> diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> index f88afd2a..c77159cf 100644
> --- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> +++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> @@ -16,6 +16,7 @@
> <chapter>
> <title>API Reference</title>
> <xi:include href="xml/drmtest.xml"/>
> + <xi:include href="xml/igt_audio.xml"/>
> <xi:include href="xml/igt_aux.xml"/>
> <xi:include href="xml/igt_chamelium.xml"/>
> <xi:include href="xml/igt_core.xml"/>
> diff --git a/lib/Makefile.am b/lib/Makefile.am
> index 9c932d6f..5ea08314 100644
> --- a/lib/Makefile.am
> +++ b/lib/Makefile.am
> @@ -33,6 +33,8 @@ if HAVE_GSL
> lib_source_list += \
> igt_frame.c \
> igt_frame.h \
> + igt_audio.c \
> + igt_audio.h \
> $(NULL)
> endif
>
> diff --git a/lib/igt.h b/lib/igt.h
> index d16a4991..a75d2db7 100644
> --- a/lib/igt.h
> +++ b/lib/igt.h
> @@ -35,6 +35,7 @@
> #include "igt_dummyload.h"
> #include "igt_fb.h"
> #include "igt_frame.h"
> +#include "igt_audio.h"
> #include "igt_gt.h"
> #include "igt_kms.h"
> #include "igt_pm.h"
> diff --git a/lib/igt_audio.c b/lib/igt_audio.c
> new file mode 100644
> index 00000000..527a4930
> --- /dev/null
> +++ b/lib/igt_audio.c
> @@ -0,0 +1,326 @@
> +/*
> + * Copyright © 2017 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person
> obtaining a
> + * copy of this software and associated documentation files (the
> "Software"),
> + * to deal in the Software without restriction, including without
> limitation
> + * the rights to use, copy, modify, merge, publish, distribute,
> sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom
> the
> + * Software is furnished to do so, subject to the following
> conditions:
> + *
> + * The above copyright notice and this permission notice (including
> the next
> + * paragraph) shall be included in all copies or substantial
> portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
> OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + * Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> + */
> +
> +#include "config.h"
> +
> +#include <math.h>
> +#include <gsl/gsl_fft_real.h>
> +
> +#include "igt.h"
> +
> +#define FREQS_MAX 8
> +
> +/**
> + * SECTION:igt_audio
> + * @short_description: Library for audio-related tests
> + * @title: Audio
> + * @include: igt_audio.h
> + *
> + * This library contains helpers for audio-related tests. More
> specifically,
> + * it allows generating additions of sine signals as well as
> detecting them.
> + */
> +
> +struct audio_signal_freq {
> + int freq;
> +
> + short *period;
> + int frames;
> + int offset;
> +};
> +
> +struct audio_signal {
> + int channels;
> + int sampling_rate;
> +
> + struct audio_signal_freq freqs[FREQS_MAX];
> + int freqs_count;
> +};
> +
> +/**
> + * audio_signal_init:
> + * @channels: The number of channels to use for the signal
> + * @sampling_rate: The sampling rate to use for the signal
> + *
> + * Allocate and initialize an audio signal structure with the given
> parameters.
> + *
> + * Returns: A newly-allocated audio signal structure
> + */
> +struct audio_signal *audio_signal_init(int channels, int
> sampling_rate)
> +{
> + struct audio_signal *signal;
> +
> + signal = malloc(sizeof(struct audio_signal));
> + memset(signal, 0, sizeof(struct audio_signal));
> +
> + signal->sampling_rate = sampling_rate;
> + signal->channels = channels;
> +
> + return signal;
> +}
> +
> +/**
> + * audio_signal_add_frequency:
> + * @signal: The target signal structure
> + * @frequency: The frequency to add to the signal
> + *
> + * Add a frequency to the signal.
> + *
> + * Returns: An integer equal to zero for success and negative for
> failure
> + */
> +int audio_signal_add_frequency(struct audio_signal *signal, int
> frequency)
> +{
> + int index = signal->freqs_count;
> +
> + if (index == FREQS_MAX)
> + return -1;
> +
> + /* Stay within the Nyquist–Shannon sampling theorem. */
> + if (frequency > signal->sampling_rate / 2)
> + return -1;
> +
> + /* Clip the frequency to an integer multiple of the sampling
> rate.
> + * This to be able to store a full period of it and use that
> for
> + * signal generation, instead of recurrent calls to sin().
> + */
> + frequency = signal->sampling_rate / (signal->sampling_rate /
> frequency);
> +
> + igt_debug("Adding test frequency %d\n", frequency);
> +
> + signal->freqs[index].freq = frequency;
> + signal->freqs[index].frames = 0;
> + signal->freqs[index].offset = 0;
> + signal->freqs_count++;
> +
> + return 0;
> +}
> +
> +/**
> + * audio_signal_synthesize:
> + * @signal: The target signal structure
> + *
> + * Synthesize the data tables for the audio signal, that can later
> be used
> + * to fill audio buffers. The resources allocated by this function
> must be
> + * freed with a call to audio_signal_clean when the signal is no
> longer used.
> + */
> +void audio_signal_synthesize(struct audio_signal *signal)
> +{
> + short *period;
> + double value;
> + int frames;
> + int freq;
> + int i, j;
> +
> + if (signal->freqs_count == 0)
> + return;
> +
> + for (i = 0; i < signal->freqs_count; i++) {
> + freq = signal->freqs[i].freq;
> + frames = signal->sampling_rate / freq;
> +
> + period = calloc(1, frames * sizeof(short));
> +
> + for (j = 0; j < frames; j++) {
> + value = 2.0 * M_PI * freq / signal-
> >sampling_rate * j;
> + value = sin(value) * SHRT_MAX / signal-
> >freqs_count;
> +
> + period[j] = (short) value;
> + }
> +
> + signal->freqs[i].period = period;
> + signal->freqs[i].frames = frames;
> + }
> +}
> +
> +/**
> + * audio_signal_synthesize:
> + * @signal: The target signal structure
> + *
> + * Free the resources allocated by audio_signal_synthesize and
> remove
> + * the previously-added frequencies.
> + */
> +void audio_signal_clean(struct audio_signal *signal)
> +{
> + int i;
> +
> + for (i = 0; i < signal->freqs_count; i++) {
> + if (signal->freqs[i].period)
> + free(signal->freqs[i].period);
> +
> + memset(&signal->freqs[i], 0, sizeof(struct
> audio_signal_freq));
> + }
> +
> + signal->freqs_count = 0;
> +}
> +
> +/**
> + * audio_signal_fill:
> + * @signal: The target signal structure
> + * @buffer: The target buffer to fill
> + * @frames: The number of frames to fill
> + *
> + * Fill the requested number of frames to the target buffer with the
> audio
> + * signal data (in interleaved S16_LE format), at the requested
> sampling rate
> + * and number of channels.
> + */
> +void audio_signal_fill(struct audio_signal *signal, short *buffer,
> int frames)
> +{
> + short *destination;
> + short *source;
> + int total;
> + int freq_frames;
> + int freq_offset;
> + int count;
> + int i, j, k;
> +
> + memset(buffer, 0, sizeof(short) * signal->channels *
> frames);
> +
> + for (i = 0; i < signal->freqs_count; i++) {
> + total = 0;
> +
> + while (total < frames) {
> + freq_frames = signal->freqs[i].frames;
> + freq_offset = signal->freqs[i].offset;
> +
> + source = signal->freqs[i].period +
> freq_offset;
> + destination = buffer + total * signal-
> >channels;
> +
> + count = freq_frames - freq_offset;
> + if (count > (frames - total))
> + count = frames - total;
> +
> + freq_offset += count;
> + freq_offset %= freq_frames;
> +
> + signal->freqs[i].offset = freq_offset;
> +
> + for (j = 0; j < count; j++) {
> + for (k = 0; k < signal->channels;
> k++) {
> + destination[j * signal-
> >channels + k] += source[j];
> + }
> + }
> +
> + total += count;
> + }
> + }
> +}
> +
> +/**
> + * audio_signal_detect:
> + * @signal: The target signal structure
> + * @channels: The input data's number of channels
> + * @sampling_rate: The input data's sampling rate
> + * @buffer: The input data's buffer
> + * @frames: The input data's number of frames
> + *
> + * Detect that the frequencies specified in @signal, and only those,
> are
> + * present in the input data. The input data's format is required to
> be S16_LE.
> + *
> + * Returns: A boolean indicating whether the detection was
> successful
> + */
> +bool audio_signal_detect(struct audio_signal *signal, int channels,
> + int sampling_rate, short *buffer, int
> frames)
> +{
> + double data[frames];
> + int amplitude[frames / 2];
> + bool detected[signal->freqs_count];
> + int threshold;
> + bool above;
> + int error;
> + int freq;
> + int max;
> + int c, i, j;
> +
> + /* Allowed error in Hz due to FFT step. */
> + error = sampling_rate / frames;
> +
> + for (c = 0; c < channels; c++) {
> + for (i = 0; i < frames; i++)
> + data[i] = (double) buffer[i * channels + c];
> +
> + gsl_fft_real_radix2_transform(data, 1, frames);
> +
> + max = 0;
> +
> + for (i = 0; i < frames / 2; i++) {
> + amplitude[i] = sqrt(data[i] * data[i] +
> + data[frames - i] *
> + data[frames - i]);
More indenting fixes? not sure if this one is just a result of it
getting formatted as an email.
> + if (amplitude[i] > max)
> + max = amplitude[i];
> + }
> +
> + for (i = 0; i < signal->freqs_count; i++)
> + detected[i] = false;
> +
> + threshold = max / 2;
> + above = false;
> + max = 0;
> +
> + for (i = 0; i < frames / 2; i++) {
> + if (amplitude[i] > threshold)
> + above = true;
> +
> + if (above) {
> + if (amplitude[i] < threshold) {
> + above = false;
> + max = 0;
> +
> + for (j = 0; j < signal-
> >freqs_count; j++) {
> + if (signal-
> >freqs[j].freq >
> + freq - error &&
> + signal-
> >freqs[j].freq <
> + freq + error) {
> + detected[j]
> = true;
> + break;
> + }
> + }
> +
> + /* Detected frequency was
> not generated. */
> + if (j == signal-
> >freqs_count) {
> + igt_debug("Detected
> additional frequency: %d\n",
> + freq);
> + return false;
> + }
> + }
> +
> + if (amplitude[i] > max) {
> + max = amplitude[i];
> + freq = sampling_rate * i /
> frames;
> + }
> + }
> + }
> +
> + for (i = 0; i < signal->freqs_count; i++) {
> + if (!detected[i]) {
> + igt_debug("Missing frequency: %d\n",
> + signal->freqs[i].freq);
> + return false;
> + }
> + }
> + }
> +
> + return true;
> +}
> diff --git a/lib/igt_audio.h b/lib/igt_audio.h
> new file mode 100644
> index 00000000..507e7ab9
> --- /dev/null
> +++ b/lib/igt_audio.h
> @@ -0,0 +1,47 @@
> +/*
> + * Copyright © 2017 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person
> obtaining a
> + * copy of this software and associated documentation files (the
> "Software"),
> + * to deal in the Software without restriction, including without
> limitation
> + * the rights to use, copy, modify, merge, publish, distribute,
> sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom
> the
> + * Software is furnished to do so, subject to the following
> conditions:
> + *
> + * The above copyright notice and this permission notice (including
> the next
> + * paragraph) shall be included in all copies or substantial
> portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
> OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + * Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> + */
> +
> +#ifndef IGT_AUDIO_H
> +#define IGT_AUDIO_H
> +
> +#ifdef HAVE_CONFIG_H
> +#include "config.h"
> +#endif
> +
> +#include "igt.h"
> +#include <stdbool.h>
> +
> +struct audio_signal;
> +
> +struct audio_signal *audio_signal_init(int channels, int
> sampling_rate);
> +int audio_signal_add_frequency(struct audio_signal *signal, int
> frequency);
> +void audio_signal_synthesize(struct audio_signal *signal);
> +void audio_signal_clean(struct audio_signal *signal);
> +void audio_signal_fill(struct audio_signal *signal, short *buffer,
> int frames);
> +bool audio_signal_detect(struct audio_signal *signal, int channels,
> + int sampling_rate, short *buffer, int
> frames);
> +
> +#endif
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH i-g-t 2/3] lib: Add ALSA library with dedicated helpers
2017-08-17 16:05 ` [PATCH i-g-t 2/3] lib: Add ALSA " Paul Kocialkowski
2017-08-18 9:46 ` Arkadiusz Hiler
@ 2017-08-18 16:20 ` Lyude Paul
2017-08-21 15:11 ` Paul Kocialkowski
1 sibling, 1 reply; 16+ messages in thread
From: Lyude Paul @ 2017-08-18 16:20 UTC (permalink / raw)
To: Paul Kocialkowski, intel-gfx
And two more small changes
On Thu, 2017-08-17 at 19:05 +0300, Paul Kocialkowski wrote:
> This introduces an ALSA library, with dedicated helpers for handling
> playback and capture. It handles ALSA device identification and
> configuration as well as a run loop with callback mechanisms for
> feeding
> output data and handling input data.
>
> This library paves the way for testing audio going through display
> connectors, such as HDMI.
>
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> ---
> configure.ac | 3 +
> .../intel-gpu-tools/intel-gpu-tools-docs.xml | 1 +
> lib/Makefile.am | 7 +
> lib/igt.h | 1 +
> lib/igt_alsa.c | 624
> +++++++++++++++++++++
> lib/igt_alsa.h | 60 ++
> 6 files changed, 696 insertions(+)
> create mode 100644 lib/igt_alsa.c
> create mode 100644 lib/igt_alsa.h
>
> diff --git a/configure.ac b/configure.ac
> index 50aa86b5..e66273a4 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -219,6 +219,9 @@ if test "x$enable_chamelium" = xyes; then
> AC_DEFINE(HAVE_CHAMELIUM, 1, [Enable Chamelium support])
> fi
>
> +PKG_CHECK_MODULES(ALSA, [alsa], [alsa=yes], [alsa=no])
> +AM_CONDITIONAL(HAVE_ALSA, [test "x$alsa" = xyes])
> +
> # ------------------------------------------------------------------
> -----------
> # Configuration options
> # ------------------------------------------------------------------
> -----------
> diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> index c77159cf..0c34e4a5 100644
> --- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> +++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> @@ -16,6 +16,7 @@
> <chapter>
> <title>API Reference</title>
> <xi:include href="xml/drmtest.xml"/>
> + <xi:include href="xml/igt_alsa.xml"/>
> <xi:include href="xml/igt_audio.xml"/>
> <xi:include href="xml/igt_aux.xml"/>
> <xi:include href="xml/igt_chamelium.xml"/>
> diff --git a/lib/Makefile.am b/lib/Makefile.am
> index 5ea08314..3ff14f66 100644
> --- a/lib/Makefile.am
> +++ b/lib/Makefile.am
> @@ -38,6 +38,13 @@ lib_source_list += \
> $(NULL)
> endif
>
> +if HAVE_ALSA
> +lib_source_list += \
> + igt_alsa.c \
> + igt_alsa.h \
> + $(NULL)
> +endif
> +
> AM_CPPFLAGS = -I$(top_srcdir)
> AM_CFLAGS = \
> $(CWARNFLAGS) \
> diff --git a/lib/igt.h b/lib/igt.h
> index a75d2db7..ebf92349 100644
> --- a/lib/igt.h
> +++ b/lib/igt.h
> @@ -35,6 +35,7 @@
> #include "igt_dummyload.h"
> #include "igt_fb.h"
> #include "igt_frame.h"
> +#include "igt_alsa.h"
> #include "igt_audio.h"
> #include "igt_gt.h"
> #include "igt_kms.h"
> diff --git a/lib/igt_alsa.c b/lib/igt_alsa.c
> new file mode 100644
> index 00000000..d8bd0873
> --- /dev/null
> +++ b/lib/igt_alsa.c
> @@ -0,0 +1,624 @@
> +/*
> + * Copyright © 2017 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person
> obtaining a
> + * copy of this software and associated documentation files (the
> "Software"),
> + * to deal in the Software without restriction, including without
> limitation
> + * the rights to use, copy, modify, merge, publish, distribute,
> sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom
> the
> + * Software is furnished to do so, subject to the following
> conditions:
> + *
> + * The above copyright notice and this permission notice (including
> the next
> + * paragraph) shall be included in all copies or substantial
> portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
> OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + * Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> + */
> +
> +#include "config.h"
> +
> +#include <alsa/asoundlib.h>
> +
> +#include "igt.h"
> +
> +#define HANDLES_MAX 8
> +
> +/**
> + * SECTION:igt_alsa
> + * @short_description: Library with ALSA helpers
> + * @title: ALSA
> + * @include: igt_alsa.h
> + *
> + * This library contains helpers for ALSA playback and capture.
> + */
> +
> +struct alsa {
> + snd_pcm_t *output_handles[HANDLES_MAX];
> + int output_handles_count;
> + int output_sampling_rate;
> + int output_channels;
> +
> + int (*output_callback)(void *data, short *buffer, int
> samples);
> + void *output_callback_data;
> + int output_samples_trigger;
> +
> + snd_pcm_t *input_handle;
> + int input_sampling_rate;
> + int input_channels;
> +
> + int (*input_callback)(void *data, short *buffer, int
> samples);
> + void *input_callback_data;
> + int input_samples_trigger;
> +};
> +
> +static void alsa_error_handler(const char *file, int line, const
> char *function,
> + int err, const char *fmt, ...)
> +{
> + if (err)
> + igt_debug("[ALSA] %s: %s\n", function,
> snd_strerror(err));
> +}
Would be a good idea to add an __attribute__((printf)) here
> +
> +/**
> + * alsa_init:
> + * Allocate and initialize an alsa structure and configure the error
> handler.
> + *
> + * Returns: A newly-allocated alsa structure
> + */
> +struct alsa *alsa_init(void)
> +{
> + struct alsa *alsa;
> +
> + alsa = malloc(sizeof(struct alsa));
> + memset(alsa, 0, sizeof(struct alsa));
> +
> + /* Redirect errors to igt_debug instead of stderr. */
> + snd_lib_error_set_handler(alsa_error_handler);
> +
> + return alsa;
> +}
> +
> +static char *alsa_resolve_indentifier(const char *device_name, int
> skip)
> +{
> + snd_ctl_card_info_t *card_info;
> + snd_pcm_info_t *pcm_info;
> + snd_ctl_t *handle = NULL;
> + const char *pcm_name;
> + char *identifier = NULL;
> + char name[32];
> + int card;
> + int dev;
> + int ret;
> +
> + snd_ctl_card_info_alloca(&card_info);
> + snd_pcm_info_alloca(&pcm_info);
> +
> + card = -1;
Just set card = -1 at it's declaration
> +
> + /* First try to open the device as-is. */
> + if (!skip) {
> + ret = snd_ctl_open(&handle, device_name, 0);
> + if (!ret) {
> + identifier = strdup(device_name);
> + goto resolved;
> + }
> + }
> +
> + do {
> + ret = snd_card_next(&card);
> + if (ret < 0 || card < 0)
> + break;
> +
> + snprintf(name, sizeof(name), "hw:%d", card);
> +
> + ret = snd_ctl_open(&handle, name, 0);
> + if (ret < 0)
> + continue;
> +
> + ret = snd_ctl_card_info(handle, card_info);
> + if (ret < 0) {
> + snd_ctl_close(handle);
> + handle = NULL;
> + continue;
> + }
> +
> + dev = -1;
> +
> + do {
> + ret = snd_ctl_pcm_next_device(handle, &dev);
> + if (ret < 0 || dev < 0)
> + break;
> +
> + snd_pcm_info_set_device(pcm_info, dev);
> + snd_pcm_info_set_subdevice(pcm_info, 0);
> +
> + ret = snd_ctl_pcm_info(handle, pcm_info);
> + if (ret < 0)
> + continue;
> +
> + pcm_name = snd_pcm_info_get_name(pcm_info);
> + if (!pcm_name)
> + continue;
> +
> + ret = strncmp(device_name, pcm_name,
> + strlen(device_name));
> +
> + if (ret == 0) {
> + if (skip > 0) {
> + skip--;
> + continue;
> + }
> +
> + snprintf(name, sizeof(name),
> "hw:%d,%d", card,
> + dev);
> +
> + identifier = strdup(name);
> + goto resolved;
> + }
> + } while (dev >= 0);
> +
> + snd_ctl_close(handle);
> + handle = NULL;
> + } while (card >= 0);
> +
> +resolved:
> + if (handle)
> + snd_ctl_close(handle);
> +
> + return identifier;
> +}
> +
> +/**
> + * alsa_open_output:
> + * @alsa: The target alsa structure
> + * @device_name: The name prefix of the output device(s) to open
> + *
> + * Open ALSA output devices whose name prefixes match the provided
> name prefix.
> + *
> + * Returns: An integer equal to zero for success and negative for
> failure
> + */
> +int alsa_open_output(struct alsa *alsa, const char *device_name)
> +{
> + snd_pcm_t *handle;
> + char *identifier;
> + int skip;
> + int index;
> + int ret;
> +
> + skip = alsa->output_handles_count;
> + index = alsa->output_handles_count;
> +
> + while (index < HANDLES_MAX) {
> + identifier = alsa_resolve_indentifier(device_name,
> skip++);
> + if (!identifier)
> + break;
> +
> + ret = snd_pcm_open(&handle, identifier,
> SND_PCM_STREAM_PLAYBACK,
> + SND_PCM_NONBLOCK);
> + if (ret < 0) {
> + free(identifier);
> + continue;
> + }
> +
> + igt_debug("Opened output %s\n", identifier);
> +
> + alsa->output_handles[index++] = handle;
> + free(identifier);
> + }
> +
> + if (index == 0)
> + return -1;
> +
> + alsa->output_handles_count = index;
> +
> + return 0;
> +}
> +
> +/**
> + * alsa_open_input:
> + * @alsa: The target alsa structure
> + * @device_name: The name of the input device to open
> + *
> + * Open the ALSA input device whose name matches the provided name
> prefix.
> + *
> + * Returns: An integer equal to zero for success and negative for
> failure
> + */
> +int alsa_open_input(struct alsa *alsa, const char *device_name)
> +{
> + snd_pcm_t *handle;
> + char *identifier;
> + int ret;
> +
> + identifier = alsa_resolve_indentifier(device_name, 0);
> +
> + ret = snd_pcm_open(&handle, device_name,
> SND_PCM_STREAM_CAPTURE,
> + SND_PCM_NONBLOCK);
> + if (ret < 0)
> + goto complete;
> +
> + igt_debug("Opened input %s\n", identifier);
> +
> + alsa->input_handle = handle;
> +
> + ret = 0;
> +
> +complete:
> + free(identifier);
> +
> + return ret;
> +}
> +
> +/**
> + * alsa_close_output:
> + * @alsa: The target alsa structure
> + *
> + * Close all the open ALSA outputs.
> + */
> +void alsa_close_output(struct alsa *alsa)
> +{
> + snd_pcm_t *handle;
> + int i;
> +
> + for (i = 0; i < alsa->output_handles_count; i++) {
> + handle = alsa->output_handles[i];
> + if (!handle)
> + continue;
> +
> + snd_pcm_close(handle);
> + alsa->output_handles[i] = NULL;
> + }
> +
> + alsa->output_handles_count = 0;
> +}
> +
> +/**
> + * alsa_close_output:
> + * @alsa: The target alsa structure
> + *
> + * Close the open ALSA input.
> + */
> +void alsa_close_input(struct alsa *alsa)
> +{
> + snd_pcm_t *handle = alsa->input_handle;
> + if (!handle)
> + return;
> +
> + snd_pcm_close(handle);
> + alsa->input_handle = NULL;
> +}
> +
> +static bool alsa_test_configuration(snd_pcm_t *handle, int channels,
> + int sampling_rate)
> +{
> + snd_pcm_hw_params_t *params;
> + int ret;
> +
> + snd_pcm_hw_params_alloca(¶ms);
> +
> + ret = snd_pcm_hw_params_any(handle, params);
> + if (ret < 0)
> + return false;
> +
> + ret = snd_pcm_hw_params_test_rate(handle, params,
> sampling_rate, 0);
> + if (ret < 0)
> + return false;
> +
> + ret = snd_pcm_hw_params_test_channels(handle, params,
> channels);
> + if (ret < 0)
> + return false;
> +
> + return true;
> +}
> +
> +/**
> + * alsa_test_output_configuration:
> + * @alsa: The target alsa structure
> + * @channels: The number of channels to test
> + * @sampling_rate: The sampling rate to test
> + *
> + * Test the output configuration specified by @channels and
> @sampling_rate
> + * for the output devices.
> + *
> + * Returns: A boolean indicating whether the test succeeded
> + */
> +bool alsa_test_output_configuration(struct alsa *alsa, int channels,
> + int sampling_rate)
> +{
> + snd_pcm_t *handle;
> + bool ret;
> + int i;
> +
> + for (i = 0; i < alsa->output_handles_count; i++) {
> + handle = alsa->output_handles[i];
> +
> + ret = alsa_test_configuration(handle, channels,
> sampling_rate);
> + if (!ret)
> + return false;
> + }
> +
> + return true;
> +}
> +
> +/**
> + * alsa_test_input_configuration:
> + * @alsa: The target alsa structure
> + * @channels: The number of channels to test
> + * @sampling_rate: The sampling rate to test
> + *
> + * Test the input configuration specified by @channels and
> @sampling_rate
> + * for the input device.
> + *
> + * Returns: A boolean indicating whether the test succeeded
> + */
> +bool alsa_test_input_configuration(struct alsa *alsa, int channels,
> + int sampling_rate)
> +{
> + return alsa_test_configuration(alsa->input_handle, channels,
> + sampling_rate);
> +}
> +
> +/**
> + * alsa_configure_output:
> + * @alsa: The target alsa structure
> + * @channels: The number of channels to test
> + * @sampling_rate: The sampling rate to test
> + *
> + * Configure the output devices with the configuration specified by
> @channels
> + * and @sampling_rate.
> + */
> +void alsa_configure_output(struct alsa *alsa, int channels,
> + int sampling_rate)
> +{
> + snd_pcm_t *handle;
> + int ret;
> + int i;
> +
> + for (i = 0; i < alsa->output_handles_count; i++) {
> + handle = alsa->output_handles[i];
> +
> + ret = snd_pcm_set_params(handle,
> SND_PCM_FORMAT_S16_LE,
> + SND_PCM_ACCESS_RW_INTERLEAV
> ED,
> + channels, sampling_rate, 0,
> 0);
> + igt_assert(ret >= 0);
> + }
> +
> + alsa->output_channels = channels;
> + alsa->output_sampling_rate = sampling_rate;
> +}
> +
> +/**
> + * alsa_configure_input:
> + * @alsa: The target alsa structure
> + * @channels: The number of channels to test
> + * @sampling_rate: The sampling rate to test
> + *
> + * Configure the input device with the configuration specified by
> @channels
> + * and @sampling_rate.
> + */
> +void alsa_configure_input(struct alsa *alsa, int channels,
> + int sampling_rate)
> +{
> + snd_pcm_t *handle;
> + int ret;
> +
> + handle = alsa->input_handle;
> +
> + ret = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE,
> + SND_PCM_ACCESS_RW_INTERLEAVED,
> channels,
> + sampling_rate, 0, 0);
> + igt_assert(ret >= 0);
> +
> + alsa->input_channels = channels;
> + alsa->input_sampling_rate = sampling_rate;
> +
> +}
> +
> +/**
> + * alsa_register_output_callback:
> + * @alsa: The target alsa structure
> + * @callback: The callback function to call to fill output data
> + * @callback_data: The data pointer to pass to the callback function
> + * @samples_trigger: The required number of samples to trigger the
> callback
> + *
> + * Register a callback function to be called to fill output data
> during a run.
> + * The callback is called when @samples_trigger samples are
> required.
> + *
> + * The callback should return an integer equal to zero for success
> and negative
> + * for failure.
> + */
> +void alsa_register_output_callback(struct alsa *alsa,
> + int (*callback)(void *data, short
> *buffer, int samples),
> + void *callback_data, int
> samples_trigger)
> +{
> + alsa->output_callback = callback;
> + alsa->output_callback_data = callback_data;
> + alsa->output_samples_trigger = samples_trigger;
> +}
> +
> +/**
> + * alsa_register_input_callback:
> + * @alsa: The target alsa structure
> + * @callback: The callback function to call when input data is
> available
> + * @callback_data: The data pointer to pass to the callback function
> + * @samples_trigger: The required number of samples to trigger the
> callback
> + *
> + * Register a callback function to be called when input data is
> available during
> + * a run. The callback is called when @samples_trigger samples are
> available.
> + *
> + * The callback should return an integer equal to zero for success,
> negative for
> + * failure and positive to indicate that the run should stop.
> + */
> +void alsa_register_input_callback(struct alsa *alsa,
> + int (*callback)(void *data, short
> *buffer, int samples),
> + void *callback_data, int
> samples_trigger)
> +{
> + alsa->input_callback = callback;
> + alsa->input_callback_data = callback_data;
> + alsa->input_samples_trigger = samples_trigger;
> +}
> +
> +/**
> + * alsa_run:
> + * @alsa: The target alsa structure
> + * @duration_ms: The maximum duration of the run in milliseconds
> + *
> + * Run ALSA playback and capture on the input and output devices for
> at
> + * most @duration_ms milliseconds, calling the registered callbacks
> when needed.
> + *
> + * Returns: An integer equal to zero for success, positive for a
> stop caused
> + * by the input callback and negative for failure
> + */
> +int alsa_run(struct alsa *alsa, int duration_ms)
> +{
> + snd_pcm_t *handle;
> + short *output_buffer = NULL;
> + short *input_buffer = NULL;
> + int output_limit;
> + int output_total = 0;
> + int output_counts[alsa->output_handles_count];
> + bool output_ready = false;
> + int output_channels;
> + int output_trigger;
> + int input_limit;
> + int input_total = 0;
> + int input_count = 0;
> + int input_channels;
> + int input_trigger;
> + bool reached;
> + int index;
> + int count;
> + int avail;
> + int i;
> + int ret;
> +
> + output_limit = alsa->output_sampling_rate * duration_ms /
> 1000;
> + output_channels = alsa->output_channels;
> + output_trigger = alsa->output_samples_trigger;
> + output_buffer = malloc(sizeof(short) * output_channels *
> + output_trigger);
> +
> + if (alsa->input_callback) {
> + input_limit = alsa->input_sampling_rate *
> duration_ms / 1000;
> + input_trigger = alsa->input_samples_trigger;
> + input_channels = alsa->input_channels;
> + input_buffer = malloc(sizeof(short) * input_channels
> *
> + input_trigger);
> + }
> +
> + do {
> + reached = true;
> +
> + if (output_total < output_limit) {
> + reached = false;
> +
> + if (!output_ready) {
> + output_ready = true;
> +
> + for (i = 0; i < alsa-
> >output_handles_count; i++)
> + output_counts[i] = 0;
> +
> + ret = alsa->output_callback(alsa-
> >output_callback_data,
> + output_b
> uffer,
> + output_t
> rigger);
> + if (ret < 0)
> + goto complete;
> + }
> +
> + for (i = 0; i < alsa->output_handles_count;
> i++) {
> + handle = alsa->output_handles[i];
> +
> + if (output_counts[i] <
> output_trigger &&
> + snd_pcm_avail(handle) > 0) {
> + index = output_counts[i] *
> + output_channels;
> + count = output_trigger -
> + output_counts[i];
> + avail =
> snd_pcm_avail(handle);
> +
> + count = avail < count ?
> avail : count;
> +
> + ret = snd_pcm_writei(handle,
> + &output
> _buffer[index],
> + count);
> + if (ret < 0) {
> + ret =
> snd_pcm_recover(handle,
> +
> count, 0);
> + if (ret < 0)
> + goto
> complete;
> + }
> +
> + output_counts[i] += ret;
> + }
> + }
> +
> + output_ready = false;
> +
> + for (i = 0; i < alsa->output_handles_count;
> i++)
> + if (output_counts[i] <
> output_trigger)
> + output_ready = true;
> +
> + if (!output_ready)
> + output_total += output_trigger;
> +
> + }
> +
> + if (alsa->input_callback && input_total <
> input_limit) {
> + reached = false;
> +
> + if (input_count == input_trigger) {
> + input_count = 0;
> +
> + ret = alsa->input_callback(alsa-
> >input_callback_data,
> + input_buf
> fer,
> + input_tri
> gger);
> + if (ret != 0)
> + goto complete;
> + }
> +
> + handle = alsa->input_handle;
> +
> + if (input_count < input_trigger &&
> + (snd_pcm_avail(handle) > 0 ||
> input_total == 0)) {
> + index = input_count *
> input_channels;
> + count = input_trigger - input_count;
> + avail = snd_pcm_avail(handle);
> +
> + count = avail > 0 && avail < count ?
> avail :
> + count;
> +
> + ret = snd_pcm_readi(handle,
> + &input_buffer[in
> dex],
> + count);
> + if (ret == -EAGAIN) {
> + ret = 0;
> + } else if (ret < 0) {
> + ret =
> snd_pcm_recover(handle, count, 0);
> + if (ret < 0)
> + goto complete;
> + }
> +
> + input_count += ret;
> + input_total += ret;
> + }
> + }
> + } while (!reached);
> +
> + ret = 0;
> +
> +complete:
> + if (output_buffer)
> + free(output_buffer);
> +
> + if (input_buffer)
> + free(input_buffer);
> +
> + return ret;
> +}
> diff --git a/lib/igt_alsa.h b/lib/igt_alsa.h
> new file mode 100644
> index 00000000..9911ddde
> --- /dev/null
> +++ b/lib/igt_alsa.h
> @@ -0,0 +1,60 @@
> +/*
> + * Copyright © 2017 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person
> obtaining a
> + * copy of this software and associated documentation files (the
> "Software"),
> + * to deal in the Software without restriction, including without
> limitation
> + * the rights to use, copy, modify, merge, publish, distribute,
> sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom
> the
> + * Software is furnished to do so, subject to the following
> conditions:
> + *
> + * The above copyright notice and this permission notice (including
> the next
> + * paragraph) shall be included in all copies or substantial
> portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
> OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + * Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> + */
> +
> +#ifndef IGT_ALSA_H
> +#define IGT_ALSA_H
> +
> +#ifdef HAVE_CONFIG_H
> +#include "config.h"
> +#endif
> +
> +#include "igt.h"
> +#include <stdbool.h>
> +
> +struct alsa;
> +
> +struct alsa *alsa_init(void);
> +int alsa_open_output(struct alsa *alsa, const char *device_name);
> +int alsa_open_input(struct alsa *alsa, const char *device_name);
> +void alsa_close_output(struct alsa *alsa);
> +void alsa_close_input(struct alsa *alsa);
> +bool alsa_test_output_configuration(struct alsa *alsa, int channels,
> + int sampling_rate);
> +bool alsa_test_input_configuration(struct alsa *alsa, int channels,
> + int sampling_rate);
> +void alsa_configure_output(struct alsa *alsa, int channels,
> + int sampling_rate);
> +void alsa_configure_input(struct alsa *alsa, int channels,
> + int sampling_rate);
> +void alsa_register_output_callback(struct alsa *alsa,
> + int (*callback)(void *data, short
> *buffer, int samples),
> + void *callback_data, int
> samples_trigger);
> +void alsa_register_input_callback(struct alsa *alsa,
> + int (*callback)(void *data, short
> *buffer, int samples),
> + void *callback_data, int
> samples_trigger);
> +int alsa_run(struct alsa *alsa, int duration_ms);
> +
> +#endif
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH i-g-t 2/3] lib: Add ALSA library with dedicated helpers
2017-08-18 9:46 ` Arkadiusz Hiler
@ 2017-08-21 7:25 ` Arkadiusz Hiler
2017-08-21 9:39 ` Paul Kocialkowski
0 siblings, 1 reply; 16+ messages in thread
From: Arkadiusz Hiler @ 2017-08-21 7:25 UTC (permalink / raw)
To: Paul Kocialkowski; +Cc: intel-gfx
On Fri, Aug 18, 2017 at 12:46:38PM +0300, Arkadiusz Hiler wrote:
> On Thu, Aug 17, 2017 at 07:05:56PM +0300, Paul Kocialkowski wrote:
> > This introduces an ALSA library, with dedicated helpers for handling
> > playback and capture. It handles ALSA device identification and
> > configuration as well as a run loop with callback mechanisms for feeding
> > output data and handling input data.
> >
> > This library paves the way for testing audio going through display
> > connectors, such as HDMI.
> >
> > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > ---
> > configure.ac | 3 +
> > .../intel-gpu-tools/intel-gpu-tools-docs.xml | 1 +
> > lib/Makefile.am | 7 +
> > lib/igt.h | 1 +
> > lib/igt_alsa.c | 624 +++++++++++++++++++++
> > lib/igt_alsa.h | 60 ++
> > 6 files changed, 696 insertions(+)
> > create mode 100644 lib/igt_alsa.c
> > create mode 100644 lib/igt_alsa.h
> >
> > diff --git a/configure.ac b/configure.ac
> > index 50aa86b5..e66273a4 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -219,6 +219,9 @@ if test "x$enable_chamelium" = xyes; then
> > AC_DEFINE(HAVE_CHAMELIUM, 1, [Enable Chamelium support])
> > fi
> >
> > +PKG_CHECK_MODULES(ALSA, [alsa], [alsa=yes], [alsa=no])
> > +AM_CONDITIONAL(HAVE_ALSA, [test "x$alsa" = xyes])
>
> please mention the new dependency in the README
One more thing that came to my mind - how do we want to have this new
dependency handled configure-time?
I see three options:
1. Having it as optional component, so after we --enable-chamelium we can
end up with the alsa part either being there or not.
2. Having to explicitly enable it, so that only with --enable-alsa we
will have this new, shiny feature (and a nice ./configure-time fail).
3. Having to explicitly disable it, i.e. --enable-chamelium enables ALSA
check, if it's not there configure fails and we can explicitly disable
it, resulting in --enable-chamelium --disable-alsa switch combo.
As a rule of thumb, anything similar to option #1 should be avoided to
not suprise people with missing features depending on machine they
compile on - unless we collectively decide that having optional
component is okay (e.g. in case we have a fallback so it doesn't matter
that much).
IMO in this case we should go with option #2.
--
Cheers,
Arek
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH i-g-t 2/3] lib: Add ALSA library with dedicated helpers
2017-08-21 7:25 ` Arkadiusz Hiler
@ 2017-08-21 9:39 ` Paul Kocialkowski
2017-08-21 9:45 ` Arkadiusz Hiler
0 siblings, 1 reply; 16+ messages in thread
From: Paul Kocialkowski @ 2017-08-21 9:39 UTC (permalink / raw)
To: Arkadiusz Hiler; +Cc: intel-gfx
On Mon, 2017-08-21 at 10:25 +0300, Arkadiusz Hiler wrote:
> On Fri, Aug 18, 2017 at 12:46:38PM +0300, Arkadiusz Hiler wrote:
> > On Thu, Aug 17, 2017 at 07:05:56PM +0300, Paul Kocialkowski wrote:
> > > This introduces an ALSA library, with dedicated helpers for
> > > handling
> > > playback and capture. It handles ALSA device identification and
> > > configuration as well as a run loop with callback mechanisms for
> > > feeding
> > > output data and handling input data.
> > >
> > > This library paves the way for testing audio going through display
> > > connectors, such as HDMI.
> > >
> > > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.co
> > > m>
> > > ---
> > > configure.ac | 3 +
> > > .../intel-gpu-tools/intel-gpu-tools-docs.xml | 1 +
> > > lib/Makefile.am | 7 +
> > > lib/igt.h | 1 +
> > > lib/igt_alsa.c | 624
> > > +++++++++++++++++++++
> > > lib/igt_alsa.h | 60 ++
> > > 6 files changed, 696 insertions(+)
> > > create mode 100644 lib/igt_alsa.c
> > > create mode 100644 lib/igt_alsa.h
> > >
> > > diff --git a/configure.ac b/configure.ac
> > > index 50aa86b5..e66273a4 100644
> > > --- a/configure.ac
> > > +++ b/configure.ac
> > > @@ -219,6 +219,9 @@ if test "x$enable_chamelium" = xyes; then
> > > AC_DEFINE(HAVE_CHAMELIUM, 1, [Enable Chamelium support])
> > > fi
> > >
> > > +PKG_CHECK_MODULES(ALSA, [alsa], [alsa=yes], [alsa=no])
> > > +AM_CONDITIONAL(HAVE_ALSA, [test "x$alsa" = xyes])
> >
> > please mention the new dependency in the README
>
> One more thing that came to my mind - how do we want to have this new
> dependency handled configure-time?
>
> I see three options:
>
> 1. Having it as optional component, so after we --enable-chamelium we
> can
> end up with the alsa part either being there or not.
>
> 2. Having to explicitly enable it, so that only with --enable-alsa we
> will have this new, shiny feature (and a nice ./configure-time fail).
>
> 3. Having to explicitly disable it, i.e. --enable-chamelium enables
> ALSA
> check, if it's not there configure fails and we can explicitly disable
> it, resulting in --enable-chamelium --disable-alsa switch combo.
>
> As a rule of thumb, anything similar to option #1 should be avoided to
> not suprise people with missing features depending on machine they
> compile on - unless we collectively decide that having optional
> component is okay (e.g. in case we have a fallback so it doesn't
> matter
> that much).
>
> IMO in this case we should go with option #2.
Note that this series is not tied to the chamelium at all: it requires
an HDMI-VGA adapter with audio out instead of a chamelium.
For this reason, it wouldn't make sense to tie it to --enable-chamelium.
The problem remains the same though: the audio part (patch 1/3) requires
the GSL library and the alsa part requires the alsa lib and we need to
decide how to handle the dependencies.
I think what would make the most sense is to have an --enable-audio
parameter (referring to the newly-introduced audio test, not the audio
library) that requires the alsa and gsl libraries. Then, when audio
support is added to the chamelium code, the alsa library should become a
dependency for --enable-chamelium as well.
For the latter, it would be consistent with the idea that --enable-
chamelium pulls-in all possible chamelium tests and thus requires all
their dependencies, instead of only enabling the tests for which
dependencies are installed.
Does that seem agreeable?
--
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH i-g-t 2/3] lib: Add ALSA library with dedicated helpers
2017-08-21 9:39 ` Paul Kocialkowski
@ 2017-08-21 9:45 ` Arkadiusz Hiler
0 siblings, 0 replies; 16+ messages in thread
From: Arkadiusz Hiler @ 2017-08-21 9:45 UTC (permalink / raw)
To: Paul Kocialkowski; +Cc: intel-gfx
On Mon, Aug 21, 2017 at 12:39:58PM +0300, Paul Kocialkowski wrote:
> On Mon, 2017-08-21 at 10:25 +0300, Arkadiusz Hiler wrote:
> > On Fri, Aug 18, 2017 at 12:46:38PM +0300, Arkadiusz Hiler wrote:
> > > On Thu, Aug 17, 2017 at 07:05:56PM +0300, Paul Kocialkowski wrote:
> > > > This introduces an ALSA library, with dedicated helpers for
> > > > handling
> > > > playback and capture. It handles ALSA device identification and
> > > > configuration as well as a run loop with callback mechanisms for
> > > > feeding
> > > > output data and handling input data.
> > > >
> > > > This library paves the way for testing audio going through display
> > > > connectors, such as HDMI.
> > > >
> > > > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.co
> > > > m>
> > > > ---
> > > > configure.ac | 3 +
> > > > .../intel-gpu-tools/intel-gpu-tools-docs.xml | 1 +
> > > > lib/Makefile.am | 7 +
> > > > lib/igt.h | 1 +
> > > > lib/igt_alsa.c | 624
> > > > +++++++++++++++++++++
> > > > lib/igt_alsa.h | 60 ++
> > > > 6 files changed, 696 insertions(+)
> > > > create mode 100644 lib/igt_alsa.c
> > > > create mode 100644 lib/igt_alsa.h
> > > >
> > > > diff --git a/configure.ac b/configure.ac
> > > > index 50aa86b5..e66273a4 100644
> > > > --- a/configure.ac
> > > > +++ b/configure.ac
> > > > @@ -219,6 +219,9 @@ if test "x$enable_chamelium" = xyes; then
> > > > AC_DEFINE(HAVE_CHAMELIUM, 1, [Enable Chamelium support])
> > > > fi
> > > >
> > > > +PKG_CHECK_MODULES(ALSA, [alsa], [alsa=yes], [alsa=no])
> > > > +AM_CONDITIONAL(HAVE_ALSA, [test "x$alsa" = xyes])
> > >
> > > please mention the new dependency in the README
> >
> > One more thing that came to my mind - how do we want to have this new
> > dependency handled configure-time?
> >
> > I see three options:
> >
> > 1. Having it as optional component, so after we --enable-chamelium we
> > can
> > end up with the alsa part either being there or not.
> >
> > 2. Having to explicitly enable it, so that only with --enable-alsa we
> > will have this new, shiny feature (and a nice ./configure-time fail).
> >
> > 3. Having to explicitly disable it, i.e. --enable-chamelium enables
> > ALSA
> > check, if it's not there configure fails and we can explicitly disable
> > it, resulting in --enable-chamelium --disable-alsa switch combo.
> >
> > As a rule of thumb, anything similar to option #1 should be avoided to
> > not suprise people with missing features depending on machine they
> > compile on - unless we collectively decide that having optional
> > component is okay (e.g. in case we have a fallback so it doesn't
> > matter
> > that much).
> >
> > IMO in this case we should go with option #2.
>
> Note that this series is not tied to the chamelium at all: it requires
> an HDMI-VGA adapter with audio out instead of a chamelium.
>
> For this reason, it wouldn't make sense to tie it to --enable-chamelium.
Ow, right. I've missed that. Thanks for clarification!
> The problem remains the same though: the audio part (patch 1/3) requires
> the GSL library and the alsa part requires the alsa lib and we need to
> decide how to handle the dependencies.
>
> I think what would make the most sense is to have an --enable-audio
> parameter (referring to the newly-introduced audio test, not the audio
> library) that requires the alsa and gsl libraries. Then, when audio
> support is added to the chamelium code, the alsa library should become a
> dependency for --enable-chamelium as well.
>
> For the latter, it would be consistent with the idea that --enable-
> chamelium pulls-in all possible chamelium tests and thus requires all
> their dependencies, instead of only enabling the tests for which
> dependencies are installed.
>
> Does that seem agreeable?
LGTM, carry on! :-)
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH i-g-t 2/3] lib: Add ALSA library with dedicated helpers
2017-08-18 16:20 ` Lyude Paul
@ 2017-08-21 15:11 ` Paul Kocialkowski
0 siblings, 0 replies; 16+ messages in thread
From: Paul Kocialkowski @ 2017-08-21 15:11 UTC (permalink / raw)
To: Lyude Paul, intel-gfx
Hi,
On Fri, 2017-08-18 at 12:20 -0400, Lyude Paul wrote:
> And two more small changes
>
> On Thu, 2017-08-17 at 19:05 +0300, Paul Kocialkowski wrote:
> > This introduces an ALSA library, with dedicated helpers for handling
> > playback and capture. It handles ALSA device identification and
> > configuration as well as a run loop with callback mechanisms for
> > feeding
> > output data and handling input data.
> >
> > This library paves the way for testing audio going through display
> > connectors, such as HDMI.
> >
> > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > ---
> > configure.ac | 3 +
> > .../intel-gpu-tools/intel-gpu-tools-docs.xml | 1 +
> > lib/Makefile.am | 7 +
> > lib/igt.h | 1 +
> > lib/igt_alsa.c | 624
> > +++++++++++++++++++++
> > lib/igt_alsa.h | 60 ++
> > 6 files changed, 696 insertions(+)
> > create mode 100644 lib/igt_alsa.c
> > create mode 100644 lib/igt_alsa.h
> >
> > diff --git a/configure.ac b/configure.ac
> > index 50aa86b5..e66273a4 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -219,6 +219,9 @@ if test "x$enable_chamelium" = xyes; then
> > AC_DEFINE(HAVE_CHAMELIUM, 1, [Enable Chamelium support])
> > fi
> >
> > +PKG_CHECK_MODULES(ALSA, [alsa], [alsa=yes], [alsa=no])
> > +AM_CONDITIONAL(HAVE_ALSA, [test "x$alsa" = xyes])
> > +
> > # ---------------------------------------------------------------
> > ---
> > -----------
> > # Configuration options
> > # ---------------------------------------------------------------
> > ---
> > -----------
> > diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> > b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> > index c77159cf..0c34e4a5 100644
> > --- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> > +++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> > @@ -16,6 +16,7 @@
> > <chapter>
> > <title>API Reference</title>
> > <xi:include href="xml/drmtest.xml"/>
> > + <xi:include href="xml/igt_alsa.xml"/>
> > <xi:include href="xml/igt_audio.xml"/>
> > <xi:include href="xml/igt_aux.xml"/>
> > <xi:include href="xml/igt_chamelium.xml"/>
> > diff --git a/lib/Makefile.am b/lib/Makefile.am
> > index 5ea08314..3ff14f66 100644
> > --- a/lib/Makefile.am
> > +++ b/lib/Makefile.am
> > @@ -38,6 +38,13 @@ lib_source_list += \
> > $(NULL)
> > endif
> >
> > +if HAVE_ALSA
> > +lib_source_list += \
> > + igt_alsa.c \
> > + igt_alsa.h \
> > + $(NULL)
> > +endif
> > +
> > AM_CPPFLAGS = -I$(top_srcdir)
> > AM_CFLAGS = \
> > $(CWARNFLAGS) \
> > diff --git a/lib/igt.h b/lib/igt.h
> > index a75d2db7..ebf92349 100644
> > --- a/lib/igt.h
> > +++ b/lib/igt.h
> > @@ -35,6 +35,7 @@
> > #include "igt_dummyload.h"
> > #include "igt_fb.h"
> > #include "igt_frame.h"
> > +#include "igt_alsa.h"
> > #include "igt_audio.h"
> > #include "igt_gt.h"
> > #include "igt_kms.h"
> > diff --git a/lib/igt_alsa.c b/lib/igt_alsa.c
> > new file mode 100644
> > index 00000000..d8bd0873
> > --- /dev/null
> > +++ b/lib/igt_alsa.c
> > @@ -0,0 +1,624 @@
> > +/*
> > + * Copyright © 2017 Intel Corporation
> > + *
> > + * Permission is hereby granted, free of charge, to any person
> > obtaining a
> > + * copy of this software and associated documentation files (the
> > "Software"),
> > + * to deal in the Software without restriction, including without
> > limitation
> > + * the rights to use, copy, modify, merge, publish, distribute,
> > sublicense,
> > + * and/or sell copies of the Software, and to permit persons to
> > whom
> > the
> > + * Software is furnished to do so, subject to the following
> > conditions:
> > + *
> > + * The above copyright notice and this permission notice (including
> > the next
> > + * paragraph) shall be included in all copies or substantial
> > portions of the
> > + * Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > EXPRESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> > EVENT SHALL
> > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
> > DAMAGES
> > OR OTHER
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> > ARISING
> > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> > OTHER DEALINGS
> > + * IN THE SOFTWARE.
> > + *
> > + * Authors:
> > + * Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > + */
> > +
> > +#include "config.h"
> > +
> > +#include <alsa/asoundlib.h>
> > +
> > +#include "igt.h"
> > +
> > +#define HANDLES_MAX 8
> > +
> > +/**
> > + * SECTION:igt_alsa
> > + * @short_description: Library with ALSA helpers
> > + * @title: ALSA
> > + * @include: igt_alsa.h
> > + *
> > + * This library contains helpers for ALSA playback and capture.
> > + */
> > +
> > +struct alsa {
> > + snd_pcm_t *output_handles[HANDLES_MAX];
> > + int output_handles_count;
> > + int output_sampling_rate;
> > + int output_channels;
> > +
> > + int (*output_callback)(void *data, short *buffer, int
> > samples);
> > + void *output_callback_data;
> > + int output_samples_trigger;
> > +
> > + snd_pcm_t *input_handle;
> > + int input_sampling_rate;
> > + int input_channels;
> > +
> > + int (*input_callback)(void *data, short *buffer, int
> > samples);
> > + void *input_callback_data;
> > + int input_samples_trigger;
> > +};
> > +
> > +static void alsa_error_handler(const char *file, int line, const
> > char *function,
> > + int err, const char *fmt, ...)
> > +{
> > + if (err)
> > + igt_debug("[ALSA] %s: %s\n", function,
> > snd_strerror(err));
> > +}
>
> Would be a good idea to add an __attribute__((printf)) here
Well, that function is registered as a callback for the ALSA library, so
there won't ever be code outside of the ALSA library that makes calls to
it. Thus, no call to the function will be built, which renders the
attribute useless.
> > +
> > +/**
> > + * alsa_init:
> > + * Allocate and initialize an alsa structure and configure the
> > error
> > handler.
> > + *
> > + * Returns: A newly-allocated alsa structure
> > + */
> > +struct alsa *alsa_init(void)
> > +{
> > + struct alsa *alsa;
> > +
> > + alsa = malloc(sizeof(struct alsa));
> > + memset(alsa, 0, sizeof(struct alsa));
> > +
> > + /* Redirect errors to igt_debug instead of stderr. */
> > + snd_lib_error_set_handler(alsa_error_handler);
> > +
> > + return alsa;
> > +}
> > +
> > +static char *alsa_resolve_indentifier(const char *device_name, int
> > skip)
> > +{
> > + snd_ctl_card_info_t *card_info;
> > + snd_pcm_info_t *pcm_info;
> > + snd_ctl_t *handle = NULL;
> > + const char *pcm_name;
> > + char *identifier = NULL;
> > + char name[32];
> > + int card;
> > + int dev;
> > + int ret;
> > +
> > + snd_ctl_card_info_alloca(&card_info);
> > + snd_pcm_info_alloca(&pcm_info);
> > +
> > + card = -1;
>
> Just set card = -1 at it's declaration
Sure thing!
> > +
> > + /* First try to open the device as-is. */
> > + if (!skip) {
> > + ret = snd_ctl_open(&handle, device_name, 0);
> > + if (!ret) {
> > + identifier = strdup(device_name);
> > + goto resolved;
> > + }
> > + }
> > +
> > + do {
> > + ret = snd_card_next(&card);
> > + if (ret < 0 || card < 0)
> > + break;
> > +
> > + snprintf(name, sizeof(name), "hw:%d", card);
> > +
> > + ret = snd_ctl_open(&handle, name, 0);
> > + if (ret < 0)
> > + continue;
> > +
> > + ret = snd_ctl_card_info(handle, card_info);
> > + if (ret < 0) {
> > + snd_ctl_close(handle);
> > + handle = NULL;
> > + continue;
> > + }
> > +
> > + dev = -1;
> > +
> > + do {
> > + ret = snd_ctl_pcm_next_device(handle,
> > &dev);
> > + if (ret < 0 || dev < 0)
> > + break;
> > +
> > + snd_pcm_info_set_device(pcm_info, dev);
> > + snd_pcm_info_set_subdevice(pcm_info, 0);
> > +
> > + ret = snd_ctl_pcm_info(handle, pcm_info);
> > + if (ret < 0)
> > + continue;
> > +
> > + pcm_name = snd_pcm_info_get_name(pcm_info);
> > + if (!pcm_name)
> > + continue;
> > +
> > + ret = strncmp(device_name, pcm_name,
> > + strlen(device_name));
> > +
> > + if (ret == 0) {
> > + if (skip > 0) {
> > + skip--;
> > + continue;
> > + }
> > +
> > + snprintf(name, sizeof(name),
> > "hw:%d,%d", card,
> > + dev);
> > +
> > + identifier = strdup(name);
> > + goto resolved;
> > + }
> > + } while (dev >= 0);
> > +
> > + snd_ctl_close(handle);
> > + handle = NULL;
> > + } while (card >= 0);
> > +
> > +resolved:
> > + if (handle)
> > + snd_ctl_close(handle);
> > +
> > + return identifier;
> > +}
> > +
> > +/**
> > + * alsa_open_output:
> > + * @alsa: The target alsa structure
> > + * @device_name: The name prefix of the output device(s) to open
> > + *
> > + * Open ALSA output devices whose name prefixes match the provided
> > name prefix.
> > + *
> > + * Returns: An integer equal to zero for success and negative for
> > failure
> > + */
> > +int alsa_open_output(struct alsa *alsa, const char *device_name)
> > +{
> > + snd_pcm_t *handle;
> > + char *identifier;
> > + int skip;
> > + int index;
> > + int ret;
> > +
> > + skip = alsa->output_handles_count;
> > + index = alsa->output_handles_count;
> > +
> > + while (index < HANDLES_MAX) {
> > + identifier = alsa_resolve_indentifier(device_name,
> > skip++);
> > + if (!identifier)
> > + break;
> > +
> > + ret = snd_pcm_open(&handle, identifier,
> > SND_PCM_STREAM_PLAYBACK,
> > + SND_PCM_NONBLOCK);
> > + if (ret < 0) {
> > + free(identifier);
> > + continue;
> > + }
> > +
> > + igt_debug("Opened output %s\n", identifier);
> > +
> > + alsa->output_handles[index++] = handle;
> > + free(identifier);
> > + }
> > +
> > + if (index == 0)
> > + return -1;
> > +
> > + alsa->output_handles_count = index;
> > +
> > + return 0;
> > +}
> > +
> > +/**
> > + * alsa_open_input:
> > + * @alsa: The target alsa structure
> > + * @device_name: The name of the input device to open
> > + *
> > + * Open the ALSA input device whose name matches the provided name
> > prefix.
> > + *
> > + * Returns: An integer equal to zero for success and negative for
> > failure
> > + */
> > +int alsa_open_input(struct alsa *alsa, const char *device_name)
> > +{
> > + snd_pcm_t *handle;
> > + char *identifier;
> > + int ret;
> > +
> > + identifier = alsa_resolve_indentifier(device_name, 0);
> > +
> > + ret = snd_pcm_open(&handle, device_name,
> > SND_PCM_STREAM_CAPTURE,
> > + SND_PCM_NONBLOCK);
> > + if (ret < 0)
> > + goto complete;
> > +
> > + igt_debug("Opened input %s\n", identifier);
> > +
> > + alsa->input_handle = handle;
> > +
> > + ret = 0;
> > +
> > +complete:
> > + free(identifier);
> > +
> > + return ret;
> > +}
> > +
> > +/**
> > + * alsa_close_output:
> > + * @alsa: The target alsa structure
> > + *
> > + * Close all the open ALSA outputs.
> > + */
> > +void alsa_close_output(struct alsa *alsa)
> > +{
> > + snd_pcm_t *handle;
> > + int i;
> > +
> > + for (i = 0; i < alsa->output_handles_count; i++) {
> > + handle = alsa->output_handles[i];
> > + if (!handle)
> > + continue;
> > +
> > + snd_pcm_close(handle);
> > + alsa->output_handles[i] = NULL;
> > + }
> > +
> > + alsa->output_handles_count = 0;
> > +}
> > +
> > +/**
> > + * alsa_close_output:
> > + * @alsa: The target alsa structure
> > + *
> > + * Close the open ALSA input.
> > + */
> > +void alsa_close_input(struct alsa *alsa)
> > +{
> > + snd_pcm_t *handle = alsa->input_handle;
> > + if (!handle)
> > + return;
> > +
> > + snd_pcm_close(handle);
> > + alsa->input_handle = NULL;
> > +}
> > +
> > +static bool alsa_test_configuration(snd_pcm_t *handle, int
> > channels,
> > + int sampling_rate)
> > +{
> > + snd_pcm_hw_params_t *params;
> > + int ret;
> > +
> > + snd_pcm_hw_params_alloca(¶ms);
> > +
> > + ret = snd_pcm_hw_params_any(handle, params);
> > + if (ret < 0)
> > + return false;
> > +
> > + ret = snd_pcm_hw_params_test_rate(handle, params,
> > sampling_rate, 0);
> > + if (ret < 0)
> > + return false;
> > +
> > + ret = snd_pcm_hw_params_test_channels(handle, params,
> > channels);
> > + if (ret < 0)
> > + return false;
> > +
> > + return true;
> > +}
> > +
> > +/**
> > + * alsa_test_output_configuration:
> > + * @alsa: The target alsa structure
> > + * @channels: The number of channels to test
> > + * @sampling_rate: The sampling rate to test
> > + *
> > + * Test the output configuration specified by @channels and
> > @sampling_rate
> > + * for the output devices.
> > + *
> > + * Returns: A boolean indicating whether the test succeeded
> > + */
> > +bool alsa_test_output_configuration(struct alsa *alsa, int
> > channels,
> > + int sampling_rate)
> > +{
> > + snd_pcm_t *handle;
> > + bool ret;
> > + int i;
> > +
> > + for (i = 0; i < alsa->output_handles_count; i++) {
> > + handle = alsa->output_handles[i];
> > +
> > + ret = alsa_test_configuration(handle, channels,
> > sampling_rate);
> > + if (!ret)
> > + return false;
> > + }
> > +
> > + return true;
> > +}
> > +
> > +/**
> > + * alsa_test_input_configuration:
> > + * @alsa: The target alsa structure
> > + * @channels: The number of channels to test
> > + * @sampling_rate: The sampling rate to test
> > + *
> > + * Test the input configuration specified by @channels and
> > @sampling_rate
> > + * for the input device.
> > + *
> > + * Returns: A boolean indicating whether the test succeeded
> > + */
> > +bool alsa_test_input_configuration(struct alsa *alsa, int channels,
> > + int sampling_rate)
> > +{
> > + return alsa_test_configuration(alsa->input_handle,
> > channels,
> > + sampling_rate);
> > +}
> > +
> > +/**
> > + * alsa_configure_output:
> > + * @alsa: The target alsa structure
> > + * @channels: The number of channels to test
> > + * @sampling_rate: The sampling rate to test
> > + *
> > + * Configure the output devices with the configuration specified by
> > @channels
> > + * and @sampling_rate.
> > + */
> > +void alsa_configure_output(struct alsa *alsa, int channels,
> > + int sampling_rate)
> > +{
> > + snd_pcm_t *handle;
> > + int ret;
> > + int i;
> > +
> > + for (i = 0; i < alsa->output_handles_count; i++) {
> > + handle = alsa->output_handles[i];
> > +
> > + ret = snd_pcm_set_params(handle,
> > SND_PCM_FORMAT_S16_LE,
> > + SND_PCM_ACCESS_RW_INTERLEA
> > V
> > ED,
> > + channels, sampling_rate,
> > 0,
> > 0);
> > + igt_assert(ret >= 0);
> > + }
> > +
> > + alsa->output_channels = channels;
> > + alsa->output_sampling_rate = sampling_rate;
> > +}
> > +
> > +/**
> > + * alsa_configure_input:
> > + * @alsa: The target alsa structure
> > + * @channels: The number of channels to test
> > + * @sampling_rate: The sampling rate to test
> > + *
> > + * Configure the input device with the configuration specified by
> > @channels
> > + * and @sampling_rate.
> > + */
> > +void alsa_configure_input(struct alsa *alsa, int channels,
> > + int sampling_rate)
> > +{
> > + snd_pcm_t *handle;
> > + int ret;
> > +
> > + handle = alsa->input_handle;
> > +
> > + ret = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE,
> > + SND_PCM_ACCESS_RW_INTERLEAVED,
> > channels,
> > + sampling_rate, 0, 0);
> > + igt_assert(ret >= 0);
> > +
> > + alsa->input_channels = channels;
> > + alsa->input_sampling_rate = sampling_rate;
> > +
> > +}
> > +
> > +/**
> > + * alsa_register_output_callback:
> > + * @alsa: The target alsa structure
> > + * @callback: The callback function to call to fill output data
> > + * @callback_data: The data pointer to pass to the callback
> > function
> > + * @samples_trigger: The required number of samples to trigger the
> > callback
> > + *
> > + * Register a callback function to be called to fill output data
> > during a run.
> > + * The callback is called when @samples_trigger samples are
> > required.
> > + *
> > + * The callback should return an integer equal to zero for success
> > and negative
> > + * for failure.
> > + */
> > +void alsa_register_output_callback(struct alsa *alsa,
> > + int (*callback)(void *data,
> > short
> > *buffer, int samples),
> > + void *callback_data, int
> > samples_trigger)
> > +{
> > + alsa->output_callback = callback;
> > + alsa->output_callback_data = callback_data;
> > + alsa->output_samples_trigger = samples_trigger;
> > +}
> > +
> > +/**
> > + * alsa_register_input_callback:
> > + * @alsa: The target alsa structure
> > + * @callback: The callback function to call when input data is
> > available
> > + * @callback_data: The data pointer to pass to the callback
> > function
> > + * @samples_trigger: The required number of samples to trigger the
> > callback
> > + *
> > + * Register a callback function to be called when input data is
> > available during
> > + * a run. The callback is called when @samples_trigger samples are
> > available.
> > + *
> > + * The callback should return an integer equal to zero for success,
> > negative for
> > + * failure and positive to indicate that the run should stop.
> > + */
> > +void alsa_register_input_callback(struct alsa *alsa,
> > + int (*callback)(void *data, short
> > *buffer, int samples),
> > + void *callback_data, int
> > samples_trigger)
> > +{
> > + alsa->input_callback = callback;
> > + alsa->input_callback_data = callback_data;
> > + alsa->input_samples_trigger = samples_trigger;
> > +}
> > +
> > +/**
> > + * alsa_run:
> > + * @alsa: The target alsa structure
> > + * @duration_ms: The maximum duration of the run in milliseconds
> > + *
> > + * Run ALSA playback and capture on the input and output devices
> > for
> > at
> > + * most @duration_ms milliseconds, calling the registered callbacks
> > when needed.
> > + *
> > + * Returns: An integer equal to zero for success, positive for a
> > stop caused
> > + * by the input callback and negative for failure
> > + */
> > +int alsa_run(struct alsa *alsa, int duration_ms)
> > +{
> > + snd_pcm_t *handle;
> > + short *output_buffer = NULL;
> > + short *input_buffer = NULL;
> > + int output_limit;
> > + int output_total = 0;
> > + int output_counts[alsa->output_handles_count];
> > + bool output_ready = false;
> > + int output_channels;
> > + int output_trigger;
> > + int input_limit;
> > + int input_total = 0;
> > + int input_count = 0;
> > + int input_channels;
> > + int input_trigger;
> > + bool reached;
> > + int index;
> > + int count;
> > + int avail;
> > + int i;
> > + int ret;
> > +
> > + output_limit = alsa->output_sampling_rate * duration_ms /
> > 1000;
> > + output_channels = alsa->output_channels;
> > + output_trigger = alsa->output_samples_trigger;
> > + output_buffer = malloc(sizeof(short) * output_channels *
> > + output_trigger);
> > +
> > + if (alsa->input_callback) {
> > + input_limit = alsa->input_sampling_rate *
> > duration_ms / 1000;
> > + input_trigger = alsa->input_samples_trigger;
> > + input_channels = alsa->input_channels;
> > + input_buffer = malloc(sizeof(short) *
> > input_channels
> > *
> > + input_trigger);
> > + }
> > +
> > + do {
> > + reached = true;
> > +
> > + if (output_total < output_limit) {
> > + reached = false;
> > +
> > + if (!output_ready) {
> > + output_ready = true;
> > +
> > + for (i = 0; i < alsa-
> > > output_handles_count; i++)
> >
> > + output_counts[i] = 0;
> > +
> > + ret = alsa->output_callback(alsa-
> > > output_callback_data,
> >
> > + output_
> > b
> > uffer,
> > + output_
> > t
> > rigger);
> > + if (ret < 0)
> > + goto complete;
> > + }
> > +
> > + for (i = 0; i < alsa->output_handles_count;
> > i++) {
> > + handle = alsa->output_handles[i];
> > +
> > + if (output_counts[i] <
> > output_trigger &&
> > + snd_pcm_avail(handle) > 0) {
> > + index = output_counts[i] *
> > + output_channels;
> > + count = output_trigger -
> > + output_counts[i];
> > + avail =
> > snd_pcm_avail(handle);
> > +
> > + count = avail < count ?
> > avail : count;
> > +
> > + ret =
> > snd_pcm_writei(handle,
> > + &outpu
> > t
> > _buffer[index],
> > + count)
> > ;
> > + if (ret < 0) {
> > + ret =
> > snd_pcm_recover(handle,
> > +
> >
> > count, 0);
> > + if (ret < 0)
> > + goto
> > complete;
> > + }
> > +
> > + output_counts[i] += ret;
> > + }
> > + }
> > +
> > + output_ready = false;
> > +
> > + for (i = 0; i < alsa->output_handles_count;
> > i++)
> > + if (output_counts[i] <
> > output_trigger)
> > + output_ready = true;
> > +
> > + if (!output_ready)
> > + output_total += output_trigger;
> > +
> > + }
> > +
> > + if (alsa->input_callback && input_total <
> > input_limit) {
> > + reached = false;
> > +
> > + if (input_count == input_trigger) {
> > + input_count = 0;
> > +
> > + ret = alsa->input_callback(alsa-
> > > input_callback_data,
> >
> > + input_bu
> > f
> > fer,
> > + input_tr
> > i
> > gger);
> > + if (ret != 0)
> > + goto complete;
> > + }
> > +
> > + handle = alsa->input_handle;
> > +
> > + if (input_count < input_trigger &&
> > + (snd_pcm_avail(handle) > 0 ||
> > input_total == 0)) {
> > + index = input_count *
> > input_channels;
> > + count = input_trigger -
> > input_count;
> > + avail = snd_pcm_avail(handle);
> > +
> > + count = avail > 0 && avail < count
> > ?
> > avail :
> > + count;
> > +
> > + ret = snd_pcm_readi(handle,
> > + &input_buffer[i
> > n
> > dex],
> > + count);
> > + if (ret == -EAGAIN) {
> > + ret = 0;
> > + } else if (ret < 0) {
> > + ret =
> > snd_pcm_recover(handle, count, 0);
> > + if (ret < 0)
> > + goto complete;
> > + }
> > +
> > + input_count += ret;
> > + input_total += ret;
> > + }
> > + }
> > + } while (!reached);
> > +
> > + ret = 0;
> > +
> > +complete:
> > + if (output_buffer)
> > + free(output_buffer);
> > +
> > + if (input_buffer)
> > + free(input_buffer);
> > +
> > + return ret;
> > +}
> > diff --git a/lib/igt_alsa.h b/lib/igt_alsa.h
> > new file mode 100644
> > index 00000000..9911ddde
> > --- /dev/null
> > +++ b/lib/igt_alsa.h
> > @@ -0,0 +1,60 @@
> > +/*
> > + * Copyright © 2017 Intel Corporation
> > + *
> > + * Permission is hereby granted, free of charge, to any person
> > obtaining a
> > + * copy of this software and associated documentation files (the
> > "Software"),
> > + * to deal in the Software without restriction, including without
> > limitation
> > + * the rights to use, copy, modify, merge, publish, distribute,
> > sublicense,
> > + * and/or sell copies of the Software, and to permit persons to
> > whom
> > the
> > + * Software is furnished to do so, subject to the following
> > conditions:
> > + *
> > + * The above copyright notice and this permission notice (including
> > the next
> > + * paragraph) shall be included in all copies or substantial
> > portions of the
> > + * Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > EXPRESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> > EVENT SHALL
> > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
> > DAMAGES
> > OR OTHER
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> > ARISING
> > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> > OTHER DEALINGS
> > + * IN THE SOFTWARE.
> > + *
> > + * Authors:
> > + * Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > + */
> > +
> > +#ifndef IGT_ALSA_H
> > +#define IGT_ALSA_H
> > +
> > +#ifdef HAVE_CONFIG_H
> > +#include "config.h"
> > +#endif
> > +
> > +#include "igt.h"
> > +#include <stdbool.h>
> > +
> > +struct alsa;
> > +
> > +struct alsa *alsa_init(void);
> > +int alsa_open_output(struct alsa *alsa, const char *device_name);
> > +int alsa_open_input(struct alsa *alsa, const char *device_name);
> > +void alsa_close_output(struct alsa *alsa);
> > +void alsa_close_input(struct alsa *alsa);
> > +bool alsa_test_output_configuration(struct alsa *alsa, int
> > channels,
> > + int sampling_rate);
> > +bool alsa_test_input_configuration(struct alsa *alsa, int channels,
> > + int sampling_rate);
> > +void alsa_configure_output(struct alsa *alsa, int channels,
> > + int sampling_rate);
> > +void alsa_configure_input(struct alsa *alsa, int channels,
> > + int sampling_rate);
> > +void alsa_register_output_callback(struct alsa *alsa,
> > + int (*callback)(void *data,
> > short
> > *buffer, int samples),
> > + void *callback_data, int
> > samples_trigger);
> > +void alsa_register_input_callback(struct alsa *alsa,
> > + int (*callback)(void *data, short
> > *buffer, int samples),
> > + void *callback_data, int
> > samples_trigger);
> > +int alsa_run(struct alsa *alsa, int duration_ms);
> > +
> > +#endif
--
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH i-g-t 3/3] tests: Introduce audio tests, starting with HDMI signal integrity
2017-08-18 16:15 ` Lyude Paul
@ 2017-08-21 15:14 ` Paul Kocialkowski
2017-08-21 15:26 ` Lyude Paul
0 siblings, 1 reply; 16+ messages in thread
From: Paul Kocialkowski @ 2017-08-21 15:14 UTC (permalink / raw)
To: Lyude Paul, intel-gfx
Hi,
On Fri, 2017-08-18 at 12:15 -0400, Lyude Paul wrote:
> Nice job! Only one small formatting change
Thanks a lot for the timely review! I only have a week and a half left
at my internship, so it is much appreciated :)
> On Thu, 2017-08-17 at 19:05 +0300, Paul Kocialkowski wrote:
> > This introduces a new test for audio going through display
> > connectors.
> > It currently contains a single subtest for HDMI signal integrity,
> > but
> > other test cases will be added later on.
> >
> > The test setup consists in using an HDMI-VGA bridge that separates
> > the
> > audio out (via a 3.5 mm jack) and feeding this back to the DUT's
> > line-in
> > where it can be recorded by ALSA with controls correctly configured.
> >
> > The audio test makes use of the audio and ALSA igt libraries
> > helpers.
> >
> > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > ---
> > tests/Makefile.am | 12 ++++
> > tests/audio.c | 170
> > ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 182 insertions(+)
> > create mode 100644 tests/audio.c
> >
> > diff --git a/tests/Makefile.am b/tests/Makefile.am
> > index f9d11e6c..471f3818 100644
> > --- a/tests/Makefile.am
> > +++ b/tests/Makefile.am
> > @@ -20,6 +20,15 @@ TESTS_progs += \
> > $(NULL)
> > endif
> >
> > +if HAVE_ALSA
> > +if HAVE_GSL
> > +TESTS_progs += \
> > + audio \
> > + $(NULL)
> > +endif
> > +endif
> > +
> > +
> > if BUILD_TESTS
> > test-list.txt: Makefile.sources
> > @echo TESTLIST > $@
> > @@ -134,6 +143,9 @@ vc4_wait_seqno_LDADD = $(LDADD) $(DRM_VC4_LIBS)
> > chamelium_CFLAGS = $(AM_CFLAGS) $(XMLRPC_CFLAGS) $(LIBUDEV_CFLAGS)
> > chamelium_LDADD = $(LDADD) $(XMLRPC_LIBS) $(LIBUDEV_LIBS)
> >
> > +audio_CFLAGS = $(AM_CFLAGS) $(ALSA_CFLAGS)
> > +audio_LDADD = $(LDADD) $(ALSA_LIBS)
> > +
> > amdgpu_amd_basic_CFLAGS = $(AM_CFLAGS) $(DRM_AMDGPU_CFLAGS)
> > amdgpu_amd_basic_LDADD = $(LDADD) $(DRM_AMDGPU_LIBS)
> > amdgpu_amd_cs_nop_CFLAGS = $(AM_CFLAGS) $(DRM_AMDGPU_CFLAGS)
> > diff --git a/tests/audio.c b/tests/audio.c
> > new file mode 100644
> > index 00000000..7099dd99
> > --- /dev/null
> > +++ b/tests/audio.c
> > @@ -0,0 +1,170 @@
> > +/*
> > + * Copyright © 2017 Intel Corporation
> > + *
> > + * Permission is hereby granted, free of charge, to any person
> > obtaining a
> > + * copy of this software and associated documentation files (the
> > "Software"),
> > + * to deal in the Software without restriction, including without
> > limitation
> > + * the rights to use, copy, modify, merge, publish, distribute,
> > sublicense,
> > + * and/or sell copies of the Software, and to permit persons to
> > whom
> > the
> > + * Software is furnished to do so, subject to the following
> > conditions:
> > + *
> > + * The above copyright notice and this permission notice (including
> > the next
> > + * paragraph) shall be included in all copies or substantial
> > portions of the
> > + * Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > EXPRESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> > EVENT SHALL
> > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
> > DAMAGES
> > OR OTHER
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> > ARISING
> > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> > OTHER DEALINGS
> > + * IN THE SOFTWARE.
> > + *
> > + * Authors:
> > + * Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > + */
> > +
> > +#include "config.h"
> > +#include "igt.h"
> > +
> > +#define PLAYBACK_CHANNELS 2
> > +#define PLAYBACK_FRAMES 1024
> > +
> > +#define CAPTURE_SAMPLE_RATE 48000
> > +#define CAPTURE_CHANNELS 2
> > +#define CAPTURE_DEVICE_NAME "default"
> > +#define CAPTURE_FRAMES 2048
>
> Might want to fix the indenting here
cat, git and my editor show them aligned, so I think this is due to
patch formating+email.
> > +
> > +#define RUN_TIMEOUT 2000
> > +
> > +struct test_data {
> > + struct alsa *alsa;
> > + struct audio_signal *signal;
> > +
> > + int streak;
> > +};
> > +
> > +static int sampling_rates[] = {
> > + 32000,
> > + 44100,
> > + 48000,
> > + 88200,
> > + 96000,
> > + 176400,
> > + 192000,
> > +};
> > +
> > +static int sampling_rates_count = sizeof(sampling_rates) /
> > sizeof(int);
> > +
> > +static int test_frequencies[] = {
> > + 300,
> > + 600,
> > + 1200,
> > + 80000,
> > + 10000,
> > +};
> > +
> > +static int test_frequencies_count = sizeof(test_frequencies) /
> > sizeof(int);
> > +
> > +static int output_callback(void *data, short *buffer, int frames)
> > +{
> > + struct test_data *test_data = (struct test_data *) data;
> > +
> > + audio_signal_fill(test_data->signal, buffer, frames);
> > +
> > + return 0;
> > +}
> > +
> > +static int input_callback(void *data, short *buffer, int frames)
> > +{
> > + struct test_data *test_data = (struct test_data *) data;
> > + bool detect;
> > +
> > + detect = audio_signal_detect(test_data->signal,
> > CAPTURE_CHANNELS,
> > + CAPTURE_SAMPLE_RATE, buffer,
> > frames);
> > + if (detect)
> > + test_data->streak++;
> > + else
> > + test_data->streak = 0;
> > +
> > + /* A streak of 3 gives confidence that the signal is good.
> > */
> > + if (test_data->streak == 3)
> > + return 1;
> > +
> > + return 0;
> > +}
> > +
> > +static void test_integrity(const char *device_name)
> > +{
> > + struct test_data data;
> > + int sampling_rate;
> > + bool run = false;
> > + bool test;
> > + int i, j;
> > + int ret;
> > +
> > + data.alsa = alsa_init();
> > + igt_assert(data.alsa);
> > +
> > + ret = alsa_open_output(data.alsa, device_name);
> > + igt_assert(ret >= 0);
> > +
> > + ret = alsa_open_input(data.alsa, CAPTURE_DEVICE_NAME);
> > + igt_assert(ret >= 0);
> > +
> > + alsa_configure_input(data.alsa, CAPTURE_CHANNELS,
> > + CAPTURE_SAMPLE_RATE);
> > +
> > + for (i = 0; i < sampling_rates_count; i++) {
> > + sampling_rate = sampling_rates[i];
> > +
> > + test = alsa_test_output_configuration(data.alsa,
> > + PLAYBACK_CHAN
> > N
> > ELS,
> > + sampling_rate
> > )
> > ;
> > + if (!test)
> > + continue;
> > +
> > + igt_debug("Testing with sampling rate %d\n",
> > sampling_rate);
> > +
> > + alsa_configure_output(data.alsa, PLAYBACK_CHANNELS,
> > + sampling_rate);
> > +
> > + data.signal = audio_signal_init(PLAYBACK_CHANNELS,
> > + sampling_rate);
> > + igt_assert(data.signal);
> > +
> > + for (j = 0; j < test_frequencies_count; j++)
> > + audio_signal_add_frequency(data.signal,
> > + test_frequencies
> > [
> > j]);
> > +
> > + audio_signal_synthesize(data.signal);
> > +
> > + alsa_register_output_callback(data.alsa,
> > output_callback,
> > + &data,
> > PLAYBACK_FRAMES);
> > + alsa_register_input_callback(data.alsa,
> > input_callback, &data,
> > + CAPTURE_FRAMES);
> > +
> > + data.streak = 0;
> > +
> > + ret = alsa_run(data.alsa, RUN_TIMEOUT);
> > + igt_assert(ret > 0);
> > +
> > + audio_signal_clean(data.signal);
> > + free(data.signal);
> > +
> > + run = true;
> > + }
> > +
> > + /* Make sure we tested at least one frequency */
> > + igt_assert(run);
> > +
> > + alsa_close_input(data.alsa);
> > + alsa_close_output(data.alsa);
> > + free(data.alsa);
> > +}
> > +
> > +igt_main
> > +{
> > + igt_subtest("hdmi-integrity")
> > + test_integrity("HDMI");
> > +}
--
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH i-g-t 3/3] tests: Introduce audio tests, starting with HDMI signal integrity
2017-08-21 15:14 ` Paul Kocialkowski
@ 2017-08-21 15:26 ` Lyude Paul
0 siblings, 0 replies; 16+ messages in thread
From: Lyude Paul @ 2017-08-21 15:26 UTC (permalink / raw)
To: Paul Kocialkowski, intel-gfx
On Mon, 2017-08-21 at 18:14 +0300, Paul Kocialkowski wrote:
> Hi,
>
> On Fri, 2017-08-18 at 12:15 -0400, Lyude Paul wrote:
> > Nice job! Only one small formatting change
>
> Thanks a lot for the timely review! I only have a week and a half
> left
> at my internship, so it is much appreciated :)
>
> > On Thu, 2017-08-17 at 19:05 +0300, Paul Kocialkowski wrote:
> > > This introduces a new test for audio going through display
> > > connectors.
> > > It currently contains a single subtest for HDMI signal integrity,
> > > but
> > > other test cases will be added later on.
> > >
> > > The test setup consists in using an HDMI-VGA bridge that
> > > separates
> > > the
> > > audio out (via a 3.5 mm jack) and feeding this back to the DUT's
> > > line-in
> > > where it can be recorded by ALSA with controls correctly
> > > configured.
> > >
> > > The audio test makes use of the audio and ALSA igt libraries
> > > helpers.
> > >
> > > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.c
> > > om>
> > > ---
> > > tests/Makefile.am | 12 ++++
> > > tests/audio.c | 170
> > > ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > > 2 files changed, 182 insertions(+)
> > > create mode 100644 tests/audio.c
> > >
> > > diff --git a/tests/Makefile.am b/tests/Makefile.am
> > > index f9d11e6c..471f3818 100644
> > > --- a/tests/Makefile.am
> > > +++ b/tests/Makefile.am
> > > @@ -20,6 +20,15 @@ TESTS_progs += \
> > > $(NULL)
> > > endif
> > >
> > > +if HAVE_ALSA
> > > +if HAVE_GSL
> > > +TESTS_progs += \
> > > + audio \
> > > + $(NULL)
> > > +endif
> > > +endif
> > > +
> > > +
> > > if BUILD_TESTS
> > > test-list.txt: Makefile.sources
> > > @echo TESTLIST > $@
> > > @@ -134,6 +143,9 @@ vc4_wait_seqno_LDADD = $(LDADD)
> > > $(DRM_VC4_LIBS)
> > > chamelium_CFLAGS = $(AM_CFLAGS) $(XMLRPC_CFLAGS)
> > > $(LIBUDEV_CFLAGS)
> > > chamelium_LDADD = $(LDADD) $(XMLRPC_LIBS) $(LIBUDEV_LIBS)
> > >
> > > +audio_CFLAGS = $(AM_CFLAGS) $(ALSA_CFLAGS)
> > > +audio_LDADD = $(LDADD) $(ALSA_LIBS)
> > > +
> > > amdgpu_amd_basic_CFLAGS = $(AM_CFLAGS) $(DRM_AMDGPU_CFLAGS)
> > > amdgpu_amd_basic_LDADD = $(LDADD) $(DRM_AMDGPU_LIBS)
> > > amdgpu_amd_cs_nop_CFLAGS = $(AM_CFLAGS) $(DRM_AMDGPU_CFLAGS)
> > > diff --git a/tests/audio.c b/tests/audio.c
> > > new file mode 100644
> > > index 00000000..7099dd99
> > > --- /dev/null
> > > +++ b/tests/audio.c
> > > @@ -0,0 +1,170 @@
> > > +/*
> > > + * Copyright © 2017 Intel Corporation
> > > + *
> > > + * Permission is hereby granted, free of charge, to any person
> > > obtaining a
> > > + * copy of this software and associated documentation files (the
> > > "Software"),
> > > + * to deal in the Software without restriction, including
> > > without
> > > limitation
> > > + * the rights to use, copy, modify, merge, publish, distribute,
> > > sublicense,
> > > + * and/or sell copies of the Software, and to permit persons to
> > > whom
> > > the
> > > + * Software is furnished to do so, subject to the following
> > > conditions:
> > > + *
> > > + * The above copyright notice and this permission notice
> > > (including
> > > the next
> > > + * paragraph) shall be included in all copies or substantial
> > > portions of the
> > > + * Software.
> > > + *
> > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
> > > KIND,
> > > EXPRESS OR
> > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > > MERCHANTABILITY,
> > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> > > EVENT SHALL
> > > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
> > > DAMAGES
> > > OR OTHER
> > > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> > > OTHERWISE,
> > > ARISING
> > > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> > > OTHER DEALINGS
> > > + * IN THE SOFTWARE.
> > > + *
> > > + * Authors:
> > > + * Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > > + */
> > > +
> > > +#include "config.h"
> > > +#include "igt.h"
> > > +
> > > +#define PLAYBACK_CHANNELS 2
> > > +#define PLAYBACK_FRAMES 1024
> > > +
> > > +#define CAPTURE_SAMPLE_RATE 48000
> > > +#define CAPTURE_CHANNELS 2
> > > +#define CAPTURE_DEVICE_NAME "default"
> > > +#define CAPTURE_FRAMES 2048
> >
> > Might want to fix the indenting here
>
> cat, git and my editor show them aligned, so I think this is due to
> patch formating+email.
Figured as much. Since that only leaves the printf attribute (it's not
used anywhere else, but I still think it's a good idea to have for the
day this code gets changed again) I'll just make that small change
myself and push the series. Thanks for the great work you've been
doing!
>
> > > +
> > > +#define RUN_TIMEOUT 2000
> > > +
> > > +struct test_data {
> > > + struct alsa *alsa;
> > > + struct audio_signal *signal;
> > > +
> > > + int streak;
> > > +};
> > > +
> > > +static int sampling_rates[] = {
> > > + 32000,
> > > + 44100,
> > > + 48000,
> > > + 88200,
> > > + 96000,
> > > + 176400,
> > > + 192000,
> > > +};
> > > +
> > > +static int sampling_rates_count = sizeof(sampling_rates) /
> > > sizeof(int);
> > > +
> > > +static int test_frequencies[] = {
> > > + 300,
> > > + 600,
> > > + 1200,
> > > + 80000,
> > > + 10000,
> > > +};
> > > +
> > > +static int test_frequencies_count = sizeof(test_frequencies) /
> > > sizeof(int);
> > > +
> > > +static int output_callback(void *data, short *buffer, int
> > > frames)
> > > +{
> > > + struct test_data *test_data = (struct test_data *) data;
> > > +
> > > + audio_signal_fill(test_data->signal, buffer, frames);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int input_callback(void *data, short *buffer, int frames)
> > > +{
> > > + struct test_data *test_data = (struct test_data *) data;
> > > + bool detect;
> > > +
> > > + detect = audio_signal_detect(test_data->signal,
> > > CAPTURE_CHANNELS,
> > > + CAPTURE_SAMPLE_RATE,
> > > buffer,
> > > frames);
> > > + if (detect)
> > > + test_data->streak++;
> > > + else
> > > + test_data->streak = 0;
> > > +
> > > + /* A streak of 3 gives confidence that the signal is
> > > good.
> > > */
> > > + if (test_data->streak == 3)
> > > + return 1;
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static void test_integrity(const char *device_name)
> > > +{
> > > + struct test_data data;
> > > + int sampling_rate;
> > > + bool run = false;
> > > + bool test;
> > > + int i, j;
> > > + int ret;
> > > +
> > > + data.alsa = alsa_init();
> > > + igt_assert(data.alsa);
> > > +
> > > + ret = alsa_open_output(data.alsa, device_name);
> > > + igt_assert(ret >= 0);
> > > +
> > > + ret = alsa_open_input(data.alsa, CAPTURE_DEVICE_NAME);
> > > + igt_assert(ret >= 0);
> > > +
> > > + alsa_configure_input(data.alsa, CAPTURE_CHANNELS,
> > > + CAPTURE_SAMPLE_RATE);
> > > +
> > > + for (i = 0; i < sampling_rates_count; i++) {
> > > + sampling_rate = sampling_rates[i];
> > > +
> > > + test = alsa_test_output_configuration(data.alsa,
> > > + PLAYBACK_C
> > > HAN
> > > N
> > > ELS,
> > > + sampling_r
> > > ate
> > > )
> > > ;
> > > + if (!test)
> > > + continue;
> > > +
> > > + igt_debug("Testing with sampling rate %d\n",
> > > sampling_rate);
> > > +
> > > + alsa_configure_output(data.alsa,
> > > PLAYBACK_CHANNELS,
> > > + sampling_rate);
> > > +
> > > + data.signal =
> > > audio_signal_init(PLAYBACK_CHANNELS,
> > > + sampling_rate);
> > > + igt_assert(data.signal);
> > > +
> > > + for (j = 0; j < test_frequencies_count; j++)
> > > + audio_signal_add_frequency(data.signal,
> > > + test_frequenc
> > > ies
> > > [
> > > j]);
> > > +
> > > + audio_signal_synthesize(data.signal);
> > > +
> > > + alsa_register_output_callback(data.alsa,
> > > output_callback,
> > > + &data,
> > > PLAYBACK_FRAMES);
> > > + alsa_register_input_callback(data.alsa,
> > > input_callback, &data,
> > > + CAPTURE_FRAMES);
> > > +
> > > + data.streak = 0;
> > > +
> > > + ret = alsa_run(data.alsa, RUN_TIMEOUT);
> > > + igt_assert(ret > 0);
> > > +
> > > + audio_signal_clean(data.signal);
> > > + free(data.signal);
> > > +
> > > + run = true;
> > > + }
> > > +
> > > + /* Make sure we tested at least one frequency */
> > > + igt_assert(run);
> > > +
> > > + alsa_close_input(data.alsa);
> > > + alsa_close_output(data.alsa);
> > > + free(data.alsa);
> > > +}
> > > +
> > > +igt_main
> > > +{
> > > + igt_subtest("hdmi-integrity")
> > > + test_integrity("HDMI");
> > > +}
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH i-g-t 1/3] lib: Add audio library with dedicated helpers
2017-08-18 16:16 ` [PATCH i-g-t 1/3] " Lyude Paul
@ 2017-08-21 15:27 ` Paul Kocialkowski
0 siblings, 0 replies; 16+ messages in thread
From: Paul Kocialkowski @ 2017-08-21 15:27 UTC (permalink / raw)
To: Lyude Paul, intel-gfx
Hi,
On Fri, 2017-08-18 at 12:16 -0400, Lyude Paul wrote:
> One more small formatting change
>
> On Thu, 2017-08-17 at 19:05 +0300, Paul Kocialkowski wrote:
> > This introduces an audio library, with dedicated helpers for both
> > generating signals and detecting peak frequencies in a signal.
> >
> > This library paves the way for testing audio going through display
> > connectors, such as HDMI.
> >
> > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > ---
> > .../intel-gpu-tools/intel-gpu-tools-docs.xml | 1 +
> > lib/Makefile.am | 2 +
> > lib/igt.h | 1 +
> > lib/igt_audio.c | 326
> > +++++++++++++++++++++
> > lib/igt_audio.h | 47 +++
> > 5 files changed, 377 insertions(+)
> > create mode 100644 lib/igt_audio.c
> > create mode 100644 lib/igt_audio.h
> >
> > diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> > b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> > index f88afd2a..c77159cf 100644
> > --- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> > +++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> > @@ -16,6 +16,7 @@
> > <chapter>
> > <title>API Reference</title>
> > <xi:include href="xml/drmtest.xml"/>
> > + <xi:include href="xml/igt_audio.xml"/>
> > <xi:include href="xml/igt_aux.xml"/>
> > <xi:include href="xml/igt_chamelium.xml"/>
> > <xi:include href="xml/igt_core.xml"/>
> > diff --git a/lib/Makefile.am b/lib/Makefile.am
> > index 9c932d6f..5ea08314 100644
> > --- a/lib/Makefile.am
> > +++ b/lib/Makefile.am
> > @@ -33,6 +33,8 @@ if HAVE_GSL
> > lib_source_list += \
> > igt_frame.c \
> > igt_frame.h \
> > + igt_audio.c \
> > + igt_audio.h \
> > $(NULL)
> > endif
> >
> > diff --git a/lib/igt.h b/lib/igt.h
> > index d16a4991..a75d2db7 100644
> > --- a/lib/igt.h
> > +++ b/lib/igt.h
> > @@ -35,6 +35,7 @@
> > #include "igt_dummyload.h"
> > #include "igt_fb.h"
> > #include "igt_frame.h"
> > +#include "igt_audio.h"
> > #include "igt_gt.h"
> > #include "igt_kms.h"
> > #include "igt_pm.h"
> > diff --git a/lib/igt_audio.c b/lib/igt_audio.c
> > new file mode 100644
> > index 00000000..527a4930
> > --- /dev/null
> > +++ b/lib/igt_audio.c
> > @@ -0,0 +1,326 @@
> > +/*
> > + * Copyright © 2017 Intel Corporation
> > + *
> > + * Permission is hereby granted, free of charge, to any person
> > obtaining a
> > + * copy of this software and associated documentation files (the
> > "Software"),
> > + * to deal in the Software without restriction, including without
> > limitation
> > + * the rights to use, copy, modify, merge, publish, distribute,
> > sublicense,
> > + * and/or sell copies of the Software, and to permit persons to
> > whom
> > the
> > + * Software is furnished to do so, subject to the following
> > conditions:
> > + *
> > + * The above copyright notice and this permission notice (including
> > the next
> > + * paragraph) shall be included in all copies or substantial
> > portions of the
> > + * Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > EXPRESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> > EVENT SHALL
> > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
> > DAMAGES
> > OR OTHER
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> > ARISING
> > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> > OTHER DEALINGS
> > + * IN THE SOFTWARE.
> > + *
> > + * Authors:
> > + * Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > + */
> > +
> > +#include "config.h"
> > +
> > +#include <math.h>
> > +#include <gsl/gsl_fft_real.h>
> > +
> > +#include "igt.h"
> > +
> > +#define FREQS_MAX 8
> > +
> > +/**
> > + * SECTION:igt_audio
> > + * @short_description: Library for audio-related tests
> > + * @title: Audio
> > + * @include: igt_audio.h
> > + *
> > + * This library contains helpers for audio-related tests. More
> > specifically,
> > + * it allows generating additions of sine signals as well as
> > detecting them.
> > + */
> > +
> > +struct audio_signal_freq {
> > + int freq;
> > +
> > + short *period;
> > + int frames;
> > + int offset;
> > +};
> > +
> > +struct audio_signal {
> > + int channels;
> > + int sampling_rate;
> > +
> > + struct audio_signal_freq freqs[FREQS_MAX];
> > + int freqs_count;
> > +};
> > +
> > +/**
> > + * audio_signal_init:
> > + * @channels: The number of channels to use for the signal
> > + * @sampling_rate: The sampling rate to use for the signal
> > + *
> > + * Allocate and initialize an audio signal structure with the given
> > parameters.
> > + *
> > + * Returns: A newly-allocated audio signal structure
> > + */
> > +struct audio_signal *audio_signal_init(int channels, int
> > sampling_rate)
> > +{
> > + struct audio_signal *signal;
> > +
> > + signal = malloc(sizeof(struct audio_signal));
> > + memset(signal, 0, sizeof(struct audio_signal));
> > +
> > + signal->sampling_rate = sampling_rate;
> > + signal->channels = channels;
> > +
> > + return signal;
> > +}
> > +
> > +/**
> > + * audio_signal_add_frequency:
> > + * @signal: The target signal structure
> > + * @frequency: The frequency to add to the signal
> > + *
> > + * Add a frequency to the signal.
> > + *
> > + * Returns: An integer equal to zero for success and negative for
> > failure
> > + */
> > +int audio_signal_add_frequency(struct audio_signal *signal, int
> > frequency)
> > +{
> > + int index = signal->freqs_count;
> > +
> > + if (index == FREQS_MAX)
> > + return -1;
> > +
> > + /* Stay within the Nyquist–Shannon sampling theorem. */
> > + if (frequency > signal->sampling_rate / 2)
> > + return -1;
> > +
> > + /* Clip the frequency to an integer multiple of the
> > sampling
> > rate.
> > + * This to be able to store a full period of it and use
> > that
> > for
> > + * signal generation, instead of recurrent calls to sin().
> > + */
> > + frequency = signal->sampling_rate / (signal->sampling_rate
> > /
> > frequency);
> > +
> > + igt_debug("Adding test frequency %d\n", frequency);
> > +
> > + signal->freqs[index].freq = frequency;
> > + signal->freqs[index].frames = 0;
> > + signal->freqs[index].offset = 0;
> > + signal->freqs_count++;
> > +
> > + return 0;
> > +}
> > +
> > +/**
> > + * audio_signal_synthesize:
> > + * @signal: The target signal structure
> > + *
> > + * Synthesize the data tables for the audio signal, that can later
> > be used
> > + * to fill audio buffers. The resources allocated by this function
> > must be
> > + * freed with a call to audio_signal_clean when the signal is no
> > longer used.
> > + */
> > +void audio_signal_synthesize(struct audio_signal *signal)
> > +{
> > + short *period;
> > + double value;
> > + int frames;
> > + int freq;
> > + int i, j;
> > +
> > + if (signal->freqs_count == 0)
> > + return;
> > +
> > + for (i = 0; i < signal->freqs_count; i++) {
> > + freq = signal->freqs[i].freq;
> > + frames = signal->sampling_rate / freq;
> > +
> > + period = calloc(1, frames * sizeof(short));
> > +
> > + for (j = 0; j < frames; j++) {
> > + value = 2.0 * M_PI * freq / signal-
> > > sampling_rate * j;
> >
> > + value = sin(value) * SHRT_MAX / signal-
> > > freqs_count;
> >
> > +
> > + period[j] = (short) value;
> > + }
> > +
> > + signal->freqs[i].period = period;
> > + signal->freqs[i].frames = frames;
> > + }
> > +}
> > +
> > +/**
> > + * audio_signal_synthesize:
> > + * @signal: The target signal structure
> > + *
> > + * Free the resources allocated by audio_signal_synthesize and
> > remove
> > + * the previously-added frequencies.
> > + */
> > +void audio_signal_clean(struct audio_signal *signal)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < signal->freqs_count; i++) {
> > + if (signal->freqs[i].period)
> > + free(signal->freqs[i].period);
> > +
> > + memset(&signal->freqs[i], 0, sizeof(struct
> > audio_signal_freq));
> > + }
> > +
> > + signal->freqs_count = 0;
> > +}
> > +
> > +/**
> > + * audio_signal_fill:
> > + * @signal: The target signal structure
> > + * @buffer: The target buffer to fill
> > + * @frames: The number of frames to fill
> > + *
> > + * Fill the requested number of frames to the target buffer with
> > the
> > audio
> > + * signal data (in interleaved S16_LE format), at the requested
> > sampling rate
> > + * and number of channels.
> > + */
> > +void audio_signal_fill(struct audio_signal *signal, short *buffer,
> > int frames)
> > +{
> > + short *destination;
> > + short *source;
> > + int total;
> > + int freq_frames;
> > + int freq_offset;
> > + int count;
> > + int i, j, k;
> > +
> > + memset(buffer, 0, sizeof(short) * signal->channels *
> > frames);
> > +
> > + for (i = 0; i < signal->freqs_count; i++) {
> > + total = 0;
> > +
> > + while (total < frames) {
> > + freq_frames = signal->freqs[i].frames;
> > + freq_offset = signal->freqs[i].offset;
> > +
> > + source = signal->freqs[i].period +
> > freq_offset;
> > + destination = buffer + total * signal-
> > > channels;
> >
> > +
> > + count = freq_frames - freq_offset;
> > + if (count > (frames - total))
> > + count = frames - total;
> > +
> > + freq_offset += count;
> > + freq_offset %= freq_frames;
> > +
> > + signal->freqs[i].offset = freq_offset;
> > +
> > + for (j = 0; j < count; j++) {
> > + for (k = 0; k < signal->channels;
> > k++) {
> > + destination[j * signal-
> > > channels + k] += source[j];
> >
> > + }
> > + }
> > +
> > + total += count;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + * audio_signal_detect:
> > + * @signal: The target signal structure
> > + * @channels: The input data's number of channels
> > + * @sampling_rate: The input data's sampling rate
> > + * @buffer: The input data's buffer
> > + * @frames: The input data's number of frames
> > + *
> > + * Detect that the frequencies specified in @signal, and only
> > those,
> > are
> > + * present in the input data. The input data's format is required
> > to
> > be S16_LE.
> > + *
> > + * Returns: A boolean indicating whether the detection was
> > successful
> > + */
> > +bool audio_signal_detect(struct audio_signal *signal, int channels,
> > + int sampling_rate, short *buffer, int
> > frames)
> > +{
> > + double data[frames];
> > + int amplitude[frames / 2];
> > + bool detected[signal->freqs_count];
> > + int threshold;
> > + bool above;
> > + int error;
> > + int freq;
> > + int max;
> > + int c, i, j;
> > +
> > + /* Allowed error in Hz due to FFT step. */
> > + error = sampling_rate / frames;
> > +
> > + for (c = 0; c < channels; c++) {
> > + for (i = 0; i < frames; i++)
> > + data[i] = (double) buffer[i * channels +
> > c];
> > +
> > + gsl_fft_real_radix2_transform(data, 1, frames);
> > +
> > + max = 0;
> > +
> > + for (i = 0; i < frames / 2; i++) {
> > + amplitude[i] = sqrt(data[i] * data[i] +
> > + data[frames - i]
> > *
> > + data[frames -
> > i]);
>
> More indenting fixes? not sure if this one is just a result of it
> getting formatted as an email.
This one was a legit mistake, good catch!
> > + if (amplitude[i] > max)
> > + max = amplitude[i];
> > + }
> > +
> > + for (i = 0; i < signal->freqs_count; i++)
> > + detected[i] = false;
> > +
> > + threshold = max / 2;
> > + above = false;
> > + max = 0;
> > +
> > + for (i = 0; i < frames / 2; i++) {
> > + if (amplitude[i] > threshold)
> > + above = true;
> > +
> > + if (above) {
> > + if (amplitude[i] < threshold) {
> > + above = false;
> > + max = 0;
> > +
> > + for (j = 0; j < signal-
> > > freqs_count; j++) {
> >
> > + if (signal-
> > > freqs[j].freq >
> >
> > + freq - error &&
> > + signal-
> > > freqs[j].freq <
> >
> > + freq + error) {
> > + detected[j]
> > = true;
> > + break;
> > + }
> > + }
> > +
> > + /* Detected frequency was
> > not generated. */
> > + if (j == signal-
> > > freqs_count) {
> >
> > + igt_debug("Detected
> > additional frequency: %d\n",
> > + freq);
> > + return false;
> > + }
> > + }
> > +
> > + if (amplitude[i] > max) {
> > + max = amplitude[i];
> > + freq = sampling_rate * i /
> > frames;
> > + }
> > + }
> > + }
> > +
> > + for (i = 0; i < signal->freqs_count; i++) {
> > + if (!detected[i]) {
> > + igt_debug("Missing frequency:
> > %d\n",
> > + signal->freqs[i].freq);
> > + return false;
> > + }
> > + }
> > + }
> > +
> > + return true;
> > +}
> > diff --git a/lib/igt_audio.h b/lib/igt_audio.h
> > new file mode 100644
> > index 00000000..507e7ab9
> > --- /dev/null
> > +++ b/lib/igt_audio.h
> > @@ -0,0 +1,47 @@
> > +/*
> > + * Copyright © 2017 Intel Corporation
> > + *
> > + * Permission is hereby granted, free of charge, to any person
> > obtaining a
> > + * copy of this software and associated documentation files (the
> > "Software"),
> > + * to deal in the Software without restriction, including without
> > limitation
> > + * the rights to use, copy, modify, merge, publish, distribute,
> > sublicense,
> > + * and/or sell copies of the Software, and to permit persons to
> > whom
> > the
> > + * Software is furnished to do so, subject to the following
> > conditions:
> > + *
> > + * The above copyright notice and this permission notice (including
> > the next
> > + * paragraph) shall be included in all copies or substantial
> > portions of the
> > + * Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > EXPRESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> > EVENT SHALL
> > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
> > DAMAGES
> > OR OTHER
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> > ARISING
> > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> > OTHER DEALINGS
> > + * IN THE SOFTWARE.
> > + *
> > + * Authors:
> > + * Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > + */
> > +
> > +#ifndef IGT_AUDIO_H
> > +#define IGT_AUDIO_H
> > +
> > +#ifdef HAVE_CONFIG_H
> > +#include "config.h"
> > +#endif
> > +
> > +#include "igt.h"
> > +#include <stdbool.h>
> > +
> > +struct audio_signal;
> > +
> > +struct audio_signal *audio_signal_init(int channels, int
> > sampling_rate);
> > +int audio_signal_add_frequency(struct audio_signal *signal, int
> > frequency);
> > +void audio_signal_synthesize(struct audio_signal *signal);
> > +void audio_signal_clean(struct audio_signal *signal);
> > +void audio_signal_fill(struct audio_signal *signal, short *buffer,
> > int frames);
> > +bool audio_signal_detect(struct audio_signal *signal, int channels,
> > + int sampling_rate, short *buffer, int
> > frames);
> > +
> > +#endif
--
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2017-08-21 15:27 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-08-17 16:05 [PATCH i-g-t 1/3] lib: Add audio library with dedicated helpers Paul Kocialkowski
2017-08-17 16:05 ` [PATCH i-g-t 2/3] lib: Add ALSA " Paul Kocialkowski
2017-08-18 9:46 ` Arkadiusz Hiler
2017-08-21 7:25 ` Arkadiusz Hiler
2017-08-21 9:39 ` Paul Kocialkowski
2017-08-21 9:45 ` Arkadiusz Hiler
2017-08-18 16:20 ` Lyude Paul
2017-08-21 15:11 ` Paul Kocialkowski
2017-08-17 16:05 ` [PATCH i-g-t 3/3] tests: Introduce audio tests, starting with HDMI signal integrity Paul Kocialkowski
2017-08-18 16:15 ` Lyude Paul
2017-08-21 15:14 ` Paul Kocialkowski
2017-08-21 15:26 ` Lyude Paul
2017-08-17 16:24 ` ✓ Fi.CI.BAT: success for series starting with [1/3] lib: Add audio library with dedicated helpers Patchwork
2017-08-18 9:59 ` Petri Latvala
2017-08-18 16:16 ` [PATCH i-g-t 1/3] " Lyude Paul
2017-08-21 15:27 ` Paul Kocialkowski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).