All of lore.kernel.org
 help / color / mirror / Atom feed
* [igt-dev] [PATCH i-g-t v6 0/7] tests/kms_chamelium: add dp-audio test
@ 2019-04-17 12:43 Simon Ser
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 1/7] " Simon Ser
                   ` (9 more replies)
  0 siblings, 10 replies; 22+ messages in thread
From: Simon Ser @ 2019-04-17 12:43 UTC (permalink / raw)
  To: igt-dev

Changes in v6:

- Rebased the whole series
- Reword the first commit to include a note about the short -> uint16_t change
- Add a HAX commit to temporarily ad dp-audio to fast-feedback (do not merge)

Simon Ser (7):
  tests/kms_chamelium: add dp-audio test
  tests/kms_chamelium: capture audio data in real-time
  tests/kms_chamelium: test we receive a signal from both audio channels
  tests/kms_chamelium: test audio channels are not mixed up
  tests/kms_chamelium: run audio test with multiple sampling rates
  lib/igt_edid: add support for Short Audio Descriptors
  HAX: add dp-audio test to fast-feedback

 docs/audio.txt                        |  45 --
 docs/chamelium.txt                    |  34 +-
 lib/igt.h                             |   1 +
 lib/igt_alsa.c                        |  83 +++-
 lib/igt_alsa.h                        |   1 +
 lib/igt_audio.c                       | 428 +++++++++++++------
 lib/igt_audio.h                       |  19 +-
 lib/igt_aux.c                         |  31 ++
 lib/igt_aux.h                         |   1 +
 lib/igt_chamelium.c                   | 161 ++++++++
 lib/igt_chamelium.h                   |  17 +
 lib/igt_chamelium_stream.c            | 572 ++++++++++++++++++++++++++
 lib/igt_chamelium_stream.h            |  50 +++
 lib/igt_edid.c                        |  73 +++-
 lib/igt_edid.h                        |  82 +++-
 lib/meson.build                       |   5 +-
 meson.build                           |  52 +--
 meson_options.txt                     |   6 -
 tests/audio.c                         | 193 ---------
 tests/intel-ci/fast-feedback.testlist |   1 +
 tests/kms_chamelium.c                 | 352 +++++++++++++++-
 tests/meson.build                     |   9 +-
 22 files changed, 1756 insertions(+), 460 deletions(-)
 delete mode 100644 docs/audio.txt
 create mode 100644 lib/igt_chamelium_stream.c
 create mode 100644 lib/igt_chamelium_stream.h
 delete mode 100644 tests/audio.c

-- 
2.21.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [igt-dev] [PATCH i-g-t v6 1/7] tests/kms_chamelium: add dp-audio test
  2019-04-17 12:43 [igt-dev] [PATCH i-g-t v6 0/7] tests/kms_chamelium: add dp-audio test Simon Ser
@ 2019-04-17 12:43 ` Simon Ser
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 2/7] tests/kms_chamelium: capture audio data in real-time Simon Ser
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 22+ messages in thread
From: Simon Ser @ 2019-04-17 12:43 UTC (permalink / raw)
  To: igt-dev

This new test ensures DisplayPort audio works by using the Chamelium.

It enables the DisplayPort output and sends an audio signal containing a set of
frequencies we choose to all HDMI/DisplayPort audio devices. It starts
recording audio on the Chamelium device and uses the stream server to retrieve
captured audio pages. It then checks that the capture audio signal contains the
frequencies we sent, and only those, by computing a FFT.

A new library has been added to libigt to communicate with the stream server.
It implements a simple custom TCP protocol.

In case the test fails, a WAV file with the captured data is saved on disk.

Right now the test has a few limitations:

- Only the first channel is checked
- IGT only generates audio with a single sampling rate (48 KHz)
- Audio data is not captured in real-time

These limitations will be lifted in future patches.

PulseAudio must not run during the tests since ALSA is used directly. To ensure
this, edit /etc/pulse/client.conf and add `autospawn=no`. Then run
`pulseaudio --kill`.

This commit deletes the existing audio tests. They weren't run and required an
exotic configuration (HDMI audio splitter, dummy HDMI sink and a line-in port
on the DUT).

This patch also changes lib/igt_audio to use uint16_t instead of short. The
rationale is:

- The standard says a short is at least 16 bit wide, but a short can be
  larger (in practice it won't happen, but better use types correctly)
- It makes it clearer that the audio format is S16_LE, since "16" is
  in the type name.

This patch depends on the following Chameleon bugs:

- https://crbug.com/948060
- https://crbug.com/950857

Signed-off-by: Simon Ser <simon.ser@intel.com>
---
 docs/audio.txt             |  45 ---
 docs/chamelium.txt         |  34 ++-
 lib/igt.h                  |   1 +
 lib/igt_alsa.c             |  42 ++-
 lib/igt_alsa.h             |   1 +
 lib/igt_audio.c            | 313 ++++++++++++++------
 lib/igt_audio.h            |  12 +-
 lib/igt_aux.c              |  31 ++
 lib/igt_aux.h              |   1 +
 lib/igt_chamelium.c        | 101 +++++++
 lib/igt_chamelium.h        |  11 +
 lib/igt_chamelium_stream.c | 589 +++++++++++++++++++++++++++++++++++++
 lib/igt_chamelium_stream.h |  52 ++++
 lib/meson.build            |   5 +-
 meson.build                |  52 ++--
 meson_options.txt          |   6 -
 tests/audio.c              | 193 ------------
 tests/kms_chamelium.c      | 276 ++++++++++++++++-
 tests/meson.build          |   9 +-
 19 files changed, 1382 insertions(+), 392 deletions(-)
 delete mode 100644 docs/audio.txt
 create mode 100644 lib/igt_chamelium_stream.c
 create mode 100644 lib/igt_chamelium_stream.h
 delete mode 100644 tests/audio.c

diff --git a/docs/audio.txt b/docs/audio.txt
deleted file mode 100644
index 158ad5d1..00000000
--- a/docs/audio.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-Audio Support in IGT
-====================
-
-This document provides information and instructions about audio support in IGT.
-
-Introduction
-------------
-
-The audio test is aimed at testing the audio features of display connectors,
-such as HDMI.
-
-Test setup
-----------
-
-The setup required for the audio test consists of using an HDMI-VGA adapter with
-an audio-out 3.5 mm jack to extract the audio from the HDMI interface.
-The audio-out jack is connected back to the device-under-test's line-in.
-
-Depending on the behavior of the adapter, it may be necessary to connect a
-ghost VGA dongle to it (in order to emulate a connected display) to enable the
-audio output. There are guides available detailing how to build these.
-
-When executed, the test will automatically send the test audio signal to all
-ALSA audio HDMI outputs and record from the standard ALSA capture device.
-
-Configuration
--------------
-
-In order to deploy the test, ALSA controls have to be configured to set the
-ALSA capture source to line-in. On Intel x86 systems, this can be achieved
-with the following calls to the amixer utility:
-# amixer sset Line 31 on
-# amixer sset "Input Source" Line
-
-It is then useful to store the ALSA state permanently with the alsactl utility:
-# alsactl store
-
-These settings can be restored with the alsactl utility:
-# alsactl restore
-
-It is desirable to ensure that the alsa-restore and alsa-state systemd services
-are enabled to do this job automatically, especially in the case of an
-automated testing system:
-# systemctl enable alsa-restore
-# systemctl enable alsa-state
diff --git a/docs/chamelium.txt b/docs/chamelium.txt
index 0cabcdc6..5cc85d6e 100644
--- a/docs/chamelium.txt
+++ b/docs/chamelium.txt
@@ -139,6 +139,23 @@ $ make remote-install CHAMELEON_HOST=192.168.72.1
 
 The process requires the Chamelium to be connected to the Internet to succeed.
 
+Audio Capture
+-------------
+
+The Chamelium supports audio capture. IGT tests take advantage of the
+Chamelium streaming server to download audio samples from the Chamelium.
+
+IGT needs direct access to audio devices through ALSA, so PulseAudio needs to
+be stopped (otherwise audio tests will automatically get skipped). To make sure
+PulseAudio isn't running:
+
+- Edit /etc/pulse/client.conf and add autospawn=no
+- Run `pulseaudio --kill` (if it succeeds, it means PulseAudio was running)
+- Make sure a DE that automatically spawns PulseAudio isn't running
+
+In case a test fails, the raw captured audio files will be dumped in a WAV
+file.
+
 Contributing Changes to the Daemon
 ----------------------------------
 
@@ -146,10 +163,11 @@ Contributions to the Chamelium daemon, just like any contribution to ChromiumOS,
 are submitted and reviewed at: https://chromium-review.googlesource.com/
 
 The ChromiumOS project provides an extensive developer guide:
-https://www.chromium.org/chromium-os/developer-guide that assumes running within
-the ChromiumOS build system. Since this is likely not the case for contributing
-to the Chamelium daemon, only the part about uploading changes is relevant:
-https://www.chromium.org/chromium-os/developer-guide#TOC-Upload-your-changes-and-get-a-code-review
+https://chromium.googlesource.com/chromiumos/docs/+/master/developer_guide.md
+It assumes running within the ChromiumOS build system. Since this is likely not
+the case for contributing to the Chamelium daemon, only the part about
+uploading changes is relevant:
+https://chromium.googlesource.com/chromiumos/docs/+/master/developer_guide.md#Upload-your-changes-and-get-a-code-review
 
 Most of the process is about using the Gerrit web interface for submitting and
 having the change reviewed and not forgetting the Change-Id, TEST= and BUG=
@@ -162,7 +180,7 @@ Support for the Chamelium platform in IGT is found in the following places:
 * lib/igt_chamelium.c: library with Chamelium-related helpers
 * tests/kms_chamelium.c: sub-tests using the Chamelium
 
-As of late August 2017, the following features are tested by IGT:
+As of early April 2019, the following features are tested by IGT:
 * Pixel-by-pixel frame integrity tests for DP and HDMI
 * Error-trend-based frame integrity tests for VGA
 * CRC-based frame integrity tests for DP and HDMI
@@ -173,6 +191,7 @@ As of late August 2017, the following features are tested by IGT:
   each interface or combined
 * EDID display identifier integrity check for all interfaces
 * EDID display identifier change during suspend for all interfaces
+* Audio Fourier-based tests for DP at 48KHz
 
 Future Developments
 -------------------
@@ -180,7 +199,10 @@ Future Developments
 With the current generation of the hardware platform, support for testing a
 number of additional display features could be included as future developments,
 including:
-* Audio capture from HDMI and DP
+* Audio capture from HDMI
+* Check all channels are independent from each other
+* Playback using more than 2 channels, different sampling rates and different
+  sample sizes
 * High-bandwidth Digital Content Protection (HDCP) streaming to the display
 * Remote control forwarding (CEC) sent from the display
 * YUV colorspace for HDMI, instead of RGB
diff --git a/lib/igt.h b/lib/igt.h
index 6654a659..5852d557 100644
--- a/lib/igt.h
+++ b/lib/igt.h
@@ -43,6 +43,7 @@
 #include "igt_stats.h"
 #ifdef HAVE_CHAMELIUM
 #include "igt_chamelium.h"
+#include "igt_chamelium_stream.h"
 #endif
 #include "instdone.h"
 #include "intel_batchbuffer.h"
diff --git a/lib/igt_alsa.c b/lib/igt_alsa.c
index bb6682cc..22089881 100644
--- a/lib/igt_alsa.c
+++ b/lib/igt_alsa.c
@@ -26,9 +26,11 @@
 
 #include "config.h"
 
+#include <limits.h>
 #include <alsa/asoundlib.h>
 
 #include "igt_alsa.h"
+#include "igt_aux.h"
 #include "igt_core.h"
 
 #define HANDLES_MAX	8
@@ -61,6 +63,26 @@ struct alsa {
 	int input_samples_trigger;
 };
 
+/**
+ * alsa_has_exclusive_access:
+ * Check whether ALSA has exclusive access to audio devices. Fails if
+ * PulseAudio is running.
+ */
+bool alsa_has_exclusive_access(void)
+{
+	if (igt_is_process_running("pulseaudio")) {
+		igt_warn("alsa doesn't have exclusive access to audio devices\n");
+		igt_warn("It seems that PulseAudio is running. Audio tests "
+			 "need direct access to audio devices, so PulseAudio "
+			 "needs to be stopped. You can do so by running "
+			 "`pulseaudio --kill`. Also make sure to add "
+			 "autospawn=no to /etc/pulse/client.conf\n");
+		return false;
+	}
+
+	return true;
+}
+
 static void alsa_error_handler(const char *file, int line, const char *function,
 			       int err, const char *fmt, ...)
 {
@@ -78,6 +100,10 @@ struct alsa *alsa_init(void)
 {
 	struct alsa *alsa;
 
+	if (!alsa_has_exclusive_access()) {
+		return NULL;
+	}
+
 	alsa = malloc(sizeof(struct alsa));
 	memset(alsa, 0, sizeof(struct alsa));
 
@@ -553,16 +579,20 @@ int alsa_run(struct alsa *alsa, int duration_ms)
 					if (ret < 0) {
 						ret = snd_pcm_recover(handle,
 								      ret, 0);
-						if (ret < 0)
+						if (ret < 0) {
+							igt_debug("snd_pcm_recover after snd_pcm_writei failed");
 							goto complete;
+						}
 					}
 
 					output_counts[i] += ret;
 				} else if (output_counts[i] < output_trigger &&
 					   ret < 0) {
 					ret = snd_pcm_recover(handle, ret, 0);
-					if (ret < 0)
+					if (ret < 0) {
+						igt_debug("snd_pcm_recover failed");
 						goto complete;
+					}
 				}
 			}
 
@@ -609,16 +639,20 @@ int alsa_run(struct alsa *alsa, int duration_ms)
 					ret = 0;
 				} else if (ret < 0) {
 					ret = snd_pcm_recover(handle, ret, 0);
-					if (ret < 0)
+					if (ret < 0) {
+						igt_debug("snd_pcm_recover after snd_pcm_readi failed");
 						goto complete;
+					}
 				}
 
 				input_count += ret;
 				input_total += ret;
 			} else if (input_count < input_trigger && ret < 0) {
 				ret = snd_pcm_recover(handle, ret, 0);
-				if (ret < 0)
+				if (ret < 0) {
+					igt_debug("snd_pcm_recover failed");
 					goto complete;
+				}
 			}
 		}
 	} while (!reached);
diff --git a/lib/igt_alsa.h b/lib/igt_alsa.h
index 50795130..5c804b46 100644
--- a/lib/igt_alsa.h
+++ b/lib/igt_alsa.h
@@ -33,6 +33,7 @@
 
 struct alsa;
 
+bool alsa_has_exclusive_access(void);
 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);
diff --git a/lib/igt_audio.c b/lib/igt_audio.c
index a0592d53..7624f565 100644
--- a/lib/igt_audio.c
+++ b/lib/igt_audio.c
@@ -26,8 +26,11 @@
 
 #include "config.h"
 
-#include <math.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <gsl/gsl_fft_real.h>
+#include <math.h>
+#include <unistd.h>
 
 #include "igt_audio.h"
 #include "igt_core.h"
@@ -128,7 +131,7 @@ int audio_signal_add_frequency(struct audio_signal *signal, int frequency)
  */
 void audio_signal_synthesize(struct audio_signal *signal)
 {
-	short *period;
+	int16_t *period;
 	double value;
 	int frames;
 	int freq;
@@ -145,9 +148,9 @@ void audio_signal_synthesize(struct audio_signal *signal)
 
 		for (j = 0; j < frames; j++) {
 			value = 2.0 * M_PI * freq / signal->sampling_rate * j;
-			value = sin(value) * SHRT_MAX / signal->freqs_count;
+			value = sin(value) * INT16_MAX / signal->freqs_count;
 
-			period[j] = (short) value;
+			period[j] = (int16_t) value;
 		}
 
 		signal->freqs[i].period = period;
@@ -186,17 +189,16 @@ void audio_signal_clean(struct audio_signal *signal)
  * 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)
+void audio_signal_fill(struct audio_signal *signal, int16_t *buffer, int frames)
 {
-	short *destination;
-	short *source;
+	int16_t *destination, *source;
 	int total;
 	int freq_frames;
 	int freq_offset;
 	int count;
 	int i, j, k;
 
-	memset(buffer, 0, sizeof(short) * signal->channels * frames);
+	memset(buffer, 0, sizeof(int16_t) * signal->channels * frames);
 
 	for (i = 0; i < signal->freqs_count; i++) {
 		total = 0;
@@ -229,97 +231,236 @@ void audio_signal_fill(struct audio_signal *signal, short *buffer, int frames)
 }
 
 /**
- * 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.
+ * Checks that frequencies specified in signal, and only those, are included
+ * in the input data.
  *
- * Returns: A boolean indicating whether the detection was successful
+ * sampling_rate is given in Hz. data_len is the number of elements in data.
  */
-bool audio_signal_detect(struct audio_signal *signal, int channels,
-			 int sampling_rate, short *buffer, int frames)
+bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
+			 double *data, size_t data_len)
 {
-	double data[frames];
-	int amplitude[frames / 2];
+	size_t bin_power_len = data_len / 2 + 1;
+	double bin_power[bin_power_len];
 	bool detected[signal->freqs_count];
-	int threshold;
-	bool above;
-	int error;
-	int freq = 0;
-	int max;
-	int c, i, j;
+	int ret, freq_accuracy, freq, local_max_freq;
+	double max, local_max, threshold;
+	size_t i, j;
+	bool above, success;
+
+	/* Allowed error in Hz due to FFT step */
+	freq_accuracy = sampling_rate / data_len;
+	igt_debug("Allowed freq. error: %d Hz\n", freq_accuracy);
+
+	ret = gsl_fft_real_radix2_transform(data, 1, data_len);
+	igt_assert(ret == 0);
+
+	/* Compute the power received by every bin of the FFT, and record the
+	 * maximum power received as a way to normalize all the others.
+	 *
+	 * For i < data_len / 2, the real part of the i-th term is stored at
+	 * data[i] and its imaginary part is stored at data[data_len - i].
+	 * i = 0 and i = data_len / 2 are special cases, they are purely real
+	 * so their imaginary part isn't stored.
+	 *
+	 * The power is encoded as the magnitude of the complex number and the
+	 * phase is encoded as its angle.
+	 */
+	max = 0;
+	bin_power[0] = data[0];
+	for (i = 1; i < bin_power_len - 1; i++) {
+		bin_power[i] = hypot(data[i], data[data_len - i]);
+		if (bin_power[i] > max)
+			max = bin_power[i];
+	}
+	bin_power[bin_power_len - 1] = data[data_len / 2];
+
+	for (i = 0; i < signal->freqs_count; i++)
+		detected[i] = false;
+
+	/* Do a linear search through the FFT bins' power to find the the local
+	 * maximums that exceed half of the absolute maximum that we previously
+	 * calculated.
+	 *
+	 * Since the frequencies might not be perfectly aligned with the bins of
+	 * the FFT, we need to find the local maximum across some consecutive
+	 * bins. Once the power returns under the power threshold, we compare
+	 * the frequency of the bin that received the maximum power to the
+	 * expected frequencies. If found, we mark this frequency as such,
+	 * otherwise we warn that an unexpected frequency was found.
+	 */
+	threshold = max / 2;
+	success = true;
+	above = false;
+	local_max = 0;
+	local_max_freq = -1;
+	for (i = 0; i < bin_power_len; i++) {
+		freq = sampling_rate * i / data_len;
+
+		if (bin_power[i] > threshold)
+			above = true;
+
+		if (!above) {
+			continue;
+		}
 
-	/* Allowed error in Hz due to FFT step. */
-	error = sampling_rate / frames;
+		/* If we were above the threshold and we're not anymore, it's
+		 * time to decide whether the peak frequency is correct or
+		 * invalid. */
+		if (bin_power[i] < threshold) {
+			for (j = 0; j < signal->freqs_count; j++) {
+				if (signal->freqs[j].freq >
+				    local_max_freq - freq_accuracy &&
+				    signal->freqs[j].freq <
+				    local_max_freq + freq_accuracy) {
+					detected[j] = true;
+					igt_debug("Frequency %d detected\n",
+						  local_max_freq);
+					break;
+				}
+			}
 
-	for (c = 0; c < channels; c++) {
-		for (i = 0; i < frames; i++)
-			data[i] = (double) buffer[i * channels + c];
+			/* We haven't generated this frequency, but we detected
+			 * it. */
+			if (j == signal->freqs_count) {
+				igt_debug("Detected additional frequency: %d\n",
+					  local_max_freq);
+				success = false;
+			}
 
-		gsl_fft_real_radix2_transform(data, 1, frames);
+			above = false;
+			local_max = 0;
+			local_max_freq = -1;
+		}
 
-		max = 0;
+		if (bin_power[i] > local_max) {
+			local_max = bin_power[i];
+			local_max_freq = freq;
+		}
+	}
 
-		for (i = 0; i < frames / 2; i++) {
-			amplitude[i] = hypot(data[i], data[frames - i]);
-			if (amplitude[i] > max)
-				max = amplitude[i];
+	/* Check that all frequencies we generated have been detected. */
+	for (i = 0; i < signal->freqs_count; i++) {
+		if (!detected[i]) {
+			igt_debug("Missing frequency: %d\n",
+				  signal->freqs[i].freq);
+			success = false;
 		}
+	}
 
-		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;
-					}
-				}
+	return success;
+}
 
-				if (amplitude[i] > max) {
-					max = amplitude[i];
-					freq = sampling_rate * i / frames;
-				}
-			}
-		}
+/**
+ * Extracts a single channel from a multi-channel S32_LE input buffer.
+ */
+size_t audio_extract_channel_s32_le(double *dst, size_t dst_cap,
+				    int32_t *src, size_t src_len,
+				    int n_channels, int channel)
+{
+	size_t dst_len, i;
 
-		for (i = 0; i < signal->freqs_count; i++) {
-			if (!detected[i]) {
-				igt_debug("Missing frequency: %d\n",
-					  signal->freqs[i].freq);
-				return false;
-			}
-		}
+	igt_assert(channel < n_channels);
+	igt_assert(src_len % n_channels == 0);
+	dst_len = src_len / n_channels;
+	igt_assert(dst_len <= dst_cap);
+	for (i = 0; i < dst_len; i++)
+		dst[i] = (double) src[i * n_channels + channel];
+
+	return dst_len;
+}
+
+#define RIFF_TAG "RIFF"
+#define WAVE_TAG "WAVE"
+#define FMT_TAG "fmt "
+#define DATA_TAG "data"
+
+static void
+append_to_buffer(char *dst, size_t *i, const void *src, size_t src_size)
+{
+	memcpy(&dst[*i], src, src_size);
+	*i += src_size;
+}
+
+/**
+ * audio_create_wav_file_s32_le:
+ * @qualifier: the basename of the file (the test name will be prepended, and
+ * the file extension will be appended)
+ * @sample_rate: the sample rate in Hz
+ * @channels: the number of channels
+ * @path: if non-NULL, will be set to a pointer to the new file path (the
+ * caller is responsible for free-ing it)
+ *
+ * Creates a new WAV file.
+ *
+ * After calling this function, the caller is expected to write S32_LE PCM data
+ * to the returned file descriptor.
+ *
+ * See http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html for
+ * a WAV file format specification.
+ *
+ * Returns: a file descriptor to the newly created file, or -1 on error.
+ */
+int audio_create_wav_file_s32_le(const char *qualifier, uint32_t sample_rate,
+				 uint16_t channels, char **path)
+{
+	char _path[PATH_MAX];
+	const char *test_name, *subtest_name;
+	int fd;
+	char header[44];
+	size_t i = 0;
+	uint32_t file_size, chunk_size, byte_rate;
+	uint16_t format, block_align, bits_per_sample;
+
+	test_name = igt_test_name();
+	subtest_name = igt_subtest_name();
+
+	igt_assert(igt_frame_dump_path);
+	snprintf(_path, sizeof(_path), "%s/audio-%s-%s-%s.wav",
+		 igt_frame_dump_path, test_name, subtest_name, qualifier);
+
+	if (path)
+		*path = strdup(_path);
+
+	igt_debug("Dumping %s audio to %s\n", qualifier, _path);
+	fd = open(_path, O_WRONLY | O_CREAT | O_TRUNC);
+	if (fd < 0) {
+		igt_warn("open failed: %s\n", strerror(errno));
+		return -1;
+	}
+
+	/* File header */
+	file_size = UINT32_MAX; /* unknown file size */
+	append_to_buffer(header, &i, RIFF_TAG, strlen(RIFF_TAG));
+	append_to_buffer(header, &i, &file_size, sizeof(file_size));
+	append_to_buffer(header, &i, WAVE_TAG, strlen(WAVE_TAG));
+
+	/* Format chunk */
+	chunk_size = 16;
+	format = 1; /* PCM */
+	bits_per_sample = 32; /* S32_LE */
+	byte_rate = sample_rate * channels * bits_per_sample / 8;
+	block_align = channels * bits_per_sample / 8;
+	append_to_buffer(header, &i, FMT_TAG, strlen(FMT_TAG));
+	append_to_buffer(header, &i, &chunk_size, sizeof(chunk_size));
+	append_to_buffer(header, &i, &format, sizeof(format));
+	append_to_buffer(header, &i, &channels, sizeof(channels));
+	append_to_buffer(header, &i, &sample_rate, sizeof(sample_rate));
+	append_to_buffer(header, &i, &byte_rate, sizeof(byte_rate));
+	append_to_buffer(header, &i, &block_align, sizeof(block_align));
+	append_to_buffer(header, &i, &bits_per_sample, sizeof(bits_per_sample));
+
+	/* Data chunk */
+	chunk_size = UINT32_MAX; /* unknown chunk size */
+	append_to_buffer(header, &i, DATA_TAG, strlen(DATA_TAG));
+	append_to_buffer(header, &i, &chunk_size, sizeof(chunk_size));
+
+	igt_assert(i == sizeof(header));
+
+	if (write(fd, header, sizeof(header)) != sizeof(header)) {
+		igt_warn("write failed: %s'n", strerror(errno));
+		close(fd);
+		return -1;
 	}
 
-	return true;
+	return fd;
 }
diff --git a/lib/igt_audio.h b/lib/igt_audio.h
index b3b658a4..4aa43e69 100644
--- a/lib/igt_audio.h
+++ b/lib/igt_audio.h
@@ -30,6 +30,7 @@
 #include "config.h"
 
 #include <stdbool.h>
+#include <stdint.h>
 
 struct audio_signal;
 
@@ -37,8 +38,13 @@ 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);
+void audio_signal_fill(struct audio_signal *signal, int16_t *buffer, int frames);
+bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
+			 double *data, size_t data_len);
+size_t audio_extract_channel_s32_le(double *dst, size_t dst_cap,
+				    int32_t *src, size_t src_len,
+				    int n_channels, int channel);
+int audio_create_wav_file_s32_le(const char *qualifier, uint32_t sample_rate,
+				 uint16_t channels, char **path);
 
 #endif
diff --git a/lib/igt_aux.c b/lib/igt_aux.c
index 05528352..3dd68d95 100644
--- a/lib/igt_aux.c
+++ b/lib/igt_aux.c
@@ -1259,6 +1259,37 @@ void igt_set_module_param_int(const char *name, int val)
 	igt_set_module_param(name, str);
 }
 
+/**
+ * igt_is_process_running:
+ * @comm: Name of process in the form found in /proc/pid/comm (limited to 15
+ * chars)
+ *
+ * Returns: true in case the process has been found, false otherwise.
+ *
+ * This function checks in the process table for an entry with the name @comm.
+ */
+int igt_is_process_running(const char *comm)
+{
+	PROCTAB *proc;
+	proc_t *proc_info;
+	bool found = false;
+
+	proc = openproc(PROC_FILLCOM | PROC_FILLSTAT);
+	igt_assert(proc != NULL);
+
+	while ((proc_info = readproc(proc, NULL))) {
+		if (!strncasecmp(proc_info->cmd, comm, sizeof(proc_info->cmd))) {
+			freeproc(proc_info);
+			found = true;
+			break;
+		}
+		freeproc(proc_info);
+	}
+
+	closeproc(proc);
+	return found;
+}
+
 /**
  * igt_terminate_process:
  * @sig: Signal to send
diff --git a/lib/igt_aux.h b/lib/igt_aux.h
index 55392790..dbd88b67 100644
--- a/lib/igt_aux.h
+++ b/lib/igt_aux.h
@@ -279,6 +279,7 @@ bool igt_allow_unlimited_files(void);
 void igt_set_module_param(const char *name, const char *val);
 void igt_set_module_param_int(const char *name, int val);
 
+int igt_is_process_running(const char *comm);
 int igt_terminate_process(int sig, const char *comm);
 void igt_lsof(const char *dpath);
 
diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index 02cc9b2c..7c9030d1 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -218,6 +218,12 @@ void chamelium_destroy_frame_dump(struct chamelium_frame_dump *dump)
 	free(dump);
 }
 
+void chamelium_destroy_audio_file(struct chamelium_audio_file *audio_file)
+{
+	free(audio_file->path);
+	free(audio_file);
+}
+
 struct fsm_monitor_args {
 	struct chamelium *chamelium;
 	struct chamelium_port *port;
@@ -924,6 +930,101 @@ int chamelium_get_captured_frame_count(struct chamelium *chamelium)
 	return ret;
 }
 
+/**
+ * chamelium_start_capturing_audio:
+ * @chamelium: the Chamelium instance
+ * @port: the port to capture audio from (it must support audio)
+ * @save_to_file: whether the captured audio data should be saved to a file on
+ * the Chamelium device
+ *
+ * Starts capturing audio from a Chamelium port. To stop the capture, use
+ * #chamelium_stop_capturing_audio. To retrieve the audio data, either use the
+ * stream server or enable @save_to_file (the latter is mainly useful for
+ * debugging purposes).
+ *
+ * It isn't possible to capture audio from multiple ports at the same time.
+ */
+void chamelium_start_capturing_audio(struct chamelium *chamelium,
+				    struct chamelium_port *port,
+				    bool save_to_file)
+{
+	xmlrpc_value *res;
+
+	res = chamelium_rpc(chamelium, port, "StartCapturingAudio", "(ib)",
+			    port->id, save_to_file);
+	xmlrpc_DECREF(res);
+}
+
+static void audio_format_from_xml(struct chamelium *chamelium,
+				  xmlrpc_value *res, int *rate, int *channels)
+{
+	xmlrpc_value *res_type, *res_rate, *res_sample_format, *res_channel;
+	char *type, *sample_format;
+
+	xmlrpc_struct_find_value(&chamelium->env, res, "file_type", &res_type);
+	xmlrpc_struct_find_value(&chamelium->env, res, "rate", &res_rate);
+	xmlrpc_struct_find_value(&chamelium->env, res, "sample_format", &res_sample_format);
+	xmlrpc_struct_find_value(&chamelium->env, res, "channel", &res_channel);
+
+	xmlrpc_read_string(&chamelium->env, res_type, (const char **) &type);
+	igt_assert(strcmp(type, "raw") == 0);
+	free(type);
+
+	xmlrpc_read_string(&chamelium->env, res_sample_format, (const char **) &sample_format);
+	igt_assert(strcmp(sample_format, "S32_LE") == 0);
+	free(sample_format);
+
+	xmlrpc_read_int(&chamelium->env, res_rate, rate);
+	xmlrpc_read_int(&chamelium->env, res_channel, channels);
+
+	xmlrpc_DECREF(res_channel);
+	xmlrpc_DECREF(res_sample_format);
+	xmlrpc_DECREF(res_rate);
+	xmlrpc_DECREF(res_type);
+}
+
+/**
+ * chamelium_stop_capturing_audio:
+ * @chamelium: the Chamelium instance
+ * @port: the port from which audio is being captured
+ *
+ * Stops capturing audio from a Chamelium port. If
+ * #chamelium_start_capturing_audio has been called with @save_to_file enabled,
+ * this function will return a #chamelium_audio_file struct containing details
+ * about the audio file. Once the caller is done with the struct, they should
+ * release it with #chamelium_destroy_audio_file.
+ */
+struct chamelium_audio_file *chamelium_stop_capturing_audio(struct chamelium *chamelium,
+							    struct chamelium_port *port)
+{
+	xmlrpc_value *res, *res_path, *res_props;
+	struct chamelium_audio_file *file = NULL;
+	char *path;
+
+	res = chamelium_rpc(chamelium, NULL, "StopCapturingAudio", "(i)",
+			    port->id);
+	xmlrpc_array_read_item(&chamelium->env, res, 0, &res_path);
+	xmlrpc_array_read_item(&chamelium->env, res, 1, &res_props);
+
+	xmlrpc_read_string(&chamelium->env, res_path, (const char **) &path);
+
+	if (strlen(path) > 0) {
+		file = calloc(1, sizeof(*file));
+		file->path = path;
+
+		audio_format_from_xml(chamelium, res_props,
+				      &file->rate, &file->channels);
+	} else {
+		free(path);
+	}
+
+	xmlrpc_DECREF(res_props);
+	xmlrpc_DECREF(res_path);
+	xmlrpc_DECREF(res);
+
+	return file;
+}
+
 static pixman_image_t *convert_frame_format(pixman_image_t *src,
 					    int format)
 {
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index 233ead85..047f8c5d 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -53,6 +53,12 @@ enum chamelium_check {
 	CHAMELIUM_CHECK_CRC,
 };
 
+struct chamelium_audio_file {
+	char *path;
+	int rate; /* Hz */
+	int channels;
+};
+
 struct chamelium *chamelium_init(int drm_fd);
 void chamelium_deinit(struct chamelium *chamelium);
 void chamelium_reset(struct chamelium *chamelium);
@@ -100,6 +106,10 @@ void chamelium_start_capture(struct chamelium *chamelium,
 void chamelium_stop_capture(struct chamelium *chamelium, int frame_count);
 void chamelium_capture(struct chamelium *chamelium, struct chamelium_port *port,
 		       int x, int y, int w, int h, int frame_count);
+void chamelium_start_capturing_audio(struct chamelium *chamelium,
+				    struct chamelium_port *port, bool save_to_file);
+struct chamelium_audio_file *chamelium_stop_capturing_audio(struct chamelium *chamelium,
+							    struct chamelium_port *port);
 igt_crc_t *chamelium_read_captured_crcs(struct chamelium *chamelium,
 					int *frame_count);
 struct chamelium_frame_dump *chamelium_read_captured_frame(struct chamelium *chamelium,
@@ -131,5 +141,6 @@ void chamelium_assert_frame_match_or_dump(struct chamelium *chamelium,
 void chamelium_crop_analog_frame(struct chamelium_frame_dump *dump, int width,
 				 int height);
 void chamelium_destroy_frame_dump(struct chamelium_frame_dump *dump);
+void chamelium_destroy_audio_file(struct chamelium_audio_file *audio_file);
 
 #endif /* IGT_CHAMELIUM_H */
diff --git a/lib/igt_chamelium_stream.c b/lib/igt_chamelium_stream.c
new file mode 100644
index 00000000..68ddb217
--- /dev/null
+++ b/lib/igt_chamelium_stream.c
@@ -0,0 +1,589 @@
+/*
+ * Copyright © 2019 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: Simon Ser <simon.ser@intel.com>
+ */
+
+#include "config.h"
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "igt_chamelium_stream.h"
+#include "igt_core.h"
+#include "igt_rc.h"
+
+#define STREAM_PORT 9994
+#define STREAM_VERSION_MAJOR 1
+#define STREAM_VERSION_MINOR 0
+
+enum stream_error {
+	STREAM_ERROR_NONE = 0,
+	STREAM_ERROR_COMMAND = 1,
+	STREAM_ERROR_ARGUMENT = 2,
+	STREAM_ERROR_EXISTS = 3,
+	STREAM_ERROR_VIDEO_MEM_OVERFLOW_STOP = 4,
+	STREAM_ERROR_VIDEO_MEM_OVERFLOW_DROP = 5,
+	STREAM_ERROR_AUDIO_MEM_OVERFLOW_STOP = 6,
+	STREAM_ERROR_AUDIO_MEM_OVERFLOW_DROP = 7,
+	STREAM_ERROR_NO_MEM = 8,
+};
+
+enum stream_message_kind {
+	STREAM_MESSAGE_REQUEST = 0,
+	STREAM_MESSAGE_RESPONSE = 1,
+	STREAM_MESSAGE_DATA = 2,
+};
+
+enum stream_message_type {
+	STREAM_MESSAGE_RESET = 0,
+	STREAM_MESSAGE_GET_VERSION = 1,
+	STREAM_MESSAGE_VIDEO_STREAM = 2,
+	STREAM_MESSAGE_SHRINK_VIDEO = 3,
+	STREAM_MESSAGE_VIDEO_FRAME = 4,
+	STREAM_MESSAGE_DUMP_REALTIME_VIDEO = 5,
+	STREAM_MESSAGE_STOP_DUMP_VIDEO = 6,
+	STREAM_MESSAGE_DUMP_REALTIME_AUDIO = 7,
+	STREAM_MESSAGE_STOP_DUMP_AUDIO = 8,
+};
+
+struct chamelium_stream {
+	char *host;
+	unsigned int port;
+
+	int fd;
+};
+
+static const char *stream_error_str(enum stream_error err)
+{
+	switch (err) {
+	case STREAM_ERROR_NONE:
+		return "no error";
+	case STREAM_ERROR_COMMAND:
+		return "invalid command";
+	case STREAM_ERROR_ARGUMENT:
+		return "invalid arguments";
+	case STREAM_ERROR_EXISTS:
+		return "dump already started";
+	case STREAM_ERROR_VIDEO_MEM_OVERFLOW_STOP:
+		return "video dump stopped after overflow";
+	case STREAM_ERROR_VIDEO_MEM_OVERFLOW_DROP:
+		return "video frame dropped after overflow";
+	case STREAM_ERROR_AUDIO_MEM_OVERFLOW_STOP:
+		return "audio dump stoppred after overflow";
+	case STREAM_ERROR_AUDIO_MEM_OVERFLOW_DROP:
+		return "audio page dropped after overflow";
+	case STREAM_ERROR_NO_MEM:
+		return "out of memory";
+	}
+	return "unknown error";
+}
+
+/**
+ * The Chamelium URL is specified in the configuration file. We need to extract
+ * the host to connect to the stream server.
+ */
+static char *parse_url_host(const char *url)
+{
+	static const char prefix[] = "http://";
+	char *colon;
+
+	if (strstr(url, prefix) != url)
+		return NULL;
+	url += strlen(prefix);
+
+	colon = strchr(url, ':');
+	if (!colon)
+		return NULL;
+
+	return strndup(url, colon - url);
+}
+
+static bool chamelium_stream_read_config(struct chamelium_stream *client)
+{
+	GError *error = NULL;
+	gchar *chamelium_url;
+
+	if (!igt_key_file) {
+		igt_warn("No configuration file available for chamelium\n");
+		return false;
+	}
+
+	chamelium_url = g_key_file_get_string(igt_key_file, "Chamelium", "URL",
+					      &error);
+	if (!chamelium_url) {
+		igt_warn("Couldn't read Chamelium URL from config file: %s\n",
+			 error->message);
+		return false;
+	}
+
+	client->host = parse_url_host(chamelium_url);
+	if (!client->host) {
+		igt_warn("Invalid Chamelium URL in config file: %s\n",
+			 chamelium_url);
+		return false;
+	}
+	client->port = STREAM_PORT;
+
+	return true;
+}
+
+static bool chamelium_stream_connect(struct chamelium_stream *client)
+{
+	int ret;
+	char port_str[16];
+	struct addrinfo hints = {};
+	struct addrinfo *results, *ai;
+	struct timeval tv = {};
+
+	igt_debug("Connecting to Chamelium stream server: tcp://%s:%u\n",
+		  client->host, client->port);
+
+	snprintf(port_str, sizeof(port_str), "%u", client->port);
+
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	ret = getaddrinfo(client->host, port_str, &hints, &results);
+	if (ret != 0) {
+		igt_warn("getaddrinfo failed: %s\n", gai_strerror(ret));
+		return false;
+	}
+
+	client->fd = -1;
+	for (ai = results; ai != NULL; ai = ai->ai_next) {
+		client->fd = socket(ai->ai_family, ai->ai_socktype,
+				    ai->ai_protocol);
+		if (client->fd == -1)
+			continue;
+
+		if (connect(client->fd, ai->ai_addr, ai->ai_addrlen) == -1) {
+			close(client->fd);
+			client->fd = -1;
+			continue;
+		}
+
+		break;
+	}
+
+	freeaddrinfo(results);
+
+	if (client->fd < 0) {
+		igt_warn("Failed to connect to Chamelium stream server\n");
+		return false;
+	}
+
+	/* Set a read and write timeout of 5 seconds. */
+	tv.tv_sec = 5;
+	setsockopt(client->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+	setsockopt(client->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+
+	return true;
+}
+
+static bool read_whole(int fd, void *buf, size_t buf_len)
+{
+	ssize_t ret;
+	size_t n = 0;
+	char *ptr;
+
+	while (n < buf_len) {
+		ptr = (char *) buf + n;
+		ret = read(fd, ptr, buf_len - n);
+		if (ret < 0) {
+			igt_warn("read failed: %s\n", strerror(errno));
+			return false;
+		} else if (ret == 0) {
+			igt_warn("short read\n");
+			return false;
+		}
+		n += ret;
+	}
+
+	return true;
+}
+
+static bool write_whole(int fd, void *buf, size_t buf_len)
+{
+	ssize_t ret;
+	size_t n = 0;
+	char *ptr;
+
+	while (n < buf_len) {
+		ptr = (char *) buf + n;
+		ret = write(fd, ptr, buf_len - n);
+		if (ret < 0) {
+			igt_warn("write failed: %s\n", strerror(errno));
+			return false;
+		} else if (ret == 0) {
+			igt_warn("short write\n");
+			return false;
+		}
+		n += ret;
+	}
+
+	return true;
+}
+
+static bool read_and_discard(int fd, size_t len)
+{
+	char buf[1024];
+	size_t n;
+
+	while (len > 0) {
+		n = len;
+		if (n > sizeof(buf))
+			n = sizeof(buf);
+
+		if (!read_whole(fd, buf, n))
+			return false;
+
+		len -= n;
+	}
+
+	return true;
+}
+
+/** Read a message header from the socket.
+ *
+ * The header is laid out as follows:
+ * - u16: message type
+ * - u16: error code
+ * - u32: message length
+ */
+static bool chamelium_stream_read_header(struct chamelium_stream *client,
+					 enum stream_message_kind *kind,
+					 enum stream_message_type *type,
+					 enum stream_error *err,
+					 size_t *len)
+{
+	uint16_t _type;
+	char buf[8];
+
+	if (!read_whole(client->fd, buf, sizeof(buf)))
+		return false;
+
+	_type = ntohs(*(uint16_t *) &buf[0]);
+	*type = _type & 0xFF;
+	*kind = _type >> 8;
+	*err = ntohs(*(uint16_t *) &buf[2]);
+	*len = ntohl(*(uint32_t *) &buf[4]);
+
+	return true;
+}
+
+static bool chamelium_stream_write_header(struct chamelium_stream *client,
+					  enum stream_message_type type,
+					  enum stream_error err,
+					  size_t len)
+{
+	char buf[8];
+	uint16_t _type;
+
+	_type = type | (STREAM_MESSAGE_REQUEST << 8);
+
+	*(uint16_t *) &buf[0] = htons(_type);
+	*(uint16_t *) &buf[2] = htons(err);
+	*(uint32_t *) &buf[4] = htonl(len);
+
+	return write_whole(client->fd, buf, sizeof(buf));
+}
+
+static bool chamelium_stream_read_response(struct chamelium_stream *client,
+					   enum stream_message_type type,
+					   void *buf, size_t buf_len)
+{
+	enum stream_message_kind read_kind;
+	enum stream_message_type read_type;
+	enum stream_error read_err;
+	size_t read_len;
+
+	if (!chamelium_stream_read_header(client, &read_kind, &read_type,
+					  &read_err, &read_len))
+		return false;
+
+	if (read_kind != STREAM_MESSAGE_RESPONSE) {
+		igt_warn("Expected a response, got kind %d\n", read_kind);
+		return false;
+	}
+	if (read_type != type) {
+		igt_warn("Expected message type %d, got %d\n",
+			 type, read_type);
+		return false;
+	}
+	if (read_err != STREAM_ERROR_NONE) {
+		igt_warn("Received error: %s (%d)\n",
+			 stream_error_str(read_err), read_err);
+		return false;
+	}
+	if (buf_len != read_len) {
+		igt_warn("Received invalid message body size "
+			 "(got %zu bytes, want %zu bytes)\n",
+			 read_len, buf_len);
+		return false;
+	}
+
+	return read_whole(client->fd, buf, buf_len);
+}
+
+static bool chamelium_stream_write_request(struct chamelium_stream *client,
+					   enum stream_message_type type,
+					   void *buf, size_t buf_len)
+{
+	if (!chamelium_stream_write_header(client, type, STREAM_ERROR_NONE,
+					   buf_len))
+		return false;
+
+	if (buf_len == 0)
+		return true;
+
+	return write_whole(client->fd, buf, buf_len);
+}
+
+static bool chamelium_stream_call(struct chamelium_stream *client,
+				  enum stream_message_type type,
+				  void *req_buf, size_t req_len,
+				  void *resp_buf, size_t resp_len)
+{
+	if (!chamelium_stream_write_request(client, type, req_buf, req_len))
+		return false;
+
+	return chamelium_stream_read_response(client, type, resp_buf, resp_len);
+}
+
+static bool chamelium_stream_check_version(struct chamelium_stream *client)
+{
+	char resp[2];
+	uint8_t major, minor;
+
+	if (!chamelium_stream_call(client, STREAM_MESSAGE_GET_VERSION,
+				   NULL, 0, resp, sizeof(resp)))
+		return false;
+
+	major = resp[0];
+	minor = resp[1];
+	if (major != STREAM_VERSION_MAJOR || minor < STREAM_VERSION_MINOR) {
+		igt_warn("Version mismatch (want %d.%d, got %d.%d)\n",
+			 STREAM_VERSION_MAJOR, STREAM_VERSION_MINOR,
+			 major, minor);
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * chamelium_stream_dump_realtime_audio:
+ *
+ * Starts audio capture. The caller can then call
+ * #chamelium_stream_receive_realtime_audio to receive audio pages.
+ */
+bool chamelium_stream_dump_realtime_audio(struct chamelium_stream *client,
+					  enum chamelium_stream_realtime_mode mode)
+{
+	char req[1];
+
+	igt_debug("Starting real-time audio capture\n");
+
+	req[0] = mode;
+	return chamelium_stream_call(client, STREAM_MESSAGE_DUMP_REALTIME_AUDIO,
+				     req, sizeof(req), NULL, 0);
+}
+
+/**
+ * chamelium_stream_receive_realtime_audio:
+ * @page_count: if non-NULL, will be set to the dumped page number
+ * @buf: must either point to a dynamically allocated memory region or NULL
+ * @buf_len: number of elements of *@buf, for zero if @buf is NULL
+ *
+ * Receives one audio page from the streaming server.
+ *
+ * In "best effort" mode, some pages can be dropped. This can be detected via
+ * the page count.
+ *
+ * buf_len will be set to the size of the page. The caller is responsible for
+ * calling free(3) on *buf.
+ */
+bool chamelium_stream_receive_realtime_audio(struct chamelium_stream *client,
+					     size_t *page_count,
+					     int32_t **buf, size_t *buf_len)
+{
+	enum stream_message_kind kind;
+	enum stream_message_type type;
+	enum stream_error err;
+	size_t body_len;
+	char page_count_buf[4];
+	int32_t *ptr;
+
+	while (true) {
+		if (!chamelium_stream_read_header(client, &kind, &type,
+						  &err, &body_len))
+			return false;
+
+		if (kind != STREAM_MESSAGE_DATA) {
+			igt_warn("Expected a data message, got kind %d\n", kind);
+			return false;
+		}
+		if (type != STREAM_MESSAGE_DUMP_REALTIME_AUDIO) {
+			igt_warn("Expected real-time audio dump message, "
+				 "got type %d\n", type);
+			return false;
+		}
+
+		if (err == STREAM_ERROR_NONE)
+			break;
+		else if (err != STREAM_ERROR_AUDIO_MEM_OVERFLOW_DROP) {
+			igt_warn("Received error: %s (%d)\n",
+				 stream_error_str(err), err);
+			return false;
+		}
+
+		igt_debug("Dropped an audio page because of an overflow\n");
+		igt_assert(body_len == 0);
+	}
+
+	igt_assert(body_len >= sizeof(page_count_buf));
+
+	if (!read_whole(client->fd, page_count_buf, sizeof(page_count_buf)))
+		return false;
+	if (page_count)
+		*page_count = ntohl(*(uint32_t *) &page_count_buf[0]);
+	body_len -= sizeof(page_count_buf);
+
+	igt_assert(body_len % sizeof(int32_t) == 0);
+	if (*buf_len * sizeof(int32_t) != body_len) {
+		ptr = realloc(*buf, body_len);
+		if (!ptr) {
+			igt_warn("realloc failed: %s\n", strerror(errno));
+			return false;
+		}
+		*buf = ptr;
+		*buf_len = body_len / sizeof(int32_t);
+	}
+
+	return read_whole(client->fd, *buf, body_len);
+}
+
+/**
+ * chamelium_stream_stop_realtime_audio:
+ *
+ * Stops real-time audio capture. This also drops any buffered audio pages.
+ * The caller shouldn't call #chamelium_stream_receive_realtime_audio after
+ * stopping audio capture.
+ */
+bool chamelium_stream_stop_realtime_audio(struct chamelium_stream *client)
+{
+	enum stream_message_kind kind;
+	enum stream_message_type type;
+	enum stream_error err;
+	size_t len;
+
+	igt_debug("Stopping real-time audio capture\n");
+
+	if (!chamelium_stream_write_request(client,
+					    STREAM_MESSAGE_STOP_DUMP_AUDIO,
+					    NULL, 0))
+		return false;
+
+	while (true) {
+		if (!chamelium_stream_read_header(client, &kind, &type,
+						  &err, &len))
+			return false;
+
+		if (kind == STREAM_MESSAGE_RESPONSE)
+			break;
+
+		if (!read_and_discard(client->fd, len))
+			return false;
+	}
+
+	if (type != STREAM_MESSAGE_STOP_DUMP_AUDIO) {
+		igt_warn("Unexpected response type %d\n", type);
+		return false;
+	}
+	if (err != STREAM_ERROR_NONE) {
+		igt_warn("Received error: %s (%d)\n",
+			 stream_error_str(err), err);
+		return false;
+	}
+	if (len != 0) {
+		igt_warn("Expected an empty response, got %zu bytes\n", len);
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * chamelium_stream_audio_format:
+ *
+ * Gets the format used for audio pages.
+ *
+ * Data will always be captured in raw pages of S32_LE elements. This function
+ * exposes the sampling rate and the number of channels.
+ */
+void chamelium_stream_audio_format(struct chamelium_stream *stream,
+				   int *rate, int *channels)
+{
+	/* TODO: the Chamelium streaming server doesn't expose those yet.
+	 * Just hardcode the values for now. */
+	*rate = 48000;
+	*channels = 8;
+}
+
+/**
+ * chamelium_stream_init:
+ *
+ * Connects to the Chamelium streaming server.
+ */
+struct chamelium_stream *chamelium_stream_init(void)
+{
+	struct chamelium_stream *client;
+
+	client = calloc(1, sizeof(*client));
+
+	if (!chamelium_stream_read_config(client))
+		goto error_client;
+	if (!chamelium_stream_connect(client))
+		goto error_client;
+	if (!chamelium_stream_check_version(client))
+		goto error_fd;
+
+	return client;
+
+error_fd:
+	close(client->fd);
+error_client:
+	free(client);
+	return NULL;
+}
+
+void chamelium_stream_deinit(struct chamelium_stream *client)
+{
+	if (close(client->fd) != 0)
+		igt_warn("close failed: %s\n", strerror(errno));
+	free(client);
+}
diff --git a/lib/igt_chamelium_stream.h b/lib/igt_chamelium_stream.h
new file mode 100644
index 00000000..de4e9931
--- /dev/null
+++ b/lib/igt_chamelium_stream.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2019 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: Simon Ser <simon.ser@intel.com>
+ */
+
+#ifndef IGT_CHAMELIUM_STREAM_H
+#define IGT_CHAMELIUM_STREAM_H
+
+#include "config.h"
+
+enum chamelium_stream_realtime_mode {
+	CHAMELIUM_STREAM_REALTIME_NONE = 0,
+	/* stop dumping when overflow */
+	CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW = 1,
+	/* drop data on overflow */
+	CHAMELIUM_STREAM_REALTIME_BEST_EFFORT = 2,
+};
+
+struct chamelium_stream;
+
+struct chamelium_stream *chamelium_stream_init(void);
+void chamelium_stream_deinit(struct chamelium_stream *client);
+bool chamelium_stream_dump_realtime_audio(struct chamelium_stream *client,
+					  enum chamelium_stream_realtime_mode mode);
+void chamelium_stream_audio_format(struct chamelium_stream *stream,
+				   int *rate, int *channels);
+bool chamelium_stream_receive_realtime_audio(struct chamelium_stream *client,
+					     size_t *page_count,
+					     int32_t **buf, size_t *buf_len);
+bool chamelium_stream_stop_realtime_audio(struct chamelium_stream *client);
+
+#endif
diff --git a/lib/meson.build b/lib/meson.build
index 20c0e3e6..16e1ae21 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -93,7 +93,7 @@ if valgrind.found()
 endif
 
 if gsl.found()
-	lib_deps += [ gsl ]
+	lib_deps += gsl
 	lib_sources += [ 'igt_frame.c', 'igt_audio.c' ]
 endif
 
@@ -102,9 +102,10 @@ if alsa.found()
 	lib_sources += 'igt_alsa.c'
 endif
 
-if chamelium.found()
+if chamelium_found
 	lib_deps += chamelium
 	lib_sources += 'igt_chamelium.c'
+	lib_sources += 'igt_chamelium_stream.c'
 endif
 
 srcdir = join_paths(meson.source_root(), 'tests')
diff --git a/meson.build b/meson.build
index 557400a5..be6dff9d 100644
--- a/meson.build
+++ b/meson.build
@@ -64,8 +64,6 @@ _build_overlay = false
 _overlay_required = false
 _build_man = false
 _man_required = false
-_build_audio = false
-_audio_required = false
 _build_chamelium = false
 _chamelium_required = false
 _build_docs = false
@@ -79,7 +77,6 @@ build_overlay = get_option('build_overlay')
 overlay_backends = get_option('overlay_backends')
 build_man = get_option('build_man')
 with_valgrind = get_option('with_valgrind')
-build_audio = get_option('build_audio')
 build_chamelium = get_option('build_chamelium')
 build_docs = get_option('build_docs')
 build_tests = get_option('build_tests')
@@ -91,8 +88,6 @@ _build_overlay = build_overlay != 'false'
 _overlay_required = build_overlay == 'true'
 _build_man = build_man != 'false'
 _man_required = build_man == 'true'
-_build_audio = build_audio != 'false'
-_audio_required = build_audio == 'true'
 _build_chamelium = build_chamelium != 'false'
 _chamelium_required = build_chamelium == 'true'
 _build_docs = build_docs != 'false'
@@ -166,26 +161,6 @@ cairo = dependency('cairo', version : '>1.12.0', required : true)
 libudev = dependency('libudev', required : true)
 glib = dependency('glib-2.0', required : true)
 
-gsl = null_dep
-alsa = null_dep
-if _build_audio or _build_chamelium
-	gsl = dependency('gsl', required : _audio_required or _chamelium_required)
-endif
-if _build_audio
-	alsa = dependency('alsa', required : _audio_required)
-endif
-
-audioinfo = 'No'
-if _build_audio and alsa.found() and gsl.found()
-	audioinfo = 'Yes'
-else
-	if _audio_required
-		error('Cannot build audio test due to missing dependencies')
-	endif
-	_build_audio = false
-endif
-build_info += 'Build audio test: ' + audioinfo
-
 xmlrpc = dependency('xmlrpc', required : false)
 xmlrpc_util = dependency('xmlrpc_util', required : false)
 xmlrpc_client = dependency('xmlrpc_client', required : false)
@@ -197,21 +172,32 @@ if not xmlrpc.found() and xmlrpc_cmd.found()
 
 	if libs_cmd.returncode() == 0 and cflags_cmd.returncode() == 0
 		xmlrpc = declare_dependency(compile_args: cflags_cmd.stdout().strip().split(),
-					   link_args : libs_cmd.stdout().strip().split())
+					    link_args : libs_cmd.stdout().strip().split())
 		xmlrpc_util = declare_dependency()
 		xmlrpc_client = declare_dependency()
 	endif
 endif
 
+gsl = null_dep
+alsa = null_dep
 chamelium = null_dep
+chamelium_found = false # TODO: use a disabler object instead
 chameliuminfo = 'No'
-if _build_chamelium and gsl.found() and xmlrpc.found() and xmlrpc_util.found() and xmlrpc_client.found()
-	chamelium = declare_dependency(dependencies : [ xmlrpc,
-							xmlrpc_util, xmlrpc_client])
-	config.set('HAVE_CHAMELIUM', 1)
-	chameliuminfo = 'Yes'
-elif _chamelium_required
-	error('Cannot build chamelium test due to missing dependencies')
+if _build_chamelium
+	gsl = dependency('gsl', required : _chamelium_required)
+	alsa = dependency('alsa', required : _chamelium_required)
+	chamelium = declare_dependency(dependencies : [
+		xmlrpc,
+		xmlrpc_util,
+		xmlrpc_client,
+		gsl,
+		alsa,
+	], required : _chamelium_required)
+	if xmlrpc.found() and xmlrpc_util.found() and xmlrpc_client.found() and gsl.found() and alsa.found()
+		config.set('HAVE_CHAMELIUM', 1)
+		chameliuminfo = 'Yes'
+		chamelium_found = true
+	endif
 endif
 build_info += 'Build Chamelium test: ' + chameliuminfo
 
diff --git a/meson_options.txt b/meson_options.txt
index 0cd3b350..888efe56 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -10,12 +10,6 @@ option('overlay_backends',
        choices : [ 'auto', 'x', 'xv' ],
        description : 'Overlay backends to enable')
 
-option('build_audio',
-       type : 'combo',
-       value : 'auto',
-       choices : ['auto', 'true', 'false'],
-       description : 'Build audio test')
-
 option('build_chamelium',
        type : 'combo',
        value : 'auto',
diff --git a/tests/audio.c b/tests/audio.c
deleted file mode 100644
index 560876a3..00000000
--- a/tests/audio.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * 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_input(data.alsa, CAPTURE_DEVICE_NAME);
-	igt_assert(ret >= 0);
-
-	alsa_configure_input(data.alsa, CAPTURE_CHANNELS,
-			     CAPTURE_SAMPLE_RATE);
-
-	alsa_register_input_callback(data.alsa, input_callback, &data,
-				     CAPTURE_FRAMES);
-
-	for (i = 0; i < sampling_rates_count; i++) {
-		ret = alsa_open_output(data.alsa, device_name);
-		igt_assert(ret >= 0);
-
-		sampling_rate = sampling_rates[i];
-
-		test = alsa_test_output_configuration(data.alsa,
-						      PLAYBACK_CHANNELS,
-						      sampling_rate);
-		if (!test) {
-			alsa_close_output(data.alsa);
-			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);
-
-		data.streak = 0;
-
-		ret = alsa_run(data.alsa, RUN_TIMEOUT);
-		igt_assert(ret > 0);
-
-		audio_signal_clean(data.signal);
-		free(data.signal);
-
-		alsa_close_output(data.alsa);
-
-		run = true;
-	}
-
-	/* Make sure we tested at least one frequency */
-	igt_assert(run);
-
-	alsa_close_input(data.alsa);
-	free(data.alsa);
-}
-
-static void test_suspend_resume_integrity(const char *device_name,
-					  enum igt_suspend_state state,
-					  enum igt_suspend_test test)
-{
-	test_integrity(device_name);
-
-	igt_system_suspend_autoresume(state, test);
-
-	test_integrity(device_name);
-}
-
-igt_main
-{
-	igt_subtest("hdmi-integrity")
-		test_integrity("HDMI");
-
-	igt_subtest("hdmi-integrity-after-suspend")
-		test_suspend_resume_integrity("HDMI", SUSPEND_STATE_MEM,
-					      SUSPEND_TEST_NONE);
-
-	igt_subtest("hdmi-integrity-after-hibernate")
-		test_suspend_resume_integrity("HDMI", SUSPEND_STATE_DISK,
-					      SUSPEND_TEST_DEVICES);
-}
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index 2dc1049d..a712250a 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -413,7 +413,7 @@ test_suspend_resume_edid_change(data_t *data, struct chamelium_port *port,
 
 static igt_output_t *
 prepare_output(data_t *data,
-	       struct chamelium_port *port)
+	       struct chamelium_port *port, bool set_edid)
 {
 	igt_display_t *display = &data->display;
 	igt_output_t *output;
@@ -428,7 +428,8 @@ prepare_output(data_t *data,
 	/* The chamelium's default EDID has a lot of resolutions, way more then
 	 * we need to test
 	 */
-	chamelium_port_set_edid(data->chamelium, port, data->edid_id);
+	if (set_edid)
+		chamelium_port_set_edid(data->chamelium, port, data->edid_id);
 
 	chamelium_plug(data->chamelium, port);
 	wait_for_connector(data, port, DRM_MODE_CONNECTED);
@@ -613,7 +614,7 @@ static void test_display_one_mode(data_t *data, struct chamelium_port *port,
 
 	reset_state(data, port);
 
-	output = prepare_output(data, port);
+	output = prepare_output(data, port, true);
 	connector = chamelium_port_get_connector(data->chamelium, port, false);
 	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
 	igt_assert(primary);
@@ -644,7 +645,7 @@ static void test_display_all_modes(data_t *data, struct chamelium_port *port,
 
 	reset_state(data, port);
 
-	output = prepare_output(data, port);
+	output = prepare_output(data, port, true);
 	connector = chamelium_port_get_connector(data->chamelium, port, false);
 	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
 	igt_assert(primary);
@@ -679,7 +680,7 @@ test_display_frame_dump(data_t *data, struct chamelium_port *port)
 
 	reset_state(data, port);
 
-	output = prepare_output(data, port);
+	output = prepare_output(data, port, true);
 	connector = chamelium_port_get_connector(data->chamelium, port, false);
 	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
 	igt_assert(primary);
@@ -710,6 +711,266 @@ test_display_frame_dump(data_t *data, struct chamelium_port *port)
 	drmModeFreeConnector(connector);
 }
 
+
+/* Playback parameters control the audio signal we synthesize and send */
+#define PLAYBACK_CHANNELS 2
+#define PLAYBACK_SAMPLES 1024
+
+/* Capture paremeters control the audio signal we receive */
+#define CAPTURE_SAMPLES 2048
+
+#define AUDIO_DURATION 2000 /* ms */
+/* A streak of 3 gives confidence that the signal is good. */
+#define MIN_STREAK 3
+
+/* TODO: Chamelium only supports 48KHz for now */
+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 audio_signal *signal = (struct audio_signal *) data;
+
+	audio_signal_fill(signal, buffer, frames);
+
+	return 0;
+}
+
+static bool
+do_test_display_audio(data_t *data, struct chamelium_port *port,
+		      struct alsa *alsa, int playback_channels,
+		      int playback_rate)
+{
+	int ret, capture_rate, capture_channels, msec;
+	struct chamelium_audio_file *audio_file;
+	struct chamelium_stream *stream;
+	enum chamelium_stream_realtime_mode stream_mode;
+	struct audio_signal *signal;
+	int32_t *recv, *buf;
+	double *channel;
+	size_t i, streak, page_count;
+	size_t recv_len, buf_len, buf_cap, buf_size, channel_len;
+	bool ok;
+	char dump_suffix[64];
+	char *dump_path = NULL;
+	int dump_fd = -1;
+
+	if (!alsa_test_output_configuration(alsa, playback_channels,
+					    playback_rate))
+		return false;
+
+	igt_debug("Testing with playback sampling rate %d\n", playback_rate);
+	alsa_configure_output(alsa, playback_channels, playback_rate);
+
+	chamelium_start_capturing_audio(data->chamelium, port, false);
+
+	stream = chamelium_stream_init();
+	igt_assert(stream);
+
+	stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
+	ok = chamelium_stream_dump_realtime_audio(stream, stream_mode);
+	igt_assert(ok);
+
+	chamelium_stream_audio_format(stream, &capture_rate, &capture_channels);
+
+	if (igt_frame_dump_is_enabled()) {
+		snprintf(dump_suffix, sizeof(dump_suffix), "capture-%dch-%d",
+			 playback_channels, playback_rate);
+
+		dump_fd = audio_create_wav_file_s32_le(dump_suffix,
+						       capture_rate,
+						       capture_channels,
+						       &dump_path);
+		igt_assert(dump_fd >= 0);
+	}
+
+	signal = audio_signal_init(playback_channels, playback_rate);
+	igt_assert(signal);
+
+	for (i = 0; i < test_frequencies_count; i++)
+		audio_signal_add_frequency(signal, test_frequencies[i]);
+	audio_signal_synthesize(signal);
+
+	alsa_register_output_callback(alsa, output_callback, signal,
+				      PLAYBACK_SAMPLES);
+
+	/* TODO: detect signal in real-time */
+	ret = alsa_run(alsa, AUDIO_DURATION);
+	igt_assert(ret == 0);
+
+	alsa_close_output(alsa);
+
+	/* Needs to be a multiple of 128, because that's the number of samples
+	 * we get per channel each time we receive an audio page from the
+	 * Chamelium device. */
+	channel_len = CAPTURE_SAMPLES;
+	channel = malloc(sizeof(double) * channel_len);
+
+	buf_cap = capture_channels * channel_len;
+	buf = malloc(sizeof(int32_t) * buf_cap);
+	buf_len = 0;
+
+	recv = NULL;
+	recv_len = 0;
+
+	streak = 0;
+	msec = 0;
+	i = 0;
+	while (streak < MIN_STREAK && msec < AUDIO_DURATION) {
+		ok = chamelium_stream_receive_realtime_audio(stream,
+							     &page_count,
+							     &recv, &recv_len);
+		igt_assert(ok);
+
+		memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
+		buf_len += recv_len;
+
+		if (buf_len < buf_cap)
+			continue;
+		igt_assert(buf_len == buf_cap);
+
+		if (dump_fd >= 0) {
+			buf_size = buf_len * sizeof(int32_t);
+			igt_assert(write(dump_fd, buf, buf_size) == buf_size);
+		}
+
+		/* TODO: check other channels too, not just the first one */
+		audio_extract_channel_s32_le(channel, channel_len, buf, buf_len,
+					     capture_channels, 0);
+
+		msec = i * channel_len / (double) capture_rate * 1000;
+		igt_debug("Detecting audio signal, t=%d msec\n", msec);
+
+		if (audio_signal_detect(signal, capture_rate, channel,
+					channel_len))
+			streak++;
+		else
+			streak = 0;
+
+		buf_len = 0;
+		i++;
+	}
+
+	if (dump_fd >= 0) {
+		close(dump_fd);
+		if (streak == MIN_STREAK) {
+			/* Test succeeded, no need to keep the captured data */
+			unlink(dump_path);
+		} else
+			igt_debug("Saved captured audio data to %s\n", dump_path);
+		free(dump_path);
+	}
+
+	free(recv);
+	free(buf);
+	free(channel);
+
+	ok = chamelium_stream_stop_realtime_audio(stream);
+	igt_assert(ok);
+
+	audio_file = chamelium_stop_capturing_audio(data->chamelium,
+						    port);
+	if (audio_file) {
+		igt_debug("Audio file saved on the Chamelium in %s\n",
+			  audio_file->path);
+		chamelium_destroy_audio_file(audio_file);
+	}
+
+	audio_signal_clean(signal);
+	free(signal);
+
+	chamelium_stream_deinit(stream);
+
+	igt_assert(streak == MIN_STREAK);
+	return true;
+}
+
+static void
+test_display_audio(data_t *data, struct chamelium_port *port,
+		   const char *audio_device)
+{
+	bool run = false;
+	struct alsa *alsa;
+	int ret;
+	igt_output_t *output;
+	igt_plane_t *primary;
+	struct igt_fb fb;
+	drmModeModeInfo *mode;
+	drmModeConnector *connector;
+	int fb_id, i;
+
+	igt_require(alsa_has_exclusive_access());
+
+	alsa = alsa_init();
+	igt_assert(alsa);
+
+	reset_state(data, port);
+
+	/* Use the default Chamelium EDID for this test, as the base IGT EDID
+	 * doesn't advertise audio support (see drm_detect_monitor_audio in
+	 * the kernel tree). */
+	output = prepare_output(data, port, false);
+	connector = chamelium_port_get_connector(data->chamelium, port, false);
+	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	/* Enable the output because the receiver won't try to receive audio if
+	 * it doesn't receive video. */
+	igt_assert(connector->count_modes > 0);
+	mode = &connector->modes[0];
+
+	fb_id = igt_create_color_pattern_fb(data->drm_fd,
+					    mode->hdisplay, mode->vdisplay,
+					    DRM_FORMAT_XRGB8888,
+					    LOCAL_DRM_FORMAT_MOD_NONE,
+					    0, 0, 0, &fb);
+	igt_assert(fb_id > 0);
+
+	enable_output(data, port, output, mode, &fb);
+
+	for (i = 0; i < sampling_rates_count; i++) {
+		ret = alsa_open_output(alsa, audio_device);
+		igt_assert(ret >= 0);
+
+		/* TODO: playback on all 8 available channels */
+		run |= do_test_display_audio(data, port, alsa,
+					     PLAYBACK_CHANNELS,
+					     sampling_rates[i]);
+
+		alsa_close_output(alsa);
+	}
+
+	/* Make sure we tested at least one frequency. */
+	igt_assert(run);
+
+	igt_remove_fb(data->drm_fd, &fb);
+
+	drmModeFreeConnector(connector);
+
+	free(alsa);
+}
+
+
 static void select_tiled_modifier(igt_plane_t *plane, uint32_t width,
 				  uint32_t height, uint32_t format,
 				  uint64_t *modifier)
@@ -1037,7 +1298,7 @@ static void test_display_planes_random(data_t *data,
 	reset_state(data, port);
 
 	/* Find the connector and pipe. */
-	output = prepare_output(data, port);
+	output = prepare_output(data, port, true);
 
 	mode = igt_output_get_mode(output);
 
@@ -1308,6 +1569,9 @@ igt_main
 
 		connector_subtest("dp-frame-dump", DisplayPort)
 			test_display_frame_dump(&data, port);
+
+		connector_subtest("dp-audio", DisplayPort)
+			test_display_audio(&data, port, "HDMI");
 	}
 
 	igt_subtest_group {
diff --git a/tests/meson.build b/tests/meson.build
index e3c8b07f..711979b4 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -239,20 +239,13 @@ if libdrm_nouveau.found()
 	test_deps += libdrm_nouveau
 endif
 
-if _build_chamelium and chamelium.found()
+if chamelium_found
 	test_progs += [
 		'kms_chamelium',
 	]
 	test_deps += chamelium
 endif
 
-if _build_audio and alsa.found() and gsl.found()
-	test_progs += [
-		'audio',
-	]
-	test_deps += alsa
-endif
-
 test_executables = []
 test_list = []
 
-- 
2.21.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [igt-dev] [PATCH i-g-t v6 2/7] tests/kms_chamelium: capture audio data in real-time
  2019-04-17 12:43 [igt-dev] [PATCH i-g-t v6 0/7] tests/kms_chamelium: add dp-audio test Simon Ser
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 1/7] " Simon Ser
@ 2019-04-17 12:43 ` Simon Ser
  2019-04-17 12:57   ` Martin Peres
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 3/7] tests/kms_chamelium: test we receive a signal from both audio channels Simon Ser
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 22+ messages in thread
From: Simon Ser @ 2019-04-17 12:43 UTC (permalink / raw)
  To: igt-dev

Before this patch, the audio test first sends an audio signal for 2s, and then
checks whether the captured signal matches.

This patch makes it so we send and check the signal in parallel. Thus we can
stop the test as soon as we receive the correct signal. This saves ~2s per
audio test.

Signed-off-by: Simon Ser <simon.ser@intel.com>
---
 lib/igt_alsa.c        | 15 +++++++-------
 tests/kms_chamelium.c | 47 +++++++++++++++++++++++++++++++++----------
 2 files changed, 43 insertions(+), 19 deletions(-)

diff --git a/lib/igt_alsa.c b/lib/igt_alsa.c
index 22089881..fc6d336b 100644
--- a/lib/igt_alsa.c
+++ b/lib/igt_alsa.c
@@ -497,7 +497,8 @@ void alsa_register_input_callback(struct alsa *alsa,
 /**
  * alsa_run:
  * @alsa: The target alsa structure
- * @duration_ms: The maximum duration of the run in milliseconds
+ * @duration_ms: The maximum duration of the run in milliseconds, or -1 for an
+ * infinite duration.
  *
  * Run ALSA playback and capture on the input and output devices for at
  * most @duration_ms milliseconds, calling the registered callbacks when needed.
@@ -545,7 +546,7 @@ int alsa_run(struct alsa *alsa, int duration_ms)
 	do {
 		reached = true;
 
-		if (output_total < output_limit) {
+		if (output_limit < 0 || output_total < output_limit) {
 			reached = false;
 
 			if (!output_ready) {
@@ -607,7 +608,8 @@ int alsa_run(struct alsa *alsa, int duration_ms)
 
 		}
 
-		if (alsa->input_callback && input_total < input_limit) {
+		if (alsa->input_callback &&
+		    (input_limit < 0 || input_total < input_limit)) {
 			reached = false;
 
 			if (input_count == input_trigger) {
@@ -660,11 +662,8 @@ int alsa_run(struct alsa *alsa, int duration_ms)
 	ret = 0;
 
 complete:
-	if (output_buffer)
-		free(output_buffer);
-
-	if (input_buffer)
-		free(input_buffer);
+	free(output_buffer);
+	free(input_buffer);
 
 	return ret;
 }
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index a712250a..014a22b3 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -29,7 +29,9 @@
 #include "igt_vc4.h"
 
 #include <fcntl.h>
+#include <pthread.h>
 #include <string.h>
+#include <stdatomic.h>
 
 typedef struct {
 	struct chamelium *chamelium;
@@ -719,7 +721,7 @@ test_display_frame_dump(data_t *data, struct chamelium_port *port)
 /* Capture paremeters control the audio signal we receive */
 #define CAPTURE_SAMPLES 2048
 
-#define AUDIO_DURATION 2000 /* ms */
+#define AUDIO_TIMEOUT 2000 /* ms */
 /* A streak of 3 gives confidence that the signal is good. */
 #define MIN_STREAK 3
 
@@ -746,14 +748,28 @@ static int test_frequencies[] = {
 
 static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
 
+struct audio_state {
+	struct audio_signal *signal;
+	atomic_bool run;
+};
+
 static int
-output_callback(void *data, short *buffer, int frames)
+audio_output_callback(void *data, short *buffer, int frames)
 {
-	struct audio_signal *signal = (struct audio_signal *) data;
+	struct audio_state *state = data;
+
+	audio_signal_fill(state->signal, buffer, frames);
 
-	audio_signal_fill(signal, buffer, frames);
+	return state->run ? 0 : -1;
+}
+
+static void *
+run_audio_thread(void *data)
+{
+	struct alsa *alsa = data;
 
-	return 0;
+	alsa_run(alsa, -1);
+	return NULL;
 }
 
 static bool
@@ -774,6 +790,8 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 	char dump_suffix[64];
 	char *dump_path = NULL;
 	int dump_fd = -1;
+	pthread_t thread;
+	struct audio_state state = {};
 
 	if (!alsa_test_output_configuration(alsa, playback_channels,
 					    playback_rate))
@@ -811,15 +829,15 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 		audio_signal_add_frequency(signal, test_frequencies[i]);
 	audio_signal_synthesize(signal);
 
-	alsa_register_output_callback(alsa, output_callback, signal,
+	state.signal = signal;
+	state.run = true;
+	alsa_register_output_callback(alsa, audio_output_callback, &state,
 				      PLAYBACK_SAMPLES);
 
-	/* TODO: detect signal in real-time */
-	ret = alsa_run(alsa, AUDIO_DURATION);
+	/* Start playing audio */
+	ret = pthread_create(&thread, NULL, run_audio_thread, alsa);
 	igt_assert(ret == 0);
 
-	alsa_close_output(alsa);
-
 	/* Needs to be a multiple of 128, because that's the number of samples
 	 * we get per channel each time we receive an audio page from the
 	 * Chamelium device. */
@@ -836,7 +854,7 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 	streak = 0;
 	msec = 0;
 	i = 0;
-	while (streak < MIN_STREAK && msec < AUDIO_DURATION) {
+	while (streak < MIN_STREAK && msec < AUDIO_TIMEOUT) {
 		ok = chamelium_stream_receive_realtime_audio(stream,
 							     &page_count,
 							     &recv, &recv_len);
@@ -871,6 +889,13 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 		i++;
 	}
 
+	igt_debug("Stopping audio playback\n");
+	state.run = false;
+	ret = pthread_join(thread, NULL);
+	igt_assert(ret == 0);
+
+	alsa_close_output(alsa);
+
 	if (dump_fd >= 0) {
 		close(dump_fd);
 		if (streak == MIN_STREAK) {
-- 
2.21.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [igt-dev] [PATCH i-g-t v6 3/7] tests/kms_chamelium: test we receive a signal from both audio channels
  2019-04-17 12:43 [igt-dev] [PATCH i-g-t v6 0/7] tests/kms_chamelium: add dp-audio test Simon Ser
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 1/7] " Simon Ser
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 2/7] tests/kms_chamelium: capture audio data in real-time Simon Ser
@ 2019-04-17 12:43 ` Simon Ser
  2019-04-23  7:41   ` Martin Peres
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 4/7] tests/kms_chamelium: test audio channels are not mixed up Simon Ser
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 22+ messages in thread
From: Simon Ser @ 2019-04-17 12:43 UTC (permalink / raw)
  To: igt-dev

This commit updates the audio test to make sure we receive a signal from both
audio channels. However this commit doesn't check that left and right channels
are not swapped. Such a check requires some more work (because the Chamelium
device does swap left and right channels) and will be implemented in a future
commit.

This commit adds a new channel argument to audio_signal_add_frequency, to add
a frequency to a single channel only.

Some light refactoring has been performed (a proper audio_signal_deinit
function has been introduced) and logging has been improved.

Signed-off-by: Simon Ser <simon.ser@intel.com>
---
 lib/igt_alsa.c        |  26 +++++++--
 lib/igt_audio.c       | 119 +++++++++++++++++++++++++-----------------
 lib/igt_audio.h       |  11 ++--
 tests/kms_chamelium.c |  56 ++++++++++++--------
 4 files changed, 137 insertions(+), 75 deletions(-)

diff --git a/lib/igt_alsa.c b/lib/igt_alsa.c
index fc6d336b..a478686a 100644
--- a/lib/igt_alsa.c
+++ b/lib/igt_alsa.c
@@ -182,6 +182,8 @@ static char *alsa_resolve_indentifier(const char *device_name, int skip)
 					continue;
 				}
 
+				igt_debug("Matched device \"%s\"\n", pcm_name);
+
 				snprintf(name, sizeof(name), "hw:%d,%d", card,
 					 dev);
 
@@ -329,6 +331,9 @@ static bool alsa_test_configuration(snd_pcm_t *handle, int channels,
 {
 	snd_pcm_hw_params_t *params;
 	int ret;
+	unsigned int min_channels, max_channels;
+	unsigned int min_rate, max_rate;
+	int min_rate_dir, max_rate_dir;
 
 	snd_pcm_hw_params_alloca(&params);
 
@@ -337,12 +342,24 @@ static bool alsa_test_configuration(snd_pcm_t *handle, int channels,
 		return false;
 
 	ret = snd_pcm_hw_params_test_rate(handle, params, sampling_rate, 0);
-	if (ret < 0)
+	if (ret < 0) {
+		snd_pcm_hw_params_get_rate_min(params, &min_rate, &min_rate_dir);
+		snd_pcm_hw_params_get_rate_max(params, &max_rate, &max_rate_dir);
+		igt_debug("Output device supports rates between %u and %u, "
+			  "requested %d\n",
+			  min_rate, max_rate, sampling_rate);
 		return false;
+	}
 
 	ret = snd_pcm_hw_params_test_channels(handle, params, channels);
-	if (ret < 0)
+	if (ret < 0) {
+		snd_pcm_hw_params_get_channels_min(params, &min_channels);
+		snd_pcm_hw_params_get_channels_max(params, &max_channels);
+		igt_debug("Output device supports between %u and "
+			  "%u channels, requested %d\n",
+			  min_channels, max_channels, channels);
 		return false;
+	}
 
 	return true;
 }
@@ -409,13 +426,16 @@ void alsa_configure_output(struct alsa *alsa, int channels,
 	snd_pcm_t *handle;
 	int ret;
 	int i;
+	int soft_resample = 0; /* Don't allow ALSA to resample */
+	unsigned int latency = 0;
 
 	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);
+					 channels, sampling_rate,
+					 soft_resample, latency);
 		igt_assert(ret >= 0);
 	}
 
diff --git a/lib/igt_audio.c b/lib/igt_audio.c
index 7624f565..a2a5c594 100644
--- a/lib/igt_audio.c
+++ b/lib/igt_audio.c
@@ -35,7 +35,7 @@
 #include "igt_audio.h"
 #include "igt_core.h"
 
-#define FREQS_MAX	8
+#define FREQS_MAX 64
 
 /**
  * SECTION:igt_audio
@@ -49,9 +49,10 @@
 
 struct audio_signal_freq {
 	int freq;
+	int channel;
 
-	short *period;
-	int frames;
+	int16_t *period;
+	size_t period_len;
 	int offset;
 };
 
@@ -60,7 +61,7 @@ struct audio_signal {
 	int sampling_rate;
 
 	struct audio_signal_freq freqs[FREQS_MAX];
-	int freqs_count;
+	size_t freqs_count;
 };
 
 /**
@@ -89,21 +90,28 @@ struct audio_signal *audio_signal_init(int channels, int sampling_rate)
  * audio_signal_add_frequency:
  * @signal: The target signal structure
  * @frequency: The frequency to add to the signal
+ * @channel: The channel to add this frequency to, or -1 to add it to all
+ * channels
  *
  * 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 audio_signal_add_frequency(struct audio_signal *signal, int frequency,
+			       int channel)
 {
-	int index = signal->freqs_count;
+	size_t index = signal->freqs_count;
+	struct audio_signal_freq *freq;
 
-	if (index == FREQS_MAX)
-		return -1;
+	igt_assert(index < FREQS_MAX);
+	igt_assert(channel < signal->channels);
 
 	/* Stay within the Nyquist–Shannon sampling theorem. */
-	if (frequency > signal->sampling_rate / 2)
+	if (frequency > signal->sampling_rate / 2) {
+		igt_debug("Skipping frequency %d: too high for a %d Hz "
+			  "sampling rate\n", frequency, signal->sampling_rate);
 		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
@@ -111,11 +119,14 @@ int audio_signal_add_frequency(struct audio_signal *signal, int frequency)
 	 */
 	frequency = signal->sampling_rate / (signal->sampling_rate / frequency);
 
-	igt_debug("Adding test frequency %d\n", frequency);
+	igt_debug("Adding test frequency %d to channel %d\n",
+		  frequency, channel);
+
+	freq = &signal->freqs[index];
+	memset(freq, 0, sizeof(*freq));
+	freq->freq = frequency;
+	freq->channel = channel;
 
-	signal->freqs[index].freq = frequency;
-	signal->freqs[index].frames = 0;
-	signal->freqs[index].offset = 0;
 	signal->freqs_count++;
 
 	return 0;
@@ -133,20 +144,17 @@ void audio_signal_synthesize(struct audio_signal *signal)
 {
 	int16_t *period;
 	double value;
-	int frames;
+	size_t period_len;
 	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_len = signal->sampling_rate / freq;
 
-		period = calloc(1, frames * sizeof(short));
+		period = calloc(1, period_len * sizeof(int16_t));
 
-		for (j = 0; j < frames; j++) {
+		for (j = 0; j < period_len; j++) {
 			value = 2.0 * M_PI * freq / signal->sampling_rate * j;
 			value = sin(value) * INT16_MAX / signal->freqs_count;
 
@@ -154,26 +162,34 @@ void audio_signal_synthesize(struct audio_signal *signal)
 		}
 
 		signal->freqs[i].period = period;
-		signal->freqs[i].frames = frames;
+		signal->freqs[i].period_len = period_len;
 	}
 }
 
 /**
- * audio_signal_synthesize:
+ * audio_signal_deinit:
+ *
+ * Release the signal.
+ */
+void audio_signal_deinit(struct audio_signal *signal)
+{
+	audio_signal_reset(signal);
+	free(signal);
+}
+
+/**
+ * audio_signal_reset:
  * @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)
+void audio_signal_reset(struct audio_signal *signal)
 {
-	int i;
+	size_t 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));
+		free(signal->freqs[i].period);
 	}
 
 	signal->freqs_count = 0;
@@ -183,44 +199,45 @@ void audio_signal_clean(struct audio_signal *signal)
  * audio_signal_fill:
  * @signal: The target signal structure
  * @buffer: The target buffer to fill
- * @frames: The number of frames to fill
+ * @samples: The number of samples to fill
  *
- * Fill the requested number of frames to the target buffer with the audio
+ * Fill the requested number of samples 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, int16_t *buffer, int frames)
+void audio_signal_fill(struct audio_signal *signal, int16_t *buffer,
+		       size_t buffer_len)
 {
 	int16_t *destination, *source;
+	struct audio_signal_freq *freq;
 	int total;
-	int freq_frames;
-	int freq_offset;
 	int count;
 	int i, j, k;
 
-	memset(buffer, 0, sizeof(int16_t) * signal->channels * frames);
+	memset(buffer, 0, sizeof(int16_t) * signal->channels * buffer_len);
 
 	for (i = 0; i < signal->freqs_count; i++) {
+		freq = &signal->freqs[i];
 		total = 0;
 
-		while (total < frames) {
-			freq_frames = signal->freqs[i].frames;
-			freq_offset = signal->freqs[i].offset;
+		igt_assert(freq->period);
 
-			source = signal->freqs[i].period + freq_offset;
+		while (total < buffer_len) {
+			source = freq->period + freq->offset;
 			destination = buffer + total * signal->channels;
 
-			count = freq_frames - freq_offset;
-			if (count > (frames - total))
-				count = frames - total;
+			count = freq->period_len - freq->offset;
+			if (count > buffer_len - total)
+				count = buffer_len - total;
 
-			freq_offset += count;
-			freq_offset %= freq_frames;
-
-			signal->freqs[i].offset = freq_offset;
+			freq->offset += count;
+			freq->offset %= freq->period_len;
 
 			for (j = 0; j < count; j++) {
 				for (k = 0; k < signal->channels; k++) {
+					if (freq->channel >= 0 &&
+					    freq->channel != k)
+						continue;
 					destination[j * signal->channels + k] += source[j];
 				}
 			}
@@ -237,11 +254,11 @@ void audio_signal_fill(struct audio_signal *signal, int16_t *buffer, int frames)
  * sampling_rate is given in Hz. data_len is the number of elements in data.
  */
 bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
-			 double *data, size_t data_len)
+			 int channel, double *data, size_t data_len)
 {
 	size_t bin_power_len = data_len / 2 + 1;
 	double bin_power[bin_power_len];
-	bool detected[signal->freqs_count];
+	bool detected[FREQS_MAX];
 	int ret, freq_accuracy, freq, local_max_freq;
 	double max, local_max, threshold;
 	size_t i, j;
@@ -308,6 +325,10 @@ bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
 		 * invalid. */
 		if (bin_power[i] < threshold) {
 			for (j = 0; j < signal->freqs_count; j++) {
+				if (signal->freqs[j].channel >= 0 &&
+				    signal->freqs[j].channel != channel)
+					continue;
+
 				if (signal->freqs[j].freq >
 				    local_max_freq - freq_accuracy &&
 				    signal->freqs[j].freq <
@@ -340,6 +361,10 @@ bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
 
 	/* Check that all frequencies we generated have been detected. */
 	for (i = 0; i < signal->freqs_count; i++) {
+		if (signal->freqs[i].channel >= 0 &&
+		    signal->freqs[i].channel != channel)
+			continue;
+
 		if (!detected[i]) {
 			igt_debug("Missing frequency: %d\n",
 				  signal->freqs[i].freq);
diff --git a/lib/igt_audio.h b/lib/igt_audio.h
index 4aa43e69..fe26bb57 100644
--- a/lib/igt_audio.h
+++ b/lib/igt_audio.h
@@ -35,12 +35,15 @@
 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_deinit(struct audio_signal *signal);
+int audio_signal_add_frequency(struct audio_signal *signal, int frequency,
+			       int channel);
 void audio_signal_synthesize(struct audio_signal *signal);
-void audio_signal_clean(struct audio_signal *signal);
-void audio_signal_fill(struct audio_signal *signal, int16_t *buffer, int frames);
+void audio_signal_reset(struct audio_signal *signal);
+void audio_signal_fill(struct audio_signal *signal, int16_t *buffer,
+		       size_t buffer_len);
 bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
-			 double *data, size_t data_len);
+			 int channel, double *data, size_t data_len);
 size_t audio_extract_channel_s32_le(double *dst, size_t dst_cap,
 				    int32_t *src, size_t src_len,
 				    int n_channels, int channel);
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index 014a22b3..d336612f 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -777,16 +777,16 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 		      struct alsa *alsa, int playback_channels,
 		      int playback_rate)
 {
-	int ret, capture_rate, capture_channels, msec;
+	int ret, capture_rate, capture_channels, msec, freq;
 	struct chamelium_audio_file *audio_file;
 	struct chamelium_stream *stream;
 	enum chamelium_stream_realtime_mode stream_mode;
 	struct audio_signal *signal;
 	int32_t *recv, *buf;
 	double *channel;
-	size_t i, streak, page_count;
+	size_t i, j, streak, page_count;
 	size_t recv_len, buf_len, buf_cap, buf_size, channel_len;
-	bool ok;
+	bool ok, success;
 	char dump_suffix[64];
 	char *dump_path = NULL;
 	int dump_fd = -1;
@@ -794,10 +794,15 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 	struct audio_state state = {};
 
 	if (!alsa_test_output_configuration(alsa, playback_channels,
-					    playback_rate))
+					    playback_rate)) {
+		igt_debug("Skipping test with sample rate %d and %d channels "
+			  "because selected output devices don't support this "
+			  "configuration\n", playback_rate, playback_channels);
 		return false;
+	}
 
-	igt_debug("Testing with playback sampling rate %d\n", playback_rate);
+	igt_debug("Testing with playback sampling rate %d and %d channels\n",
+		  playback_rate, playback_channels);
 	alsa_configure_output(alsa, playback_channels, playback_rate);
 
 	chamelium_start_capturing_audio(data->chamelium, port, false);
@@ -825,8 +830,12 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 	signal = audio_signal_init(playback_channels, playback_rate);
 	igt_assert(signal);
 
-	for (i = 0; i < test_frequencies_count; i++)
-		audio_signal_add_frequency(signal, test_frequencies[i]);
+	for (i = 0; i < test_frequencies_count; i++) {
+		for (j = 0; j < playback_channels; j++) {
+			freq = test_frequencies[i];
+			audio_signal_add_frequency(signal, freq, j);
+		}
+	}
 	audio_signal_synthesize(signal);
 
 	state.signal = signal;
@@ -851,10 +860,11 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 	recv = NULL;
 	recv_len = 0;
 
+	success = false;
 	streak = 0;
 	msec = 0;
 	i = 0;
-	while (streak < MIN_STREAK && msec < AUDIO_TIMEOUT) {
+	while (!success && msec < AUDIO_TIMEOUT) {
 		ok = chamelium_stream_receive_realtime_audio(stream,
 							     &page_count,
 							     &recv, &recv_len);
@@ -872,21 +882,27 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 			igt_assert(write(dump_fd, buf, buf_size) == buf_size);
 		}
 
-		/* TODO: check other channels too, not just the first one */
-		audio_extract_channel_s32_le(channel, channel_len, buf, buf_len,
-					     capture_channels, 0);
-
 		msec = i * channel_len / (double) capture_rate * 1000;
 		igt_debug("Detecting audio signal, t=%d msec\n", msec);
 
-		if (audio_signal_detect(signal, capture_rate, channel,
-					channel_len))
-			streak++;
-		else
-			streak = 0;
+		for (j = 0; j < playback_channels; j++) {
+			igt_debug("Processing channel %zu\n", j);
+
+			audio_extract_channel_s32_le(channel, channel_len,
+						     buf, buf_len,
+						     capture_channels, j);
+
+			if (audio_signal_detect(signal, capture_rate, j,
+						channel, channel_len))
+				streak++;
+			else
+				streak = 0;
+		}
 
 		buf_len = 0;
 		i++;
+
+		success = streak == MIN_STREAK * playback_channels;
 	}
 
 	igt_debug("Stopping audio playback\n");
@@ -921,12 +937,10 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 		chamelium_destroy_audio_file(audio_file);
 	}
 
-	audio_signal_clean(signal);
-	free(signal);
-
+	audio_signal_deinit(signal);
 	chamelium_stream_deinit(stream);
 
-	igt_assert(streak == MIN_STREAK);
+	igt_assert(success);
 	return true;
 }
 
-- 
2.21.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [igt-dev] [PATCH i-g-t v6 4/7] tests/kms_chamelium: test audio channels are not mixed up
  2019-04-17 12:43 [igt-dev] [PATCH i-g-t v6 0/7] tests/kms_chamelium: add dp-audio test Simon Ser
                   ` (2 preceding siblings ...)
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 3/7] tests/kms_chamelium: test we receive a signal from both audio channels Simon Ser
@ 2019-04-17 12:43 ` Simon Ser
  2019-04-23  7:51   ` Martin Peres
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 5/7] tests/kms_chamelium: run audio test with multiple sampling rates Simon Ser
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 22+ messages in thread
From: Simon Ser @ 2019-04-17 12:43 UTC (permalink / raw)
  To: igt-dev

Send a different signal to each channel and make sure captured audio channels
are not swapped or mixed up.

The Chamelium device has a bug and already swaps the left and right channels.
For this reason, clients need to retrieve the Chamelium channel mapping and
accomodate for this. See https://crbug.com/950922 for a discussion about this.

Signed-off-by: Simon Ser <simon.ser@intel.com>
---
 lib/igt_chamelium.c   | 34 ++++++++++++++++++++++++++++++++++
 lib/igt_chamelium.h   |  3 +++
 tests/kms_chamelium.c | 37 +++++++++++++++++++++++++++++++------
 3 files changed, 68 insertions(+), 6 deletions(-)

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index 7c9030d1..6ac7b722 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -930,6 +930,40 @@ int chamelium_get_captured_frame_count(struct chamelium *chamelium)
 	return ret;
 }
 
+/**
+ * chamelium_get_audio_channel_mapping:
+ * @chamelium: the Chamelium instance
+ * @port: the audio port
+ * @mapping: will be filled with the channel mapping
+ *
+ * Obtains the channel mapping for an audio port.
+ *
+ * Audio channels are not guaranteed not to be swapped. Users can use the
+ * channel mapping to match an input channel to a capture channel.
+ *
+ * The mapping contains one element per capture channel. Each element indicates
+ * which input channel the capture channel is mapped to. As a special case, -1
+ * means that the channel isn't mapped.
+ */
+void chamelium_get_audio_channel_mapping(struct chamelium *chamelium,
+					 struct chamelium_port *port,
+					 int mapping[static 8])
+{
+	xmlrpc_value *res, *res_channel;
+	int res_len, i;
+
+	res = chamelium_rpc(chamelium, port, "GetAudioChannelMapping", "(i)",
+			    port->id);
+	res_len = xmlrpc_array_size(&chamelium->env, res);
+	igt_assert(res_len == 8);
+	for (i = 0; i < res_len; i++) {
+		xmlrpc_array_read_item(&chamelium->env, res, i, &res_channel);
+		xmlrpc_read_int(&chamelium->env, res_channel, &mapping[i]);
+		xmlrpc_DECREF(res_channel);
+	}
+	xmlrpc_DECREF(res);
+}
+
 /**
  * chamelium_start_capturing_audio:
  * @chamelium: the Chamelium instance
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index 047f8c5d..728d16ea 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -106,6 +106,9 @@ void chamelium_start_capture(struct chamelium *chamelium,
 void chamelium_stop_capture(struct chamelium *chamelium, int frame_count);
 void chamelium_capture(struct chamelium *chamelium, struct chamelium_port *port,
 		       int x, int y, int w, int h, int frame_count);
+void chamelium_get_audio_channel_mapping(struct chamelium *chamelium,
+					 struct chamelium_port *port,
+					 int mapping[static 8]);
 void chamelium_start_capturing_audio(struct chamelium *chamelium,
 				    struct chamelium_port *port, bool save_to_file);
 struct chamelium_audio_file *chamelium_stop_capturing_audio(struct chamelium *chamelium,
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index d336612f..8d6cc092 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -777,7 +777,7 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 		      struct alsa *alsa, int playback_channels,
 		      int playback_rate)
 {
-	int ret, capture_rate, capture_channels, msec, freq;
+	int ret, capture_rate, capture_channels, msec, freq, step;
 	struct chamelium_audio_file *audio_file;
 	struct chamelium_stream *stream;
 	enum chamelium_stream_realtime_mode stream_mode;
@@ -792,16 +792,17 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 	int dump_fd = -1;
 	pthread_t thread;
 	struct audio_state state = {};
+	int channel_mapping[8], capture_chan;
 
 	if (!alsa_test_output_configuration(alsa, playback_channels,
 					    playback_rate)) {
-		igt_debug("Skipping test with sample rate %d and %d channels "
+		igt_debug("Skipping test with sample rate %d Hz and %d channels "
 			  "because selected output devices don't support this "
 			  "configuration\n", playback_rate, playback_channels);
 		return false;
 	}
 
-	igt_debug("Testing with playback sampling rate %d and %d channels\n",
+	igt_debug("Testing with playback sampling rate %d Hz and %d channels\n",
 		  playback_rate, playback_channels);
 	alsa_configure_output(alsa, playback_channels, playback_rate);
 
@@ -830,9 +831,15 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 	signal = audio_signal_init(playback_channels, playback_rate);
 	igt_assert(signal);
 
+	/* We'll choose different frequencies per channel to make sure they are
+	 * independent from each other. To do so, we'll add a different offset
+	 * to the base frequencies for each channel. We need to choose a big
+	 * enough offset so that we're sure to detect mixed up channels.
+	 */
+	step = 2 * capture_rate / CAPTURE_SAMPLES;
 	for (i = 0; i < test_frequencies_count; i++) {
 		for (j = 0; j < playback_channels; j++) {
-			freq = test_frequencies[i];
+			freq = test_frequencies[i] + j * step;
 			audio_signal_add_frequency(signal, freq, j);
 		}
 	}
@@ -847,6 +854,20 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 	ret = pthread_create(&thread, NULL, run_audio_thread, alsa);
 	igt_assert(ret == 0);
 
+	chamelium_get_audio_channel_mapping(data->chamelium, port,
+					    channel_mapping);
+	/* Make sure we can capture all channels we send. */
+	for (i = 0; i < playback_channels; i++) {
+		ok = false;
+		for (j = 0; j < capture_channels; j++) {
+			if (channel_mapping[j] == i) {
+				ok = true;
+				break;
+			}
+		}
+		igt_assert(ok);
+	}
+
 	/* Needs to be a multiple of 128, because that's the number of samples
 	 * we get per channel each time we receive an audio page from the
 	 * Chamelium device. */
@@ -886,11 +907,15 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 		igt_debug("Detecting audio signal, t=%d msec\n", msec);
 
 		for (j = 0; j < playback_channels; j++) {
-			igt_debug("Processing channel %zu\n", j);
+			capture_chan = channel_mapping[j];
+			igt_assert(capture_chan >= 0);
+			igt_debug("Processing channel %zu (captured as "
+				  "channel %d)\n", j, capture_chan);
 
 			audio_extract_channel_s32_le(channel, channel_len,
 						     buf, buf_len,
-						     capture_channels, j);
+						     capture_channels,
+						     capture_chan);
 
 			if (audio_signal_detect(signal, capture_rate, j,
 						channel, channel_len))
-- 
2.21.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [igt-dev] [PATCH i-g-t v6 5/7] tests/kms_chamelium: run audio test with multiple sampling rates
  2019-04-17 12:43 [igt-dev] [PATCH i-g-t v6 0/7] tests/kms_chamelium: add dp-audio test Simon Ser
                   ` (3 preceding siblings ...)
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 4/7] tests/kms_chamelium: test audio channels are not mixed up Simon Ser
@ 2019-04-17 12:43 ` Simon Ser
  2019-04-23  7:58   ` Martin Peres
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 6/7] lib/igt_edid: add support for Short Audio Descriptors Simon Ser
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 22+ messages in thread
From: Simon Ser @ 2019-04-17 12:43 UTC (permalink / raw)
  To: igt-dev

The audio test is now run multiple times with a variety of playback sampling
rates.

We now query the capture audio format from the Chamelium XML-RPC API instead of
hardcoding it.

One limitation is that we need to start sendting an audio signal before being
able to query the capture audio format. However we need the capture sample rate
to decide which frequencies we generate. For now we use the playback rate and
check that it's the same as the capture rate.

Another limitation is that the DP receiver reports an unknown sampling rate
during the 41.1KHz test. In this case we assume the capture rate is the same as
the playback rate. We'll fail later anyway if this assumption is incorrect
since we check the signal we receive.

Chameleon bug: https://crbug.com/950913

Signed-off-by: Simon Ser <simon.ser@intel.com>
---
 lib/igt_chamelium.c        | 80 +++++++++++++++++++++++++-------------
 lib/igt_chamelium.h        |  3 ++
 lib/igt_chamelium_stream.c | 17 --------
 lib/igt_chamelium_stream.h |  2 -
 tests/kms_chamelium.c      | 56 +++++++++++++++-----------
 5 files changed, 90 insertions(+), 68 deletions(-)

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index 6ac7b722..ffc68f35 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -964,31 +964,6 @@ void chamelium_get_audio_channel_mapping(struct chamelium *chamelium,
 	xmlrpc_DECREF(res);
 }
 
-/**
- * chamelium_start_capturing_audio:
- * @chamelium: the Chamelium instance
- * @port: the port to capture audio from (it must support audio)
- * @save_to_file: whether the captured audio data should be saved to a file on
- * the Chamelium device
- *
- * Starts capturing audio from a Chamelium port. To stop the capture, use
- * #chamelium_stop_capturing_audio. To retrieve the audio data, either use the
- * stream server or enable @save_to_file (the latter is mainly useful for
- * debugging purposes).
- *
- * It isn't possible to capture audio from multiple ports at the same time.
- */
-void chamelium_start_capturing_audio(struct chamelium *chamelium,
-				    struct chamelium_port *port,
-				    bool save_to_file)
-{
-	xmlrpc_value *res;
-
-	res = chamelium_rpc(chamelium, port, "StartCapturingAudio", "(ib)",
-			    port->id, save_to_file);
-	xmlrpc_DECREF(res);
-}
-
 static void audio_format_from_xml(struct chamelium *chamelium,
 				  xmlrpc_value *res, int *rate, int *channels)
 {
@@ -1008,8 +983,10 @@ static void audio_format_from_xml(struct chamelium *chamelium,
 	igt_assert(strcmp(sample_format, "S32_LE") == 0);
 	free(sample_format);
 
-	xmlrpc_read_int(&chamelium->env, res_rate, rate);
-	xmlrpc_read_int(&chamelium->env, res_channel, channels);
+	if (rate)
+		xmlrpc_read_int(&chamelium->env, res_rate, rate);
+	if (channels)
+		xmlrpc_read_int(&chamelium->env, res_channel, channels);
 
 	xmlrpc_DECREF(res_channel);
 	xmlrpc_DECREF(res_sample_format);
@@ -1017,6 +994,55 @@ static void audio_format_from_xml(struct chamelium *chamelium,
 	xmlrpc_DECREF(res_type);
 }
 
+/**
+ * chamelium_get_audio_format:
+ * @chamelium: the Chamelium instance
+ * @port: the audio port
+ * @rate: if non-NULL, will be set to the sample rate in Hz
+ * @channels: if non-NULL, will be set to the number of channels
+ *
+ * Obtains the audio format of the captured data. Users should start sending an
+ * audio signal to the Chamelium device prior to calling this function.
+ *
+ * The captured data is guaranteed to be in the S32_LE format.
+ */
+void chamelium_get_audio_format(struct chamelium *chamelium,
+				struct chamelium_port *port,
+				int *rate, int *channels)
+{
+	xmlrpc_value *res;
+
+	res = chamelium_rpc(chamelium, port, "GetAudioFormat", "(i)",
+			    port->id);
+	audio_format_from_xml(chamelium, res, rate, channels);
+	xmlrpc_DECREF(res);
+}
+
+/**
+ * chamelium_start_capturing_audio:
+ * @chamelium: the Chamelium instance
+ * @port: the port to capture audio from (it must support audio)
+ * @save_to_file: whether the captured audio data should be saved to a file on
+ * the Chamelium device
+ *
+ * Starts capturing audio from a Chamelium port. To stop the capture, use
+ * #chamelium_stop_capturing_audio. To retrieve the audio data, either use the
+ * stream server or enable @save_to_file (the latter is mainly useful for
+ * debugging purposes).
+ *
+ * It isn't possible to capture audio from multiple ports at the same time.
+ */
+void chamelium_start_capturing_audio(struct chamelium *chamelium,
+				    struct chamelium_port *port,
+				    bool save_to_file)
+{
+	xmlrpc_value *res;
+
+	res = chamelium_rpc(chamelium, port, "StartCapturingAudio", "(ib)",
+			    port->id, save_to_file);
+	xmlrpc_DECREF(res);
+}
+
 /**
  * chamelium_stop_capturing_audio:
  * @chamelium: the Chamelium instance
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index 728d16ea..f47b84cb 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -109,6 +109,9 @@ void chamelium_capture(struct chamelium *chamelium, struct chamelium_port *port,
 void chamelium_get_audio_channel_mapping(struct chamelium *chamelium,
 					 struct chamelium_port *port,
 					 int mapping[static 8]);
+void chamelium_get_audio_format(struct chamelium *chamelium,
+				struct chamelium_port *port,
+				int *rate, int *channels);
 void chamelium_start_capturing_audio(struct chamelium *chamelium,
 				    struct chamelium_port *port, bool save_to_file);
 struct chamelium_audio_file *chamelium_stop_capturing_audio(struct chamelium *chamelium,
diff --git a/lib/igt_chamelium_stream.c b/lib/igt_chamelium_stream.c
index 68ddb217..a8cd19e5 100644
--- a/lib/igt_chamelium_stream.c
+++ b/lib/igt_chamelium_stream.c
@@ -537,23 +537,6 @@ bool chamelium_stream_stop_realtime_audio(struct chamelium_stream *client)
 	return true;
 }
 
-/**
- * chamelium_stream_audio_format:
- *
- * Gets the format used for audio pages.
- *
- * Data will always be captured in raw pages of S32_LE elements. This function
- * exposes the sampling rate and the number of channels.
- */
-void chamelium_stream_audio_format(struct chamelium_stream *stream,
-				   int *rate, int *channels)
-{
-	/* TODO: the Chamelium streaming server doesn't expose those yet.
-	 * Just hardcode the values for now. */
-	*rate = 48000;
-	*channels = 8;
-}
-
 /**
  * chamelium_stream_init:
  *
diff --git a/lib/igt_chamelium_stream.h b/lib/igt_chamelium_stream.h
index de4e9931..3e1c5d14 100644
--- a/lib/igt_chamelium_stream.h
+++ b/lib/igt_chamelium_stream.h
@@ -42,8 +42,6 @@ struct chamelium_stream *chamelium_stream_init(void);
 void chamelium_stream_deinit(struct chamelium_stream *client);
 bool chamelium_stream_dump_realtime_audio(struct chamelium_stream *client,
 					  enum chamelium_stream_realtime_mode mode);
-void chamelium_stream_audio_format(struct chamelium_stream *stream,
-				   int *rate, int *channels);
 bool chamelium_stream_receive_realtime_audio(struct chamelium_stream *client,
 					     size_t *page_count,
 					     int32_t **buf, size_t *buf_len);
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index 8d6cc092..f535ca52 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -725,15 +725,14 @@ test_display_frame_dump(data_t *data, struct chamelium_port *port)
 /* A streak of 3 gives confidence that the signal is good. */
 #define MIN_STREAK 3
 
-/* TODO: Chamelium only supports 48KHz for now */
 static int sampling_rates[] = {
-/*	32000, */
-/*	44100, */
+	32000,
+	44100,
 	48000,
-/*	88200, */
-/*	96000, */
-/*	176400, */
-/*	192000, */
+	88200,
+	96000,
+	176400,
+	192000,
 };
 
 static int sampling_rates_count = sizeof(sampling_rates) / sizeof(int);
@@ -815,19 +814,6 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 	ok = chamelium_stream_dump_realtime_audio(stream, stream_mode);
 	igt_assert(ok);
 
-	chamelium_stream_audio_format(stream, &capture_rate, &capture_channels);
-
-	if (igt_frame_dump_is_enabled()) {
-		snprintf(dump_suffix, sizeof(dump_suffix), "capture-%dch-%d",
-			 playback_channels, playback_rate);
-
-		dump_fd = audio_create_wav_file_s32_le(dump_suffix,
-						       capture_rate,
-						       capture_channels,
-						       &dump_path);
-		igt_assert(dump_fd >= 0);
-	}
-
 	signal = audio_signal_init(playback_channels, playback_rate);
 	igt_assert(signal);
 
@@ -835,8 +821,12 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 	 * independent from each other. To do so, we'll add a different offset
 	 * to the base frequencies for each channel. We need to choose a big
 	 * enough offset so that we're sure to detect mixed up channels.
+	 *
+	 * Note that we assume capture_rate == playback_rate. We'll assert this
+	 * later on. We cannot retrieve the capture rate before starting
+	 * playing audio, so we don't really have the choice.
 	 */
-	step = 2 * capture_rate / CAPTURE_SAMPLES;
+	step = 2 * playback_rate / CAPTURE_SAMPLES;
 	for (i = 0; i < test_frequencies_count; i++) {
 		for (j = 0; j < playback_channels; j++) {
 			freq = test_frequencies[i] + j * step;
@@ -854,6 +844,17 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 	ret = pthread_create(&thread, NULL, run_audio_thread, alsa);
 	igt_assert(ret == 0);
 
+	/* Only after we've started playing audio, we can retrieve the capture
+	 * format used by the Chamelium device. */
+	chamelium_get_audio_format(data->chamelium, port,
+				   &capture_rate, &capture_channels);
+	if (capture_rate == 0) {
+		igt_debug("Audio receiver doesn't indicate the capture "
+			 "sampling rate, assuming it's %d Hz\n", playback_rate);
+		capture_rate = playback_rate;
+	} else
+		igt_assert(capture_rate == playback_rate);
+
 	chamelium_get_audio_channel_mapping(data->chamelium, port,
 					    channel_mapping);
 	/* Make sure we can capture all channels we send. */
@@ -868,6 +869,17 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 		igt_assert(ok);
 	}
 
+	if (igt_frame_dump_is_enabled()) {
+		snprintf(dump_suffix, sizeof(dump_suffix), "capture-%dch-%d",
+			 playback_channels, playback_rate);
+
+		dump_fd = audio_create_wav_file_s32_le(dump_suffix,
+						       capture_rate,
+						       capture_channels,
+						       &dump_path);
+		igt_assert(dump_fd >= 0);
+	}
+
 	/* Needs to be a multiple of 128, because that's the number of samples
 	 * we get per channel each time we receive an audio page from the
 	 * Chamelium device. */
@@ -939,7 +951,7 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 
 	if (dump_fd >= 0) {
 		close(dump_fd);
-		if (streak == MIN_STREAK) {
+		if (success) {
 			/* Test succeeded, no need to keep the captured data */
 			unlink(dump_path);
 		} else
-- 
2.21.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [igt-dev] [PATCH i-g-t v6 6/7] lib/igt_edid: add support for Short Audio Descriptors
  2019-04-17 12:43 [igt-dev] [PATCH i-g-t v6 0/7] tests/kms_chamelium: add dp-audio test Simon Ser
                   ` (4 preceding siblings ...)
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 5/7] tests/kms_chamelium: run audio test with multiple sampling rates Simon Ser
@ 2019-04-17 12:43 ` Simon Ser
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 7/7] HAX: add dp-audio test to fast-feedback Simon Ser
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 22+ messages in thread
From: Simon Ser @ 2019-04-17 12:43 UTC (permalink / raw)
  To: igt-dev

Signed-off-by: Simon Ser <simon.ser@intel.com>
---
 lib/igt_edid.c | 73 +++++++++++++++++++++++++++++++++++++++-----
 lib/igt_edid.h | 82 ++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 145 insertions(+), 10 deletions(-)

diff --git a/lib/igt_edid.c b/lib/igt_edid.c
index 52e66ab2..3d40d3b3 100644
--- a/lib/igt_edid.c
+++ b/lib/igt_edid.c
@@ -252,19 +252,76 @@ void edid_init_with_mode(struct edid *edid, drmModeModeInfo *mode)
 				   EDID_DETAIL_MONITOR_NAME, "IGT");
 }
 
+static uint8_t compute_checksum(const uint8_t *buf, size_t size)
+{
+	size_t i;
+	uint8_t sum = 0;
+
+	assert(size > 0);
+	for (i = 0; i < size - 1; i++) {
+		sum += buf[i];
+	}
+
+	return 256 - sum;
+}
+
 /**
  * edid_update_checksum: compute and update the EDID checksum
  */
 void edid_update_checksum(struct edid *edid)
 {
-	size_t i;
-	const uint8_t *buf = (const uint8_t *) edid;
-	uint8_t sum = 0;
+	edid->checksum = compute_checksum((uint8_t *) edid,
+					  sizeof(struct edid));
+}
 
-	/* calculate checksum */
-	for (i = 0; i < sizeof(struct edid) - 1; i++) {
-		sum = sum + buf[i];
-	}
+/**
+ * cea_sad_init_pcm:
+ * @channels: the number of supported channels (max. 8)
+ * @sampling_rates: bitfield of enum cea_sad_sampling_rate
+ * @sample_sizes: bitfield of enum cea_sad_pcm_sample_size
+ *
+ * Initialize a Short Audio Descriptor to advertise PCM support.
+ */
+void cea_sad_init_pcm(struct cea_sad *sad, int channels,
+		      uint8_t sampling_rates, uint8_t sample_sizes)
+{
+	assert(channels <= 8);
+	sad->format_channels = CEA_SAD_FORMAT_PCM << 3 | (channels - 1);
+	sad->sampling_rates = sampling_rates;
+	sad->bitrate = sample_sizes;
+}
+
+static void edid_cea_finalize(struct edid_cea *cea)
+{
+	cea->checksum = compute_checksum((uint8_t *) cea,
+					 sizeof(struct edid_cea));
+}
+
+/**
+ * edid_ext_set_cea_sad: set an extension block to be CEA SAD
+ */
+void edid_ext_set_cea_sad(struct edid_ext *ext, const struct cea_sad *sads,
+			  size_t sads_len)
+{
+	struct edid_cea *cea = &ext->data.cea;
+	struct edid_cea_data_block *data_block;
+	size_t sads_size, data_block_size;
+
+	memset(ext, 0, sizeof(struct edid_ext));
+
+	sads_size = sizeof(struct cea_sad) * sads_len;
+	data_block_size = sizeof(struct edid_cea_data_block) + sads_size;
+
+	ext->tag = EDID_EXT_CEA;
+
+	cea->revision = 3;
+	cea->dtd_start = 4 + data_block_size;
+	cea->misc = 1 << 6; /* basic audio, no DTD */
+
+	assert(sads_size <= 0xFF);
+	data_block = (struct edid_cea_data_block *) cea->data;
+	data_block->type_len = EDID_CEA_DATA_AUDIO << 5 | sads_size;
+	memcpy(data_block->data.sads, sads, sads_size);
 
-	edid->checksum = 256 - sum;
+	edid_cea_finalize(cea);
 }
diff --git a/lib/igt_edid.h b/lib/igt_edid.h
index bbcb939a..33fd7bd2 100644
--- a/lib/igt_edid.h
+++ b/lib/igt_edid.h
@@ -142,6 +142,79 @@ struct detailed_timing {
 	} data;
 } __attribute__((packed));
 
+enum cea_sad_format {
+	CEA_SAD_FORMAT_PCM = 1,
+	CEA_SAD_FORMAT_AC3 = 2,
+	CEA_SAD_FORMAT_MPEG1 = 3, /* Layers 1 & 2 */
+	CEA_SAD_FORMAT_MP3 = 4,
+	CEA_SAD_FORMAT_MPEG2 = 5,
+	CEA_SAD_FORMAT_AAC = 6,
+	CEA_SAD_FORMAT_DTS = 7,
+	CEA_SAD_FORMAT_ATRAC = 8,
+	CEA_SAD_FORMAT_SACD = 9, /* One-bit audio */
+	CEA_SAD_FORMAT_DD_PLUS = 10,
+	CEA_SAD_FORMAT_DTS_HD = 11,
+	CEA_SAD_FORMAT_DOLBY = 12, /* MLP/Dolby TrueHD */
+	CEA_SAD_FORMAT_DST = 13,
+	CEA_SAD_FORMAT_WMA = 14, /* Microsoft WMA Pro */
+};
+
+enum cea_sad_sampling_rate {
+	CEA_SAD_SAMPLING_32KHZ = 1 << 0,
+	CEA_SAD_SAMPLING_44KHZ = 1 << 1,
+	CEA_SAD_SAMPLING_48KHZ = 1 << 2,
+	CEA_SAD_SAMPLING_88KHZ = 1 << 3,
+	CEA_SAD_SAMPLING_96KHZ = 1 << 4,
+	CEA_SAD_SAMPLING_176KHZ = 1 << 5,
+	CEA_SAD_SAMPLING_192KHZ = 1 << 6,
+};
+
+/* for PCM only */
+enum cea_sad_pcm_sample_size {
+	CEA_SAD_BITRATE_16 = 1 << 0,
+	CEA_SAD_BITRATE_20 = 1 << 1,
+	CEA_SAD_BITRATE_24 = 1 << 2,
+};
+
+struct cea_sad {
+	uint8_t format_channels;
+	uint8_t sampling_rates;
+	uint8_t bitrate;
+};
+
+enum edid_cea_data_type {
+	EDID_CEA_DATA_AUDIO = 1,
+	EDID_CEA_DATA_VIDEO = 2,
+	EDID_CEA_DATA_VENDOR_SPECIFIC = 3,
+	EDID_CEA_DATA_SPEAKER_ALLOC = 4,
+};
+
+struct edid_cea_data_block {
+	uint8_t type_len; /* type is from enum edid_cea_data_type */
+	union {
+		struct cea_sad sads[0];
+	} data;
+} __attribute__((packed));
+
+struct edid_cea {
+	uint8_t revision;
+	uint8_t dtd_start;
+	uint8_t misc;
+	char data[123]; /* DBC & DTD collection, padded with zeros */
+	uint8_t checksum;
+} __attribute__((packed));
+
+enum edid_ext_tag {
+	EDID_EXT_CEA = 0x02,
+};
+
+struct edid_ext {
+	uint8_t tag; /* enum edid_ext_tag */
+	union {
+		struct edid_cea cea;
+	} data;
+} __attribute__((packed));
+
 struct edid {
 	char header[8];
 	/* Vendor & product info */
@@ -177,9 +250,9 @@ struct edid {
 	/* Detailing timings 1-4 */
 	struct detailed_timing detailed_timings[DETAILED_TIMINGS_LEN];
 	/* Number of 128 byte ext. blocks */
-	uint8_t extensions;
-	/* Checksum */
+	uint8_t extensions_len;
 	uint8_t checksum;
+	struct edid_ext extensions[];
 } __attribute__((packed));
 
 void edid_init(struct edid *edid);
@@ -193,4 +266,9 @@ void detailed_timing_set_string(struct detailed_timing *dt,
 				enum detailed_non_pixel_type type,
 				const char *str);
 
+void cea_sad_init_pcm(struct cea_sad *sad, int channels,
+		      uint8_t sampling_rates, uint8_t sample_sizes);
+void edid_ext_set_cea_sad(struct edid_ext *ext, const struct cea_sad *sads,
+			  size_t sads_len);
+
 #endif
-- 
2.21.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [igt-dev] [PATCH i-g-t v6 7/7] HAX: add dp-audio test to fast-feedback
  2019-04-17 12:43 [igt-dev] [PATCH i-g-t v6 0/7] tests/kms_chamelium: add dp-audio test Simon Ser
                   ` (5 preceding siblings ...)
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 6/7] lib/igt_edid: add support for Short Audio Descriptors Simon Ser
@ 2019-04-17 12:43 ` Simon Ser
  2019-04-23  8:04   ` Martin Peres
  2019-04-17 13:25 ` [igt-dev] ✗ Fi.CI.BAT: failure for tests/kms_chamelium: add dp-audio test (rev6) Patchwork
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 22+ messages in thread
From: Simon Ser @ 2019-04-17 12:43 UTC (permalink / raw)
  To: igt-dev

Waiting for the whole series to be complete to decide whether or not we want
this test in fast-feedback.

Signed-off-by: Simon Ser <simon.ser@intel.com>
---
 tests/intel-ci/fast-feedback.testlist | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tests/intel-ci/fast-feedback.testlist b/tests/intel-ci/fast-feedback.testlist
index 40475b1a..28f5fa55 100644
--- a/tests/intel-ci/fast-feedback.testlist
+++ b/tests/intel-ci/fast-feedback.testlist
@@ -175,6 +175,7 @@ igt@kms_addfb_basic@unused-pitches
 igt@kms_busy@basic-flip-a
 igt@kms_busy@basic-flip-b
 igt@kms_busy@basic-flip-c
+igt@kms_chamelium@dp-audio
 igt@kms_chamelium@dp-hpd-fast
 igt@kms_chamelium@dp-edid-read
 igt@kms_chamelium@dp-crc-fast
-- 
2.21.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [igt-dev] [PATCH i-g-t v6 2/7] tests/kms_chamelium: capture audio data in real-time
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 2/7] tests/kms_chamelium: capture audio data in real-time Simon Ser
@ 2019-04-17 12:57   ` Martin Peres
  0 siblings, 0 replies; 22+ messages in thread
From: Martin Peres @ 2019-04-17 12:57 UTC (permalink / raw)
  To: Simon Ser, igt-dev

On 17/04/2019 15:43, Simon Ser wrote:
> Before this patch, the audio test first sends an audio signal for 2s, and then
> checks whether the captured signal matches.
> 
> This patch makes it so we send and check the signal in parallel. Thus we can
> stop the test as soon as we receive the correct signal. This saves ~2s per
> audio test.

Given that run_audio_thread is the one calling the callback, we should
not have coherency issues.

This patch is:

Reviewed-by: Martin Peres <martin.peres@linux.intel.com>
> 
> Signed-off-by: Simon Ser <simon.ser@intel.com>
> ---
>  lib/igt_alsa.c        | 15 +++++++-------
>  tests/kms_chamelium.c | 47 +++++++++++++++++++++++++++++++++----------
>  2 files changed, 43 insertions(+), 19 deletions(-)
> 
> diff --git a/lib/igt_alsa.c b/lib/igt_alsa.c
> index 22089881..fc6d336b 100644
> --- a/lib/igt_alsa.c
> +++ b/lib/igt_alsa.c
> @@ -497,7 +497,8 @@ void alsa_register_input_callback(struct alsa *alsa,
>  /**
>   * alsa_run:
>   * @alsa: The target alsa structure
> - * @duration_ms: The maximum duration of the run in milliseconds
> + * @duration_ms: The maximum duration of the run in milliseconds, or -1 for an
> + * infinite duration.
>   *
>   * Run ALSA playback and capture on the input and output devices for at
>   * most @duration_ms milliseconds, calling the registered callbacks when needed.
> @@ -545,7 +546,7 @@ int alsa_run(struct alsa *alsa, int duration_ms)
>  	do {
>  		reached = true;
>  
> -		if (output_total < output_limit) {
> +		if (output_limit < 0 || output_total < output_limit) {
>  			reached = false;
>  
>  			if (!output_ready) {
> @@ -607,7 +608,8 @@ int alsa_run(struct alsa *alsa, int duration_ms)
>  
>  		}
>  
> -		if (alsa->input_callback && input_total < input_limit) {
> +		if (alsa->input_callback &&
> +		    (input_limit < 0 || input_total < input_limit)) {
>  			reached = false;
>  
>  			if (input_count == input_trigger) {
> @@ -660,11 +662,8 @@ int alsa_run(struct alsa *alsa, int duration_ms)
>  	ret = 0;
>  
>  complete:
> -	if (output_buffer)
> -		free(output_buffer);
> -
> -	if (input_buffer)
> -		free(input_buffer);
> +	free(output_buffer);
> +	free(input_buffer);
>  
>  	return ret;
>  }
> diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
> index a712250a..014a22b3 100644
> --- a/tests/kms_chamelium.c
> +++ b/tests/kms_chamelium.c
> @@ -29,7 +29,9 @@
>  #include "igt_vc4.h"
>  
>  #include <fcntl.h>
> +#include <pthread.h>
>  #include <string.h>
> +#include <stdatomic.h>
>  
>  typedef struct {
>  	struct chamelium *chamelium;
> @@ -719,7 +721,7 @@ test_display_frame_dump(data_t *data, struct chamelium_port *port)
>  /* Capture paremeters control the audio signal we receive */
>  #define CAPTURE_SAMPLES 2048
>  
> -#define AUDIO_DURATION 2000 /* ms */
> +#define AUDIO_TIMEOUT 2000 /* ms */
>  /* A streak of 3 gives confidence that the signal is good. */
>  #define MIN_STREAK 3
>  
> @@ -746,14 +748,28 @@ static int test_frequencies[] = {
>  
>  static int test_frequencies_count = sizeof(test_frequencies) / sizeof(int);
>  
> +struct audio_state {
> +	struct audio_signal *signal;
> +	atomic_bool run;
> +};
> +
>  static int
> -output_callback(void *data, short *buffer, int frames)
> +audio_output_callback(void *data, short *buffer, int frames)
>  {
> -	struct audio_signal *signal = (struct audio_signal *) data;
> +	struct audio_state *state = data;
> +
> +	audio_signal_fill(state->signal, buffer, frames);
>  
> -	audio_signal_fill(signal, buffer, frames);
> +	return state->run ? 0 : -1;
> +}
> +
> +static void *
> +run_audio_thread(void *data)
> +{
> +	struct alsa *alsa = data;
>  
> -	return 0;
> +	alsa_run(alsa, -1);
> +	return NULL;
>  }
>  
>  static bool
> @@ -774,6 +790,8 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  	char dump_suffix[64];
>  	char *dump_path = NULL;
>  	int dump_fd = -1;
> +	pthread_t thread;
> +	struct audio_state state = {};
>  
>  	if (!alsa_test_output_configuration(alsa, playback_channels,
>  					    playback_rate))
> @@ -811,15 +829,15 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  		audio_signal_add_frequency(signal, test_frequencies[i]);
>  	audio_signal_synthesize(signal);
>  
> -	alsa_register_output_callback(alsa, output_callback, signal,
> +	state.signal = signal;
> +	state.run = true;
> +	alsa_register_output_callback(alsa, audio_output_callback, &state,
>  				      PLAYBACK_SAMPLES);
>  
> -	/* TODO: detect signal in real-time */
> -	ret = alsa_run(alsa, AUDIO_DURATION);
> +	/* Start playing audio */
> +	ret = pthread_create(&thread, NULL, run_audio_thread, alsa);
>  	igt_assert(ret == 0);
>  
> -	alsa_close_output(alsa);
> -
>  	/* Needs to be a multiple of 128, because that's the number of samples
>  	 * we get per channel each time we receive an audio page from the
>  	 * Chamelium device. */
> @@ -836,7 +854,7 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  	streak = 0;
>  	msec = 0;
>  	i = 0;
> -	while (streak < MIN_STREAK && msec < AUDIO_DURATION) {
> +	while (streak < MIN_STREAK && msec < AUDIO_TIMEOUT) {
>  		ok = chamelium_stream_receive_realtime_audio(stream,
>  							     &page_count,
>  							     &recv, &recv_len);
> @@ -871,6 +889,13 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  		i++;
>  	}
>  
> +	igt_debug("Stopping audio playback\n");
> +	state.run = false;
> +	ret = pthread_join(thread, NULL);
> +	igt_assert(ret == 0);
> +
> +	alsa_close_output(alsa);
> +
>  	if (dump_fd >= 0) {
>  		close(dump_fd);
>  		if (streak == MIN_STREAK) {
> 
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [igt-dev] ✗ Fi.CI.BAT: failure for tests/kms_chamelium: add dp-audio test (rev6)
  2019-04-17 12:43 [igt-dev] [PATCH i-g-t v6 0/7] tests/kms_chamelium: add dp-audio test Simon Ser
                   ` (6 preceding siblings ...)
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 7/7] HAX: add dp-audio test to fast-feedback Simon Ser
@ 2019-04-17 13:25 ` Patchwork
  2019-04-17 16:27   ` Ser, Simon
  2019-04-17 17:23 ` [igt-dev] ✓ Fi.CI.BAT: success for tests/kms_chamelium: add dp-audio test (rev7) Patchwork
  2019-04-18  1:25 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
  9 siblings, 1 reply; 22+ messages in thread
From: Patchwork @ 2019-04-17 13:25 UTC (permalink / raw)
  To: Ser, Simon; +Cc: igt-dev

== Series Details ==

Series: tests/kms_chamelium: add dp-audio test (rev6)
URL   : https://patchwork.freedesktop.org/series/59058/
State : failure

== Summary ==

CI Bug Log - changes from CI_DRM_5946 -> IGTPW_2883
====================================================

Summary
-------

  **FAILURE**

  Serious unknown changes coming with IGTPW_2883 absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in IGTPW_2883, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/59058/revisions/6/mbox/

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in IGTPW_2883:

### IGT changes ###

#### Possible regressions ####

  * igt@amdgpu/amd_prime@i915-to-amd:
    - fi-icl-y:           NOTRUN -> INCOMPLETE

  
New tests
---------

  New tests have been introduced between CI_DRM_5946 and IGTPW_2883:

### New IGT tests (1) ###

  * igt@kms_chamelium@dp-audio:
    - Statuses :
    - Exec time: [None] s

  

Known issues
------------

  Here are the changes found in IGTPW_2883 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@amdgpu/amd_basic@semaphore:
    - fi-kbl-7500u:       NOTRUN -> SKIP [fdo#109271] +26

  * igt@amdgpu/amd_cs_nop@fork-compute0:
    - fi-icl-y:           NOTRUN -> SKIP [fdo#109315] +15

  * igt@gem_ctx_create@basic-files:
    - fi-gdg-551:         NOTRUN -> SKIP [fdo#109271] +92

  * igt@gem_exec_basic@basic-bsd2:
    - fi-icl-y:           NOTRUN -> SKIP [fdo#109276] +7

  * igt@gem_exec_basic@gtt-bsd2:
    - fi-byt-clapper:     NOTRUN -> SKIP [fdo#109271] +43

  * igt@gem_exec_parse@basic-rejected:
    - fi-icl-y:           NOTRUN -> SKIP [fdo#109289] +1

  * igt@kms_busy@basic-flip-a:
    - fi-bsw-n3050:       NOTRUN -> SKIP [fdo#109271] / [fdo#109278] +1

  * igt@kms_busy@basic-flip-c:
    - fi-skl-6770hq:      PASS -> SKIP [fdo#109271] / [fdo#109278] +2
    - fi-blb-e6850:       NOTRUN -> SKIP [fdo#109271] / [fdo#109278]
    - fi-byt-clapper:     NOTRUN -> SKIP [fdo#109271] / [fdo#109278]
    - fi-gdg-551:         NOTRUN -> SKIP [fdo#109271] / [fdo#109278]

  * igt@kms_flip@basic-flip-vs-dpms:
    - fi-skl-6770hq:      PASS -> SKIP [fdo#109271] +23

  * igt@kms_force_connector_basic@force-load-detect:
    - fi-bxt-j4205:       NOTRUN -> SKIP [fdo#109271] +38
    - fi-icl-y:           NOTRUN -> SKIP [fdo#109285] +3

  * igt@kms_pipe_crc_basic@hang-read-crc-pipe-a:
    - fi-bsw-n3050:       NOTRUN -> SKIP [fdo#109271] +48

  * igt@kms_psr@primary_mmap_gtt:
    - fi-skl-guc:         NOTRUN -> SKIP [fdo#109271] +38
    - fi-icl-y:           NOTRUN -> SKIP [fdo#110189] +3
    - fi-blb-e6850:       NOTRUN -> SKIP [fdo#109271] +34

  * igt@prime_vgem@basic-fence-flip:
    - fi-icl-y:           NOTRUN -> SKIP [fdo#109294]

  
#### Possible fixes ####

  * igt@gem_exec_suspend@basic-s3:
    - fi-blb-e6850:       INCOMPLETE [fdo#107718] -> PASS

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#107718]: https://bugs.freedesktop.org/show_bug.cgi?id=107718
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109276]: https://bugs.freedesktop.org/show_bug.cgi?id=109276
  [fdo#109278]: https://bugs.freedesktop.org/show_bug.cgi?id=109278
  [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
  [fdo#109289]: https://bugs.freedesktop.org/show_bug.cgi?id=109289
  [fdo#109294]: https://bugs.freedesktop.org/show_bug.cgi?id=109294
  [fdo#109315]: https://bugs.freedesktop.org/show_bug.cgi?id=109315
  [fdo#110189]: https://bugs.freedesktop.org/show_bug.cgi?id=110189


Participating hosts (41 -> 42)
------------------------------

  Additional (7): fi-kbl-7567u fi-bsw-n3050 fi-skl-guc fi-bxt-j4205 fi-gdg-551 fi-icl-y fi-byt-clapper 
  Missing    (6): fi-ilk-m540 fi-bsw-cyan fi-icl-u2 fi-skl-6260u fi-ctg-p8600 fi-bdw-samus 


Build changes
-------------

    * IGT: IGT_4956 -> IGTPW_2883

  CI_DRM_5946: 9b74ad002155a574710fccc43f2960855c18ca7c @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_2883: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2883/
  IGT_4956: 1d921615b0b706f25c856aa0eb096f274380c199 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools



== Testlist changes ==

-igt@kms_chamelium@common-hpd-after-hibernate
-igt@kms_chamelium@common-hpd-after-suspend
-igt@kms_chamelium@dp-crc-fast
-igt@kms_chamelium@dp-crc-multiple
-igt@kms_chamelium@dp-crc-single
-igt@kms_chamelium@dp-edid-change-during-hibernate
-igt@kms_chamelium@dp-edid-change-during-suspend
-igt@kms_chamelium@dp-edid-read
-igt@kms_chamelium@dp-frame-dump
-igt@kms_chamelium@dp-hpd
-igt@kms_chamelium@dp-hpd-after-hibernate
-igt@kms_chamelium@dp-hpd-after-suspend
-igt@kms_chamelium@dp-hpd-fast
-igt@kms_chamelium@dp-hpd-storm
-igt@kms_chamelium@dp-hpd-storm-disable
-igt@kms_chamelium@hdmi-cmp-nv12
-igt@kms_chamelium@hdmi-cmp-nv16
-igt@kms_chamelium@hdmi-cmp-nv21
-igt@kms_chamelium@hdmi-cmp-nv61
-igt@kms_chamelium@hdmi-cmp-planes-random
-igt@kms_chamelium@hdmi-cmp-yu12
-igt@kms_chamelium@hdmi-cmp-yu16
-igt@kms_chamelium@hdmi-cmp-yv12
-igt@kms_chamelium@hdmi-cmp-yv16
-igt@kms_chamelium@hdmi-crc-abgr8888
-igt@kms_chamelium@hdmi-crc-argb1555
-igt@kms_chamelium@hdmi-crc-argb8888
-igt@kms_chamelium@hdmi-crc-bgr565
-igt@kms_chamelium@hdmi-crc-bgr888
-igt@kms_chamelium@hdmi-crc-fast
-igt@kms_chamelium@hdmi-crc-multiple
-igt@kms_chamelium@hdmi-crc-planes-random
-igt@kms_chamelium@hdmi-crc-rgb565
-igt@kms_chamelium@hdmi-crc-rgb888
-igt@kms_chamelium@hdmi-crc-single
-igt@kms_chamelium@hdmi-crc-xbgr8888
-igt@kms_chamelium@hdmi-crc-xrgb1555
-igt@kms_chamelium@hdmi-crc-xrgb8888
-igt@kms_chamelium@hdmi-edid-change-during-hibernate
-igt@kms_chamelium@hdmi-edid-change-during-suspend
-igt@kms_chamelium@hdmi-edid-read
-igt@kms_chamelium@hdmi-frame-dump
-igt@kms_chamelium@hdmi-hpd
-igt@kms_chamelium@hdmi-hpd-after-hibernate
-igt@kms_chamelium@hdmi-hpd-after-suspend
-igt@kms_chamelium@hdmi-hpd-fast
-igt@kms_chamelium@hdmi-hpd-storm
-igt@kms_chamelium@hdmi-hpd-storm-disable
-igt@kms_chamelium@vga-edid-read
-igt@kms_chamelium@vga-frame-dump
-igt@kms_chamelium@vga-hpd
-igt@kms_chamelium@vga-hpd-after-hibernate
-igt@kms_chamelium@vga-hpd-after-suspend
-igt@kms_chamelium@vga-hpd-fast
-igt@kms_chamelium@vga-hpd-without-ddc

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2883/
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [igt-dev] ✗ Fi.CI.BAT: failure for tests/kms_chamelium: add dp-audio test (rev6)
  2019-04-17 13:25 ` [igt-dev] ✗ Fi.CI.BAT: failure for tests/kms_chamelium: add dp-audio test (rev6) Patchwork
@ 2019-04-17 16:27   ` Ser, Simon
  0 siblings, 0 replies; 22+ messages in thread
From: Ser, Simon @ 2019-04-17 16:27 UTC (permalink / raw)
  To: igt-dev

On Wed, 2019-04-17 at 13:25 +0000, Patchwork wrote:
> == Series Details ==
> 
> Series: tests/kms_chamelium: add dp-audio test (rev6)
> URL   : https://patchwork.freedesktop.org/series/59058/
> State : failure
> 
> == Summary ==
> 
> CI Bug Log - changes from CI_DRM_5946 -> IGTPW_2883
> ====================================================
> 
> Summary
> -------
> 
>   **FAILURE**
> 
>   Serious unknown changes coming with IGTPW_2883 absolutely need to
> be
>   verified manually.
>   
>   If you think the reported changes have nothing to do with the
> changes
>   introduced in IGTPW_2883, please notify your bug team to allow them
>   to document this new failure mode, which will reduce false
> positives in CI.
> 
>   External URL: 
> https://patchwork.freedesktop.org/api/1.0/series/59058/revisions/6/mbox/
> 
> Possible new issues
> -------------------
> 
>   Here are the unknown changes that may have been introduced in
> IGTPW_2883:
> 
> ### IGT changes ###
> 
> #### Possible regressions ####
> 
>   * igt@amdgpu/amd_prime@i915-to-amd:
>     - fi-icl-y:           NOTRUN -> INCOMPLETE
> 
>   
> New tests
> ---------
> 
>   New tests have been introduced between CI_DRM_5946 and IGTPW_2883:
> 
> ### New IGT tests (1) ###
> 
>   * igt@kms_chamelium@dp-audio:
>     - Statuses :
>     - Exec time: [None] s

All Chamelium tests were not run because alsa-dev is missing and is now
required to build them.

> 
>   
> 
> Known issues
> ------------
> 
>   Here are the changes found in IGTPW_2883 that come from known
> issues:
> 
> ### IGT changes ###
> 
> #### Issues hit ####
> 
>   * igt@amdgpu/amd_basic@semaphore:
>     - fi-kbl-7500u:       NOTRUN -> SKIP [fdo#109271] +26
> 
>   * igt@amdgpu/amd_cs_nop@fork-compute0:
>     - fi-icl-y:           NOTRUN -> SKIP [fdo#109315] +15
> 
>   * igt@gem_ctx_create@basic-files:
>     - fi-gdg-551:         NOTRUN -> SKIP [fdo#109271] +92
> 
>   * igt@gem_exec_basic@basic-bsd2:
>     - fi-icl-y:           NOTRUN -> SKIP [fdo#109276] +7
> 
>   * igt@gem_exec_basic@gtt-bsd2:
>     - fi-byt-clapper:     NOTRUN -> SKIP [fdo#109271] +43
> 
>   * igt@gem_exec_parse@basic-rejected:
>     - fi-icl-y:           NOTRUN -> SKIP [fdo#109289] +1
> 
>   * igt@kms_busy@basic-flip-a:
>     - fi-bsw-n3050:       NOTRUN -> SKIP [fdo#109271] / [fdo#109278]
> +1
> 
>   * igt@kms_busy@basic-flip-c:
>     - fi-skl-6770hq:      PASS -> SKIP [fdo#109271] / [fdo#109278] +2
>     - fi-blb-e6850:       NOTRUN -> SKIP [fdo#109271] / [fdo#109278]
>     - fi-byt-clapper:     NOTRUN -> SKIP [fdo#109271] / [fdo#109278]
>     - fi-gdg-551:         NOTRUN -> SKIP [fdo#109271] / [fdo#109278]
> 
>   * igt@kms_flip@basic-flip-vs-dpms:
>     - fi-skl-6770hq:      PASS -> SKIP [fdo#109271] +23
> 
>   * igt@kms_force_connector_basic@force-load-detect:
>     - fi-bxt-j4205:       NOTRUN -> SKIP [fdo#109271] +38
>     - fi-icl-y:           NOTRUN -> SKIP [fdo#109285] +3
> 
>   * igt@kms_pipe_crc_basic@hang-read-crc-pipe-a:
>     - fi-bsw-n3050:       NOTRUN -> SKIP [fdo#109271] +48
> 
>   * igt@kms_psr@primary_mmap_gtt:
>     - fi-skl-guc:         NOTRUN -> SKIP [fdo#109271] +38
>     - fi-icl-y:           NOTRUN -> SKIP [fdo#110189] +3
>     - fi-blb-e6850:       NOTRUN -> SKIP [fdo#109271] +34
> 
>   * igt@prime_vgem@basic-fence-flip:
>     - fi-icl-y:           NOTRUN -> SKIP [fdo#109294]
> 
>   
> #### Possible fixes ####
> 
>   * igt@gem_exec_suspend@basic-s3:
>     - fi-blb-e6850:       INCOMPLETE [fdo#107718] -> PASS
> 
>   
>   {name}: This element is suppressed. This means it is ignored when
> computing
>           the status of the difference (SUCCESS, WARNING, or
> FAILURE).
> 
>   [fdo#107718]: https://bugs.freedesktop.org/show_bug.cgi?id=107718
>   [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
>   [fdo#109276]: https://bugs.freedesktop.org/show_bug.cgi?id=109276
>   [fdo#109278]: https://bugs.freedesktop.org/show_bug.cgi?id=109278
>   [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
>   [fdo#109289]: https://bugs.freedesktop.org/show_bug.cgi?id=109289
>   [fdo#109294]: https://bugs.freedesktop.org/show_bug.cgi?id=109294
>   [fdo#109315]: https://bugs.freedesktop.org/show_bug.cgi?id=109315
>   [fdo#110189]: https://bugs.freedesktop.org/show_bug.cgi?id=110189
> 
> 
> Participating hosts (41 -> 42)
> ------------------------------
> 
>   Additional (7): fi-kbl-7567u fi-bsw-n3050 fi-skl-guc fi-bxt-j4205
> fi-gdg-551 fi-icl-y fi-byt-clapper 
>   Missing    (6): fi-ilk-m540 fi-bsw-cyan fi-icl-u2 fi-skl-6260u fi-
> ctg-p8600 fi-bdw-samus 
> 
> 
> Build changes
> -------------
> 
>     * IGT: IGT_4956 -> IGTPW_2883
> 
>   CI_DRM_5946: 9b74ad002155a574710fccc43f2960855c18ca7c @
> git://anongit.freedesktop.org/gfx-ci/linux
>   IGTPW_2883: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2883/
>   IGT_4956: 1d921615b0b706f25c856aa0eb096f274380c199 @
> git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
> 
> 
> 
> == Testlist changes ==
> 
> -igt@kms_chamelium@common-hpd-after-hibernate
> -igt@kms_chamelium@common-hpd-after-suspend
> -igt@kms_chamelium@dp-crc-fast
> -igt@kms_chamelium@dp-crc-multiple
> -igt@kms_chamelium@dp-crc-single
> -igt@kms_chamelium@dp-edid-change-during-hibernate
> -igt@kms_chamelium@dp-edid-change-during-suspend
> -igt@kms_chamelium@dp-edid-read
> -igt@kms_chamelium@dp-frame-dump
> -igt@kms_chamelium@dp-hpd
> -igt@kms_chamelium@dp-hpd-after-hibernate
> -igt@kms_chamelium@dp-hpd-after-suspend
> -igt@kms_chamelium@dp-hpd-fast
> -igt@kms_chamelium@dp-hpd-storm
> -igt@kms_chamelium@dp-hpd-storm-disable
> -igt@kms_chamelium@hdmi-cmp-nv12
> -igt@kms_chamelium@hdmi-cmp-nv16
> -igt@kms_chamelium@hdmi-cmp-nv21
> -igt@kms_chamelium@hdmi-cmp-nv61
> -igt@kms_chamelium@hdmi-cmp-planes-random
> -igt@kms_chamelium@hdmi-cmp-yu12
> -igt@kms_chamelium@hdmi-cmp-yu16
> -igt@kms_chamelium@hdmi-cmp-yv12
> -igt@kms_chamelium@hdmi-cmp-yv16
> -igt@kms_chamelium@hdmi-crc-abgr8888
> -igt@kms_chamelium@hdmi-crc-argb1555
> -igt@kms_chamelium@hdmi-crc-argb8888
> -igt@kms_chamelium@hdmi-crc-bgr565
> -igt@kms_chamelium@hdmi-crc-bgr888
> -igt@kms_chamelium@hdmi-crc-fast
> -igt@kms_chamelium@hdmi-crc-multiple
> -igt@kms_chamelium@hdmi-crc-planes-random
> -igt@kms_chamelium@hdmi-crc-rgb565
> -igt@kms_chamelium@hdmi-crc-rgb888
> -igt@kms_chamelium@hdmi-crc-single
> -igt@kms_chamelium@hdmi-crc-xbgr8888
> -igt@kms_chamelium@hdmi-crc-xrgb1555
> -igt@kms_chamelium@hdmi-crc-xrgb8888
> -igt@kms_chamelium@hdmi-edid-change-during-hibernate
> -igt@kms_chamelium@hdmi-edid-change-during-suspend
> -igt@kms_chamelium@hdmi-edid-read
> -igt@kms_chamelium@hdmi-frame-dump
> -igt@kms_chamelium@hdmi-hpd
> -igt@kms_chamelium@hdmi-hpd-after-hibernate
> -igt@kms_chamelium@hdmi-hpd-after-suspend
> -igt@kms_chamelium@hdmi-hpd-fast
> -igt@kms_chamelium@hdmi-hpd-storm
> -igt@kms_chamelium@hdmi-hpd-storm-disable
> -igt@kms_chamelium@vga-edid-read
> -igt@kms_chamelium@vga-frame-dump
> -igt@kms_chamelium@vga-hpd
> -igt@kms_chamelium@vga-hpd-after-hibernate
> -igt@kms_chamelium@vga-hpd-after-suspend
> -igt@kms_chamelium@vga-hpd-fast
> -igt@kms_chamelium@vga-hpd-without-ddc
> 
> == Logs ==
> 
> For more details see: 
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2883/
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [igt-dev] ✓ Fi.CI.BAT: success for tests/kms_chamelium: add dp-audio test (rev7)
  2019-04-17 12:43 [igt-dev] [PATCH i-g-t v6 0/7] tests/kms_chamelium: add dp-audio test Simon Ser
                   ` (7 preceding siblings ...)
  2019-04-17 13:25 ` [igt-dev] ✗ Fi.CI.BAT: failure for tests/kms_chamelium: add dp-audio test (rev6) Patchwork
@ 2019-04-17 17:23 ` Patchwork
  2019-04-23  8:05   ` Martin Peres
  2019-04-18  1:25 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
  9 siblings, 1 reply; 22+ messages in thread
From: Patchwork @ 2019-04-17 17:23 UTC (permalink / raw)
  To: Ser, Simon; +Cc: igt-dev

== Series Details ==

Series: tests/kms_chamelium: add dp-audio test (rev7)
URL   : https://patchwork.freedesktop.org/series/59058/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_5948 -> IGTPW_2887
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/59058/revisions/7/mbox/

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in IGTPW_2887:

### IGT changes ###

#### Possible regressions ####

  * {igt@kms_chamelium@dp-audio} (NEW):
    - fi-kbl-7500u:       NOTRUN -> FAIL

  
New tests
---------

  New tests have been introduced between CI_DRM_5948 and IGTPW_2887:

### New IGT tests (1) ###

  * igt@kms_chamelium@dp-audio:
    - Statuses : 1 fail(s) 37 skip(s)
    - Exec time: [0.0, 1.30] s

  

Known issues
------------

  Here are the changes found in IGTPW_2887 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@gem_exec_basic@gtt-bsd2:
    - fi-byt-clapper:     NOTRUN -> SKIP [fdo#109271] +53

  * igt@gem_exec_store@basic-bsd2:
    - fi-hsw-4770:        NOTRUN -> SKIP [fdo#109271] +42

  * igt@i915_module_load@reload-with-fault-injection:
    - fi-icl-y:           PASS -> INCOMPLETE [fdo#107713]

  * igt@kms_addfb_basic@addfb25-y-tiled-small:
    - fi-byt-n2820:       NOTRUN -> SKIP [fdo#109271] +52

  * igt@kms_busy@basic-flip-c:
    - fi-byt-j1900:       NOTRUN -> SKIP [fdo#109271] / [fdo#109278]
    - fi-byt-clapper:     NOTRUN -> SKIP [fdo#109271] / [fdo#109278]
    - fi-byt-n2820:       NOTRUN -> SKIP [fdo#109271] / [fdo#109278]

  * {igt@kms_chamelium@dp-audio} (NEW):
    - fi-skl-6770hq:      NOTRUN -> SKIP [fdo#109271]
    - fi-snb-2600:        NOTRUN -> SKIP [fdo#109271]
    - fi-bwr-2160:        NOTRUN -> SKIP [fdo#109271]
    - fi-skl-lmem:        NOTRUN -> SKIP [fdo#109271]
    - fi-kbl-8809g:       NOTRUN -> SKIP [fdo#109271]
    - fi-kbl-r:           NOTRUN -> SKIP [fdo#109271]
    - fi-apl-guc:         NOTRUN -> SKIP [fdo#109271]
    - {fi-kbl-7567u}:     NOTRUN -> SKIP [fdo#109271]
    - fi-kbl-x1275:       NOTRUN -> SKIP [fdo#109271]
    - fi-icl-y:           NOTRUN -> SKIP [fdo#109284]
    - fi-skl-iommu:       NOTRUN -> SKIP [fdo#109271]
    - fi-blb-e6850:       NOTRUN -> SKIP [fdo#109271]
    - fi-elk-e7500:       NOTRUN -> SKIP [fdo#109271]
    - fi-skl-6700k2:      NOTRUN -> SKIP [fdo#109271]
    - fi-whl-u:           NOTRUN -> SKIP [fdo#109271]
    - fi-bdw-5557u:       NOTRUN -> SKIP [fdo#109271]
    - fi-kbl-guc:         NOTRUN -> SKIP [fdo#109271]
    - fi-cfl-8109u:       NOTRUN -> SKIP [fdo#109271]
    - fi-hsw-4770r:       NOTRUN -> SKIP [fdo#109271]
    - fi-cfl-8700k:       NOTRUN -> SKIP [fdo#109271]
    - fi-glk-dsi:         NOTRUN -> SKIP [fdo#109271]
    - fi-skl-guc:         NOTRUN -> SKIP [fdo#109271]
    - fi-cfl-guc:         NOTRUN -> SKIP [fdo#109271]
    - fi-bdw-gvtdvm:      NOTRUN -> SKIP [fdo#109271]
    - fi-bsw-n3050:       NOTRUN -> SKIP [fdo#109271]
    - fi-ilk-650:         NOTRUN -> SKIP [fdo#109271]
    - fi-ivb-3770:        NOTRUN -> SKIP [fdo#109271]
    - fi-skl-gvtdvm:      NOTRUN -> SKIP [fdo#109271]
    - fi-skl-6260u:       NOTRUN -> SKIP [fdo#109271]
    - fi-bxt-j4205:       NOTRUN -> SKIP [fdo#109271]
    - fi-bxt-dsi:         NOTRUN -> SKIP [fdo#109271]
    - fi-icl-u3:          NOTRUN -> SKIP [fdo#109284]

  * igt@kms_chamelium@hdmi-crc-fast:
    - fi-byt-j1900:       NOTRUN -> SKIP [fdo#109271] +48

  * igt@kms_chamelium@hdmi-edid-read:
    - fi-hsw-peppy:       NOTRUN -> SKIP [fdo#109271] +47

  * igt@kms_frontbuffer_tracking@basic:
    - fi-hsw-peppy:       NOTRUN -> DMESG-FAIL [fdo#102614] / [fdo#107814]
    - fi-byt-clapper:     NOTRUN -> FAIL [fdo#103167]

  
#### Possible fixes ####

  * igt@i915_selftest@live_execlists:
    - fi-apl-guc:         INCOMPLETE [fdo#103927] / [fdo#109720] -> PASS

  * igt@i915_selftest@live_hangcheck:
    - fi-skl-iommu:       INCOMPLETE [fdo#108602] / [fdo#108744] -> PASS

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#102614]: https://bugs.freedesktop.org/show_bug.cgi?id=102614
  [fdo#103167]: https://bugs.freedesktop.org/show_bug.cgi?id=103167
  [fdo#103927]: https://bugs.freedesktop.org/show_bug.cgi?id=103927
  [fdo#107713]: https://bugs.freedesktop.org/show_bug.cgi?id=107713
  [fdo#107814]: https://bugs.freedesktop.org/show_bug.cgi?id=107814
  [fdo#108602]: https://bugs.freedesktop.org/show_bug.cgi?id=108602
  [fdo#108744]: https://bugs.freedesktop.org/show_bug.cgi?id=108744
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109278]: https://bugs.freedesktop.org/show_bug.cgi?id=109278
  [fdo#109284]: https://bugs.freedesktop.org/show_bug.cgi?id=109284
  [fdo#109720]: https://bugs.freedesktop.org/show_bug.cgi?id=109720


Participating hosts (43 -> 40)
------------------------------

  Additional (5): fi-byt-j1900 fi-hsw-peppy fi-hsw-4770 fi-byt-n2820 fi-byt-clapper 
  Missing    (8): fi-ilk-m540 fi-byt-squawks fi-snb-2520m fi-ctg-p8600 fi-gdg-551 fi-pnv-d510 fi-bdw-samus fi-skl-6600u 


Build changes
-------------

    * IGT: IGT_4956 -> IGTPW_2887

  CI_DRM_5948: cb5afe9301dbef678a0af3bda9ed9f4ee0b3dbf7 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_2887: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2887/
  IGT_4956: 1d921615b0b706f25c856aa0eb096f274380c199 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools



== Testlist changes ==

+igt@kms_chamelium@dp-audio

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2887/
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [igt-dev] ✓ Fi.CI.IGT: success for tests/kms_chamelium: add dp-audio test (rev7)
  2019-04-17 12:43 [igt-dev] [PATCH i-g-t v6 0/7] tests/kms_chamelium: add dp-audio test Simon Ser
                   ` (8 preceding siblings ...)
  2019-04-17 17:23 ` [igt-dev] ✓ Fi.CI.BAT: success for tests/kms_chamelium: add dp-audio test (rev7) Patchwork
@ 2019-04-18  1:25 ` Patchwork
  9 siblings, 0 replies; 22+ messages in thread
From: Patchwork @ 2019-04-18  1:25 UTC (permalink / raw)
  To: Ser, Simon; +Cc: igt-dev

== Series Details ==

Series: tests/kms_chamelium: add dp-audio test (rev7)
URL   : https://patchwork.freedesktop.org/series/59058/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_5948_full -> IGTPW_2887_full
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/59058/revisions/7/mbox/

New tests
---------

  New tests have been introduced between CI_DRM_5948_full and IGTPW_2887_full:

### New IGT tests (1) ###

  * igt@kms_chamelium@dp-audio:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  

Known issues
------------

  Here are the changes found in IGTPW_2887_full that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@gem_exec_params@no-blt:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109283]

  * igt@gem_mocs_settings@mocs-rc6-dirty-render:
    - shard-iclb:         NOTRUN -> SKIP [fdo#110206]

  * igt@gem_pwrite@huge-cpu-fbr:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109290] +1

  * igt@gem_stolen@stolen-clear:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109277]

  * igt@gem_tiled_swapping@non-threaded:
    - shard-hsw:          PASS -> DMESG-WARN [fdo#108686]

  * igt@gem_userptr_blits@readonly-pwrite-unsync:
    - shard-iclb:         NOTRUN -> SKIP [fdo#110426] +1

  * igt@gen3_render_mixed_blits:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109289] +1

  * igt@i915_pm_rc6_residency@rc6-accuracy:
    - shard-snb:          PASS -> SKIP [fdo#109271]

  * igt@i915_pm_rpm@dpms-non-lpsp:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109308]

  * igt@i915_pm_rpm@modeset-lpsp-stress:
    - shard-apl:          NOTRUN -> SKIP [fdo#109271] +119

  * igt@i915_pm_sseu@full-enable:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109288]

  * igt@kms_busy@extended-modeset-hang-oldfb-with-reset-render-f:
    - shard-kbl:          NOTRUN -> SKIP [fdo#109271] / [fdo#109278]

  * {igt@kms_chamelium@dp-audio} (NEW):
    - shard-glk:          NOTRUN -> SKIP [fdo#109271]

  * igt@kms_chamelium@hdmi-crc-planes-random:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109284] +6

  * igt@kms_content_protection@atomic:
    - shard-apl:          NOTRUN -> FAIL [fdo#110321] / [fdo#110336] +1

  * igt@kms_cursor_crc@cursor-256x256-suspend:
    - shard-kbl:          PASS -> DMESG-WARN [fdo#108566]

  * igt@kms_cursor_crc@cursor-512x512-suspend:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109279] +1

  * igt@kms_cursor_crc@cursor-64x64-suspend:
    - shard-apl:          NOTRUN -> DMESG-WARN [fdo#108566]

  * igt@kms_cursor_legacy@cursorb-vs-flipb-atomic:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109274] +4

  * igt@kms_flip@2x-flip-vs-expired-vblank-interruptible:
    - shard-glk:          PASS -> FAIL [fdo#105363]

  * igt@kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-render:
    - shard-iclb:         NOTRUN -> FAIL [fdo#103167]

  * igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-indfb-draw-blt:
    - shard-iclb:         PASS -> FAIL [fdo#103167] +8

  * igt@kms_frontbuffer_tracking@fbcpsr-2p-primscrn-spr-indfb-draw-render:
    - shard-hsw:          NOTRUN -> SKIP [fdo#109271] +20

  * igt@kms_frontbuffer_tracking@psr-1p-primscrn-cur-indfb-draw-mmap-wc:
    - shard-kbl:          NOTRUN -> SKIP [fdo#109271] +3

  * igt@kms_frontbuffer_tracking@psr-2p-primscrn-pri-shrfb-draw-blt:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109280] +26

  * igt@kms_frontbuffer_tracking@psr-2p-scndscrn-indfb-msflip-blt:
    - shard-snb:          NOTRUN -> SKIP [fdo#109271] +75

  * igt@kms_lease@setcrtc_implicit_plane:
    - shard-apl:          NOTRUN -> FAIL [fdo#110281]

  * igt@kms_pipe_crc_basic@hang-read-crc-pipe-d:
    - shard-hsw:          NOTRUN -> SKIP [fdo#109271] / [fdo#109278]

  * igt@kms_pipe_crc_basic@hang-read-crc-pipe-e:
    - shard-apl:          NOTRUN -> SKIP [fdo#109271] / [fdo#109278] +8

  * igt@kms_pipe_crc_basic@suspend-read-crc-pipe-b:
    - shard-apl:          PASS -> DMESG-WARN [fdo#108566] +2

  * igt@kms_plane_alpha_blend@pipe-a-alpha-7efc:
    - shard-apl:          NOTRUN -> FAIL [fdo#108145] +3

  * igt@kms_plane_scaling@2x-scaler-multi-pipe:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109274] / [fdo#109278]

  * igt@kms_plane_scaling@pipe-b-scaler-with-clipping-clamping:
    - shard-glk:          PASS -> SKIP [fdo#109271] / [fdo#109278]

  * igt@kms_psr2_su@frontbuffer:
    - shard-iclb:         PASS -> SKIP [fdo#109642]

  * igt@kms_psr@no_drrs:
    - shard-iclb:         PASS -> FAIL [fdo#108341]

  * igt@kms_psr@psr2_primary_mmap_cpu:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109441] +2

  * igt@kms_psr@psr2_primary_page_flip:
    - shard-iclb:         PASS -> SKIP [fdo#109441] +2

  * igt@kms_sysfs_edid_timing:
    - shard-iclb:         PASS -> FAIL [fdo#100047]

  * igt@kms_tv_load_detect@load-detect:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109309]

  * igt@kms_universal_plane@disable-primary-vs-flip-pipe-d:
    - shard-snb:          NOTRUN -> SKIP [fdo#109271] / [fdo#109278] +5

  * igt@kms_universal_plane@universal-plane-gen9-features-pipe-d:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109278] +3

  * igt@perf_pmu@rc6:
    - shard-kbl:          PASS -> SKIP [fdo#109271]

  * igt@prime_nv_api@i915_nv_import_twice_check_flink_name:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109291] +3

  * igt@prime_vgem@fence-wait-bsd1:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109276] +13

  * igt@v3d_get_bo_offset@create-get-offsets:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109315]

  
#### Possible fixes ####

  * igt@gem_ctx_isolation@bcs0-s3:
    - shard-kbl:          DMESG-WARN [fdo#108566] -> PASS +2

  * igt@gem_eio@in-flight-immediate:
    - shard-apl:          INCOMPLETE [fdo#103927] -> PASS

  * igt@gem_exec_suspend@basic-s3:
    - shard-kbl:          INCOMPLETE [fdo#103665] -> PASS

  * igt@i915_suspend@fence-restore-tiled2untiled:
    - shard-apl:          DMESG-WARN [fdo#108566] -> PASS +7

  * igt@kms_cursor_legacy@2x-long-flip-vs-cursor-atomic:
    - shard-glk:          FAIL [fdo#104873] -> PASS

  * igt@kms_flip@flip-vs-suspend-interruptible:
    - shard-hsw:          INCOMPLETE [fdo#103540] -> PASS

  * igt@kms_frontbuffer_tracking@fbc-1p-primscrn-cur-indfb-draw-blt:
    - shard-iclb:         FAIL [fdo#103167] -> PASS +1

  * igt@kms_plane@pixel-format-pipe-c-planes-source-clamping:
    - shard-glk:          SKIP [fdo#109271] -> PASS

  * igt@kms_plane_lowres@pipe-a-tiling-y:
    - shard-iclb:         FAIL [fdo#103166] -> PASS

  * igt@kms_plane_scaling@pipe-a-scaler-with-clipping-clamping:
    - shard-glk:          SKIP [fdo#109271] / [fdo#109278] -> PASS

  * igt@kms_psr2_su@page_flip:
    - shard-iclb:         SKIP [fdo#109642] -> PASS

  * igt@kms_psr@psr2_basic:
    - shard-iclb:         SKIP [fdo#109441] -> PASS +1

  
#### Warnings ####

  * igt@kms_cursor_legacy@2x-long-nonblocking-modeset-vs-cursor-atomic:
    - shard-apl:          INCOMPLETE [fdo#103927] -> SKIP [fdo#109271]

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#100047]: https://bugs.freedesktop.org/show_bug.cgi?id=100047
  [fdo#103166]: https://bugs.freedesktop.org/show_bug.cgi?id=103166
  [fdo#103167]: https://bugs.freedesktop.org/show_bug.cgi?id=103167
  [fdo#103540]: https://bugs.freedesktop.org/show_bug.cgi?id=103540
  [fdo#103665]: https://bugs.freedesktop.org/show_bug.cgi?id=103665
  [fdo#103927]: https://bugs.freedesktop.org/show_bug.cgi?id=103927
  [fdo#104873]: https://bugs.freedesktop.org/show_bug.cgi?id=104873
  [fdo#105363]: https://bugs.freedesktop.org/show_bug.cgi?id=105363
  [fdo#108145]: https://bugs.freedesktop.org/show_bug.cgi?id=108145
  [fdo#108341]: https://bugs.freedesktop.org/show_bug.cgi?id=108341
  [fdo#108566]: https://bugs.freedesktop.org/show_bug.cgi?id=108566
  [fdo#108686]: https://bugs.freedesktop.org/show_bug.cgi?id=108686
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109274]: https://bugs.freedesktop.org/show_bug.cgi?id=109274
  [fdo#109276]: https://bugs.freedesktop.org/show_bug.cgi?id=109276
  [fdo#109277]: https://bugs.freedesktop.org/show_bug.cgi?id=109277
  [fdo#109278]: https://bugs.freedesktop.org/show_bug.cgi?id=109278
  [fdo#109279]: https://bugs.freedesktop.org/show_bug.cgi?id=109279
  [fdo#109280]: https://bugs.freedesktop.org/show_bug.cgi?id=109280
  [fdo#109283]: https://bugs.freedesktop.org/show_bug.cgi?id=109283
  [fdo#109284]: https://bugs.freedesktop.org/show_bug.cgi?id=109284
  [fdo#109288]: https://bugs.freedesktop.org/show_bug.cgi?id=109288
  [fdo#109289]: https://bugs.freedesktop.org/show_bug.cgi?id=109289
  [fdo#109290]: https://bugs.freedesktop.org/show_bug.cgi?id=109290
  [fdo#109291]: https://bugs.freedesktop.org/show_bug.cgi?id=109291
  [fdo#109308]: https://bugs.freedesktop.org/show_bug.cgi?id=109308
  [fdo#109309]: https://bugs.freedesktop.org/show_bug.cgi?id=109309
  [fdo#109315]: https://bugs.freedesktop.org/show_bug.cgi?id=109315
  [fdo#109441]: https://bugs.freedesktop.org/show_bug.cgi?id=109441
  [fdo#109642]: https://bugs.freedesktop.org/show_bug.cgi?id=109642
  [fdo#110206]: https://bugs.freedesktop.org/show_bug.cgi?id=110206
  [fdo#110281]: https://bugs.freedesktop.org/show_bug.cgi?id=110281
  [fdo#110321]: https://bugs.freedesktop.org/show_bug.cgi?id=110321
  [fdo#110336]: https://bugs.freedesktop.org/show_bug.cgi?id=110336
  [fdo#110426]: https://bugs.freedesktop.org/show_bug.cgi?id=110426


Participating hosts (10 -> 6)
------------------------------

  Missing    (4): pig-skl-6260u shard-skl pig-hsw-4770r pig-glk-j5005 


Build changes
-------------

    * IGT: IGT_4956 -> IGTPW_2887
    * Piglit: piglit_4509 -> None

  CI_DRM_5948: cb5afe9301dbef678a0af3bda9ed9f4ee0b3dbf7 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_2887: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2887/
  IGT_4956: 1d921615b0b706f25c856aa0eb096f274380c199 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2887/
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [igt-dev] [PATCH i-g-t v6 3/7] tests/kms_chamelium: test we receive a signal from both audio channels
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 3/7] tests/kms_chamelium: test we receive a signal from both audio channels Simon Ser
@ 2019-04-23  7:41   ` Martin Peres
  2019-04-23 12:23     ` Ser, Simon
  0 siblings, 1 reply; 22+ messages in thread
From: Martin Peres @ 2019-04-23  7:41 UTC (permalink / raw)
  To: Simon Ser, igt-dev

On 17/04/2019 15:43, Simon Ser wrote:
> This commit updates the audio test to make sure we receive a signal from both
> audio channels. However this commit doesn't check that left and right channels
> are not swapped. Such a check requires some more work (because the Chamelium
> device does swap left and right channels) and will be implemented in a future
> commit.
> 
> This commit adds a new channel argument to audio_signal_add_frequency, to add
> a frequency to a single channel only.
> 
> Some light refactoring has been performed (a proper audio_signal_deinit
> function has been introduced) and logging has been improved.
> 
> Signed-off-by: Simon Ser <simon.ser@intel.com>
> ---
>  lib/igt_alsa.c        |  26 +++++++--
>  lib/igt_audio.c       | 119 +++++++++++++++++++++++++-----------------
>  lib/igt_audio.h       |  11 ++--
>  tests/kms_chamelium.c |  56 ++++++++++++--------
>  4 files changed, 137 insertions(+), 75 deletions(-)
> 
> diff --git a/lib/igt_alsa.c b/lib/igt_alsa.c
> index fc6d336b..a478686a 100644
> --- a/lib/igt_alsa.c
> +++ b/lib/igt_alsa.c
> @@ -182,6 +182,8 @@ static char *alsa_resolve_indentifier(const char *device_name, int skip)
>  					continue;
>  				}
>  
> +				igt_debug("Matched device \"%s\"\n", pcm_name);
> +

Should have been a separate commit.

>  				snprintf(name, sizeof(name), "hw:%d,%d", card,
>  					 dev);
>  
> @@ -329,6 +331,9 @@ static bool alsa_test_configuration(snd_pcm_t *handle, int channels,
>  {
>  	snd_pcm_hw_params_t *params;
>  	int ret;
> +	unsigned int min_channels, max_channels;
> +	unsigned int min_rate, max_rate;
> +	int min_rate_dir, max_rate_dir;
>  
>  	snd_pcm_hw_params_alloca(&params);
>  
> @@ -337,12 +342,24 @@ static bool alsa_test_configuration(snd_pcm_t *handle, int channels,
>  		return false;
>  
>  	ret = snd_pcm_hw_params_test_rate(handle, params, sampling_rate, 0);
> -	if (ret < 0)
> +	if (ret < 0) {
> +		snd_pcm_hw_params_get_rate_min(params, &min_rate, &min_rate_dir);
> +		snd_pcm_hw_params_get_rate_max(params, &max_rate, &max_rate_dir);
> +		igt_debug("Output device supports rates between %u and %u, "
> +			  "requested %d\n",
> +			  min_rate, max_rate, sampling_rate);
>  		return false;
> +	}

This likely should be in patch 5/7.

>  
>  	ret = snd_pcm_hw_params_test_channels(handle, params, channels);
> -	if (ret < 0)
> +	if (ret < 0) {
> +		snd_pcm_hw_params_get_channels_min(params, &min_channels);
> +		snd_pcm_hw_params_get_channels_max(params, &max_channels);
> +		igt_debug("Output device supports between %u and "
> +			  "%u channels, requested %d\n",
> +			  min_channels, max_channels, channels);
>  		return false;
> +	}
>  
>  	return true;
>  }
> @@ -409,13 +426,16 @@ void alsa_configure_output(struct alsa *alsa, int channels,
>  	snd_pcm_t *handle;
>  	int ret;
>  	int i;
> +	int soft_resample = 0; /* Don't allow ALSA to resample */
> +	unsigned int latency = 0;
>  
>  	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);
> +					 channels, sampling_rate,
> +					 soft_resample, latency);

Probably should have been a separate commit again ;)

>  		igt_assert(ret >= 0);
>  	}
>  
> diff --git a/lib/igt_audio.c b/lib/igt_audio.c
> index 7624f565..a2a5c594 100644
> --- a/lib/igt_audio.c
> +++ b/lib/igt_audio.c
> @@ -35,7 +35,7 @@
>  #include "igt_audio.h"
>  #include "igt_core.h"
>  
> -#define FREQS_MAX	8
> +#define FREQS_MAX 64
>  
>  /**
>   * SECTION:igt_audio
> @@ -49,9 +49,10 @@
>  
>  struct audio_signal_freq {
>  	int freq;
> +	int channel;
>  
> -	short *period;
> -	int frames;
> +	int16_t *period;
> +	size_t period_len;
>  	int offset;
>  };
>  
> @@ -60,7 +61,7 @@ struct audio_signal {
>  	int sampling_rate;
>  
>  	struct audio_signal_freq freqs[FREQS_MAX];
> -	int freqs_count;
> +	size_t freqs_count;
>  };
>  
>  /**
> @@ -89,21 +90,28 @@ struct audio_signal *audio_signal_init(int channels, int sampling_rate)
>   * audio_signal_add_frequency:
>   * @signal: The target signal structure
>   * @frequency: The frequency to add to the signal
> + * @channel: The channel to add this frequency to, or -1 to add it to all
> + * channels
>   *
>   * 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 audio_signal_add_frequency(struct audio_signal *signal, int frequency,
> +			       int channel)

Is the alignment correct here? Doesn't look like it!

>  {
> -	int index = signal->freqs_count;
> +	size_t index = signal->freqs_count;
> +	struct audio_signal_freq *freq;
>  
> -	if (index == FREQS_MAX)
> -		return -1;
> +	igt_assert(index < FREQS_MAX);
> +	igt_assert(channel < signal->channels);
>  
>  	/* Stay within the Nyquist–Shannon sampling theorem. */
> -	if (frequency > signal->sampling_rate / 2)
> +	if (frequency > signal->sampling_rate / 2) {
> +		igt_debug("Skipping frequency %d: too high for a %d Hz "
> +			  "sampling rate\n", frequency, signal->sampling_rate);
>  		return -1;
> +	}

Should have been a separate commit.

>  
>  	/* 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
> @@ -111,11 +119,14 @@ int audio_signal_add_frequency(struct audio_signal *signal, int frequency)
>  	 */
>  	frequency = signal->sampling_rate / (signal->sampling_rate / frequency);
>  
> -	igt_debug("Adding test frequency %d\n", frequency);
> +	igt_debug("Adding test frequency %d to channel %d\n",
> +		  frequency, channel);
> +
> +	freq = &signal->freqs[index];
> +	memset(freq, 0, sizeof(*freq));
> +	freq->freq = frequency;
> +	freq->channel = channel;
>  
> -	signal->freqs[index].freq = frequency;
> -	signal->freqs[index].frames = 0;
> -	signal->freqs[index].offset = 0;
>  	signal->freqs_count++;
>  
>  	return 0;
> @@ -133,20 +144,17 @@ void audio_signal_synthesize(struct audio_signal *signal)
>  {
>  	int16_t *period;
>  	double value;
> -	int frames;
> +	size_t period_len;
>  	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_len = signal->sampling_rate / freq;
>  
> -		period = calloc(1, frames * sizeof(short));
> +		period = calloc(1, period_len * sizeof(int16_t));
>  
> -		for (j = 0; j < frames; j++) {
> +		for (j = 0; j < period_len; j++) {
>  			value = 2.0 * M_PI * freq / signal->sampling_rate * j;
>  			value = sin(value) * INT16_MAX / signal->freqs_count;
>  
> @@ -154,26 +162,34 @@ void audio_signal_synthesize(struct audio_signal *signal)
>  		}
>  
>  		signal->freqs[i].period = period;
> -		signal->freqs[i].frames = frames;
> +		signal->freqs[i].period_len = period_len;
>  	}
>  }
>  
>  /**
> - * audio_signal_synthesize:
> + * audio_signal_deinit:
> + *
> + * Release the signal.
> + */
> +void audio_signal_deinit(struct audio_signal *signal)

Is the coding style to use deinit or fini?

> +{
> +	audio_signal_reset(signal);
> +	free(signal);
> +}
> +
> +/**
> + * audio_signal_reset:
>   * @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)
> +void audio_signal_reset(struct audio_signal *signal)
>  {
> -	int i;
> +	size_t 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));
> +		free(signal->freqs[i].period);
>  	}
>  
>  	signal->freqs_count = 0;
> @@ -183,44 +199,45 @@ void audio_signal_clean(struct audio_signal *signal)
>   * audio_signal_fill:
>   * @signal: The target signal structure
>   * @buffer: The target buffer to fill
> - * @frames: The number of frames to fill
> + * @samples: The number of samples to fill
>   *
> - * Fill the requested number of frames to the target buffer with the audio
> + * Fill the requested number of samples 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, int16_t *buffer, int frames)
> +void audio_signal_fill(struct audio_signal *signal, int16_t *buffer,
> +		       size_t buffer_len)
>  {
>  	int16_t *destination, *source;
> +	struct audio_signal_freq *freq;
>  	int total;
> -	int freq_frames;
> -	int freq_offset;
>  	int count;
>  	int i, j, k;
>  
> -	memset(buffer, 0, sizeof(int16_t) * signal->channels * frames);
> +	memset(buffer, 0, sizeof(int16_t) * signal->channels * buffer_len);
>  
>  	for (i = 0; i < signal->freqs_count; i++) {
> +		freq = &signal->freqs[i];
>  		total = 0;
>  
> -		while (total < frames) {
> -			freq_frames = signal->freqs[i].frames;
> -			freq_offset = signal->freqs[i].offset;
> +		igt_assert(freq->period);
>  
> -			source = signal->freqs[i].period + freq_offset;
> +		while (total < buffer_len) {
> +			source = freq->period + freq->offset;
>  			destination = buffer + total * signal->channels;
>  
> -			count = freq_frames - freq_offset;
> -			if (count > (frames - total))
> -				count = frames - total;
> +			count = freq->period_len - freq->offset;
> +			if (count > buffer_len - total)
> +				count = buffer_len - total;
>  
> -			freq_offset += count;
> -			freq_offset %= freq_frames;
> -
> -			signal->freqs[i].offset = freq_offset;
> +			freq->offset += count;
> +			freq->offset %= freq->period_len;
>  
>  			for (j = 0; j < count; j++) {
>  				for (k = 0; k < signal->channels; k++) {
> +					if (freq->channel >= 0 &&
> +					    freq->channel != k)
> +						continue;
>  					destination[j * signal->channels + k] += source[j];
>  				}
>  			}
> @@ -237,11 +254,11 @@ void audio_signal_fill(struct audio_signal *signal, int16_t *buffer, int frames)
>   * sampling_rate is given in Hz. data_len is the number of elements in data.
>   */
>  bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
> -			 double *data, size_t data_len)
> +			 int channel, double *data, size_t data_len)
>  {
>  	size_t bin_power_len = data_len / 2 + 1;
>  	double bin_power[bin_power_len];
> -	bool detected[signal->freqs_count];
> +	bool detected[FREQS_MAX];
>  	int ret, freq_accuracy, freq, local_max_freq;
>  	double max, local_max, threshold;
>  	size_t i, j;
> @@ -308,6 +325,10 @@ bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
>  		 * invalid. */
>  		if (bin_power[i] < threshold) {
>  			for (j = 0; j < signal->freqs_count; j++) {
> +				if (signal->freqs[j].channel >= 0 &&
> +				    signal->freqs[j].channel != channel)
> +					continue;
> +
>  				if (signal->freqs[j].freq >
>  				    local_max_freq - freq_accuracy &&
>  				    signal->freqs[j].freq <
> @@ -340,6 +361,10 @@ bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
>  
>  	/* Check that all frequencies we generated have been detected. */
>  	for (i = 0; i < signal->freqs_count; i++) {
> +		if (signal->freqs[i].channel >= 0 &&
> +		    signal->freqs[i].channel != channel)
> +			continue;
> +
>  		if (!detected[i]) {
>  			igt_debug("Missing frequency: %d\n",
>  				  signal->freqs[i].freq);
> diff --git a/lib/igt_audio.h b/lib/igt_audio.h
> index 4aa43e69..fe26bb57 100644
> --- a/lib/igt_audio.h
> +++ b/lib/igt_audio.h
> @@ -35,12 +35,15 @@
>  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_deinit(struct audio_signal *signal);
> +int audio_signal_add_frequency(struct audio_signal *signal, int frequency,
> +			       int channel);
>  void audio_signal_synthesize(struct audio_signal *signal);
> -void audio_signal_clean(struct audio_signal *signal);
> -void audio_signal_fill(struct audio_signal *signal, int16_t *buffer, int frames);
> +void audio_signal_reset(struct audio_signal *signal);
> +void audio_signal_fill(struct audio_signal *signal, int16_t *buffer,
> +		       size_t buffer_len);
>  bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
> -			 double *data, size_t data_len);
> +			 int channel, double *data, size_t data_len);
>  size_t audio_extract_channel_s32_le(double *dst, size_t dst_cap,
>  				    int32_t *src, size_t src_len,
>  				    int n_channels, int channel);
> diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
> index 014a22b3..d336612f 100644
> --- a/tests/kms_chamelium.c
> +++ b/tests/kms_chamelium.c
> @@ -777,16 +777,16 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  		      struct alsa *alsa, int playback_channels,
>  		      int playback_rate)
>  {
> -	int ret, capture_rate, capture_channels, msec;
> +	int ret, capture_rate, capture_channels, msec, freq;
>  	struct chamelium_audio_file *audio_file;
>  	struct chamelium_stream *stream;
>  	enum chamelium_stream_realtime_mode stream_mode;
>  	struct audio_signal *signal;
>  	int32_t *recv, *buf;
>  	double *channel;
> -	size_t i, streak, page_count;
> +	size_t i, j, streak, page_count;
>  	size_t recv_len, buf_len, buf_cap, buf_size, channel_len;
> -	bool ok;
> +	bool ok, success;
>  	char dump_suffix[64];
>  	char *dump_path = NULL;
>  	int dump_fd = -1;
> @@ -794,10 +794,15 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  	struct audio_state state = {};
>  
>  	if (!alsa_test_output_configuration(alsa, playback_channels,
> -					    playback_rate))
> +					    playback_rate)) {
> +		igt_debug("Skipping test with sample rate %d and %d channels "
> +			  "because selected output devices don't support this "
> +			  "configuration\n", playback_rate, playback_channels);
>  		return false;
> +	}
>  
> -	igt_debug("Testing with playback sampling rate %d\n", playback_rate);
> +	igt_debug("Testing with playback sampling rate %d and %d channels\n",
> +		  playback_rate, playback_channels);
>  	alsa_configure_output(alsa, playback_channels, playback_rate);
>  
>  	chamelium_start_capturing_audio(data->chamelium, port, false);
> @@ -825,8 +830,12 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  	signal = audio_signal_init(playback_channels, playback_rate);
>  	igt_assert(signal);
>  
> -	for (i = 0; i < test_frequencies_count; i++)
> -		audio_signal_add_frequency(signal, test_frequencies[i]);
> +	for (i = 0; i < test_frequencies_count; i++) {
> +		for (j = 0; j < playback_channels; j++) {
> +			freq = test_frequencies[i];
> +			audio_signal_add_frequency(signal, freq, j);
> +		}
> +	}
>  	audio_signal_synthesize(signal);
>  
>  	state.signal = signal;
> @@ -851,10 +860,11 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  	recv = NULL;
>  	recv_len = 0;
>  
> +	success = false;
>  	streak = 0;
>  	msec = 0;
>  	i = 0;
> -	while (streak < MIN_STREAK && msec < AUDIO_TIMEOUT) {
> +	while (!success && msec < AUDIO_TIMEOUT) {
>  		ok = chamelium_stream_receive_realtime_audio(stream,
>  							     &page_count,
>  							     &recv, &recv_len);
> @@ -872,21 +882,27 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  			igt_assert(write(dump_fd, buf, buf_size) == buf_size);
>  		}
>  
> -		/* TODO: check other channels too, not just the first one */
> -		audio_extract_channel_s32_le(channel, channel_len, buf, buf_len,
> -					     capture_channels, 0);
> -
>  		msec = i * channel_len / (double) capture_rate * 1000;
>  		igt_debug("Detecting audio signal, t=%d msec\n", msec);
>  
> -		if (audio_signal_detect(signal, capture_rate, channel,
> -					channel_len))
> -			streak++;
> -		else
> -			streak = 0;
> +		for (j = 0; j < playback_channels; j++) {
> +			igt_debug("Processing channel %zu\n", j);
> +
> +			audio_extract_channel_s32_le(channel, channel_len,
> +						     buf, buf_len,
> +						     capture_channels, j);
> +
> +			if (audio_signal_detect(signal, capture_rate, j,
> +						channel, channel_len))
> +				streak++;
> +			else
> +				streak = 0;
> +		}
>  
>  		buf_len = 0;
>  		i++;
> +
> +		success = streak == MIN_STREAK * playback_channels;
>  	}
>  
>  	igt_debug("Stopping audio playback\n");
> @@ -921,12 +937,10 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  		chamelium_destroy_audio_file(audio_file);
>  	}
>  
> -	audio_signal_clean(signal);
> -	free(signal);
> -
> +	audio_signal_deinit(signal);
>  	chamelium_stream_deinit(stream);
>  
> -	igt_assert(streak == MIN_STREAK);
> +	igt_assert(success);
>  	return true;
>  }
>  

With the coding style issues fixed:

Reviewed-by: Martin Peres <martin.peres@linux.intel.com>
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [igt-dev] [PATCH i-g-t v6 4/7] tests/kms_chamelium: test audio channels are not mixed up
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 4/7] tests/kms_chamelium: test audio channels are not mixed up Simon Ser
@ 2019-04-23  7:51   ` Martin Peres
  2019-04-23 12:57     ` Ser, Simon
  0 siblings, 1 reply; 22+ messages in thread
From: Martin Peres @ 2019-04-23  7:51 UTC (permalink / raw)
  To: Simon Ser, igt-dev

On 17/04/2019 15:43, Simon Ser wrote:
> Send a different signal to each channel and make sure captured audio channels
> are not swapped or mixed up.
> 
> The Chamelium device has a bug and already swaps the left and right channels.
> For this reason, clients need to retrieve the Chamelium channel mapping and
> accomodate for this. See https://crbug.com/950922 for a discussion about this.
> 
> Signed-off-by: Simon Ser <simon.ser@intel.com>
> ---
>  lib/igt_chamelium.c   | 34 ++++++++++++++++++++++++++++++++++
>  lib/igt_chamelium.h   |  3 +++
>  tests/kms_chamelium.c | 37 +++++++++++++++++++++++++++++++------
>  3 files changed, 68 insertions(+), 6 deletions(-)
> 
> diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> index 7c9030d1..6ac7b722 100644
> --- a/lib/igt_chamelium.c
> +++ b/lib/igt_chamelium.c
> @@ -930,6 +930,40 @@ int chamelium_get_captured_frame_count(struct chamelium *chamelium)
>  	return ret;
>  }
>  
> +/**
> + * chamelium_get_audio_channel_mapping:
> + * @chamelium: the Chamelium instance
> + * @port: the audio port
> + * @mapping: will be filled with the channel mapping
> + *
> + * Obtains the channel mapping for an audio port.
> + *
> + * Audio channels are not guaranteed not to be swapped. Users can use the
> + * channel mapping to match an input channel to a capture channel.
> + *
> + * The mapping contains one element per capture channel. Each element indicates
> + * which input channel the capture channel is mapped to. As a special case, -1
> + * means that the channel isn't mapped.
> + */
> +void chamelium_get_audio_channel_mapping(struct chamelium *chamelium,
> +					 struct chamelium_port *port,
> +					 int mapping[static 8])
> +{
> +	xmlrpc_value *res, *res_channel;
> +	int res_len, i;
> +
> +	res = chamelium_rpc(chamelium, port, "GetAudioChannelMapping", "(i)",
> +			    port->id);
> +	res_len = xmlrpc_array_size(&chamelium->env, res);
> +	igt_assert(res_len == 8);
> +	for (i = 0; i < res_len; i++) {
> +		xmlrpc_array_read_item(&chamelium->env, res, i, &res_channel);
> +		xmlrpc_read_int(&chamelium->env, res_channel, &mapping[i]);
> +		xmlrpc_DECREF(res_channel);
> +	}
> +	xmlrpc_DECREF(res);
> +}
> +
>  /**
>   * chamelium_start_capturing_audio:
>   * @chamelium: the Chamelium instance
> diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> index 047f8c5d..728d16ea 100644
> --- a/lib/igt_chamelium.h
> +++ b/lib/igt_chamelium.h
> @@ -106,6 +106,9 @@ void chamelium_start_capture(struct chamelium *chamelium,
>  void chamelium_stop_capture(struct chamelium *chamelium, int frame_count);
>  void chamelium_capture(struct chamelium *chamelium, struct chamelium_port *port,
>  		       int x, int y, int w, int h, int frame_count);
> +void chamelium_get_audio_channel_mapping(struct chamelium *chamelium,
> +					 struct chamelium_port *port,
> +					 int mapping[static 8]);
>  void chamelium_start_capturing_audio(struct chamelium *chamelium,
>  				    struct chamelium_port *port, bool save_to_file);
>  struct chamelium_audio_file *chamelium_stop_capturing_audio(struct chamelium *chamelium,
> diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
> index d336612f..8d6cc092 100644
> --- a/tests/kms_chamelium.c
> +++ b/tests/kms_chamelium.c
> @@ -777,7 +777,7 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  		      struct alsa *alsa, int playback_channels,
>  		      int playback_rate)
>  {
> -	int ret, capture_rate, capture_channels, msec, freq;
> +	int ret, capture_rate, capture_channels, msec, freq, step;
>  	struct chamelium_audio_file *audio_file;
>  	struct chamelium_stream *stream;
>  	enum chamelium_stream_realtime_mode stream_mode;
> @@ -792,16 +792,17 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  	int dump_fd = -1;
>  	pthread_t thread;
>  	struct audio_state state = {};
> +	int channel_mapping[8], capture_chan;
>  
>  	if (!alsa_test_output_configuration(alsa, playback_channels,
>  					    playback_rate)) {
> -		igt_debug("Skipping test with sample rate %d and %d channels "
> +		igt_debug("Skipping test with sample rate %d Hz and %d channels "
>  			  "because selected output devices don't support this "

How about "because at least some output devices do not support this"?

>  			  "configuration\n", playback_rate, playback_channels);
>  		return false;
>  	}
>  
> -	igt_debug("Testing with playback sampling rate %d and %d channels\n",
> +	igt_debug("Testing with playback sampling rate %d Hz and %d channels\n",
>  		  playback_rate, playback_channels);
>  	alsa_configure_output(alsa, playback_channels, playback_rate);
>  
> @@ -830,9 +831,15 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  	signal = audio_signal_init(playback_channels, playback_rate);
>  	igt_assert(signal);
>  
> +	/* We'll choose different frequencies per channel to make sure they are
> +	 * independent from each other. To do so, we'll add a different offset
> +	 * to the base frequencies for each channel. We need to choose a big
> +	 * enough offset so that we're sure to detect mixed up channels.
> +	 */
> +	step = 2 * capture_rate / CAPTURE_SAMPLES;

Please say that this formula adds an offset of 2 bins in the final FFT,
thus enforcing a clear difference (please make sure of that).

>  	for (i = 0; i < test_frequencies_count; i++) {
>  		for (j = 0; j < playback_channels; j++) {
> -			freq = test_frequencies[i];
> +			freq = test_frequencies[i] + j * step;
>  			audio_signal_add_frequency(signal, freq, j);
>  		}
>  	}
> @@ -847,6 +854,20 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  	ret = pthread_create(&thread, NULL, run_audio_thread, alsa);
>  	igt_assert(ret == 0);
>  
> +	chamelium_get_audio_channel_mapping(data->chamelium, port,
> +					    channel_mapping);
> +	/* Make sure we can capture all channels we send. */
> +	for (i = 0; i < playback_channels; i++) {
> +		ok = false;
> +		for (j = 0; j < capture_channels; j++) {
> +			if (channel_mapping[j] == i) {
> +				ok = true;
> +				break;
> +			}
> +		}
> +		igt_assert(ok);
> +	}
> +
>  	/* Needs to be a multiple of 128, because that's the number of samples
>  	 * we get per channel each time we receive an audio page from the
>  	 * Chamelium device. */
> @@ -886,11 +907,15 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  		igt_debug("Detecting audio signal, t=%d msec\n", msec);
>  
>  		for (j = 0; j < playback_channels; j++) {
> -			igt_debug("Processing channel %zu\n", j);
> +			capture_chan = channel_mapping[j];
> +			igt_assert(capture_chan >= 0);
> +			igt_debug("Processing channel %zu (captured as "
> +				  "channel %d)\n", j, capture_chan);
>  
>  			audio_extract_channel_s32_le(channel, channel_len,
>  						     buf, buf_len,
> -						     capture_channels, j);
> +						     capture_channels,
> +						     capture_chan);
>  
>  			if (audio_signal_detect(signal, capture_rate, j,
>  						channel, channel_len))
> 

Looks great!

Reviewed-by: Martin Peres <martin.peres@linux.intel.com>
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [igt-dev] [PATCH i-g-t v6 5/7] tests/kms_chamelium: run audio test with multiple sampling rates
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 5/7] tests/kms_chamelium: run audio test with multiple sampling rates Simon Ser
@ 2019-04-23  7:58   ` Martin Peres
  2019-04-23 12:59     ` Ser, Simon
  0 siblings, 1 reply; 22+ messages in thread
From: Martin Peres @ 2019-04-23  7:58 UTC (permalink / raw)
  To: Simon Ser, igt-dev

On 17/04/2019 15:43, Simon Ser wrote:
> The audio test is now run multiple times with a variety of playback sampling
> rates.
> 
> We now query the capture audio format from the Chamelium XML-RPC API instead of
> hardcoding it.
> 
> One limitation is that we need to start sendting an audio signal before being

Typo on sending.

> able to query the capture audio format. However we need the capture sample rate
> to decide which frequencies we generate. For now we use the playback rate and
> check that it's the same as the capture rate.
> 
> Another limitation is that the DP receiver reports an unknown sampling rate
> during the 41.1KHz test. In this case we assume the capture rate is the same as
> the playback rate. We'll fail later anyway if this assumption is incorrect
> since we check the signal we receive.
> 
> Chameleon bug: https://crbug.com/950913
> 
> Signed-off-by: Simon Ser <simon.ser@intel.com>
> ---
>  lib/igt_chamelium.c        | 80 +++++++++++++++++++++++++-------------
>  lib/igt_chamelium.h        |  3 ++
>  lib/igt_chamelium_stream.c | 17 --------
>  lib/igt_chamelium_stream.h |  2 -
>  tests/kms_chamelium.c      | 56 +++++++++++++++-----------
>  5 files changed, 90 insertions(+), 68 deletions(-)
> 
> diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> index 6ac7b722..ffc68f35 100644
> --- a/lib/igt_chamelium.c
> +++ b/lib/igt_chamelium.c
> @@ -964,31 +964,6 @@ void chamelium_get_audio_channel_mapping(struct chamelium *chamelium,
>  	xmlrpc_DECREF(res);
>  }
>  
> -/**
> - * chamelium_start_capturing_audio:
> - * @chamelium: the Chamelium instance
> - * @port: the port to capture audio from (it must support audio)
> - * @save_to_file: whether the captured audio data should be saved to a file on
> - * the Chamelium device
> - *
> - * Starts capturing audio from a Chamelium port. To stop the capture, use
> - * #chamelium_stop_capturing_audio. To retrieve the audio data, either use the
> - * stream server or enable @save_to_file (the latter is mainly useful for
> - * debugging purposes).
> - *
> - * It isn't possible to capture audio from multiple ports at the same time.
> - */
> -void chamelium_start_capturing_audio(struct chamelium *chamelium,
> -				    struct chamelium_port *port,
> -				    bool save_to_file)
> -{
> -	xmlrpc_value *res;
> -
> -	res = chamelium_rpc(chamelium, port, "StartCapturingAudio", "(ib)",
> -			    port->id, save_to_file);
> -	xmlrpc_DECREF(res);
> -}
> -
>  static void audio_format_from_xml(struct chamelium *chamelium,
>  				  xmlrpc_value *res, int *rate, int *channels)
>  {
> @@ -1008,8 +983,10 @@ static void audio_format_from_xml(struct chamelium *chamelium,
>  	igt_assert(strcmp(sample_format, "S32_LE") == 0);
>  	free(sample_format);
>  
> -	xmlrpc_read_int(&chamelium->env, res_rate, rate);
> -	xmlrpc_read_int(&chamelium->env, res_channel, channels);
> +	if (rate)
> +		xmlrpc_read_int(&chamelium->env, res_rate, rate);
> +	if (channels)
> +		xmlrpc_read_int(&chamelium->env, res_channel, channels);
>  
>  	xmlrpc_DECREF(res_channel);
>  	xmlrpc_DECREF(res_sample_format);
> @@ -1017,6 +994,55 @@ static void audio_format_from_xml(struct chamelium *chamelium,
>  	xmlrpc_DECREF(res_type);
>  }
>  
> +/**
> + * chamelium_get_audio_format:
> + * @chamelium: the Chamelium instance
> + * @port: the audio port
> + * @rate: if non-NULL, will be set to the sample rate in Hz
> + * @channels: if non-NULL, will be set to the number of channels
> + *
> + * Obtains the audio format of the captured data. Users should start sending an
> + * audio signal to the Chamelium device prior to calling this function.
> + *
> + * The captured data is guaranteed to be in the S32_LE format.
> + */
> +void chamelium_get_audio_format(struct chamelium *chamelium,
> +				struct chamelium_port *port,
> +				int *rate, int *channels)
> +{
> +	xmlrpc_value *res;
> +
> +	res = chamelium_rpc(chamelium, port, "GetAudioFormat", "(i)",
> +			    port->id);
> +	audio_format_from_xml(chamelium, res, rate, channels);
> +	xmlrpc_DECREF(res);
> +}
> +
> +/**
> + * chamelium_start_capturing_audio:
> + * @chamelium: the Chamelium instance
> + * @port: the port to capture audio from (it must support audio)
> + * @save_to_file: whether the captured audio data should be saved to a file on
> + * the Chamelium device
> + *
> + * Starts capturing audio from a Chamelium port. To stop the capture, use
> + * #chamelium_stop_capturing_audio. To retrieve the audio data, either use the
> + * stream server or enable @save_to_file (the latter is mainly useful for
> + * debugging purposes).
> + *
> + * It isn't possible to capture audio from multiple ports at the same time.
> + */
> +void chamelium_start_capturing_audio(struct chamelium *chamelium,
> +				    struct chamelium_port *port,
> +				    bool save_to_file)
> +{
> +	xmlrpc_value *res;
> +
> +	res = chamelium_rpc(chamelium, port, "StartCapturingAudio", "(ib)",
> +			    port->id, save_to_file);
> +	xmlrpc_DECREF(res);
> +}
> +
>  /**
>   * chamelium_stop_capturing_audio:
>   * @chamelium: the Chamelium instance
> diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> index 728d16ea..f47b84cb 100644
> --- a/lib/igt_chamelium.h
> +++ b/lib/igt_chamelium.h
> @@ -109,6 +109,9 @@ void chamelium_capture(struct chamelium *chamelium, struct chamelium_port *port,
>  void chamelium_get_audio_channel_mapping(struct chamelium *chamelium,
>  					 struct chamelium_port *port,
>  					 int mapping[static 8]);
> +void chamelium_get_audio_format(struct chamelium *chamelium,
> +				struct chamelium_port *port,
> +				int *rate, int *channels);
>  void chamelium_start_capturing_audio(struct chamelium *chamelium,
>  				    struct chamelium_port *port, bool save_to_file);
>  struct chamelium_audio_file *chamelium_stop_capturing_audio(struct chamelium *chamelium,
> diff --git a/lib/igt_chamelium_stream.c b/lib/igt_chamelium_stream.c
> index 68ddb217..a8cd19e5 100644
> --- a/lib/igt_chamelium_stream.c
> +++ b/lib/igt_chamelium_stream.c
> @@ -537,23 +537,6 @@ bool chamelium_stream_stop_realtime_audio(struct chamelium_stream *client)
>  	return true;
>  }
>  
> -/**
> - * chamelium_stream_audio_format:
> - *
> - * Gets the format used for audio pages.
> - *
> - * Data will always be captured in raw pages of S32_LE elements. This function
> - * exposes the sampling rate and the number of channels.
> - */
> -void chamelium_stream_audio_format(struct chamelium_stream *stream,
> -				   int *rate, int *channels)
> -{
> -	/* TODO: the Chamelium streaming server doesn't expose those yet.
> -	 * Just hardcode the values for now. */
> -	*rate = 48000;
> -	*channels = 8;
> -}
> -
>  /**
>   * chamelium_stream_init:
>   *
> diff --git a/lib/igt_chamelium_stream.h b/lib/igt_chamelium_stream.h
> index de4e9931..3e1c5d14 100644
> --- a/lib/igt_chamelium_stream.h
> +++ b/lib/igt_chamelium_stream.h
> @@ -42,8 +42,6 @@ struct chamelium_stream *chamelium_stream_init(void);
>  void chamelium_stream_deinit(struct chamelium_stream *client);
>  bool chamelium_stream_dump_realtime_audio(struct chamelium_stream *client,
>  					  enum chamelium_stream_realtime_mode mode);
> -void chamelium_stream_audio_format(struct chamelium_stream *stream,
> -				   int *rate, int *channels);
>  bool chamelium_stream_receive_realtime_audio(struct chamelium_stream *client,
>  					     size_t *page_count,
>  					     int32_t **buf, size_t *buf_len);
> diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
> index 8d6cc092..f535ca52 100644
> --- a/tests/kms_chamelium.c
> +++ b/tests/kms_chamelium.c
> @@ -725,15 +725,14 @@ test_display_frame_dump(data_t *data, struct chamelium_port *port)
>  /* A streak of 3 gives confidence that the signal is good. */
>  #define MIN_STREAK 3
>  
> -/* TODO: Chamelium only supports 48KHz for now */
>  static int sampling_rates[] = {
> -/*	32000, */
> -/*	44100, */
> +	32000,
> +	44100,
>  	48000,
> -/*	88200, */
> -/*	96000, */
> -/*	176400, */
> -/*	192000, */
> +	88200,
> +	96000,
> +	176400,
> +	192000,
>  };
>  
>  static int sampling_rates_count = sizeof(sampling_rates) / sizeof(int);
> @@ -815,19 +814,6 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  	ok = chamelium_stream_dump_realtime_audio(stream, stream_mode);
>  	igt_assert(ok);
>  
> -	chamelium_stream_audio_format(stream, &capture_rate, &capture_channels);
> -
> -	if (igt_frame_dump_is_enabled()) {
> -		snprintf(dump_suffix, sizeof(dump_suffix), "capture-%dch-%d",
> -			 playback_channels, playback_rate);
> -
> -		dump_fd = audio_create_wav_file_s32_le(dump_suffix,
> -						       capture_rate,
> -						       capture_channels,
> -						       &dump_path);
> -		igt_assert(dump_fd >= 0);
> -	}
> -
>  	signal = audio_signal_init(playback_channels, playback_rate);
>  	igt_assert(signal);
>  
> @@ -835,8 +821,12 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  	 * independent from each other. To do so, we'll add a different offset
>  	 * to the base frequencies for each channel. We need to choose a big
>  	 * enough offset so that we're sure to detect mixed up channels.
> +	 *
> +	 * Note that we assume capture_rate == playback_rate. We'll assert this
> +	 * later on. We cannot retrieve the capture rate before starting
> +	 * playing audio, so we don't really have the choice.
>  	 */
> -	step = 2 * capture_rate / CAPTURE_SAMPLES;
> +	step = 2 * playback_rate / CAPTURE_SAMPLES;
>  	for (i = 0; i < test_frequencies_count; i++) {
>  		for (j = 0; j < playback_channels; j++) {
>  			freq = test_frequencies[i] + j * step;
> @@ -854,6 +844,17 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  	ret = pthread_create(&thread, NULL, run_audio_thread, alsa);
>  	igt_assert(ret == 0);
>  
> +	/* Only after we've started playing audio, we can retrieve the capture
> +	 * format used by the Chamelium device. */
> +	chamelium_get_audio_format(data->chamelium, port,
> +				   &capture_rate, &capture_channels);
> +	if (capture_rate == 0) {
> +		igt_debug("Audio receiver doesn't indicate the capture "
> +			 "sampling rate, assuming it's %d Hz\n", playback_rate);
> +		capture_rate = playback_rate;
> +	} else
> +		igt_assert(capture_rate == playback_rate);
> +
>  	chamelium_get_audio_channel_mapping(data->chamelium, port,
>  					    channel_mapping);
>  	/* Make sure we can capture all channels we send. */
> @@ -868,6 +869,17 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  		igt_assert(ok);
>  	}
>  
> +	if (igt_frame_dump_is_enabled()) {
> +		snprintf(dump_suffix, sizeof(dump_suffix), "capture-%dch-%d",
> +			 playback_channels, playback_rate);
> +
> +		dump_fd = audio_create_wav_file_s32_le(dump_suffix,
> +						       capture_rate,
> +						       capture_channels,
> +						       &dump_path);
> +		igt_assert(dump_fd >= 0);
> +	}
> +

This belongs to another commit.

>  	/* Needs to be a multiple of 128, because that's the number of samples
>  	 * we get per channel each time we receive an audio page from the
>  	 * Chamelium device. */
> @@ -939,7 +951,7 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>  
>  	if (dump_fd >= 0) {
>  		close(dump_fd);
> -		if (streak == MIN_STREAK) {
> +		if (success) {
>  			/* Test succeeded, no need to keep the captured data */
>  			unlink(dump_path);
>  		} else
> 

Dito.

Otherwise, the code looks OK:

Reviewed-by: Martin Peres <martin.peres@linux.intel.com>
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [igt-dev] [PATCH i-g-t v6 7/7] HAX: add dp-audio test to fast-feedback
  2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 7/7] HAX: add dp-audio test to fast-feedback Simon Ser
@ 2019-04-23  8:04   ` Martin Peres
  0 siblings, 0 replies; 22+ messages in thread
From: Martin Peres @ 2019-04-23  8:04 UTC (permalink / raw)
  To: Simon Ser, igt-dev

On 17/04/2019 15:43, Simon Ser wrote:
> Waiting for the whole series to be complete to decide whether or not we want
> this test in fast-feedback.

Let's have a discussion to run these in BAT whenever we have confidence
that these tests can be run in less than 10s and work reliably :)

> 
> Signed-off-by: Simon Ser <simon.ser@intel.com>
> ---
>  tests/intel-ci/fast-feedback.testlist | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/tests/intel-ci/fast-feedback.testlist b/tests/intel-ci/fast-feedback.testlist
> index 40475b1a..28f5fa55 100644
> --- a/tests/intel-ci/fast-feedback.testlist
> +++ b/tests/intel-ci/fast-feedback.testlist
> @@ -175,6 +175,7 @@ igt@kms_addfb_basic@unused-pitches
>  igt@kms_busy@basic-flip-a
>  igt@kms_busy@basic-flip-b
>  igt@kms_busy@basic-flip-c
> +igt@kms_chamelium@dp-audio
>  igt@kms_chamelium@dp-hpd-fast
>  igt@kms_chamelium@dp-edid-read
>  igt@kms_chamelium@dp-crc-fast
> 
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [igt-dev] ✓ Fi.CI.BAT: success for tests/kms_chamelium: add dp-audio test (rev7)
  2019-04-17 17:23 ` [igt-dev] ✓ Fi.CI.BAT: success for tests/kms_chamelium: add dp-audio test (rev7) Patchwork
@ 2019-04-23  8:05   ` Martin Peres
  0 siblings, 0 replies; 22+ messages in thread
From: Martin Peres @ 2019-04-23  8:05 UTC (permalink / raw)
  To: igt-dev, Patchwork, Ser, Simon

On 17/04/2019 20:23, Patchwork wrote:
> == Series Details ==
> 
> Series: tests/kms_chamelium: add dp-audio test (rev7)
> URL   : https://patchwork.freedesktop.org/series/59058/
> State : success
> 
> == Summary ==
> 
> CI Bug Log - changes from CI_DRM_5948 -> IGTPW_2887
> ====================================================
> 
> Summary
> -------
> 
>   **SUCCESS**
> 
>   No regressions found.
> 
>   External URL: https://patchwork.freedesktop.org/api/1.0/series/59058/revisions/7/mbox/
> 
> Possible new issues
> -------------------
> 
>   Here are the unknown changes that may have been introduced in IGTPW_2887:
> 
> ### IGT changes ###
> 
> #### Possible regressions ####
> 
>   * {igt@kms_chamelium@dp-audio} (NEW):
>     - fi-kbl-7500u:       NOTRUN -> FAIL

This is expected because the chamelium in CI has not been updated.

Anyway, outstanding work Simon! Congratulations!

Martin
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [igt-dev] [PATCH i-g-t v6 3/7] tests/kms_chamelium: test we receive a signal from both audio channels
  2019-04-23  7:41   ` Martin Peres
@ 2019-04-23 12:23     ` Ser, Simon
  0 siblings, 0 replies; 22+ messages in thread
From: Ser, Simon @ 2019-04-23 12:23 UTC (permalink / raw)
  To: igt-dev, martin.peres

On Tue, 2019-04-23 at 10:41 +0300, Martin Peres wrote:
> On 17/04/2019 15:43, Simon Ser wrote:
> > This commit updates the audio test to make sure we receive a signal from both
> > audio channels. However this commit doesn't check that left and right channels
> > are not swapped. Such a check requires some more work (because the Chamelium
> > device does swap left and right channels) and will be implemented in a future
> > commit.
> > 
> > This commit adds a new channel argument to audio_signal_add_frequency, to add
> > a frequency to a single channel only.
> > 
> > Some light refactoring has been performed (a proper audio_signal_deinit
> > function has been introduced) and logging has been improved.
> > 
> > Signed-off-by: Simon Ser <simon.ser@intel.com>
> > ---
> >  lib/igt_alsa.c        |  26 +++++++--
> >  lib/igt_audio.c       | 119 +++++++++++++++++++++++++-----------------
> >  lib/igt_audio.h       |  11 ++--
> >  tests/kms_chamelium.c |  56 ++++++++++++--------
> >  4 files changed, 137 insertions(+), 75 deletions(-)
> > 
> > diff --git a/lib/igt_alsa.c b/lib/igt_alsa.c
> > index fc6d336b..a478686a 100644
> > --- a/lib/igt_alsa.c
> > +++ b/lib/igt_alsa.c
> > @@ -182,6 +182,8 @@ static char *alsa_resolve_indentifier(const char *device_name, int skip)
> >  					continue;
> >  				}
> >  
> > +				igt_debug("Matched device \"%s\"\n", pcm_name);
> > +
> 
> Should have been a separate commit.

Split into a separate commit.

> >  				snprintf(name, sizeof(name), "hw:%d,%d", card,
> >  					 dev);
> >  
> > @@ -329,6 +331,9 @@ static bool alsa_test_configuration(snd_pcm_t *handle, int channels,
> >  {
> >  	snd_pcm_hw_params_t *params;
> >  	int ret;
> > +	unsigned int min_channels, max_channels;
> > +	unsigned int min_rate, max_rate;
> > +	int min_rate_dir, max_rate_dir;
> >  
> >  	snd_pcm_hw_params_alloca(&params);
> >  
> > @@ -337,12 +342,24 @@ static bool alsa_test_configuration(snd_pcm_t *handle, int channels,
> >  		return false;
> >  
> >  	ret = snd_pcm_hw_params_test_rate(handle, params, sampling_rate, 0);
> > -	if (ret < 0)
> > +	if (ret < 0) {
> > +		snd_pcm_hw_params_get_rate_min(params, &min_rate, &min_rate_dir);
> > +		snd_pcm_hw_params_get_rate_max(params, &max_rate, &max_rate_dir);
> > +		igt_debug("Output device supports rates between %u and %u, "
> > +			  "requested %d\n",
> > +			  min_rate, max_rate, sampling_rate);
> >  		return false;
> > +	}
> 
> This likely should be in patch 5/7.

Split into a separate commit instead (with other logging-related
changes).

> >  
> >  	ret = snd_pcm_hw_params_test_channels(handle, params, channels);
> > -	if (ret < 0)
> > +	if (ret < 0) {
> > +		snd_pcm_hw_params_get_channels_min(params, &min_channels);
> > +		snd_pcm_hw_params_get_channels_max(params, &max_channels);
> > +		igt_debug("Output device supports between %u and "
> > +			  "%u channels, requested %d\n",
> > +			  min_channels, max_channels, channels);
> >  		return false;
> > +	}
> >  
> >  	return true;
> >  }
> > @@ -409,13 +426,16 @@ void alsa_configure_output(struct alsa *alsa, int channels,
> >  	snd_pcm_t *handle;
> >  	int ret;
> >  	int i;
> > +	int soft_resample = 0; /* Don't allow ALSA to resample */
> > +	unsigned int latency = 0;
> >  
> >  	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);
> > +					 channels, sampling_rate,
> > +					 soft_resample, latency);
> 
> Probably should have been a separate commit again ;)

Split into a separate commit.

> >  		igt_assert(ret >= 0);
> >  	}
> >  
> > diff --git a/lib/igt_audio.c b/lib/igt_audio.c
> > index 7624f565..a2a5c594 100644
> > --- a/lib/igt_audio.c
> > +++ b/lib/igt_audio.c
> > @@ -35,7 +35,7 @@
> >  #include "igt_audio.h"
> >  #include "igt_core.h"
> >  
> > -#define FREQS_MAX	8
> > +#define FREQS_MAX 64
> >  
> >  /**
> >   * SECTION:igt_audio
> > @@ -49,9 +49,10 @@
> >  
> >  struct audio_signal_freq {
> >  	int freq;
> > +	int channel;
> >  
> > -	short *period;
> > -	int frames;
> > +	int16_t *period;
> > +	size_t period_len;
> >  	int offset;
> >  };
> >  
> > @@ -60,7 +61,7 @@ struct audio_signal {
> >  	int sampling_rate;
> >  
> >  	struct audio_signal_freq freqs[FREQS_MAX];
> > -	int freqs_count;
> > +	size_t freqs_count;
> >  };
> >  
> >  /**
> > @@ -89,21 +90,28 @@ struct audio_signal *audio_signal_init(int channels, int sampling_rate)
> >   * audio_signal_add_frequency:
> >   * @signal: The target signal structure
> >   * @frequency: The frequency to add to the signal
> > + * @channel: The channel to add this frequency to, or -1 to add it to all
> > + * channels
> >   *
> >   * 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 audio_signal_add_frequency(struct audio_signal *signal, int frequency,
> > +			       int channel)
> 
> Is the alignment correct here? Doesn't look like it!

Not sure what's going on with vim. It looks fine in vim, but looks bad
in git. Let's trust git.

> >  {
> > -	int index = signal->freqs_count;
> > +	size_t index = signal->freqs_count;
> > +	struct audio_signal_freq *freq;
> >  
> > -	if (index == FREQS_MAX)
> > -		return -1;
> > +	igt_assert(index < FREQS_MAX);
> > +	igt_assert(channel < signal->channels);
> >  
> >  	/* Stay within the Nyquist–Shannon sampling theorem. */
> > -	if (frequency > signal->sampling_rate / 2)
> > +	if (frequency > signal->sampling_rate / 2) {
> > +		igt_debug("Skipping frequency %d: too high for a %d Hz "
> > +			  "sampling rate\n", frequency, signal->sampling_rate);
> >  		return -1;
> > +	}
> 
> Should have been a separate commit.

Split into a separate commit (along with other logging-related
changes).

> >  
> >  	/* 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
> > @@ -111,11 +119,14 @@ int audio_signal_add_frequency(struct audio_signal *signal, int frequency)
> >  	 */
> >  	frequency = signal->sampling_rate / (signal->sampling_rate / frequency);
> >  
> > -	igt_debug("Adding test frequency %d\n", frequency);
> > +	igt_debug("Adding test frequency %d to channel %d\n",
> > +		  frequency, channel);
> > +
> > +	freq = &signal->freqs[index];
> > +	memset(freq, 0, sizeof(*freq));
> > +	freq->freq = frequency;
> > +	freq->channel = channel;
> >  
> > -	signal->freqs[index].freq = frequency;
> > -	signal->freqs[index].frames = 0;
> > -	signal->freqs[index].offset = 0;
> >  	signal->freqs_count++;
> >  
> >  	return 0;
> > @@ -133,20 +144,17 @@ void audio_signal_synthesize(struct audio_signal *signal)
> >  {
> >  	int16_t *period;
> >  	double value;
> > -	int frames;
> > +	size_t period_len;
> >  	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_len = signal->sampling_rate / freq;
> >  
> > -		period = calloc(1, frames * sizeof(short));
> > +		period = calloc(1, period_len * sizeof(int16_t));
> >  
> > -		for (j = 0; j < frames; j++) {
> > +		for (j = 0; j < period_len; j++) {
> >  			value = 2.0 * M_PI * freq / signal->sampling_rate * j;
> >  			value = sin(value) * INT16_MAX / signal->freqs_count;
> >  
> > @@ -154,26 +162,34 @@ void audio_signal_synthesize(struct audio_signal *signal)
> >  		}
> >  
> >  		signal->freqs[i].period = period;
> > -		signal->freqs[i].frames = frames;
> > +		signal->freqs[i].period_len = period_len;
> >  	}
> >  }
> >  
> >  /**
> > - * audio_signal_synthesize:
> > + * audio_signal_deinit:
> > + *
> > + * Release the signal.
> > + */
> > +void audio_signal_deinit(struct audio_signal *signal)
> 
> Is the coding style to use deinit or fini?

I've used deinit as the code I've seen (igt_alsa, igt_chamelium) uses
it. grep says _fini is used a lot more often though, so let's switch to
that convention.

> > +{
> > +	audio_signal_reset(signal);
> > +	free(signal);
> > +}
> > +
> > +/**
> > + * audio_signal_reset:
> >   * @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)
> > +void audio_signal_reset(struct audio_signal *signal)
> >  {
> > -	int i;
> > +	size_t 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));
> > +		free(signal->freqs[i].period);
> >  	}
> >  
> >  	signal->freqs_count = 0;
> > @@ -183,44 +199,45 @@ void audio_signal_clean(struct audio_signal *signal)
> >   * audio_signal_fill:
> >   * @signal: The target signal structure
> >   * @buffer: The target buffer to fill
> > - * @frames: The number of frames to fill
> > + * @samples: The number of samples to fill
> >   *
> > - * Fill the requested number of frames to the target buffer with the audio
> > + * Fill the requested number of samples 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, int16_t *buffer, int frames)
> > +void audio_signal_fill(struct audio_signal *signal, int16_t *buffer,
> > +		       size_t buffer_len)
> >  {
> >  	int16_t *destination, *source;
> > +	struct audio_signal_freq *freq;
> >  	int total;
> > -	int freq_frames;
> > -	int freq_offset;
> >  	int count;
> >  	int i, j, k;
> >  
> > -	memset(buffer, 0, sizeof(int16_t) * signal->channels * frames);
> > +	memset(buffer, 0, sizeof(int16_t) * signal->channels * buffer_len);
> >  
> >  	for (i = 0; i < signal->freqs_count; i++) {
> > +		freq = &signal->freqs[i];
> >  		total = 0;
> >  
> > -		while (total < frames) {
> > -			freq_frames = signal->freqs[i].frames;
> > -			freq_offset = signal->freqs[i].offset;
> > +		igt_assert(freq->period);
> >  
> > -			source = signal->freqs[i].period + freq_offset;
> > +		while (total < buffer_len) {
> > +			source = freq->period + freq->offset;
> >  			destination = buffer + total * signal->channels;
> >  
> > -			count = freq_frames - freq_offset;
> > -			if (count > (frames - total))
> > -				count = frames - total;
> > +			count = freq->period_len - freq->offset;
> > +			if (count > buffer_len - total)
> > +				count = buffer_len - total;
> >  
> > -			freq_offset += count;
> > -			freq_offset %= freq_frames;
> > -
> > -			signal->freqs[i].offset = freq_offset;
> > +			freq->offset += count;
> > +			freq->offset %= freq->period_len;
> >  
> >  			for (j = 0; j < count; j++) {
> >  				for (k = 0; k < signal->channels; k++) {
> > +					if (freq->channel >= 0 &&
> > +					    freq->channel != k)
> > +						continue;
> >  					destination[j * signal->channels + k] += source[j];
> >  				}
> >  			}
> > @@ -237,11 +254,11 @@ void audio_signal_fill(struct audio_signal *signal, int16_t *buffer, int frames)
> >   * sampling_rate is given in Hz. data_len is the number of elements in data.
> >   */
> >  bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
> > -			 double *data, size_t data_len)
> > +			 int channel, double *data, size_t data_len)
> >  {
> >  	size_t bin_power_len = data_len / 2 + 1;
> >  	double bin_power[bin_power_len];
> > -	bool detected[signal->freqs_count];
> > +	bool detected[FREQS_MAX];
> >  	int ret, freq_accuracy, freq, local_max_freq;
> >  	double max, local_max, threshold;
> >  	size_t i, j;
> > @@ -308,6 +325,10 @@ bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
> >  		 * invalid. */
> >  		if (bin_power[i] < threshold) {
> >  			for (j = 0; j < signal->freqs_count; j++) {
> > +				if (signal->freqs[j].channel >= 0 &&
> > +				    signal->freqs[j].channel != channel)
> > +					continue;
> > +
> >  				if (signal->freqs[j].freq >
> >  				    local_max_freq - freq_accuracy &&
> >  				    signal->freqs[j].freq <
> > @@ -340,6 +361,10 @@ bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
> >  
> >  	/* Check that all frequencies we generated have been detected. */
> >  	for (i = 0; i < signal->freqs_count; i++) {
> > +		if (signal->freqs[i].channel >= 0 &&
> > +		    signal->freqs[i].channel != channel)
> > +			continue;
> > +
> >  		if (!detected[i]) {
> >  			igt_debug("Missing frequency: %d\n",
> >  				  signal->freqs[i].freq);
> > diff --git a/lib/igt_audio.h b/lib/igt_audio.h
> > index 4aa43e69..fe26bb57 100644
> > --- a/lib/igt_audio.h
> > +++ b/lib/igt_audio.h
> > @@ -35,12 +35,15 @@
> >  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_deinit(struct audio_signal *signal);
> > +int audio_signal_add_frequency(struct audio_signal *signal, int frequency,
> > +			       int channel);
> >  void audio_signal_synthesize(struct audio_signal *signal);
> > -void audio_signal_clean(struct audio_signal *signal);
> > -void audio_signal_fill(struct audio_signal *signal, int16_t *buffer, int frames);
> > +void audio_signal_reset(struct audio_signal *signal);
> > +void audio_signal_fill(struct audio_signal *signal, int16_t *buffer,
> > +		       size_t buffer_len);
> >  bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
> > -			 double *data, size_t data_len);
> > +			 int channel, double *data, size_t data_len);
> >  size_t audio_extract_channel_s32_le(double *dst, size_t dst_cap,
> >  				    int32_t *src, size_t src_len,
> >  				    int n_channels, int channel);
> > diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
> > index 014a22b3..d336612f 100644
> > --- a/tests/kms_chamelium.c
> > +++ b/tests/kms_chamelium.c
> > @@ -777,16 +777,16 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
> >  		      struct alsa *alsa, int playback_channels,
> >  		      int playback_rate)
> >  {
> > -	int ret, capture_rate, capture_channels, msec;
> > +	int ret, capture_rate, capture_channels, msec, freq;
> >  	struct chamelium_audio_file *audio_file;
> >  	struct chamelium_stream *stream;
> >  	enum chamelium_stream_realtime_mode stream_mode;
> >  	struct audio_signal *signal;
> >  	int32_t *recv, *buf;
> >  	double *channel;
> > -	size_t i, streak, page_count;
> > +	size_t i, j, streak, page_count;
> >  	size_t recv_len, buf_len, buf_cap, buf_size, channel_len;
> > -	bool ok;
> > +	bool ok, success;
> >  	char dump_suffix[64];
> >  	char *dump_path = NULL;
> >  	int dump_fd = -1;
> > @@ -794,10 +794,15 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
> >  	struct audio_state state = {};
> >  
> >  	if (!alsa_test_output_configuration(alsa, playback_channels,
> > -					    playback_rate))
> > +					    playback_rate)) {
> > +		igt_debug("Skipping test with sample rate %d and %d channels "
> > +			  "because selected output devices don't support this "
> > +			  "configuration\n", playback_rate, playback_channels);
> >  		return false;
> > +	}
> >  
> > -	igt_debug("Testing with playback sampling rate %d\n", playback_rate);
> > +	igt_debug("Testing with playback sampling rate %d and %d channels\n",
> > +		  playback_rate, playback_channels);
> >  	alsa_configure_output(alsa, playback_channels, playback_rate);
> >  
> >  	chamelium_start_capturing_audio(data->chamelium, port, false);
> > @@ -825,8 +830,12 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
> >  	signal = audio_signal_init(playback_channels, playback_rate);
> >  	igt_assert(signal);
> >  
> > -	for (i = 0; i < test_frequencies_count; i++)
> > -		audio_signal_add_frequency(signal, test_frequencies[i]);
> > +	for (i = 0; i < test_frequencies_count; i++) {
> > +		for (j = 0; j < playback_channels; j++) {
> > +			freq = test_frequencies[i];
> > +			audio_signal_add_frequency(signal, freq, j);
> > +		}
> > +	}
> >  	audio_signal_synthesize(signal);
> >  
> >  	state.signal = signal;
> > @@ -851,10 +860,11 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
> >  	recv = NULL;
> >  	recv_len = 0;
> >  
> > +	success = false;
> >  	streak = 0;
> >  	msec = 0;
> >  	i = 0;
> > -	while (streak < MIN_STREAK && msec < AUDIO_TIMEOUT) {
> > +	while (!success && msec < AUDIO_TIMEOUT) {
> >  		ok = chamelium_stream_receive_realtime_audio(stream,
> >  							     &page_count,
> >  							     &recv, &recv_len);
> > @@ -872,21 +882,27 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
> >  			igt_assert(write(dump_fd, buf, buf_size) == buf_size);
> >  		}
> >  
> > -		/* TODO: check other channels too, not just the first one */
> > -		audio_extract_channel_s32_le(channel, channel_len, buf, buf_len,
> > -					     capture_channels, 0);
> > -
> >  		msec = i * channel_len / (double) capture_rate * 1000;
> >  		igt_debug("Detecting audio signal, t=%d msec\n", msec);
> >  
> > -		if (audio_signal_detect(signal, capture_rate, channel,
> > -					channel_len))
> > -			streak++;
> > -		else
> > -			streak = 0;
> > +		for (j = 0; j < playback_channels; j++) {
> > +			igt_debug("Processing channel %zu\n", j);
> > +
> > +			audio_extract_channel_s32_le(channel, channel_len,
> > +						     buf, buf_len,
> > +						     capture_channels, j);
> > +
> > +			if (audio_signal_detect(signal, capture_rate, j,
> > +						channel, channel_len))
> > +				streak++;
> > +			else
> > +				streak = 0;
> > +		}
> >  
> >  		buf_len = 0;
> >  		i++;
> > +
> > +		success = streak == MIN_STREAK * playback_channels;
> >  	}
> >  
> >  	igt_debug("Stopping audio playback\n");
> > @@ -921,12 +937,10 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
> >  		chamelium_destroy_audio_file(audio_file);
> >  	}
> >  
> > -	audio_signal_clean(signal);
> > -	free(signal);
> > -
> > +	audio_signal_deinit(signal);
> >  	chamelium_stream_deinit(stream);
> >  
> > -	igt_assert(streak == MIN_STREAK);
> > +	igt_assert(success);
> >  	return true;
> >  }
> >  
> 
> With the coding style issues fixed:
> 
> Reviewed-by: Martin Peres <martin.peres@linux.intel.com>

Thanks for the review!
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [igt-dev] [PATCH i-g-t v6 4/7] tests/kms_chamelium: test audio channels are not mixed up
  2019-04-23  7:51   ` Martin Peres
@ 2019-04-23 12:57     ` Ser, Simon
  0 siblings, 0 replies; 22+ messages in thread
From: Ser, Simon @ 2019-04-23 12:57 UTC (permalink / raw)
  To: igt-dev, martin.peres

On Tue, 2019-04-23 at 10:51 +0300, Martin Peres wrote:
> On 17/04/2019 15:43, Simon Ser wrote:
> > Send a different signal to each channel and make sure captured audio channels
> > are not swapped or mixed up.
> > 
> > The Chamelium device has a bug and already swaps the left and right channels.
> > For this reason, clients need to retrieve the Chamelium channel mapping and
> > accomodate for this. See https://crbug.com/950922 for a discussion about this.
> > 
> > Signed-off-by: Simon Ser <simon.ser@intel.com>
> > ---
> >  lib/igt_chamelium.c   | 34 ++++++++++++++++++++++++++++++++++
> >  lib/igt_chamelium.h   |  3 +++
> >  tests/kms_chamelium.c | 37 +++++++++++++++++++++++++++++++------
> >  3 files changed, 68 insertions(+), 6 deletions(-)
> > 
> > diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> > index 7c9030d1..6ac7b722 100644
> > --- a/lib/igt_chamelium.c
> > +++ b/lib/igt_chamelium.c
> > @@ -930,6 +930,40 @@ int chamelium_get_captured_frame_count(struct chamelium *chamelium)
> >  	return ret;
> >  }
> >  
> > +/**
> > + * chamelium_get_audio_channel_mapping:
> > + * @chamelium: the Chamelium instance
> > + * @port: the audio port
> > + * @mapping: will be filled with the channel mapping
> > + *
> > + * Obtains the channel mapping for an audio port.
> > + *
> > + * Audio channels are not guaranteed not to be swapped. Users can use the
> > + * channel mapping to match an input channel to a capture channel.
> > + *
> > + * The mapping contains one element per capture channel. Each element indicates
> > + * which input channel the capture channel is mapped to. As a special case, -1
> > + * means that the channel isn't mapped.
> > + */
> > +void chamelium_get_audio_channel_mapping(struct chamelium *chamelium,
> > +					 struct chamelium_port *port,
> > +					 int mapping[static 8])
> > +{
> > +	xmlrpc_value *res, *res_channel;
> > +	int res_len, i;
> > +
> > +	res = chamelium_rpc(chamelium, port, "GetAudioChannelMapping", "(i)",
> > +			    port->id);
> > +	res_len = xmlrpc_array_size(&chamelium->env, res);
> > +	igt_assert(res_len == 8);
> > +	for (i = 0; i < res_len; i++) {
> > +		xmlrpc_array_read_item(&chamelium->env, res, i, &res_channel);
> > +		xmlrpc_read_int(&chamelium->env, res_channel, &mapping[i]);
> > +		xmlrpc_DECREF(res_channel);
> > +	}
> > +	xmlrpc_DECREF(res);
> > +}
> > +
> >  /**
> >   * chamelium_start_capturing_audio:
> >   * @chamelium: the Chamelium instance
> > diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> > index 047f8c5d..728d16ea 100644
> > --- a/lib/igt_chamelium.h
> > +++ b/lib/igt_chamelium.h
> > @@ -106,6 +106,9 @@ void chamelium_start_capture(struct chamelium *chamelium,
> >  void chamelium_stop_capture(struct chamelium *chamelium, int frame_count);
> >  void chamelium_capture(struct chamelium *chamelium, struct chamelium_port *port,
> >  		       int x, int y, int w, int h, int frame_count);
> > +void chamelium_get_audio_channel_mapping(struct chamelium *chamelium,
> > +					 struct chamelium_port *port,
> > +					 int mapping[static 8]);
> >  void chamelium_start_capturing_audio(struct chamelium *chamelium,
> >  				    struct chamelium_port *port, bool save_to_file);
> >  struct chamelium_audio_file *chamelium_stop_capturing_audio(struct chamelium *chamelium,
> > diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
> > index d336612f..8d6cc092 100644
> > --- a/tests/kms_chamelium.c
> > +++ b/tests/kms_chamelium.c
> > @@ -777,7 +777,7 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
> >  		      struct alsa *alsa, int playback_channels,
> >  		      int playback_rate)
> >  {
> > -	int ret, capture_rate, capture_channels, msec, freq;
> > +	int ret, capture_rate, capture_channels, msec, freq, step;
> >  	struct chamelium_audio_file *audio_file;
> >  	struct chamelium_stream *stream;
> >  	enum chamelium_stream_realtime_mode stream_mode;
> > @@ -792,16 +792,17 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
> >  	int dump_fd = -1;
> >  	pthread_t thread;
> >  	struct audio_state state = {};
> > +	int channel_mapping[8], capture_chan;
> >  
> >  	if (!alsa_test_output_configuration(alsa, playback_channels,
> >  					    playback_rate)) {
> > -		igt_debug("Skipping test with sample rate %d and %d channels "
> > +		igt_debug("Skipping test with sample rate %d Hz and %d channels "
> >  			  "because selected output devices don't support this "
> 
> How about "because at least some output devices do not support this"?
> 
> >  			  "configuration\n", playback_rate, playback_channels);
> >  		return false;
> >  	}
> >  
> > -	igt_debug("Testing with playback sampling rate %d and %d channels\n",
> > +	igt_debug("Testing with playback sampling rate %d Hz and %d channels\n",
> >  		  playback_rate, playback_channels);
> >  	alsa_configure_output(alsa, playback_channels, playback_rate);
> >  
> > @@ -830,9 +831,15 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
> >  	signal = audio_signal_init(playback_channels, playback_rate);
> >  	igt_assert(signal);
> >  
> > +	/* We'll choose different frequencies per channel to make sure they are
> > +	 * independent from each other. To do so, we'll add a different offset
> > +	 * to the base frequencies for each channel. We need to choose a big
> > +	 * enough offset so that we're sure to detect mixed up channels.
> > +	 */
> > +	step = 2 * capture_rate / CAPTURE_SAMPLES;
> 
> Please say that this formula adds an offset of 2 bins in the final FFT,
> thus enforcing a clear difference (please make sure of that).

Indeed, better to be clear about this. Yeah, made sure this is correct,
the formula is the same as the one in audio_signal_detect:

    freq = sampling_rate * i / data_len;

i is the bin index, data_len the number of samples.

> >  	for (i = 0; i < test_frequencies_count; i++) {
> >  		for (j = 0; j < playback_channels; j++) {
> > -			freq = test_frequencies[i];
> > +			freq = test_frequencies[i] + j * step;
> >  			audio_signal_add_frequency(signal, freq, j);
> >  		}
> >  	}
> > @@ -847,6 +854,20 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
> >  	ret = pthread_create(&thread, NULL, run_audio_thread, alsa);
> >  	igt_assert(ret == 0);
> >  
> > +	chamelium_get_audio_channel_mapping(data->chamelium, port,
> > +					    channel_mapping);
> > +	/* Make sure we can capture all channels we send. */
> > +	for (i = 0; i < playback_channels; i++) {
> > +		ok = false;
> > +		for (j = 0; j < capture_channels; j++) {
> > +			if (channel_mapping[j] == i) {
> > +				ok = true;
> > +				break;
> > +			}
> > +		}
> > +		igt_assert(ok);
> > +	}
> > +
> >  	/* Needs to be a multiple of 128, because that's the number of samples
> >  	 * we get per channel each time we receive an audio page from the
> >  	 * Chamelium device. */
> > @@ -886,11 +907,15 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
> >  		igt_debug("Detecting audio signal, t=%d msec\n", msec);
> >  
> >  		for (j = 0; j < playback_channels; j++) {
> > -			igt_debug("Processing channel %zu\n", j);
> > +			capture_chan = channel_mapping[j];
> > +			igt_assert(capture_chan >= 0);
> > +			igt_debug("Processing channel %zu (captured as "
> > +				  "channel %d)\n", j, capture_chan);
> >  
> >  			audio_extract_channel_s32_le(channel, channel_len,
> >  						     buf, buf_len,
> > -						     capture_channels, j);
> > +						     capture_channels,
> > +						     capture_chan);
> >  
> >  			if (audio_signal_detect(signal, capture_rate, j,
> >  						channel, channel_len))
> > 
> 
> Looks great!
> 
> Reviewed-by: Martin Peres <martin.peres@linux.intel.com>
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [igt-dev] [PATCH i-g-t v6 5/7] tests/kms_chamelium: run audio test with multiple sampling rates
  2019-04-23  7:58   ` Martin Peres
@ 2019-04-23 12:59     ` Ser, Simon
  2019-04-25  9:58       ` Martin Peres
  0 siblings, 1 reply; 22+ messages in thread
From: Ser, Simon @ 2019-04-23 12:59 UTC (permalink / raw)
  To: igt-dev, martin.peres

On Tue, 2019-04-23 at 10:58 +0300, Martin Peres wrote:
> On 17/04/2019 15:43, Simon Ser wrote:
> > The audio test is now run multiple times with a variety of playback sampling
> > rates.
> > 
> > We now query the capture audio format from the Chamelium XML-RPC API instead of
> > hardcoding it.
> > 
> > One limitation is that we need to start sendting an audio signal before being
> 
> Typo on sending.
> 
> > able to query the capture audio format. However we need the capture sample rate
> > to decide which frequencies we generate. For now we use the playback rate and
> > check that it's the same as the capture rate.
> > 
> > Another limitation is that the DP receiver reports an unknown sampling rate
> > during the 41.1KHz test. In this case we assume the capture rate is the same as
> > the playback rate. We'll fail later anyway if this assumption is incorrect
> > since we check the signal we receive.
> > 
> > Chameleon bug: https://crbug.com/950913
> > 
> > Signed-off-by: Simon Ser <simon.ser@intel.com>
> > ---
> >  lib/igt_chamelium.c        | 80 +++++++++++++++++++++++++-------------
> >  lib/igt_chamelium.h        |  3 ++
> >  lib/igt_chamelium_stream.c | 17 --------
> >  lib/igt_chamelium_stream.h |  2 -
> >  tests/kms_chamelium.c      | 56 +++++++++++++++-----------
> >  5 files changed, 90 insertions(+), 68 deletions(-)
> > 
> > diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> > index 6ac7b722..ffc68f35 100644
> > --- a/lib/igt_chamelium.c
> > +++ b/lib/igt_chamelium.c
> > @@ -964,31 +964,6 @@ void chamelium_get_audio_channel_mapping(struct chamelium *chamelium,
> >  	xmlrpc_DECREF(res);
> >  }
> >  
> > -/**
> > - * chamelium_start_capturing_audio:
> > - * @chamelium: the Chamelium instance
> > - * @port: the port to capture audio from (it must support audio)
> > - * @save_to_file: whether the captured audio data should be saved to a file on
> > - * the Chamelium device
> > - *
> > - * Starts capturing audio from a Chamelium port. To stop the capture, use
> > - * #chamelium_stop_capturing_audio. To retrieve the audio data, either use the
> > - * stream server or enable @save_to_file (the latter is mainly useful for
> > - * debugging purposes).
> > - *
> > - * It isn't possible to capture audio from multiple ports at the same time.
> > - */
> > -void chamelium_start_capturing_audio(struct chamelium *chamelium,
> > -				    struct chamelium_port *port,
> > -				    bool save_to_file)
> > -{
> > -	xmlrpc_value *res;
> > -
> > -	res = chamelium_rpc(chamelium, port, "StartCapturingAudio", "(ib)",
> > -			    port->id, save_to_file);
> > -	xmlrpc_DECREF(res);
> > -}
> > -
> >  static void audio_format_from_xml(struct chamelium *chamelium,
> >  				  xmlrpc_value *res, int *rate, int *channels)
> >  {
> > @@ -1008,8 +983,10 @@ static void audio_format_from_xml(struct chamelium *chamelium,
> >  	igt_assert(strcmp(sample_format, "S32_LE") == 0);
> >  	free(sample_format);
> >  
> > -	xmlrpc_read_int(&chamelium->env, res_rate, rate);
> > -	xmlrpc_read_int(&chamelium->env, res_channel, channels);
> > +	if (rate)
> > +		xmlrpc_read_int(&chamelium->env, res_rate, rate);
> > +	if (channels)
> > +		xmlrpc_read_int(&chamelium->env, res_channel, channels);
> >  
> >  	xmlrpc_DECREF(res_channel);
> >  	xmlrpc_DECREF(res_sample_format);
> > @@ -1017,6 +994,55 @@ static void audio_format_from_xml(struct chamelium *chamelium,
> >  	xmlrpc_DECREF(res_type);
> >  }
> >  
> > +/**
> > + * chamelium_get_audio_format:
> > + * @chamelium: the Chamelium instance
> > + * @port: the audio port
> > + * @rate: if non-NULL, will be set to the sample rate in Hz
> > + * @channels: if non-NULL, will be set to the number of channels
> > + *
> > + * Obtains the audio format of the captured data. Users should start sending an
> > + * audio signal to the Chamelium device prior to calling this function.
> > + *
> > + * The captured data is guaranteed to be in the S32_LE format.
> > + */
> > +void chamelium_get_audio_format(struct chamelium *chamelium,
> > +				struct chamelium_port *port,
> > +				int *rate, int *channels)
> > +{
> > +	xmlrpc_value *res;
> > +
> > +	res = chamelium_rpc(chamelium, port, "GetAudioFormat", "(i)",
> > +			    port->id);
> > +	audio_format_from_xml(chamelium, res, rate, channels);
> > +	xmlrpc_DECREF(res);
> > +}
> > +
> > +/**
> > + * chamelium_start_capturing_audio:
> > + * @chamelium: the Chamelium instance
> > + * @port: the port to capture audio from (it must support audio)
> > + * @save_to_file: whether the captured audio data should be saved to a file on
> > + * the Chamelium device
> > + *
> > + * Starts capturing audio from a Chamelium port. To stop the capture, use
> > + * #chamelium_stop_capturing_audio. To retrieve the audio data, either use the
> > + * stream server or enable @save_to_file (the latter is mainly useful for
> > + * debugging purposes).
> > + *
> > + * It isn't possible to capture audio from multiple ports at the same time.
> > + */
> > +void chamelium_start_capturing_audio(struct chamelium *chamelium,
> > +				    struct chamelium_port *port,
> > +				    bool save_to_file)
> > +{
> > +	xmlrpc_value *res;
> > +
> > +	res = chamelium_rpc(chamelium, port, "StartCapturingAudio", "(ib)",
> > +			    port->id, save_to_file);
> > +	xmlrpc_DECREF(res);
> > +}
> > +
> >  /**
> >   * chamelium_stop_capturing_audio:
> >   * @chamelium: the Chamelium instance
> > diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> > index 728d16ea..f47b84cb 100644
> > --- a/lib/igt_chamelium.h
> > +++ b/lib/igt_chamelium.h
> > @@ -109,6 +109,9 @@ void chamelium_capture(struct chamelium *chamelium, struct chamelium_port *port,
> >  void chamelium_get_audio_channel_mapping(struct chamelium *chamelium,
> >  					 struct chamelium_port *port,
> >  					 int mapping[static 8]);
> > +void chamelium_get_audio_format(struct chamelium *chamelium,
> > +				struct chamelium_port *port,
> > +				int *rate, int *channels);
> >  void chamelium_start_capturing_audio(struct chamelium *chamelium,
> >  				    struct chamelium_port *port, bool save_to_file);
> >  struct chamelium_audio_file *chamelium_stop_capturing_audio(struct chamelium *chamelium,
> > diff --git a/lib/igt_chamelium_stream.c b/lib/igt_chamelium_stream.c
> > index 68ddb217..a8cd19e5 100644
> > --- a/lib/igt_chamelium_stream.c
> > +++ b/lib/igt_chamelium_stream.c
> > @@ -537,23 +537,6 @@ bool chamelium_stream_stop_realtime_audio(struct chamelium_stream *client)
> >  	return true;
> >  }
> >  
> > -/**
> > - * chamelium_stream_audio_format:
> > - *
> > - * Gets the format used for audio pages.
> > - *
> > - * Data will always be captured in raw pages of S32_LE elements. This function
> > - * exposes the sampling rate and the number of channels.
> > - */
> > -void chamelium_stream_audio_format(struct chamelium_stream *stream,
> > -				   int *rate, int *channels)
> > -{
> > -	/* TODO: the Chamelium streaming server doesn't expose those yet.
> > -	 * Just hardcode the values for now. */
> > -	*rate = 48000;
> > -	*channels = 8;
> > -}
> > -
> >  /**
> >   * chamelium_stream_init:
> >   *
> > diff --git a/lib/igt_chamelium_stream.h b/lib/igt_chamelium_stream.h
> > index de4e9931..3e1c5d14 100644
> > --- a/lib/igt_chamelium_stream.h
> > +++ b/lib/igt_chamelium_stream.h
> > @@ -42,8 +42,6 @@ struct chamelium_stream *chamelium_stream_init(void);
> >  void chamelium_stream_deinit(struct chamelium_stream *client);
> >  bool chamelium_stream_dump_realtime_audio(struct chamelium_stream *client,
> >  					  enum chamelium_stream_realtime_mode mode);
> > -void chamelium_stream_audio_format(struct chamelium_stream *stream,
> > -				   int *rate, int *channels);
> >  bool chamelium_stream_receive_realtime_audio(struct chamelium_stream *client,
> >  					     size_t *page_count,
> >  					     int32_t **buf, size_t *buf_len);
> > diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
> > index 8d6cc092..f535ca52 100644
> > --- a/tests/kms_chamelium.c
> > +++ b/tests/kms_chamelium.c
> > @@ -725,15 +725,14 @@ test_display_frame_dump(data_t *data, struct chamelium_port *port)
> >  /* A streak of 3 gives confidence that the signal is good. */
> >  #define MIN_STREAK 3
> >  
> > -/* TODO: Chamelium only supports 48KHz for now */
> >  static int sampling_rates[] = {
> > -/*	32000, */
> > -/*	44100, */
> > +	32000,
> > +	44100,
> >  	48000,
> > -/*	88200, */
> > -/*	96000, */
> > -/*	176400, */
> > -/*	192000, */
> > +	88200,
> > +	96000,
> > +	176400,
> > +	192000,
> >  };
> >  
> >  static int sampling_rates_count = sizeof(sampling_rates) / sizeof(int);
> > @@ -815,19 +814,6 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
> >  	ok = chamelium_stream_dump_realtime_audio(stream, stream_mode);
> >  	igt_assert(ok);
> >  
> > -	chamelium_stream_audio_format(stream, &capture_rate, &capture_channels);
> > -
> > -	if (igt_frame_dump_is_enabled()) {
> > -		snprintf(dump_suffix, sizeof(dump_suffix), "capture-%dch-%d",
> > -			 playback_channels, playback_rate);
> > -
> > -		dump_fd = audio_create_wav_file_s32_le(dump_suffix,
> > -						       capture_rate,
> > -						       capture_channels,
> > -						       &dump_path);
> > -		igt_assert(dump_fd >= 0);
> > -	}
> > -
> >  	signal = audio_signal_init(playback_channels, playback_rate);
> >  	igt_assert(signal);
> >  
> > @@ -835,8 +821,12 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
> >  	 * independent from each other. To do so, we'll add a different offset
> >  	 * to the base frequencies for each channel. We need to choose a big
> >  	 * enough offset so that we're sure to detect mixed up channels.
> > +	 *
> > +	 * Note that we assume capture_rate == playback_rate. We'll assert this
> > +	 * later on. We cannot retrieve the capture rate before starting
> > +	 * playing audio, so we don't really have the choice.
> >  	 */
> > -	step = 2 * capture_rate / CAPTURE_SAMPLES;
> > +	step = 2 * playback_rate / CAPTURE_SAMPLES;
> >  	for (i = 0; i < test_frequencies_count; i++) {
> >  		for (j = 0; j < playback_channels; j++) {
> >  			freq = test_frequencies[i] + j * step;
> > @@ -854,6 +844,17 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
> >  	ret = pthread_create(&thread, NULL, run_audio_thread, alsa);
> >  	igt_assert(ret == 0);
> >  
> > +	/* Only after we've started playing audio, we can retrieve the capture
> > +	 * format used by the Chamelium device. */
> > +	chamelium_get_audio_format(data->chamelium, port,
> > +				   &capture_rate, &capture_channels);
> > +	if (capture_rate == 0) {
> > +		igt_debug("Audio receiver doesn't indicate the capture "
> > +			 "sampling rate, assuming it's %d Hz\n", playback_rate);
> > +		capture_rate = playback_rate;
> > +	} else
> > +		igt_assert(capture_rate == playback_rate);
> > +
> >  	chamelium_get_audio_channel_mapping(data->chamelium, port,
> >  					    channel_mapping);
> >  	/* Make sure we can capture all channels we send. */
> > @@ -868,6 +869,17 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
> >  		igt_assert(ok);
> >  	}
> >  
> > +	if (igt_frame_dump_is_enabled()) {
> > +		snprintf(dump_suffix, sizeof(dump_suffix), "capture-%dch-%d",
> > +			 playback_channels, playback_rate);
> > +
> > +		dump_fd = audio_create_wav_file_s32_le(dump_suffix,
> > +						       capture_rate,
> > +						       capture_channels,
> > +						       &dump_path);
> > +		igt_assert(dump_fd >= 0);
> > +	}
> > +
> 
> This belongs to another commit.

Nack. This has just been moved around, see line 815 above. This is
necessary because of the new chamelium_get_audio_format call.

> >  	/* Needs to be a multiple of 128, because that's the number of samples
> >  	 * we get per channel each time we receive an audio page from the
> >  	 * Chamelium device. */
> > @@ -939,7 +951,7 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
> >  
> >  	if (dump_fd >= 0) {
> >  		close(dump_fd);
> > -		if (streak == MIN_STREAK) {
> > +		if (success) {
> >  			/* Test succeeded, no need to keep the captured data */
> >  			unlink(dump_path);
> >  		} else
> > 
> 
> Dito.

Ack. Moved to patch 3 "tests/kms_chamelium: test we receive a signal
from both audio channels" which introduced this variable.

> Otherwise, the code looks OK:
> 
> Reviewed-by: Martin Peres <martin.peres@linux.intel.com>
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [igt-dev] [PATCH i-g-t v6 5/7] tests/kms_chamelium: run audio test with multiple sampling rates
  2019-04-23 12:59     ` Ser, Simon
@ 2019-04-25  9:58       ` Martin Peres
  0 siblings, 0 replies; 22+ messages in thread
From: Martin Peres @ 2019-04-25  9:58 UTC (permalink / raw)
  To: Ser, Simon, igt-dev

On 23/04/2019 15:59, Ser, Simon wrote:
> On Tue, 2019-04-23 at 10:58 +0300, Martin Peres wrote:
>> On 17/04/2019 15:43, Simon Ser wrote:
>>> The audio test is now run multiple times with a variety of playback sampling
>>> rates.
>>>
>>> We now query the capture audio format from the Chamelium XML-RPC API instead of
>>> hardcoding it.
>>>
>>> One limitation is that we need to start sendting an audio signal before being
>>
>> Typo on sending.
>>
>>> able to query the capture audio format. However we need the capture sample rate
>>> to decide which frequencies we generate. For now we use the playback rate and
>>> check that it's the same as the capture rate.
>>>
>>> Another limitation is that the DP receiver reports an unknown sampling rate
>>> during the 41.1KHz test. In this case we assume the capture rate is the same as
>>> the playback rate. We'll fail later anyway if this assumption is incorrect
>>> since we check the signal we receive.
>>>
>>> Chameleon bug: https://crbug.com/950913
>>>
>>> Signed-off-by: Simon Ser <simon.ser@intel.com>
>>> ---
>>>  lib/igt_chamelium.c        | 80 +++++++++++++++++++++++++-------------
>>>  lib/igt_chamelium.h        |  3 ++
>>>  lib/igt_chamelium_stream.c | 17 --------
>>>  lib/igt_chamelium_stream.h |  2 -
>>>  tests/kms_chamelium.c      | 56 +++++++++++++++-----------
>>>  5 files changed, 90 insertions(+), 68 deletions(-)
>>>
>>> diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
>>> index 6ac7b722..ffc68f35 100644
>>> --- a/lib/igt_chamelium.c
>>> +++ b/lib/igt_chamelium.c
>>> @@ -964,31 +964,6 @@ void chamelium_get_audio_channel_mapping(struct chamelium *chamelium,
>>>  	xmlrpc_DECREF(res);
>>>  }
>>>  
>>> -/**
>>> - * chamelium_start_capturing_audio:
>>> - * @chamelium: the Chamelium instance
>>> - * @port: the port to capture audio from (it must support audio)
>>> - * @save_to_file: whether the captured audio data should be saved to a file on
>>> - * the Chamelium device
>>> - *
>>> - * Starts capturing audio from a Chamelium port. To stop the capture, use
>>> - * #chamelium_stop_capturing_audio. To retrieve the audio data, either use the
>>> - * stream server or enable @save_to_file (the latter is mainly useful for
>>> - * debugging purposes).
>>> - *
>>> - * It isn't possible to capture audio from multiple ports at the same time.
>>> - */
>>> -void chamelium_start_capturing_audio(struct chamelium *chamelium,
>>> -				    struct chamelium_port *port,
>>> -				    bool save_to_file)
>>> -{
>>> -	xmlrpc_value *res;
>>> -
>>> -	res = chamelium_rpc(chamelium, port, "StartCapturingAudio", "(ib)",
>>> -			    port->id, save_to_file);
>>> -	xmlrpc_DECREF(res);
>>> -}
>>> -
>>>  static void audio_format_from_xml(struct chamelium *chamelium,
>>>  				  xmlrpc_value *res, int *rate, int *channels)
>>>  {
>>> @@ -1008,8 +983,10 @@ static void audio_format_from_xml(struct chamelium *chamelium,
>>>  	igt_assert(strcmp(sample_format, "S32_LE") == 0);
>>>  	free(sample_format);
>>>  
>>> -	xmlrpc_read_int(&chamelium->env, res_rate, rate);
>>> -	xmlrpc_read_int(&chamelium->env, res_channel, channels);
>>> +	if (rate)
>>> +		xmlrpc_read_int(&chamelium->env, res_rate, rate);
>>> +	if (channels)
>>> +		xmlrpc_read_int(&chamelium->env, res_channel, channels);
>>>  
>>>  	xmlrpc_DECREF(res_channel);
>>>  	xmlrpc_DECREF(res_sample_format);
>>> @@ -1017,6 +994,55 @@ static void audio_format_from_xml(struct chamelium *chamelium,
>>>  	xmlrpc_DECREF(res_type);
>>>  }
>>>  
>>> +/**
>>> + * chamelium_get_audio_format:
>>> + * @chamelium: the Chamelium instance
>>> + * @port: the audio port
>>> + * @rate: if non-NULL, will be set to the sample rate in Hz
>>> + * @channels: if non-NULL, will be set to the number of channels
>>> + *
>>> + * Obtains the audio format of the captured data. Users should start sending an
>>> + * audio signal to the Chamelium device prior to calling this function.
>>> + *
>>> + * The captured data is guaranteed to be in the S32_LE format.
>>> + */
>>> +void chamelium_get_audio_format(struct chamelium *chamelium,
>>> +				struct chamelium_port *port,
>>> +				int *rate, int *channels)
>>> +{
>>> +	xmlrpc_value *res;
>>> +
>>> +	res = chamelium_rpc(chamelium, port, "GetAudioFormat", "(i)",
>>> +			    port->id);
>>> +	audio_format_from_xml(chamelium, res, rate, channels);
>>> +	xmlrpc_DECREF(res);
>>> +}
>>> +
>>> +/**
>>> + * chamelium_start_capturing_audio:
>>> + * @chamelium: the Chamelium instance
>>> + * @port: the port to capture audio from (it must support audio)
>>> + * @save_to_file: whether the captured audio data should be saved to a file on
>>> + * the Chamelium device
>>> + *
>>> + * Starts capturing audio from a Chamelium port. To stop the capture, use
>>> + * #chamelium_stop_capturing_audio. To retrieve the audio data, either use the
>>> + * stream server or enable @save_to_file (the latter is mainly useful for
>>> + * debugging purposes).
>>> + *
>>> + * It isn't possible to capture audio from multiple ports at the same time.
>>> + */
>>> +void chamelium_start_capturing_audio(struct chamelium *chamelium,
>>> +				    struct chamelium_port *port,
>>> +				    bool save_to_file)
>>> +{
>>> +	xmlrpc_value *res;
>>> +
>>> +	res = chamelium_rpc(chamelium, port, "StartCapturingAudio", "(ib)",
>>> +			    port->id, save_to_file);
>>> +	xmlrpc_DECREF(res);
>>> +}
>>> +
>>>  /**
>>>   * chamelium_stop_capturing_audio:
>>>   * @chamelium: the Chamelium instance
>>> diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
>>> index 728d16ea..f47b84cb 100644
>>> --- a/lib/igt_chamelium.h
>>> +++ b/lib/igt_chamelium.h
>>> @@ -109,6 +109,9 @@ void chamelium_capture(struct chamelium *chamelium, struct chamelium_port *port,
>>>  void chamelium_get_audio_channel_mapping(struct chamelium *chamelium,
>>>  					 struct chamelium_port *port,
>>>  					 int mapping[static 8]);
>>> +void chamelium_get_audio_format(struct chamelium *chamelium,
>>> +				struct chamelium_port *port,
>>> +				int *rate, int *channels);
>>>  void chamelium_start_capturing_audio(struct chamelium *chamelium,
>>>  				    struct chamelium_port *port, bool save_to_file);
>>>  struct chamelium_audio_file *chamelium_stop_capturing_audio(struct chamelium *chamelium,
>>> diff --git a/lib/igt_chamelium_stream.c b/lib/igt_chamelium_stream.c
>>> index 68ddb217..a8cd19e5 100644
>>> --- a/lib/igt_chamelium_stream.c
>>> +++ b/lib/igt_chamelium_stream.c
>>> @@ -537,23 +537,6 @@ bool chamelium_stream_stop_realtime_audio(struct chamelium_stream *client)
>>>  	return true;
>>>  }
>>>  
>>> -/**
>>> - * chamelium_stream_audio_format:
>>> - *
>>> - * Gets the format used for audio pages.
>>> - *
>>> - * Data will always be captured in raw pages of S32_LE elements. This function
>>> - * exposes the sampling rate and the number of channels.
>>> - */
>>> -void chamelium_stream_audio_format(struct chamelium_stream *stream,
>>> -				   int *rate, int *channels)
>>> -{
>>> -	/* TODO: the Chamelium streaming server doesn't expose those yet.
>>> -	 * Just hardcode the values for now. */
>>> -	*rate = 48000;
>>> -	*channels = 8;
>>> -}
>>> -
>>>  /**
>>>   * chamelium_stream_init:
>>>   *
>>> diff --git a/lib/igt_chamelium_stream.h b/lib/igt_chamelium_stream.h
>>> index de4e9931..3e1c5d14 100644
>>> --- a/lib/igt_chamelium_stream.h
>>> +++ b/lib/igt_chamelium_stream.h
>>> @@ -42,8 +42,6 @@ struct chamelium_stream *chamelium_stream_init(void);
>>>  void chamelium_stream_deinit(struct chamelium_stream *client);
>>>  bool chamelium_stream_dump_realtime_audio(struct chamelium_stream *client,
>>>  					  enum chamelium_stream_realtime_mode mode);
>>> -void chamelium_stream_audio_format(struct chamelium_stream *stream,
>>> -				   int *rate, int *channels);
>>>  bool chamelium_stream_receive_realtime_audio(struct chamelium_stream *client,
>>>  					     size_t *page_count,
>>>  					     int32_t **buf, size_t *buf_len);
>>> diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
>>> index 8d6cc092..f535ca52 100644
>>> --- a/tests/kms_chamelium.c
>>> +++ b/tests/kms_chamelium.c
>>> @@ -725,15 +725,14 @@ test_display_frame_dump(data_t *data, struct chamelium_port *port)
>>>  /* A streak of 3 gives confidence that the signal is good. */
>>>  #define MIN_STREAK 3
>>>  
>>> -/* TODO: Chamelium only supports 48KHz for now */
>>>  static int sampling_rates[] = {
>>> -/*	32000, */
>>> -/*	44100, */
>>> +	32000,
>>> +	44100,
>>>  	48000,
>>> -/*	88200, */
>>> -/*	96000, */
>>> -/*	176400, */
>>> -/*	192000, */
>>> +	88200,
>>> +	96000,
>>> +	176400,
>>> +	192000,
>>>  };
>>>  
>>>  static int sampling_rates_count = sizeof(sampling_rates) / sizeof(int);
>>> @@ -815,19 +814,6 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>>>  	ok = chamelium_stream_dump_realtime_audio(stream, stream_mode);
>>>  	igt_assert(ok);
>>>  
>>> -	chamelium_stream_audio_format(stream, &capture_rate, &capture_channels);
>>> -
>>> -	if (igt_frame_dump_is_enabled()) {
>>> -		snprintf(dump_suffix, sizeof(dump_suffix), "capture-%dch-%d",
>>> -			 playback_channels, playback_rate);
>>> -
>>> -		dump_fd = audio_create_wav_file_s32_le(dump_suffix,
>>> -						       capture_rate,
>>> -						       capture_channels,
>>> -						       &dump_path);
>>> -		igt_assert(dump_fd >= 0);
>>> -	}
>>> -
>>>  	signal = audio_signal_init(playback_channels, playback_rate);
>>>  	igt_assert(signal);
>>>  
>>> @@ -835,8 +821,12 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>>>  	 * independent from each other. To do so, we'll add a different offset
>>>  	 * to the base frequencies for each channel. We need to choose a big
>>>  	 * enough offset so that we're sure to detect mixed up channels.
>>> +	 *
>>> +	 * Note that we assume capture_rate == playback_rate. We'll assert this
>>> +	 * later on. We cannot retrieve the capture rate before starting
>>> +	 * playing audio, so we don't really have the choice.
>>>  	 */
>>> -	step = 2 * capture_rate / CAPTURE_SAMPLES;
>>> +	step = 2 * playback_rate / CAPTURE_SAMPLES;
>>>  	for (i = 0; i < test_frequencies_count; i++) {
>>>  		for (j = 0; j < playback_channels; j++) {
>>>  			freq = test_frequencies[i] + j * step;
>>> @@ -854,6 +844,17 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>>>  	ret = pthread_create(&thread, NULL, run_audio_thread, alsa);
>>>  	igt_assert(ret == 0);
>>>  
>>> +	/* Only after we've started playing audio, we can retrieve the capture
>>> +	 * format used by the Chamelium device. */
>>> +	chamelium_get_audio_format(data->chamelium, port,
>>> +				   &capture_rate, &capture_channels);
>>> +	if (capture_rate == 0) {
>>> +		igt_debug("Audio receiver doesn't indicate the capture "
>>> +			 "sampling rate, assuming it's %d Hz\n", playback_rate);
>>> +		capture_rate = playback_rate;
>>> +	} else
>>> +		igt_assert(capture_rate == playback_rate);
>>> +
>>>  	chamelium_get_audio_channel_mapping(data->chamelium, port,
>>>  					    channel_mapping);
>>>  	/* Make sure we can capture all channels we send. */
>>> @@ -868,6 +869,17 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>>>  		igt_assert(ok);
>>>  	}
>>>  
>>> +	if (igt_frame_dump_is_enabled()) {
>>> +		snprintf(dump_suffix, sizeof(dump_suffix), "capture-%dch-%d",
>>> +			 playback_channels, playback_rate);
>>> +
>>> +		dump_fd = audio_create_wav_file_s32_le(dump_suffix,
>>> +						       capture_rate,
>>> +						       capture_channels,
>>> +						       &dump_path);
>>> +		igt_assert(dump_fd >= 0);
>>> +	}
>>> +
>>
>> This belongs to another commit.
> 
> Nack. This has just been moved around, see line 815 above. This is
> necessary because of the new chamelium_get_audio_format call.

OK, fair enough!

> 
>>>  	/* Needs to be a multiple of 128, because that's the number of samples
>>>  	 * we get per channel each time we receive an audio page from the
>>>  	 * Chamelium device. */
>>> @@ -939,7 +951,7 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
>>>  
>>>  	if (dump_fd >= 0) {
>>>  		close(dump_fd);
>>> -		if (streak == MIN_STREAK) {
>>> +		if (success) {
>>>  			/* Test succeeded, no need to keep the captured data */
>>>  			unlink(dump_path);
>>>  		} else
>>>
>>
>> Dito.
> 
> Ack. Moved to patch 3 "tests/kms_chamelium: test we receive a signal
> from both audio channels" which introduced this variable.

OK! Please apply my R-b!

> 
>> Otherwise, the code looks OK:
>>
>> Reviewed-by: Martin Peres <martin.peres@linux.intel.com>
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2019-04-25  9:58 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-17 12:43 [igt-dev] [PATCH i-g-t v6 0/7] tests/kms_chamelium: add dp-audio test Simon Ser
2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 1/7] " Simon Ser
2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 2/7] tests/kms_chamelium: capture audio data in real-time Simon Ser
2019-04-17 12:57   ` Martin Peres
2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 3/7] tests/kms_chamelium: test we receive a signal from both audio channels Simon Ser
2019-04-23  7:41   ` Martin Peres
2019-04-23 12:23     ` Ser, Simon
2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 4/7] tests/kms_chamelium: test audio channels are not mixed up Simon Ser
2019-04-23  7:51   ` Martin Peres
2019-04-23 12:57     ` Ser, Simon
2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 5/7] tests/kms_chamelium: run audio test with multiple sampling rates Simon Ser
2019-04-23  7:58   ` Martin Peres
2019-04-23 12:59     ` Ser, Simon
2019-04-25  9:58       ` Martin Peres
2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 6/7] lib/igt_edid: add support for Short Audio Descriptors Simon Ser
2019-04-17 12:43 ` [igt-dev] [PATCH i-g-t v6 7/7] HAX: add dp-audio test to fast-feedback Simon Ser
2019-04-23  8:04   ` Martin Peres
2019-04-17 13:25 ` [igt-dev] ✗ Fi.CI.BAT: failure for tests/kms_chamelium: add dp-audio test (rev6) Patchwork
2019-04-17 16:27   ` Ser, Simon
2019-04-17 17:23 ` [igt-dev] ✓ Fi.CI.BAT: success for tests/kms_chamelium: add dp-audio test (rev7) Patchwork
2019-04-23  8:05   ` Martin Peres
2019-04-18  1:25 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.