From: Simon Ser <simon.ser@intel.com>
To: igt-dev@lists.freedesktop.org
Cc: Simon Ser <contact@emersion.fr>
Subject: [igt-dev] [PATCH i-g-t v3 3/4] tests/kms_chamelium: test we receive a signal from both audio channels
Date: Thu, 11 Apr 2019 13:03:51 +0300 [thread overview]
Message-ID: <20190411100352.1722-4-simon.ser@intel.com> (raw)
In-Reply-To: <20190411100352.1722-1-simon.ser@intel.com>
From: Simon Ser <contact@emersion.fr>
This commit updates the audio test to make sure we receive a signal from both
audio channels. However this commit doesn't check that left and right channels
are not swapped. Such a check requires some more work (because the Chamelium
device does swap left and right channels) and will be implemented in a future
commit.
This commit adds a new channel argument to audio_signal_add_frequency, to add
a frequency to a single channel only.
Some light refactoring has been performed (a proper audio_signal_deinit
function has been introduced) and logging has been improved.
Signed-off-by: Simon Ser <simon.ser@intel.com>
---
lib/igt_alsa.c | 26 +++++++--
lib/igt_audio.c | 121 +++++++++++++++++++++++++-----------------
lib/igt_audio.h | 11 ++--
tests/kms_chamelium.c | 56 +++++++++++--------
4 files changed, 138 insertions(+), 76 deletions(-)
diff --git a/lib/igt_alsa.c b/lib/igt_alsa.c
index cc34e3d1..e1848301 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(¶ms);
@@ -337,12 +342,24 @@ static bool alsa_test_configuration(snd_pcm_t *handle, int channels,
return false;
ret = snd_pcm_hw_params_test_rate(handle, params, sampling_rate, 0);
- if (ret < 0)
+ if (ret < 0) {
+ snd_pcm_hw_params_get_rate_min(params, &min_rate, &min_rate_dir);
+ snd_pcm_hw_params_get_rate_max(params, &max_rate, &max_rate_dir);
+ igt_debug("Output device supports rates between %u and %u, "
+ "requested %d\n",
+ min_rate, max_rate, sampling_rate);
return false;
+ }
ret = snd_pcm_hw_params_test_channels(handle, params, channels);
- if (ret < 0)
+ if (ret < 0) {
+ snd_pcm_hw_params_get_channels_min(params, &min_channels);
+ snd_pcm_hw_params_get_channels_max(params, &max_channels);
+ igt_debug("Output device supports between %u and "
+ "%u channels, requested %d\n",
+ min_channels, max_channels, channels);
return false;
+ }
return true;
}
@@ -409,13 +426,16 @@ void alsa_configure_output(struct alsa *alsa, int channels,
snd_pcm_t *handle;
int ret;
int i;
+ int soft_resample = 0; /* Don't allow ALSA to resample */
+ unsigned int latency = 0;
for (i = 0; i < alsa->output_handles_count; i++) {
handle = alsa->output_handles[i];
ret = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE,
SND_PCM_ACCESS_RW_INTERLEAVED,
- channels, sampling_rate, 0, 0);
+ channels, sampling_rate,
+ soft_resample, latency);
igt_assert(ret >= 0);
}
diff --git a/lib/igt_audio.c b/lib/igt_audio.c
index 4cc9bdf0..ba8152f3 100644
--- a/lib/igt_audio.c
+++ b/lib/igt_audio.c
@@ -35,7 +35,7 @@
#include "igt_audio.h"
#include "igt_core.h"
-#define FREQS_MAX 8
+#define FREQS_MAX 64
/**
* SECTION:igt_audio
@@ -49,9 +49,10 @@
struct audio_signal_freq {
int freq;
+ int channel;
- short *period;
- int frames;
+ int16_t *period;
+ size_t period_len;
int offset;
};
@@ -60,7 +61,7 @@ struct audio_signal {
int sampling_rate;
struct audio_signal_freq freqs[FREQS_MAX];
- int freqs_count;
+ size_t freqs_count;
};
/**
@@ -89,21 +90,28 @@ struct audio_signal *audio_signal_init(int channels, int sampling_rate)
* audio_signal_add_frequency:
* @signal: The target signal structure
* @frequency: The frequency to add to the signal
+ * @channel: The channel to add this frequency to, or -1 to add it to all
+ * channels
*
* Add a frequency to the signal.
*
* Returns: An integer equal to zero for success and negative for failure
*/
-int audio_signal_add_frequency(struct audio_signal *signal, int frequency)
+int audio_signal_add_frequency(struct audio_signal *signal, int frequency,
+ int channel)
{
- int index = signal->freqs_count;
+ size_t index = signal->freqs_count;
+ struct audio_signal_freq *freq;
- if (index == FREQS_MAX)
- return -1;
+ igt_assert(index < FREQS_MAX);
+ igt_assert(channel < signal->channels);
/* Stay within the Nyquist–Shannon sampling theorem. */
- if (frequency > signal->sampling_rate / 2)
+ if (frequency > signal->sampling_rate / 2) {
+ igt_debug("Skipping frequency %d: too high for a %d Hz "
+ "sampling rate\n", frequency, signal->sampling_rate);
return -1;
+ }
/* Clip the frequency to an integer multiple of the sampling rate.
* This to be able to store a full period of it and use that for
@@ -111,11 +119,14 @@ int audio_signal_add_frequency(struct audio_signal *signal, int frequency)
*/
frequency = signal->sampling_rate / (signal->sampling_rate / frequency);
- igt_debug("Adding test frequency %d\n", frequency);
+ igt_debug("Adding test frequency %d to channel %d\n",
+ frequency, channel);
+
+ freq = &signal->freqs[index];
+ memset(freq, 0, sizeof(*freq));
+ freq->freq = frequency;
+ freq->channel = channel;
- signal->freqs[index].freq = frequency;
- signal->freqs[index].frames = 0;
- signal->freqs[index].offset = 0;
signal->freqs_count++;
return 0;
@@ -133,20 +144,17 @@ void audio_signal_synthesize(struct audio_signal *signal)
{
int16_t *period;
double value;
- int frames;
+ size_t period_len;
int freq;
int i, j;
- if (signal->freqs_count == 0)
- return;
-
for (i = 0; i < signal->freqs_count; i++) {
freq = signal->freqs[i].freq;
- frames = signal->sampling_rate / freq;
+ period_len = signal->sampling_rate / freq;
- period = calloc(1, frames * sizeof(short));
+ period = calloc(1, period_len * sizeof(int16_t));
- for (j = 0; j < frames; j++) {
+ for (j = 0; j < period_len; j++) {
value = 2.0 * M_PI * freq / signal->sampling_rate * j;
value = sin(value) * INT16_MAX / signal->freqs_count;
@@ -154,26 +162,34 @@ void audio_signal_synthesize(struct audio_signal *signal)
}
signal->freqs[i].period = period;
- signal->freqs[i].frames = frames;
+ signal->freqs[i].period_len = period_len;
}
}
/**
- * audio_signal_synthesize:
+ * audio_signal_deinit:
+ *
+ * Release the signal.
+ */
+void audio_signal_deinit(struct audio_signal *signal)
+{
+ audio_signal_reset(signal);
+ free(signal);
+}
+
+/**
+ * audio_signal_reset:
* @signal: The target signal structure
*
* Free the resources allocated by audio_signal_synthesize and remove
* the previously-added frequencies.
*/
-void audio_signal_clean(struct audio_signal *signal)
+void audio_signal_reset(struct audio_signal *signal)
{
- int i;
+ size_t i;
for (i = 0; i < signal->freqs_count; i++) {
- if (signal->freqs[i].period)
- free(signal->freqs[i].period);
-
- memset(&signal->freqs[i], 0, sizeof(struct audio_signal_freq));
+ free(signal->freqs[i].period);
}
signal->freqs_count = 0;
@@ -183,44 +199,45 @@ void audio_signal_clean(struct audio_signal *signal)
* audio_signal_fill:
* @signal: The target signal structure
* @buffer: The target buffer to fill
- * @frames: The number of frames to fill
+ * @samples: The number of samples to fill
*
- * Fill the requested number of frames to the target buffer with the audio
+ * Fill the requested number of samples to the target buffer with the audio
* signal data (in interleaved S16_LE format), at the requested sampling rate
* and number of channels.
*/
-void audio_signal_fill(struct audio_signal *signal, int16_t *buffer, int frames)
+void audio_signal_fill(struct audio_signal *signal, int16_t *buffer,
+ size_t buffer_len)
{
int16_t *destination, *source;
+ struct audio_signal_freq *freq;
int total;
- int freq_frames;
- int freq_offset;
int count;
int i, j, k;
- memset(buffer, 0, sizeof(int16_t) * signal->channels * frames);
+ memset(buffer, 0, sizeof(int16_t) * signal->channels * buffer_len);
for (i = 0; i < signal->freqs_count; i++) {
+ freq = &signal->freqs[i];
total = 0;
- while (total < frames) {
- freq_frames = signal->freqs[i].frames;
- freq_offset = signal->freqs[i].offset;
+ igt_assert(freq->period);
- source = signal->freqs[i].period + freq_offset;
+ while (total < buffer_len) {
+ source = freq->period + freq->offset;
destination = buffer + total * signal->channels;
- count = freq_frames - freq_offset;
- if (count > (frames - total))
- count = frames - total;
+ count = freq->period_len - freq->offset;
+ if (count > buffer_len - total)
+ count = buffer_len - total;
- freq_offset += count;
- freq_offset %= freq_frames;
-
- signal->freqs[i].offset = freq_offset;
+ freq->offset += count;
+ freq->offset %= freq->period_len;
for (j = 0; j < count; j++) {
for (k = 0; k < signal->channels; k++) {
+ if (freq->channel >= 0 &&
+ freq->channel != k)
+ continue;
destination[j * signal->channels + k] += source[j];
}
}
@@ -237,11 +254,11 @@ void audio_signal_fill(struct audio_signal *signal, int16_t *buffer, int frames)
* sampling_rate is given in Hz. data_len is the number of elements in data.
*/
bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
- double *data, size_t data_len)
+ int channel, double *data, size_t data_len)
{
size_t amplitude_len = data_len / 2 + 1;
double amplitude[amplitude_len];
- bool detected[signal->freqs_count];
+ bool detected[FREQS_MAX];
int ret, epsilon, freq, max_freq;
double max, threshold;
size_t i, j;
@@ -249,7 +266,7 @@ bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
/* Allowed error in Hz due to FFT step */
epsilon = sampling_rate / data_len;
- igt_debug("allowed freq. error: %d Hz\n", epsilon);
+ igt_debug("Allowed freq. error: %d Hz\n", epsilon);
ret = gsl_fft_real_radix2_transform(data, 1, data_len);
igt_assert(ret == 0);
@@ -295,6 +312,10 @@ bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
* invalid. */
if (amplitude[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 >
max_freq - epsilon &&
signal->freqs[j].freq <
@@ -327,6 +348,10 @@ bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
/* Check that all frequencies we generated have been detected. */
for (i = 0; i < signal->freqs_count; i++) {
+ if (signal->freqs[i].channel >= 0 &&
+ signal->freqs[i].channel != channel)
+ continue;
+
if (!detected[i]) {
igt_debug("Missing frequency: %d\n",
signal->freqs[i].freq);
diff --git a/lib/igt_audio.h b/lib/igt_audio.h
index 4aa43e69..fe26bb57 100644
--- a/lib/igt_audio.h
+++ b/lib/igt_audio.h
@@ -35,12 +35,15 @@
struct audio_signal;
struct audio_signal *audio_signal_init(int channels, int sampling_rate);
-int audio_signal_add_frequency(struct audio_signal *signal, int frequency);
+void audio_signal_deinit(struct audio_signal *signal);
+int audio_signal_add_frequency(struct audio_signal *signal, int frequency,
+ int channel);
void audio_signal_synthesize(struct audio_signal *signal);
-void audio_signal_clean(struct audio_signal *signal);
-void audio_signal_fill(struct audio_signal *signal, int16_t *buffer, int frames);
+void audio_signal_reset(struct audio_signal *signal);
+void audio_signal_fill(struct audio_signal *signal, int16_t *buffer,
+ size_t buffer_len);
bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
- double *data, size_t data_len);
+ int channel, double *data, size_t data_len);
size_t audio_extract_channel_s32_le(double *dst, size_t dst_cap,
int32_t *src, size_t src_len,
int n_channels, int channel);
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index 44010534..12ab9997 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -777,16 +777,16 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
struct alsa *alsa, int playback_channels,
int playback_rate)
{
- int ret, capture_rate, capture_channels, msec;
+ int ret, capture_rate, capture_channels, msec, freq;
struct chamelium_audio_file *audio_file;
struct chamelium_stream *stream;
enum chamelium_stream_realtime_mode stream_mode;
struct audio_signal *signal;
int32_t *recv, *buf;
double *channel;
- size_t i, streak, page_count;
+ size_t i, j, streak, page_count;
size_t recv_len, buf_len, buf_cap, buf_size, channel_len;
- bool ok;
+ bool ok, success;
char dump_suffix[64];
char *dump_path = NULL;
int dump_fd = -1;
@@ -794,10 +794,15 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
struct audio_state state = {};
if (!alsa_test_output_configuration(alsa, playback_channels,
- playback_rate))
+ playback_rate)) {
+ igt_debug("Skipping test with sample rate %d and %d channels "
+ "because selected output devices don't support this "
+ "configuration\n", playback_rate, playback_channels);
return false;
+ }
- igt_debug("Testing with playback sampling rate %d\n", playback_rate);
+ igt_debug("Testing with playback sampling rate %d and %d channels\n",
+ playback_rate, playback_channels);
alsa_configure_output(alsa, playback_channels, playback_rate);
chamelium_start_capturing_audio(data->chamelium, port, false);
@@ -825,8 +830,12 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
signal = audio_signal_init(playback_channels, playback_rate);
igt_assert(signal);
- for (i = 0; i < test_frequencies_count; i++)
- audio_signal_add_frequency(signal, test_frequencies[i]);
+ for (i = 0; i < test_frequencies_count; i++) {
+ for (j = 0; j < playback_channels; j++) {
+ freq = test_frequencies[i];
+ audio_signal_add_frequency(signal, freq, j);
+ }
+ }
audio_signal_synthesize(signal);
state.signal = signal;
@@ -851,10 +860,11 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
recv = NULL;
recv_len = 0;
+ success = false;
streak = 0;
msec = 0;
i = 0;
- while (streak < MIN_STREAK && msec < AUDIO_TIMEOUT) {
+ while (!success && msec < AUDIO_TIMEOUT) {
ok = chamelium_stream_receive_realtime_audio(stream,
&page_count,
&recv, &recv_len);
@@ -872,21 +882,27 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
igt_assert(write(dump_fd, buf, buf_size) == buf_size);
}
- /* TODO: check other channels too, not just the first one */
- audio_extract_channel_s32_le(channel, channel_len, buf, buf_len,
- capture_channels, 0);
-
msec = i * channel_len / (double) capture_rate * 1000;
igt_debug("Detecting audio signal, t=%d msec\n", msec);
- if (audio_signal_detect(signal, capture_rate, channel,
- channel_len))
- streak++;
- else
- streak = 0;
+ for (j = 0; j < playback_channels; j++) {
+ igt_debug("Processing channel %zu\n", j);
+
+ audio_extract_channel_s32_le(channel, channel_len,
+ buf, buf_len,
+ capture_channels, j);
+
+ if (audio_signal_detect(signal, capture_rate, j,
+ channel, channel_len))
+ streak++;
+ else
+ streak = 0;
+ }
buf_len = 0;
i++;
+
+ success = streak == MIN_STREAK * playback_channels;
}
igt_debug("Stopping audio playback\n");
@@ -921,12 +937,10 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
chamelium_destroy_audio_file(audio_file);
}
- audio_signal_clean(signal);
- free(signal);
-
+ audio_signal_deinit(signal);
chamelium_stream_deinit(stream);
- igt_assert(streak == MIN_STREAK);
+ igt_assert(success);
return true;
}
--
2.21.0
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev
next prev parent reply other threads:[~2019-04-11 10:04 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-04-11 10:03 [igt-dev] [PATCH i-g-t v3 0/4] tests/kms_chamelium: add dp-audio test Simon Ser
2019-04-11 10:03 ` [igt-dev] [PATCH i-g-t v3 1/4] " Simon Ser
2019-04-11 10:03 ` [igt-dev] [PATCH i-g-t v3 2/4] tests/kms_chamelium: capture audio data in real-time Simon Ser
2019-04-11 10:03 ` Simon Ser [this message]
2019-04-11 10:03 ` [igt-dev] [PATCH i-g-t v3 4/4] tests/kms_chamelium: test audio channels are not mixed up Simon Ser
2019-04-11 10:09 ` [igt-dev] [PATCH i-g-t v3 0/4] tests/kms_chamelium: add dp-audio test Ser, Simon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190411100352.1722-4-simon.ser@intel.com \
--to=simon.ser@intel.com \
--cc=contact@emersion.fr \
--cc=igt-dev@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.