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

Changes in v7: addressed Martin's comments

Thanks for the detailed review! I've tried splitting some commits, let me know
if more splitting is needed.

Simon Ser (8):
  tests/kms_chamelium: add dp-audio test
  tests/kms_chamelium: capture audio data in real-time
  lib/igt_{alsa,audio}: improve logging
  lib/igt_alsa: use variables to improve readability
  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
  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/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                 | 355 +++++++++++++++-
 tests/meson.build                     |   9 +-
 20 files changed, 1614 insertions(+), 450 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] 16+ messages in thread

* [igt-dev] [PATCH i-g-t v7 1/8] tests/kms_chamelium: add dp-audio test
  2019-04-23 13:04 [igt-dev] [PATCH i-g-t v7 0/8] tests/kms_chamelium: add dp-audio test Simon Ser
@ 2019-04-23 13:04 ` Simon Ser
  2019-04-25 10:16   ` Petri Latvala
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 2/8] tests/kms_chamelium: capture audio data in real-time Simon Ser
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 16+ messages in thread
From: Simon Ser @ 2019-04-23 13:04 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 97f701c7..e0b9cf51 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -94,7 +94,7 @@ if valgrind.found()
 endif
 
 if gsl.found()
-	lib_deps += [ gsl ]
+	lib_deps += gsl
 	lib_sources += [ 'igt_frame.c', 'igt_audio.c' ]
 endif
 
@@ -103,9 +103,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] 16+ messages in thread

* [igt-dev] [PATCH i-g-t v7 2/8] tests/kms_chamelium: capture audio data in real-time
  2019-04-23 13:04 [igt-dev] [PATCH i-g-t v7 0/8] tests/kms_chamelium: add dp-audio test Simon Ser
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 1/8] " Simon Ser
@ 2019-04-23 13:04 ` Simon Ser
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 3/8] lib/igt_{alsa, audio}: improve logging Simon Ser
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Simon Ser @ 2019-04-23 13:04 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] 16+ messages in thread

* [igt-dev] [PATCH i-g-t v7 3/8] lib/igt_{alsa, audio}: improve logging
  2019-04-23 13:04 [igt-dev] [PATCH i-g-t v7 0/8] tests/kms_chamelium: add dp-audio test Simon Ser
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 1/8] " Simon Ser
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 2/8] tests/kms_chamelium: capture audio data in real-time Simon Ser
@ 2019-04-23 13:04 ` Simon Ser
  2019-04-25  9:53   ` Martin Peres
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 4/8] lib/igt_alsa: use variables to improve readability Simon Ser
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 16+ messages in thread
From: Simon Ser @ 2019-04-23 13:04 UTC (permalink / raw)
  To: igt-dev

- Print matched audio devices
- Print min/max values when alsa_test_configuration fails
- Print debug log line when skipping a frequency

Signed-off-by: Simon Ser <simon.ser@intel.com>
---
 lib/igt_alsa.c  | 21 +++++++++++++++++++--
 lib/igt_audio.c |  5 ++++-
 2 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/lib/igt_alsa.c b/lib/igt_alsa.c
index fc6d336b..3b1a9e90 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;
 }
diff --git a/lib/igt_audio.c b/lib/igt_audio.c
index 7624f565..5822fed7 100644
--- a/lib/igt_audio.c
+++ b/lib/igt_audio.c
@@ -102,8 +102,11 @@ int audio_signal_add_frequency(struct audio_signal *signal, int frequency)
 		return -1;
 
 	/* 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
-- 
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] 16+ messages in thread

* [igt-dev] [PATCH i-g-t v7 4/8] lib/igt_alsa: use variables to improve readability
  2019-04-23 13:04 [igt-dev] [PATCH i-g-t v7 0/8] tests/kms_chamelium: add dp-audio test Simon Ser
                   ` (2 preceding siblings ...)
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 3/8] lib/igt_{alsa, audio}: improve logging Simon Ser
@ 2019-04-23 13:04 ` Simon Ser
  2019-04-25  9:54   ` Martin Peres
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 5/8] tests/kms_chamelium: test we receive a signal from both audio channels Simon Ser
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 16+ messages in thread
From: Simon Ser @ 2019-04-23 13:04 UTC (permalink / raw)
  To: igt-dev

Most people don't have "remember what the last two parameters of
snd_pcm_set_params are" in their lifegoals list. Use variables so that it's
clearer what those are.

Signed-off-by: Simon Ser <simon.ser@intel.com>
---
 lib/igt_alsa.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lib/igt_alsa.c b/lib/igt_alsa.c
index 3b1a9e90..a478686a 100644
--- a/lib/igt_alsa.c
+++ b/lib/igt_alsa.c
@@ -426,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);
 	}
 
-- 
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] 16+ messages in thread

* [igt-dev] [PATCH i-g-t v7 5/8] tests/kms_chamelium: test we receive a signal from both audio channels
  2019-04-23 13:04 [igt-dev] [PATCH i-g-t v7 0/8] tests/kms_chamelium: add dp-audio test Simon Ser
                   ` (3 preceding siblings ...)
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 4/8] lib/igt_alsa: use variables to improve readability Simon Ser
@ 2019-04-23 13:04 ` Simon Ser
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 6/8] tests/kms_chamelium: test audio channels are not mixed up Simon Ser
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Simon Ser @ 2019-04-23 13:04 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_fini
function has been introduced and size_t in now used when it should be.

Signed-off-by: Simon Ser <simon.ser@intel.com>
---
 lib/igt_audio.c       | 114 +++++++++++++++++++++++++-----------------
 lib/igt_audio.h       |  11 ++--
 tests/kms_chamelium.c |  58 +++++++++++++--------
 3 files changed, 111 insertions(+), 72 deletions(-)

diff --git a/lib/igt_audio.c b/lib/igt_audio.c
index 5822fed7..5b0860e6 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,17 +90,21 @@ 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) {
@@ -114,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;
@@ -136,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;
 
@@ -157,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_fini:
+ *
+ * Release the signal.
+ */
+void audio_signal_fini(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;
@@ -186,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];
 				}
 			}
@@ -240,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;
@@ -311,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 <
@@ -343,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..466e772a 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_fini(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..687f64c4 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");
@@ -898,7 +914,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
@@ -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_fini(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] 16+ messages in thread

* [igt-dev] [PATCH i-g-t v7 6/8] tests/kms_chamelium: test audio channels are not mixed up
  2019-04-23 13:04 [igt-dev] [PATCH i-g-t v7 0/8] tests/kms_chamelium: add dp-audio test Simon Ser
                   ` (4 preceding siblings ...)
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 5/8] tests/kms_chamelium: test we receive a signal from both audio channels Simon Ser
@ 2019-04-23 13:04 ` Simon Ser
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 7/8] tests/kms_chamelium: run audio test with multiple sampling rates Simon Ser
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Simon Ser @ 2019-04-23 13:04 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>
Reviewed-by: Martin Peres <martin.peres@linux.intel.com>
---
 lib/igt_chamelium.c   | 34 +++++++++++++++++++++++++++++++++
 lib/igt_chamelium.h   |  3 +++
 tests/kms_chamelium.c | 44 +++++++++++++++++++++++++++++++++++--------
 3 files changed, 73 insertions(+), 8 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 687f64c4..1118da86 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,18 @@ 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 "
-			  "because selected output devices don't support this "
-			  "configuration\n", playback_rate, playback_channels);
+		igt_debug("Skipping test with sample rate %d Hz and %d channels "
+			  "because at least one of the selected output devices "
+			  "doesn'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 +832,17 @@ 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. We
+	 * choose an offset of two 2 bins in the final FFT to enforce a clear
+	 * difference.
+	 */
+	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 +857,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 +910,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] 16+ messages in thread

* [igt-dev] [PATCH i-g-t v7 7/8] tests/kms_chamelium: run audio test with multiple sampling rates
  2019-04-23 13:04 [igt-dev] [PATCH i-g-t v7 0/8] tests/kms_chamelium: add dp-audio test Simon Ser
                   ` (5 preceding siblings ...)
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 6/8] tests/kms_chamelium: test audio channels are not mixed up Simon Ser
@ 2019-04-23 13:04 ` Simon Ser
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 8/8] HAX: add dp-audio test to fast-feedback Simon Ser
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Simon Ser @ 2019-04-23 13:04 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 sending 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 44.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      | 54 +++++++++++++++----------
 5 files changed, 89 insertions(+), 67 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 1118da86..714e5e06 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);
@@ -816,19 +815,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);
 
@@ -838,8 +824,12 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
 	 * enough offset so that we're sure to detect mixed up channels. We
 	 * choose an offset of two 2 bins in the final FFT to enforce a clear
 	 * difference.
+	 *
+	 * 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;
@@ -857,6 +847,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. */
@@ -871,6 +872,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. */
-- 
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] 16+ messages in thread

* [igt-dev] [PATCH i-g-t v7 8/8] HAX: add dp-audio test to fast-feedback
  2019-04-23 13:04 [igt-dev] [PATCH i-g-t v7 0/8] tests/kms_chamelium: add dp-audio test Simon Ser
                   ` (6 preceding siblings ...)
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 7/8] tests/kms_chamelium: run audio test with multiple sampling rates Simon Ser
@ 2019-04-23 13:04 ` Simon Ser
  2019-04-23 15:29 ` [igt-dev] ✓ Fi.CI.BAT: success for tests/kms_chamelium: add dp-audio test (rev8) Patchwork
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Simon Ser @ 2019-04-23 13:04 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] 16+ messages in thread

* [igt-dev] ✓ Fi.CI.BAT: success for tests/kms_chamelium: add dp-audio test (rev8)
  2019-04-23 13:04 [igt-dev] [PATCH i-g-t v7 0/8] tests/kms_chamelium: add dp-audio test Simon Ser
                   ` (7 preceding siblings ...)
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 8/8] HAX: add dp-audio test to fast-feedback Simon Ser
@ 2019-04-23 15:29 ` Patchwork
  2019-04-23 18:33 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
  2019-04-25 10:00 ` [igt-dev] [PATCH i-g-t v7 0/8] tests/kms_chamelium: add dp-audio test Martin Peres
  10 siblings, 0 replies; 16+ messages in thread
From: Patchwork @ 2019-04-23 15:29 UTC (permalink / raw)
  To: Simon Ser; +Cc: igt-dev

== Series Details ==

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

== Summary ==

CI Bug Log - changes from CI_DRM_5971 -> IGTPW_2905
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

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

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

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

### IGT changes ###

#### Possible regressions ####

  * {igt@kms_chamelium@dp-audio} (NEW):
    - fi-kbl-7500u:       NOTRUN -> [FAIL][1]
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-kbl-7500u/igt@kms_chamelium@dp-audio.html
    - fi-icl-u2:          NOTRUN -> [SKIP][2]
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-icl-u2/igt@kms_chamelium@dp-audio.html

  
New tests
---------

  New tests have been introduced between CI_DRM_5971 and IGTPW_2905:

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

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

  

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

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

### IGT changes ###

#### Issues hit ####

  * igt@gem_exec_suspend@basic-s3:
    - fi-blb-e6850:       [PASS][3] -> [INCOMPLETE][4] ([fdo#107718])
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/fi-blb-e6850/igt@gem_exec_suspend@basic-s3.html
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-blb-e6850/igt@gem_exec_suspend@basic-s3.html

  * {igt@kms_chamelium@dp-audio} (NEW):
    - fi-skl-6770hq:      NOTRUN -> [SKIP][5] ([fdo#109271])
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-skl-6770hq/igt@kms_chamelium@dp-audio.html
    - fi-snb-2600:        NOTRUN -> [SKIP][6] ([fdo#109271])
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-snb-2600/igt@kms_chamelium@dp-audio.html
    - fi-bwr-2160:        NOTRUN -> [SKIP][7] ([fdo#109271])
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-bwr-2160/igt@kms_chamelium@dp-audio.html
    - fi-gdg-551:         NOTRUN -> [SKIP][8] ([fdo#109271])
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-gdg-551/igt@kms_chamelium@dp-audio.html
    - fi-skl-lmem:        NOTRUN -> [SKIP][9] ([fdo#109271])
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-skl-lmem/igt@kms_chamelium@dp-audio.html
    - fi-hsw-peppy:       NOTRUN -> [SKIP][10] ([fdo#109271])
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-hsw-peppy/igt@kms_chamelium@dp-audio.html
    - fi-kbl-8809g:       NOTRUN -> [SKIP][11] ([fdo#109271])
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-kbl-8809g/igt@kms_chamelium@dp-audio.html
    - fi-byt-n2820:       NOTRUN -> [SKIP][12] ([fdo#109271])
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-byt-n2820/igt@kms_chamelium@dp-audio.html
    - fi-kbl-r:           NOTRUN -> [SKIP][13] ([fdo#109271])
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-kbl-r/igt@kms_chamelium@dp-audio.html
    - fi-apl-guc:         NOTRUN -> [SKIP][14] ([fdo#109271])
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-apl-guc/igt@kms_chamelium@dp-audio.html
    - fi-kbl-7567u:       NOTRUN -> [SKIP][15] ([fdo#109271])
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-kbl-7567u/igt@kms_chamelium@dp-audio.html
    - fi-kbl-x1275:       NOTRUN -> [SKIP][16] ([fdo#109271])
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-kbl-x1275/igt@kms_chamelium@dp-audio.html
    - fi-pnv-d510:        NOTRUN -> [SKIP][17] ([fdo#109271])
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-pnv-d510/igt@kms_chamelium@dp-audio.html
    - fi-skl-6600u:       NOTRUN -> [SKIP][18] ([fdo#109271])
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-skl-6600u/igt@kms_chamelium@dp-audio.html
    - fi-icl-y:           NOTRUN -> [SKIP][19] ([fdo#109284])
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-icl-y/igt@kms_chamelium@dp-audio.html
    - fi-skl-iommu:       NOTRUN -> [SKIP][20] ([fdo#109271])
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-skl-iommu/igt@kms_chamelium@dp-audio.html
    - fi-byt-j1900:       NOTRUN -> [SKIP][21] ([fdo#109271])
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-byt-j1900/igt@kms_chamelium@dp-audio.html
    - fi-elk-e7500:       NOTRUN -> [SKIP][22] ([fdo#109271])
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-elk-e7500/igt@kms_chamelium@dp-audio.html
    - fi-skl-6700k2:      NOTRUN -> [SKIP][23] ([fdo#109271])
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-skl-6700k2/igt@kms_chamelium@dp-audio.html
    - fi-whl-u:           NOTRUN -> [SKIP][24] ([fdo#109271])
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-whl-u/igt@kms_chamelium@dp-audio.html
    - fi-bdw-5557u:       NOTRUN -> [SKIP][25] ([fdo#109271])
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-bdw-5557u/igt@kms_chamelium@dp-audio.html
    - fi-kbl-guc:         NOTRUN -> [SKIP][26] ([fdo#109271])
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-kbl-guc/igt@kms_chamelium@dp-audio.html
    - fi-cfl-8109u:       NOTRUN -> [SKIP][27] ([fdo#109271])
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-cfl-8109u/igt@kms_chamelium@dp-audio.html
    - fi-byt-clapper:     NOTRUN -> [SKIP][28] ([fdo#109271])
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-byt-clapper/igt@kms_chamelium@dp-audio.html
    - fi-hsw-4770r:       NOTRUN -> [SKIP][29] ([fdo#109271])
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-hsw-4770r/igt@kms_chamelium@dp-audio.html
    - fi-cfl-8700k:       NOTRUN -> [SKIP][30] ([fdo#109271])
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-cfl-8700k/igt@kms_chamelium@dp-audio.html
    - fi-bsw-kefka:       NOTRUN -> [SKIP][31] ([fdo#109271])
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-bsw-kefka/igt@kms_chamelium@dp-audio.html
    - fi-snb-2520m:       NOTRUN -> [SKIP][32] ([fdo#109271])
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-snb-2520m/igt@kms_chamelium@dp-audio.html
    - fi-skl-guc:         NOTRUN -> [SKIP][33] ([fdo#109271])
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-skl-guc/igt@kms_chamelium@dp-audio.html
    - fi-cfl-guc:         NOTRUN -> [SKIP][34] ([fdo#109271])
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-cfl-guc/igt@kms_chamelium@dp-audio.html
    - fi-bdw-gvtdvm:      NOTRUN -> [SKIP][35] ([fdo#109271])
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-bdw-gvtdvm/igt@kms_chamelium@dp-audio.html
    - fi-bsw-n3050:       NOTRUN -> [SKIP][36] ([fdo#109271])
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-bsw-n3050/igt@kms_chamelium@dp-audio.html
    - fi-ilk-650:         NOTRUN -> [SKIP][37] ([fdo#109271])
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-ilk-650/igt@kms_chamelium@dp-audio.html
    - fi-ivb-3770:        NOTRUN -> [SKIP][38] ([fdo#109271])
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-ivb-3770/igt@kms_chamelium@dp-audio.html
    - fi-skl-gvtdvm:      NOTRUN -> [SKIP][39] ([fdo#109271])
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-skl-gvtdvm/igt@kms_chamelium@dp-audio.html
    - fi-skl-6260u:       NOTRUN -> [SKIP][40] ([fdo#109271])
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-skl-6260u/igt@kms_chamelium@dp-audio.html
    - fi-bxt-j4205:       NOTRUN -> [SKIP][41] ([fdo#109271])
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-bxt-j4205/igt@kms_chamelium@dp-audio.html
    - fi-bxt-dsi:         NOTRUN -> [SKIP][42] ([fdo#109271])
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-bxt-dsi/igt@kms_chamelium@dp-audio.html
    - fi-hsw-4770:        NOTRUN -> [SKIP][43] ([fdo#109271])
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-hsw-4770/igt@kms_chamelium@dp-audio.html
    - fi-icl-u3:          NOTRUN -> [SKIP][44] ([fdo#109284])
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-icl-u3/igt@kms_chamelium@dp-audio.html

  * igt@kms_frontbuffer_tracking@basic:
    - fi-byt-clapper:     [PASS][45] -> [FAIL][46] ([fdo#103167])
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/fi-byt-clapper/igt@kms_frontbuffer_tracking@basic.html
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-byt-clapper/igt@kms_frontbuffer_tracking@basic.html

  * igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a:
    - fi-byt-clapper:     [PASS][47] -> [FAIL][48] ([fdo#103191])
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/fi-byt-clapper/igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a.html
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-byt-clapper/igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a.html

  
#### Possible fixes ####

  * igt@kms_flip@basic-flip-vs-wf_vblank:
    - fi-bwr-2160:        [FAIL][49] ([fdo#100368]) -> [PASS][50]
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/fi-bwr-2160/igt@kms_flip@basic-flip-vs-wf_vblank.html
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/fi-bwr-2160/igt@kms_flip@basic-flip-vs-wf_vblank.html

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

  [fdo#100368]: https://bugs.freedesktop.org/show_bug.cgi?id=100368
  [fdo#103167]: https://bugs.freedesktop.org/show_bug.cgi?id=103167
  [fdo#103191]: https://bugs.freedesktop.org/show_bug.cgi?id=103191
  [fdo#107718]: https://bugs.freedesktop.org/show_bug.cgi?id=107718
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109284]: https://bugs.freedesktop.org/show_bug.cgi?id=109284


Participating hosts (50 -> 44)
------------------------------

  Missing    (6): fi-ilk-m540 fi-hsw-4200u fi-byt-squawks fi-bsw-cyan fi-ctg-p8600 fi-bdw-samus 


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

  * IGT: IGT_4959 -> IGTPW_2905

  CI_DRM_5971: e91b848a66e8672c48ea65d082b260f13f2c86b9 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_2905: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/
  IGT_4959: 504367d33b787de2ba8e007a5b620cfd6f0b3074 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools



== Testlist changes ==

+igt@kms_chamelium@dp-audio
-igt@audio@hdmi-integrity
-igt@audio@hdmi-integrity-after-hibernate
-igt@audio@hdmi-integrity-after-suspend

== Logs ==

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

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

* [igt-dev] ✓ Fi.CI.IGT: success for tests/kms_chamelium: add dp-audio test (rev8)
  2019-04-23 13:04 [igt-dev] [PATCH i-g-t v7 0/8] tests/kms_chamelium: add dp-audio test Simon Ser
                   ` (8 preceding siblings ...)
  2019-04-23 15:29 ` [igt-dev] ✓ Fi.CI.BAT: success for tests/kms_chamelium: add dp-audio test (rev8) Patchwork
@ 2019-04-23 18:33 ` Patchwork
  2019-04-25 10:00 ` [igt-dev] [PATCH i-g-t v7 0/8] tests/kms_chamelium: add dp-audio test Martin Peres
  10 siblings, 0 replies; 16+ messages in thread
From: Patchwork @ 2019-04-23 18:33 UTC (permalink / raw)
  To: Simon Ser; +Cc: igt-dev

== Series Details ==

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

== Summary ==

CI Bug Log - changes from CI_DRM_5971_full -> IGTPW_2905_full
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

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

New tests
---------

  New tests have been introduced between CI_DRM_5971_full and IGTPW_2905_full:

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

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

  

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

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

### IGT changes ###

#### Issues hit ####

  * igt@gem_eio@unwedge-stress:
    - shard-snb:          [PASS][1] -> [FAIL][2] ([fdo#109661])
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-snb2/igt@gem_eio@unwedge-stress.html
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-snb7/igt@gem_eio@unwedge-stress.html

  * igt@gem_workarounds@suspend-resume-context:
    - shard-apl:          [PASS][3] -> [DMESG-WARN][4] ([fdo#108566]) +6 similar issues
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-apl5/igt@gem_workarounds@suspend-resume-context.html
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-apl5/igt@gem_workarounds@suspend-resume-context.html

  * {igt@kms_chamelium@dp-audio} (NEW):
    - shard-snb:          NOTRUN -> [SKIP][5] ([fdo#109271])
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-snb1/igt@kms_chamelium@dp-audio.html
    - shard-apl:          NOTRUN -> [SKIP][6] ([fdo#109271])
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-apl8/igt@kms_chamelium@dp-audio.html
    - shard-iclb:         NOTRUN -> [SKIP][7] ([fdo#109284])
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-iclb8/igt@kms_chamelium@dp-audio.html
    - shard-kbl:          NOTRUN -> [SKIP][8] ([fdo#109271])
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-kbl2/igt@kms_chamelium@dp-audio.html

  * igt@kms_cursor_crc@cursor-256x256-suspend:
    - shard-kbl:          [PASS][9] -> [FAIL][10] ([fdo#103232])
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-kbl7/igt@kms_cursor_crc@cursor-256x256-suspend.html
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-kbl6/igt@kms_cursor_crc@cursor-256x256-suspend.html

  * igt@kms_cursor_legacy@pipe-b-torture-bo:
    - shard-kbl:          [PASS][11] -> [DMESG-WARN][12] ([fdo#107122])
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-kbl4/igt@kms_cursor_legacy@pipe-b-torture-bo.html
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-kbl1/igt@kms_cursor_legacy@pipe-b-torture-bo.html

  * igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-shrfb-draw-pwrite:
    - shard-iclb:         [PASS][13] -> [FAIL][14] ([fdo#103167]) +7 similar issues
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-iclb6/igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-shrfb-draw-pwrite.html
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-iclb7/igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-shrfb-draw-pwrite.html

  * igt@kms_frontbuffer_tracking@psr-2p-scndscrn-indfb-plflip-blt:
    - shard-hsw:          NOTRUN -> [SKIP][15] ([fdo#109271]) +7 similar issues
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-hsw2/igt@kms_frontbuffer_tracking@psr-2p-scndscrn-indfb-plflip-blt.html

  * igt@kms_plane@plane-panning-bottom-right-suspend-pipe-a-planes:
    - shard-kbl:          [PASS][16] -> [INCOMPLETE][17] ([fdo#103665])
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-kbl4/igt@kms_plane@plane-panning-bottom-right-suspend-pipe-a-planes.html
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-kbl6/igt@kms_plane@plane-panning-bottom-right-suspend-pipe-a-planes.html

  * igt@kms_plane_alpha_blend@pipe-b-coverage-7efc:
    - shard-hsw:          NOTRUN -> [SKIP][18] ([fdo#109271] / [fdo#109278]) +1 similar issue
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-hsw8/igt@kms_plane_alpha_blend@pipe-b-coverage-7efc.html

  * igt@kms_plane_scaling@pipe-a-scaler-with-clipping-clamping:
    - shard-glk:          [PASS][19] -> [SKIP][20] ([fdo#109271] / [fdo#109278]) +1 similar issue
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-glk9/igt@kms_plane_scaling@pipe-a-scaler-with-clipping-clamping.html
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-glk3/igt@kms_plane_scaling@pipe-a-scaler-with-clipping-clamping.html

  * igt@kms_psr2_su@frontbuffer:
    - shard-iclb:         [PASS][21] -> [SKIP][22] ([fdo#109642])
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-iclb2/igt@kms_psr2_su@frontbuffer.html
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-iclb7/igt@kms_psr2_su@frontbuffer.html

  * igt@kms_rotation_crc@multiplane-rotation-cropping-top:
    - shard-kbl:          [PASS][23] -> [FAIL][24] ([fdo#109016])
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-kbl1/igt@kms_rotation_crc@multiplane-rotation-cropping-top.html
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-kbl5/igt@kms_rotation_crc@multiplane-rotation-cropping-top.html

  * igt@kms_setmode@basic:
    - shard-kbl:          [PASS][25] -> [FAIL][26] ([fdo#99912])
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-kbl4/igt@kms_setmode@basic.html
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-kbl7/igt@kms_setmode@basic.html

  
#### Possible fixes ####

  * igt@i915_pm_rc6_residency@rc6-accuracy:
    - shard-snb:          [SKIP][27] ([fdo#109271]) -> [PASS][28]
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-snb7/igt@i915_pm_rc6_residency@rc6-accuracy.html
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-snb6/igt@i915_pm_rc6_residency@rc6-accuracy.html

  * igt@i915_pm_rpm@i2c:
    - shard-iclb:         [FAIL][29] ([fdo#104097]) -> [PASS][30]
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-iclb8/igt@i915_pm_rpm@i2c.html
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-iclb6/igt@i915_pm_rpm@i2c.html

  * igt@i915_suspend@forcewake:
    - shard-apl:          [DMESG-WARN][31] ([fdo#108566]) -> [PASS][32] +2 similar issues
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-apl4/igt@i915_suspend@forcewake.html
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-apl3/igt@i915_suspend@forcewake.html

  * igt@kms_flip@flip-vs-suspend-interruptible:
    - shard-hsw:          [INCOMPLETE][33] ([fdo#103540]) -> [PASS][34]
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-hsw2/igt@kms_flip@flip-vs-suspend-interruptible.html
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-hsw8/igt@kms_flip@flip-vs-suspend-interruptible.html

  * igt@kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-blt:
    - shard-iclb:         [FAIL][35] ([fdo#103167]) -> [PASS][36] +1 similar issue
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-iclb4/igt@kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-blt.html
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-iclb8/igt@kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-blt.html

  * igt@kms_frontbuffer_tracking@fbc-1p-rte:
    - shard-iclb:         [FAIL][37] ([fdo#103167] / [fdo#110378]) -> [PASS][38]
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-iclb1/igt@kms_frontbuffer_tracking@fbc-1p-rte.html
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-iclb6/igt@kms_frontbuffer_tracking@fbc-1p-rte.html

  * igt@kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-draw-pwrite:
    - shard-glk:          [FAIL][39] ([fdo#103167]) -> [PASS][40]
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-glk8/igt@kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-draw-pwrite.html
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-glk6/igt@kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-draw-pwrite.html

  * igt@kms_psr@psr2_sprite_mmap_gtt:
    - shard-iclb:         [SKIP][41] ([fdo#109441]) -> [PASS][42] +2 similar issues
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-iclb7/igt@kms_psr@psr2_sprite_mmap_gtt.html
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-iclb2/igt@kms_psr@psr2_sprite_mmap_gtt.html

  * igt@kms_setmode@basic:
    - shard-apl:          [FAIL][43] ([fdo#99912]) -> [PASS][44]
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-apl6/igt@kms_setmode@basic.html
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-apl1/igt@kms_setmode@basic.html

  
#### Warnings ####

  * igt@gem_tiled_swapping@non-threaded:
    - shard-iclb:         [FAIL][45] ([fdo#108686]) -> [INCOMPLETE][46] ([fdo#107713] / [fdo#108686])
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-iclb1/igt@gem_tiled_swapping@non-threaded.html
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-iclb5/igt@gem_tiled_swapping@non-threaded.html

  * igt@kms_cursor_crc@cursor-256x256-suspend:
    - shard-apl:          [DMESG-WARN][47] ([fdo#108566]) -> [FAIL][48] ([fdo#103232])
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_5971/shard-apl5/igt@kms_cursor_crc@cursor-256x256-suspend.html
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/shard-apl5/igt@kms_cursor_crc@cursor-256x256-suspend.html

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

  [fdo#103167]: https://bugs.freedesktop.org/show_bug.cgi?id=103167
  [fdo#103232]: https://bugs.freedesktop.org/show_bug.cgi?id=103232
  [fdo#103540]: https://bugs.freedesktop.org/show_bug.cgi?id=103540
  [fdo#103665]: https://bugs.freedesktop.org/show_bug.cgi?id=103665
  [fdo#104097]: https://bugs.freedesktop.org/show_bug.cgi?id=104097
  [fdo#107122]: https://bugs.freedesktop.org/show_bug.cgi?id=107122
  [fdo#107713]: https://bugs.freedesktop.org/show_bug.cgi?id=107713
  [fdo#108566]: https://bugs.freedesktop.org/show_bug.cgi?id=108566
  [fdo#108686]: https://bugs.freedesktop.org/show_bug.cgi?id=108686
  [fdo#109016]: https://bugs.freedesktop.org/show_bug.cgi?id=109016
  [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#109441]: https://bugs.freedesktop.org/show_bug.cgi?id=109441
  [fdo#109642]: https://bugs.freedesktop.org/show_bug.cgi?id=109642
  [fdo#109661]: https://bugs.freedesktop.org/show_bug.cgi?id=109661
  [fdo#110378]: https://bugs.freedesktop.org/show_bug.cgi?id=110378
  [fdo#99912]: https://bugs.freedesktop.org/show_bug.cgi?id=99912


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

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


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

  * IGT: IGT_4959 -> IGTPW_2905
  * Piglit: piglit_4509 -> None

  CI_DRM_5971: e91b848a66e8672c48ea65d082b260f13f2c86b9 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_2905: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2905/
  IGT_4959: 504367d33b787de2ba8e007a5b620cfd6f0b3074 @ 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_2905/
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* Re: [igt-dev] [PATCH i-g-t v7 3/8] lib/igt_{alsa, audio}: improve logging
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 3/8] lib/igt_{alsa, audio}: improve logging Simon Ser
@ 2019-04-25  9:53   ` Martin Peres
  0 siblings, 0 replies; 16+ messages in thread
From: Martin Peres @ 2019-04-25  9:53 UTC (permalink / raw)
  To: Simon Ser, igt-dev

On 23/04/2019 16:04, Simon Ser wrote:
> - Print matched audio devices
> - Print min/max values when alsa_test_configuration fails
> - Print debug log line when skipping a frequency
> 
> Signed-off-by: Simon Ser <simon.ser@intel.com>

Reviewed-by: Martin Peres <martin.peres@linux.intel.com>

> ---
>  lib/igt_alsa.c  | 21 +++++++++++++++++++--
>  lib/igt_audio.c |  5 ++++-
>  2 files changed, 23 insertions(+), 3 deletions(-)
> 
> diff --git a/lib/igt_alsa.c b/lib/igt_alsa.c
> index fc6d336b..3b1a9e90 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;
>  }
> diff --git a/lib/igt_audio.c b/lib/igt_audio.c
> index 7624f565..5822fed7 100644
> --- a/lib/igt_audio.c
> +++ b/lib/igt_audio.c
> @@ -102,8 +102,11 @@ int audio_signal_add_frequency(struct audio_signal *signal, int frequency)
>  		return -1;
>  
>  	/* 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
> 
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* Re: [igt-dev] [PATCH i-g-t v7 4/8] lib/igt_alsa: use variables to improve readability
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 4/8] lib/igt_alsa: use variables to improve readability Simon Ser
@ 2019-04-25  9:54   ` Martin Peres
  0 siblings, 0 replies; 16+ messages in thread
From: Martin Peres @ 2019-04-25  9:54 UTC (permalink / raw)
  To: Simon Ser, igt-dev

On 23/04/2019 16:04, Simon Ser wrote:
> Most people don't have "remember what the last two parameters of
> snd_pcm_set_params are" in their lifegoals list. Use variables so that it's
> clearer what those are.
> 
> Signed-off-by: Simon Ser <simon.ser@intel.com>

Reviewed-by: Martin Peres <martin.peres@linux.intel.com>
> ---
>  lib/igt_alsa.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/lib/igt_alsa.c b/lib/igt_alsa.c
> index 3b1a9e90..a478686a 100644
> --- a/lib/igt_alsa.c
> +++ b/lib/igt_alsa.c
> @@ -426,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);
>  	}
>  
> 
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* Re: [igt-dev] [PATCH i-g-t v7 0/8] tests/kms_chamelium: add dp-audio test
  2019-04-23 13:04 [igt-dev] [PATCH i-g-t v7 0/8] tests/kms_chamelium: add dp-audio test Simon Ser
                   ` (9 preceding siblings ...)
  2019-04-23 18:33 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
@ 2019-04-25 10:00 ` Martin Peres
  10 siblings, 0 replies; 16+ messages in thread
From: Martin Peres @ 2019-04-25 10:00 UTC (permalink / raw)
  To: Simon Ser, igt-dev

On 23/04/2019 16:04, Simon Ser wrote:
> Changes in v7: addressed Martin's comments
> 
> Thanks for the detailed review! I've tried splitting some commits, let me know
> if more splitting is needed.

Thanks for the changes! The series is (excluding the HAX patch):

Reviewed-by: Martin Peres <martin.peres@linux.intel.com>

> 
> Simon Ser (8):
>   tests/kms_chamelium: add dp-audio test
>   tests/kms_chamelium: capture audio data in real-time
>   lib/igt_{alsa,audio}: improve logging
>   lib/igt_alsa: use variables to improve readability
>   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
>   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/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                 | 355 +++++++++++++++-
>  tests/meson.build                     |   9 +-
>  20 files changed, 1614 insertions(+), 450 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
> 
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* Re: [igt-dev] [PATCH i-g-t v7 1/8] tests/kms_chamelium: add dp-audio test
  2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 1/8] " Simon Ser
@ 2019-04-25 10:16   ` Petri Latvala
  2019-04-25 11:37     ` Arkadiusz Hiler
  0 siblings, 1 reply; 16+ messages in thread
From: Petri Latvala @ 2019-04-25 10:16 UTC (permalink / raw)
  To: Simon Ser; +Cc: igt-dev

This patch broke autotools build. See gitlab.


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

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

* Re: [igt-dev] [PATCH i-g-t v7 1/8] tests/kms_chamelium: add dp-audio test
  2019-04-25 10:16   ` Petri Latvala
@ 2019-04-25 11:37     ` Arkadiusz Hiler
  0 siblings, 0 replies; 16+ messages in thread
From: Arkadiusz Hiler @ 2019-04-25 11:37 UTC (permalink / raw)
  To: Simon Ser, igt-dev

On Thu, Apr 25, 2019 at 01:16:10PM +0300, Petri Latvala wrote:
> This patch broke autotools build. See gitlab.

Fix is merged now. Skipped mailing list as nothing here verifies
autotools, so it would only waste some cycles.
-- 
Cheers,
Arek
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

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

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-23 13:04 [igt-dev] [PATCH i-g-t v7 0/8] tests/kms_chamelium: add dp-audio test Simon Ser
2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 1/8] " Simon Ser
2019-04-25 10:16   ` Petri Latvala
2019-04-25 11:37     ` Arkadiusz Hiler
2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 2/8] tests/kms_chamelium: capture audio data in real-time Simon Ser
2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 3/8] lib/igt_{alsa, audio}: improve logging Simon Ser
2019-04-25  9:53   ` Martin Peres
2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 4/8] lib/igt_alsa: use variables to improve readability Simon Ser
2019-04-25  9:54   ` Martin Peres
2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 5/8] tests/kms_chamelium: test we receive a signal from both audio channels Simon Ser
2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 6/8] tests/kms_chamelium: test audio channels are not mixed up Simon Ser
2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 7/8] tests/kms_chamelium: run audio test with multiple sampling rates Simon Ser
2019-04-23 13:04 ` [igt-dev] [PATCH i-g-t v7 8/8] HAX: add dp-audio test to fast-feedback Simon Ser
2019-04-23 15:29 ` [igt-dev] ✓ Fi.CI.BAT: success for tests/kms_chamelium: add dp-audio test (rev8) Patchwork
2019-04-23 18:33 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
2019-04-25 10:00 ` [igt-dev] [PATCH i-g-t v7 0/8] tests/kms_chamelium: add dp-audio test Martin Peres

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.