* [igt-dev] [PATCH i-g-t 1/8] tests/kms_chamelium: refactor audio test
2019-05-24 8:07 [igt-dev] [PATCH i-g-t 0/8] tests/kms_chamelium: add amplitude test Simon Ser
@ 2019-05-24 8:07 ` Simon Ser
2019-05-24 8:07 ` [igt-dev] [PATCH i-g-t 2/8] tests/kms_chamelium: introduce audio_state_receive Simon Ser
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Simon Ser @ 2019-05-24 8:07 UTC (permalink / raw)
To: igt-dev
Instead of shaving everything into do_test_display_audio, extract the logic to
initialize, start, stop, finish an audio test in helper functions. The struct
audio_state now carries all audio-related state.
This will allow to easily add more audio tests that don't use sine waves (via
audio_signal). This is necessary for future delay and amplitude tests.
Signed-off-by: Simon Ser <simon.ser@intel.com>
---
tests/kms_chamelium.c | 324 ++++++++++++++++++++++++------------------
1 file changed, 189 insertions(+), 135 deletions(-)
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index f4fe38459dd9..1fb4df3020d6 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -812,17 +812,173 @@ static const snd_pcm_format_t test_formats[] = {
static const size_t test_formats_count = sizeof(test_formats) / sizeof(test_formats[0]);
struct audio_state {
+ struct alsa *alsa;
+ struct chamelium *chamelium;
+ struct chamelium_port *port;
+ struct chamelium_stream *stream;
+
+ /* The capture format is only available after capture has started. */
+ struct {
+ snd_pcm_format_t format;
+ int channels;
+ int rate;
+ } playback, capture;
+
struct audio_signal *signal;
- snd_pcm_format_t format;
+ int channel_mapping[8];
+
+ int dump_fd;
+ char *dump_path;
+
+ pthread_t thread;
atomic_bool run;
};
+static void audio_state_init(struct audio_state *state, data_t *data,
+ struct alsa *alsa, struct chamelium_port *port,
+ snd_pcm_format_t format, int channels, int rate)
+{
+ memset(state, 0, sizeof(*state));
+ state->dump_fd = -1;
+
+ state->alsa = alsa;
+ state->chamelium = data->chamelium;
+ state->port = port;
+
+ state->playback.format = format;
+ state->playback.channels = channels;
+ state->playback.rate = rate;
+
+ alsa_configure_output(alsa, format, channels, rate);
+
+ state->stream = chamelium_stream_init();
+ igt_assert(state->stream);
+}
+
+static void audio_state_fini(struct audio_state *state)
+{
+ chamelium_stream_deinit(state->stream);
+}
+
+static void *run_audio_thread(void *data)
+{
+ struct alsa *alsa = data;
+
+ alsa_run(alsa, -1);
+ return NULL;
+}
+
+static void audio_state_start(struct audio_state *state)
+{
+ int ret;
+ bool ok;
+ size_t i, j;
+ enum chamelium_stream_realtime_mode stream_mode;
+ char dump_suffix[64];
+
+ igt_debug("Starting test with playback format %s, sampling rate %d Hz "
+ "and %d channels\n",
+ snd_pcm_format_name(state->playback.format),
+ state->playback.rate, state->playback.channels);
+
+ chamelium_start_capturing_audio(state->chamelium, state->port, false);
+
+ stream_mode = CHAMELIUM_STREAM_REALTIME_STOP_WHEN_OVERFLOW;
+ ok = chamelium_stream_dump_realtime_audio(state->stream, stream_mode);
+ igt_assert(ok);
+
+ /* Start playing audio */
+ state->run = true;
+ ret = pthread_create(&state->thread, NULL,
+ run_audio_thread, state->alsa);
+ igt_assert(ret == 0);
+
+ /* The Chamelium device only supports this PCM format. */
+ state->capture.format = SND_PCM_FORMAT_S32_LE;
+
+ /* Only after we've started playing audio, we can retrieve the capture
+ * format used by the Chamelium device. */
+ chamelium_get_audio_format(state->chamelium, state->port,
+ &state->capture.rate,
+ &state->capture.channels);
+ if (state->capture.rate == 0) {
+ igt_debug("Audio receiver doesn't indicate the capture "
+ "sampling rate, assuming it's %d Hz\n",
+ state->playback.rate);
+ state->capture.rate = state->playback.rate;
+ }
+
+ chamelium_get_audio_channel_mapping(state->chamelium, state->port,
+ state->channel_mapping);
+ /* Make sure we can capture all channels we send. */
+ for (i = 0; i < state->playback.channels; i++) {
+ ok = false;
+ for (j = 0; j < state->capture.channels; j++) {
+ if (state->channel_mapping[j] == i) {
+ ok = true;
+ break;
+ }
+ }
+ igt_assert(ok);
+ }
+
+ if (igt_frame_dump_is_enabled()) {
+ snprintf(dump_suffix, sizeof(dump_suffix),
+ "capture-%s-%dch-%dHz",
+ snd_pcm_format_name(state->playback.format),
+ state->playback.channels, state->playback.rate);
+
+ state->dump_fd = audio_create_wav_file_s32_le(dump_suffix,
+ state->capture.rate,
+ state->capture.channels,
+ &state->dump_path);
+ igt_assert(state->dump_fd >= 0);
+ }
+}
+
+static void audio_state_stop(struct audio_state *state, bool success)
+{
+ bool ok;
+ int ret;
+ struct chamelium_audio_file *audio_file;
+
+ igt_debug("Stopping audio playback\n");
+ state->run = false;
+ ret = pthread_join(state->thread, NULL);
+ igt_assert(ret == 0);
+
+ ok = chamelium_stream_stop_realtime_audio(state->stream);
+ igt_assert(ok);
+
+ audio_file = chamelium_stop_capturing_audio(state->chamelium,
+ state->port);
+ if (audio_file) {
+ igt_debug("Audio file saved on the Chamelium in %s\n",
+ audio_file->path);
+ chamelium_destroy_audio_file(audio_file);
+ }
+
+ if (state->dump_fd >= 0) {
+ close(state->dump_fd);
+ state->dump_fd = -1;
+
+ if (success) {
+ /* Test succeeded, no need to keep the captured data */
+ unlink(state->dump_path);
+ } else
+ igt_debug("Saved captured audio data to %s\n",
+ state->dump_path);
+ free(state->dump_path);
+ state->dump_path = NULL;
+ }
+}
+
static int
audio_output_callback(void *data, void *buffer, int samples)
{
struct audio_state *state = data;
- switch (state->format) {
+ switch (state->playback.format) {
case SND_PCM_FORMAT_S16_LE:
audio_signal_fill_s16_le(state->signal, buffer, samples);
break;
@@ -839,55 +995,19 @@ audio_output_callback(void *data, void *buffer, int samples)
return state->run ? 0 : -1;
}
-static void *
-run_audio_thread(void *data)
+static bool do_test_display_audio(struct audio_state *state)
{
- struct alsa *alsa = data;
-
- alsa_run(alsa, -1);
- return NULL;
-}
-
-static bool
-do_test_display_audio(data_t *data, struct chamelium_port *port,
- struct alsa *alsa, snd_pcm_format_t playback_format,
- int playback_channels, int playback_rate)
-{
- 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;
- struct audio_signal *signal;
+ int msec, freq, step;
int32_t *recv, *buf;
double *channel;
size_t i, j, streak, page_count;
size_t recv_len, buf_len, buf_cap, buf_size, channel_len;
bool ok, success;
- char dump_suffix[64];
- char *dump_path = NULL;
- int dump_fd = -1;
- pthread_t thread;
- struct audio_state state = {};
- int channel_mapping[8], capture_chan;
+ int capture_chan;
- igt_debug("Testing with playback format %s, sampling rate %d Hz and "
- "%d channels\n",
- snd_pcm_format_name(playback_format),
- playback_rate, playback_channels);
- alsa_configure_output(alsa, playback_format,
- 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);
-
- signal = audio_signal_init(playback_channels, playback_rate);
- igt_assert(signal);
+ state->signal = audio_signal_init(state->playback.channels,
+ state->playback.rate);
+ igt_assert(state->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
@@ -900,62 +1020,21 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
* later on. We cannot retrieve the capture rate before starting
* playing audio, so we don't really have the choice.
*/
- step = 2 * playback_rate / CAPTURE_SAMPLES;
+ step = 2 * state->playback.rate / CAPTURE_SAMPLES;
for (i = 0; i < test_frequencies_count; i++) {
- for (j = 0; j < playback_channels; j++) {
+ for (j = 0; j < state->playback.channels; j++) {
freq = test_frequencies[i] + j * step;
- audio_signal_add_frequency(signal, freq, j);
+ audio_signal_add_frequency(state->signal, freq, j);
}
}
- audio_signal_synthesize(signal);
+ audio_signal_synthesize(state->signal);
- state.signal = signal;
- state.format = playback_format;
- state.run = true;
- alsa_register_output_callback(alsa, audio_output_callback, &state,
+ alsa_register_output_callback(state->alsa, audio_output_callback, state,
PLAYBACK_SAMPLES);
- /* Start playing audio */
- ret = pthread_create(&thread, NULL, run_audio_thread, alsa);
- igt_assert(ret == 0);
+ audio_state_start(state);
- /* 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. */
- 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);
- }
-
- if (igt_frame_dump_is_enabled()) {
- snprintf(dump_suffix, sizeof(dump_suffix),
- "capture-%s-%dch-%dHz",
- snd_pcm_format_name(playback_format),
- 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);
- }
+ igt_assert(state->capture.rate == state->playback.rate);
/* 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
@@ -970,7 +1049,7 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
channel_len = CAPTURE_SAMPLES;
channel = malloc(sizeof(double) * channel_len);
- buf_cap = capture_channels * channel_len;
+ buf_cap = state->capture.channels * channel_len;
buf = malloc(sizeof(int32_t) * buf_cap);
buf_len = 0;
@@ -982,7 +1061,7 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
msec = 0;
i = 0;
while (!success && msec < AUDIO_TIMEOUT) {
- ok = chamelium_stream_receive_realtime_audio(stream,
+ ok = chamelium_stream_receive_realtime_audio(state->stream,
&page_count,
&recv, &recv_len);
igt_assert(ok);
@@ -994,26 +1073,27 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
continue;
igt_assert(buf_len == buf_cap);
- if (dump_fd >= 0) {
+ if (state->dump_fd >= 0) {
buf_size = buf_len * sizeof(int32_t);
- igt_assert(write(dump_fd, buf, buf_size) == buf_size);
+ igt_assert(write(state->dump_fd, buf, buf_size) == buf_size);
}
- msec = i * channel_len / (double) capture_rate * 1000;
+ msec = i * channel_len / (double) state->capture.rate * 1000;
igt_debug("Detecting audio signal, t=%d msec\n", msec);
- for (j = 0; j < playback_channels; j++) {
- capture_chan = channel_mapping[j];
+ for (j = 0; j < state->playback.channels; j++) {
+ capture_chan = state->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,
+ state->capture.channels,
capture_chan);
- if (audio_signal_detect(signal, capture_rate, j,
+ if (audio_signal_detect(state->signal,
+ state->capture.rate, j,
channel, channel_len))
streak++;
else
@@ -1023,43 +1103,15 @@ do_test_display_audio(data_t *data, struct chamelium_port *port,
buf_len = 0;
i++;
- success = streak == MIN_STREAK * playback_channels;
+ success = streak == MIN_STREAK * state->playback.channels;
}
- 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 (success) {
- /* 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);
- }
+ audio_state_stop(state, success);
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_fini(signal);
- chamelium_stream_deinit(stream);
+ audio_signal_fini(state->signal);
return success;
}
@@ -1106,6 +1158,7 @@ test_display_audio(data_t *data, struct chamelium_port *port,
int fb_id, i, j;
int channels, sampling_rate;
snd_pcm_format_t format;
+ struct audio_state state;
igt_require(alsa_has_exclusive_access());
@@ -1155,9 +1208,10 @@ test_display_audio(data_t *data, struct chamelium_port *port,
run = true;
- success &= do_test_display_audio(data, port, alsa,
- format, channels,
- sampling_rate);
+ audio_state_init(&state, data, alsa, port,
+ format, channels, sampling_rate);
+ success &= do_test_display_audio(&state);
+ audio_state_fini(&state);
alsa_close_output(alsa);
}
--
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] 10+ messages in thread
* [igt-dev] [PATCH i-g-t 2/8] tests/kms_chamelium: introduce audio_state_receive
2019-05-24 8:07 [igt-dev] [PATCH i-g-t 0/8] tests/kms_chamelium: add amplitude test Simon Ser
2019-05-24 8:07 ` [igt-dev] [PATCH i-g-t 1/8] tests/kms_chamelium: refactor audio test Simon Ser
@ 2019-05-24 8:07 ` Simon Ser
2019-05-24 8:07 ` [igt-dev] [PATCH i-g-t 3/8] tests/kms_chamelium: rename do_test_display_audio and test_audio_configuration Simon Ser
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Simon Ser @ 2019-05-24 8:07 UTC (permalink / raw)
To: igt-dev
This extracts the logic receiving audio pages in do_test_display_audio into a
new audio_state_receive function. The function takes care of updating the
current msec counter and dumping the received data in a file.
Signed-off-by: Simon Ser <simon.ser@intel.com>
---
tests/kms_chamelium.c | 55 ++++++++++++++++++++++++++++---------------
1 file changed, 36 insertions(+), 19 deletions(-)
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index 1fb4df3020d6..3a78aa150bef 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -827,6 +827,9 @@ struct audio_state {
struct audio_signal *signal;
int channel_mapping[8];
+ size_t recv_pages;
+ int msec;
+
int dump_fd;
char *dump_path;
@@ -876,6 +879,9 @@ static void audio_state_start(struct audio_state *state)
enum chamelium_stream_realtime_mode stream_mode;
char dump_suffix[64];
+ state->recv_pages = 0;
+ state->msec = 0;
+
igt_debug("Starting test with playback format %s, sampling rate %d Hz "
"and %d channels\n",
snd_pcm_format_name(state->playback.format),
@@ -936,6 +942,29 @@ static void audio_state_start(struct audio_state *state)
}
}
+static void audio_state_receive(struct audio_state *state,
+ int32_t **recv, size_t *recv_len)
+{
+ bool ok;
+ size_t page_count;
+ size_t recv_size;
+
+ ok = chamelium_stream_receive_realtime_audio(state->stream,
+ &page_count,
+ recv, recv_len);
+ igt_assert(ok);
+
+ state->msec = state->recv_pages * *recv_len
+ / (double) state->capture.channels
+ / (double) state->capture.rate * 1000;
+ state->recv_pages++;
+
+ if (state->dump_fd >= 0) {
+ recv_size = *recv_len * sizeof(int32_t);
+ igt_assert(write(state->dump_fd, *recv, recv_size) == recv_size);
+ }
+}
+
static void audio_state_stop(struct audio_state *state, bool success)
{
bool ok;
@@ -997,12 +1026,12 @@ audio_output_callback(void *data, void *buffer, int samples)
static bool do_test_display_audio(struct audio_state *state)
{
- int msec, freq, step;
+ int freq, step;
int32_t *recv, *buf;
double *channel;
- size_t i, j, streak, page_count;
- size_t recv_len, buf_len, buf_cap, buf_size, channel_len;
- bool ok, success;
+ size_t i, j, streak;
+ size_t recv_len, buf_len, buf_cap, channel_len;
+ bool success;
int capture_chan;
state->signal = audio_signal_init(state->playback.channels,
@@ -1058,13 +1087,8 @@ static bool do_test_display_audio(struct audio_state *state)
success = false;
streak = 0;
- msec = 0;
- i = 0;
- while (!success && msec < AUDIO_TIMEOUT) {
- ok = chamelium_stream_receive_realtime_audio(state->stream,
- &page_count,
- &recv, &recv_len);
- igt_assert(ok);
+ while (!success && state->msec < AUDIO_TIMEOUT) {
+ audio_state_receive(state, &recv, &recv_len);
memcpy(&buf[buf_len], recv, recv_len * sizeof(int32_t));
buf_len += recv_len;
@@ -1073,13 +1097,7 @@ static bool do_test_display_audio(struct audio_state *state)
continue;
igt_assert(buf_len == buf_cap);
- if (state->dump_fd >= 0) {
- buf_size = buf_len * sizeof(int32_t);
- igt_assert(write(state->dump_fd, buf, buf_size) == buf_size);
- }
-
- msec = i * channel_len / (double) state->capture.rate * 1000;
- igt_debug("Detecting audio signal, t=%d msec\n", msec);
+ igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
for (j = 0; j < state->playback.channels; j++) {
capture_chan = state->channel_mapping[j];
@@ -1101,7 +1119,6 @@ static bool do_test_display_audio(struct audio_state *state)
}
buf_len = 0;
- i++;
success = streak == MIN_STREAK * state->playback.channels;
}
--
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] 10+ messages in thread
* [igt-dev] [PATCH i-g-t 3/8] tests/kms_chamelium: rename do_test_display_audio and test_audio_configuration
2019-05-24 8:07 [igt-dev] [PATCH i-g-t 0/8] tests/kms_chamelium: add amplitude test Simon Ser
2019-05-24 8:07 ` [igt-dev] [PATCH i-g-t 1/8] tests/kms_chamelium: refactor audio test Simon Ser
2019-05-24 8:07 ` [igt-dev] [PATCH i-g-t 2/8] tests/kms_chamelium: introduce audio_state_receive Simon Ser
@ 2019-05-24 8:07 ` Simon Ser
2019-05-24 8:07 ` [igt-dev] [PATCH i-g-t 4/8] tests/kms_chamelium: explain why 8-channel tests aren't performed Simon Ser
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Simon Ser @ 2019-05-24 8:07 UTC (permalink / raw)
To: igt-dev
- Rename do_test_display_audio to test_audio_frequencies to prepare for a
future amplitude/delay test
- Rename test_audio_configuration to check_audio_configuration because this
function doesn't execute any test, it just checks whether we can perform
audio tests using a particular configuration
Signed-off-by: Simon Ser <simon.ser@intel.com>
---
tests/kms_chamelium.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index 3a78aa150bef..0324d81b81e3 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -1003,7 +1003,7 @@ static void audio_state_stop(struct audio_state *state, bool success)
}
static int
-audio_output_callback(void *data, void *buffer, int samples)
+audio_output_frequencies_callback(void *data, void *buffer, int samples)
{
struct audio_state *state = data;
@@ -1024,7 +1024,7 @@ audio_output_callback(void *data, void *buffer, int samples)
return state->run ? 0 : -1;
}
-static bool do_test_display_audio(struct audio_state *state)
+static bool test_audio_frequencies(struct audio_state *state)
{
int freq, step;
int32_t *recv, *buf;
@@ -1058,7 +1058,8 @@ static bool do_test_display_audio(struct audio_state *state)
}
audio_signal_synthesize(state->signal);
- alsa_register_output_callback(state->alsa, audio_output_callback, state,
+ alsa_register_output_callback(state->alsa,
+ audio_output_frequencies_callback, state,
PLAYBACK_SAMPLES);
audio_state_start(state);
@@ -1133,8 +1134,8 @@ static bool do_test_display_audio(struct audio_state *state)
return success;
}
-static bool test_audio_configuration(struct alsa *alsa, snd_pcm_format_t format,
- int channels, int sampling_rate)
+static bool check_audio_configuration(struct alsa *alsa, snd_pcm_format_t format,
+ int channels, int sampling_rate)
{
if (!alsa_test_output_configuration(alsa, format, channels,
sampling_rate)) {
@@ -1219,15 +1220,15 @@ test_display_audio(data_t *data, struct chamelium_port *port,
channels = PLAYBACK_CHANNELS;
sampling_rate = test_sampling_rates[i];
- if (!test_audio_configuration(alsa, format, channels,
- sampling_rate))
+ if (!check_audio_configuration(alsa, format, channels,
+ sampling_rate))
continue;
run = true;
audio_state_init(&state, data, alsa, port,
format, channels, sampling_rate);
- success &= do_test_display_audio(&state);
+ success &= test_audio_frequencies(&state);
audio_state_fini(&state);
alsa_close_output(alsa);
--
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] 10+ messages in thread
* [igt-dev] [PATCH i-g-t 4/8] tests/kms_chamelium: explain why 8-channel tests aren't performed
2019-05-24 8:07 [igt-dev] [PATCH i-g-t 0/8] tests/kms_chamelium: add amplitude test Simon Ser
` (2 preceding siblings ...)
2019-05-24 8:07 ` [igt-dev] [PATCH i-g-t 3/8] tests/kms_chamelium: rename do_test_display_audio and test_audio_configuration Simon Ser
@ 2019-05-24 8:07 ` Simon Ser
2019-05-24 8:07 ` [igt-dev] [PATCH i-g-t 5/8] lib/igt_audio: introduce audio_convert_to Simon Ser
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Simon Ser @ 2019-05-24 8:07 UTC (permalink / raw)
To: igt-dev
Also add a reference to the relevant Chromium bug.
Signed-off-by: Simon Ser <simon.ser@intel.com>
---
tests/kms_chamelium.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index 0324d81b81e3..61578d4cffad 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -1215,7 +1215,9 @@ test_display_audio(data_t *data, struct chamelium_port *port,
ret = alsa_open_output(alsa, audio_device);
igt_assert(ret >= 0);
- /* TODO: playback on all 8 available channels */
+ /* TODO: playback on all 8 available channels (this
+ * isn't supported by Chamelium devices yet, see
+ * https://crbug.com/950917) */
format = test_formats[j];
channels = PLAYBACK_CHANNELS;
sampling_rate = test_sampling_rates[i];
--
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] 10+ messages in thread
* [igt-dev] [PATCH i-g-t 5/8] lib/igt_audio: introduce audio_convert_to
2019-05-24 8:07 [igt-dev] [PATCH i-g-t 0/8] tests/kms_chamelium: add amplitude test Simon Ser
` (3 preceding siblings ...)
2019-05-24 8:07 ` [igt-dev] [PATCH i-g-t 4/8] tests/kms_chamelium: explain why 8-channel tests aren't performed Simon Ser
@ 2019-05-24 8:07 ` Simon Ser
2019-05-24 8:07 ` [igt-dev] [PATCH i-g-t 6/8] tests/kms_chamelium: add name parameter to audio_state_start Simon Ser
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Simon Ser @ 2019-05-24 8:07 UTC (permalink / raw)
To: igt-dev
This function converts normalized doubles into an ALSA PCM format.
Instead of having per-format audio_signal_fill_* functions, we can only have
audio_signal_fill that outputs normalized doubles. Then in ALSA's playback
callback, we can simply use the new audio_convert_to function to fill the
buffer.
This makes the test code simpler and prevents code duplication when another
ALSA playback callback is implemented.
This adds a dependency of igt_audio over ALSA for the PCM format enum, but I
don't think this is a concern, since I don't see the point of using igt_audio
without igt_alsa. If this is an issue, it would always be possible to replace
ALSA's enum with our own in the future.
Signed-off-by: Simon Ser <simon.ser@intel.com>
---
lib/igt_audio.c | 87 +++++++++++++++++++++----------------------
lib/igt_audio.h | 12 +++---
tests/kms_chamelium.c | 22 ++++-------
3 files changed, 55 insertions(+), 66 deletions(-)
diff --git a/lib/igt_audio.c b/lib/igt_audio.c
index 376e04ba6ed6..f2aac0e23a37 100644
--- a/lib/igt_audio.c
+++ b/lib/igt_audio.c
@@ -304,51 +304,6 @@ void audio_signal_fill(struct audio_signal *signal, double *buffer,
audio_sanity_check(buffer, signal->channels * samples);
}
-void audio_signal_fill_s16_le(struct audio_signal *signal, int16_t *buffer,
- size_t samples)
-{
- double *tmp;
- size_t i;
-
- tmp = malloc(sizeof(double) * signal->channels * samples);
- audio_signal_fill(signal, tmp, samples);
-
- for (i = 0; i < signal->channels * samples; ++i)
- buffer[i] = INT16_MAX * tmp[i];
-
- free(tmp);
-}
-
-void audio_signal_fill_s24_le(struct audio_signal *signal, int32_t *buffer,
- size_t samples)
-{
- double *tmp;
- size_t i;
-
- tmp = malloc(sizeof(double) * signal->channels * samples);
- audio_signal_fill(signal, tmp, samples);
-
- for (i = 0; i < signal->channels * samples; ++i)
- buffer[i] = 0x7FFFFF * tmp[i];
-
- free(tmp);
-}
-
-void audio_signal_fill_s32_le(struct audio_signal *signal, int32_t *buffer,
- size_t samples)
-{
- double *tmp;
- size_t i;
-
- tmp = malloc(sizeof(double) * signal->channels * samples);
- audio_signal_fill(signal, tmp, samples);
-
- for (i = 0; i < signal->channels * samples; ++i)
- buffer[i] = INT32_MAX * tmp[i];
-
- free(tmp);
-}
-
/**
* Checks that frequencies specified in signal, and only those, are included
* in the input data.
@@ -508,6 +463,48 @@ size_t audio_extract_channel_s32_le(double *dst, size_t dst_cap,
return dst_len;
}
+static void audio_convert_to_s16_le(int16_t *dst, double *src, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; ++i)
+ dst[i] = INT16_MAX * src[i];
+}
+
+static void audio_convert_to_s24_le(int32_t *dst, double *src, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; ++i)
+ dst[i] = 0x7FFFFF * src[i];
+}
+
+static void audio_convert_to_s32_le(int32_t *dst, double *src, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; ++i)
+ dst[i] = INT32_MAX * src[i];
+}
+
+void audio_convert_to(void *dst, double *src, size_t len,
+ snd_pcm_format_t format)
+{
+ switch (format) {
+ case SND_PCM_FORMAT_S16_LE:
+ audio_convert_to_s16_le(dst, src, len);
+ break;
+ case SND_PCM_FORMAT_S24_LE:
+ audio_convert_to_s24_le(dst, src, len);
+ break;
+ case SND_PCM_FORMAT_S32_LE:
+ audio_convert_to_s32_le(dst, src, len);
+ break;
+ default:
+ assert(false); /* unreachable */
+ }
+}
+
#define RIFF_TAG "RIFF"
#define WAVE_TAG "WAVE"
#define FMT_TAG "fmt "
diff --git a/lib/igt_audio.h b/lib/igt_audio.h
index c8de70871faa..5c910c27304d 100644
--- a/lib/igt_audio.h
+++ b/lib/igt_audio.h
@@ -32,6 +32,8 @@
#include <stdbool.h>
#include <stdint.h>
+#include <alsa/asoundlib.h>
+
struct audio_signal;
struct audio_signal *audio_signal_init(int channels, int sampling_rate);
@@ -41,18 +43,14 @@ int audio_signal_add_frequency(struct audio_signal *signal, int frequency,
void audio_signal_synthesize(struct audio_signal *signal);
void audio_signal_reset(struct audio_signal *signal);
void audio_signal_fill(struct audio_signal *signal, double *buffer,
- size_t buffer_len);
-void audio_signal_fill_s16_le(struct audio_signal *signal, int16_t *buffer,
- size_t buffer_len);
-void audio_signal_fill_s24_le(struct audio_signal *signal, int32_t *buffer,
- size_t buffer_len);
-void audio_signal_fill_s32_le(struct audio_signal *signal, int32_t *buffer,
- size_t buffer_len);
+ size_t samples);
bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
int channel, const double *samples, size_t samples_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);
+void audio_convert_to(void *dst, double *src, size_t len,
+ snd_pcm_format_t format);
int audio_create_wav_file_s32_le(const char *qualifier, uint32_t sample_rate,
uint16_t channels, char **path);
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index 61578d4cffad..9ae957f06dbf 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -1006,20 +1006,14 @@ static int
audio_output_frequencies_callback(void *data, void *buffer, int samples)
{
struct audio_state *state = data;
-
- switch (state->playback.format) {
- case SND_PCM_FORMAT_S16_LE:
- audio_signal_fill_s16_le(state->signal, buffer, samples);
- break;
- case SND_PCM_FORMAT_S24_LE:
- audio_signal_fill_s24_le(state->signal, buffer, samples);
- break;
- case SND_PCM_FORMAT_S32_LE:
- audio_signal_fill_s32_le(state->signal, buffer, samples);
- break;
- default:
- assert(false); /* unreachable */
- }
+ double *tmp;
+ size_t len;
+
+ len = samples * state->playback.channels;
+ tmp = malloc(len * sizeof(double));
+ audio_signal_fill(state->signal, tmp, samples);
+ audio_convert_to(buffer, tmp, len, state->playback.format);
+ free(tmp);
return state->run ? 0 : -1;
}
--
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] 10+ messages in thread
* [igt-dev] [PATCH i-g-t 6/8] tests/kms_chamelium: add name parameter to audio_state_start
2019-05-24 8:07 [igt-dev] [PATCH i-g-t 0/8] tests/kms_chamelium: add amplitude test Simon Ser
` (4 preceding siblings ...)
2019-05-24 8:07 ` [igt-dev] [PATCH i-g-t 5/8] lib/igt_audio: introduce audio_convert_to Simon Ser
@ 2019-05-24 8:07 ` Simon Ser
2019-05-24 8:07 ` [igt-dev] [PATCH i-g-t 7/8] lib/igt_audio: make audio_extract_channel_s32_le support a NULL dst Simon Ser
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Simon Ser @ 2019-05-24 8:07 UTC (permalink / raw)
To: igt-dev
This identifies the audio test name. This is required for adding multiple
audio tests.
Signed-off-by: Simon Ser <simon.ser@intel.com>
---
tests/kms_chamelium.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index 9ae957f06dbf..54251d6a47ca 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -871,7 +871,7 @@ static void *run_audio_thread(void *data)
return NULL;
}
-static void audio_state_start(struct audio_state *state)
+static void audio_state_start(struct audio_state *state, const char *name)
{
int ret;
bool ok;
@@ -882,9 +882,9 @@ static void audio_state_start(struct audio_state *state)
state->recv_pages = 0;
state->msec = 0;
- igt_debug("Starting test with playback format %s, sampling rate %d Hz "
- "and %d channels\n",
- snd_pcm_format_name(state->playback.format),
+ igt_debug("Starting %s test with playback format %s, "
+ "sampling rate %d Hz and %d channels\n",
+ name, snd_pcm_format_name(state->playback.format),
state->playback.rate, state->playback.channels);
chamelium_start_capturing_audio(state->chamelium, state->port, false);
@@ -930,8 +930,8 @@ static void audio_state_start(struct audio_state *state)
if (igt_frame_dump_is_enabled()) {
snprintf(dump_suffix, sizeof(dump_suffix),
- "capture-%s-%dch-%dHz",
- snd_pcm_format_name(state->playback.format),
+ "capture-%s-%s-%dch-%dHz",
+ name, snd_pcm_format_name(state->playback.format),
state->playback.channels, state->playback.rate);
state->dump_fd = audio_create_wav_file_s32_le(dump_suffix,
@@ -1056,7 +1056,7 @@ static bool test_audio_frequencies(struct audio_state *state)
audio_output_frequencies_callback, state,
PLAYBACK_SAMPLES);
- audio_state_start(state);
+ audio_state_start(state, "frequencies");
igt_assert(state->capture.rate == state->playback.rate);
--
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] 10+ messages in thread
* [igt-dev] [PATCH i-g-t 7/8] lib/igt_audio: make audio_extract_channel_s32_le support a NULL dst
2019-05-24 8:07 [igt-dev] [PATCH i-g-t 0/8] tests/kms_chamelium: add amplitude test Simon Ser
` (5 preceding siblings ...)
2019-05-24 8:07 ` [igt-dev] [PATCH i-g-t 6/8] tests/kms_chamelium: add name parameter to audio_state_start Simon Ser
@ 2019-05-24 8:07 ` Simon Ser
2019-05-24 8:07 ` [igt-dev] [PATCH i-g-t 8/8] tests/kms_chamelium: add pulse audio test Simon Ser
2019-05-24 10:41 ` [igt-dev] ✗ Fi.CI.BAT: failure for tests/kms_chamelium: add amplitude test Patchwork
8 siblings, 0 replies; 10+ messages in thread
From: Simon Ser @ 2019-05-24 8:07 UTC (permalink / raw)
To: igt-dev
This adds a snprintf-like behaviour to audio_extract_channel_s32_le.
Signed-off-by: Simon Ser <simon.ser@intel.com>
---
lib/igt_audio.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/lib/igt_audio.c b/lib/igt_audio.c
index f2aac0e23a37..c7407fa1a97b 100644
--- a/lib/igt_audio.c
+++ b/lib/igt_audio.c
@@ -445,7 +445,13 @@ bool audio_signal_detect(struct audio_signal *signal, int sampling_rate,
}
/**
- * Extracts a single channel from a multi-channel S32_LE input buffer.
+ * audio_extract_channel_s32_le: extracts a single channel from a multi-channel
+ * S32_LE input buffer.
+ *
+ * If dst_cap is zero, no copy is performed. This can be used to compute the
+ * minimum required capacity.
+ *
+ * Returns: the number of samples extracted.
*/
size_t audio_extract_channel_s32_le(double *dst, size_t dst_cap,
int32_t *src, size_t src_len,
@@ -456,6 +462,9 @@ size_t audio_extract_channel_s32_le(double *dst, size_t dst_cap,
igt_assert(channel < n_channels);
igt_assert(src_len % n_channels == 0);
dst_len = src_len / n_channels;
+ if (dst_cap == 0)
+ return dst_len;
+
igt_assert(dst_len <= dst_cap);
for (i = 0; i < dst_len; i++)
dst[i] = (double) src[i * n_channels + channel] / INT32_MAX;
--
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] 10+ messages in thread
* [igt-dev] [PATCH i-g-t 8/8] tests/kms_chamelium: add pulse audio test
2019-05-24 8:07 [igt-dev] [PATCH i-g-t 0/8] tests/kms_chamelium: add amplitude test Simon Ser
` (6 preceding siblings ...)
2019-05-24 8:07 ` [igt-dev] [PATCH i-g-t 7/8] lib/igt_audio: make audio_extract_channel_s32_le support a NULL dst Simon Ser
@ 2019-05-24 8:07 ` Simon Ser
2019-05-24 10:41 ` [igt-dev] ✗ Fi.CI.BAT: failure for tests/kms_chamelium: add amplitude test Patchwork
8 siblings, 0 replies; 10+ messages in thread
From: Simon Ser @ 2019-05-24 8:07 UTC (permalink / raw)
To: igt-dev
This commit adds a pulse test alongside the existing frequencies test.
The test sends an infinite pulse and checks that the amplitude is correct. A
window is used to check that each sample is within acceptable bounds. The test
is stopped as soon as 3 audio pages pass the test.
Signed-off-by: Simon Ser <simon.ser@intel.com>
---
tests/kms_chamelium.c | 100 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 100 insertions(+)
diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
index 54251d6a47ca..a1b139e55b4a 100644
--- a/tests/kms_chamelium.c
+++ b/tests/kms_chamelium.c
@@ -772,6 +772,9 @@ 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
+#define PULSE_AMPLITUDE 0.9 /* normalized, ie. in [0, 1] */
+#define PULSE_ACCURACY 0.001 /* ± 0.1 % of the full amplitude */
+
/* TODO: enable >48KHz rates, these are not reliable */
static int test_sampling_rates[] = {
32000,
@@ -1128,6 +1131,102 @@ static bool test_audio_frequencies(struct audio_state *state)
return success;
}
+static int audio_output_pulse_callback(void *data, void *buffer, int samples)
+{
+ struct audio_state *state = data;
+ double *tmp;
+ size_t len, i;
+
+ len = samples * state->playback.channels;
+ tmp = malloc(len * sizeof(double));
+ for (i = 0; i < len; i++)
+ tmp[i] = 0.9;
+ audio_convert_to(buffer, tmp, len, state->playback.format);
+ free(tmp);
+
+ return state->run ? 0 : -1;
+}
+
+static bool detect_pulse_amplitude(double *buf, size_t buf_len)
+{
+ double min, max;
+ size_t i;
+ bool ok;
+
+ min = max = NAN;
+ for (i = 0; i < buf_len; i++) {
+ if (isnan(min) || buf[i] < min)
+ min = buf[i];
+ if (isnan(max) || buf[i] > max)
+ max = buf[i];
+ }
+
+ ok = (min >= PULSE_AMPLITUDE - PULSE_ACCURACY &&
+ max <= PULSE_AMPLITUDE + PULSE_ACCURACY);
+ if (ok)
+ igt_debug("Pulse detected\n");
+ else
+ igt_debug("Pulse not detected (min=%f, max=%f)\n",
+ min, max);
+ return ok;
+}
+
+static bool test_audio_pulse(struct audio_state *state)
+{
+ bool success;
+ int32_t *recv;
+ size_t recv_len, i, channel_len;
+ int streak, capture_chan;
+ double *channel;
+
+ alsa_register_output_callback(state->alsa,
+ audio_output_pulse_callback, state,
+ PLAYBACK_SAMPLES);
+
+ audio_state_start(state, "pulse");
+
+ recv = NULL;
+ recv_len = 0;
+ success = false;
+ while (!success && state->msec < AUDIO_TIMEOUT) {
+ audio_state_receive(state, &recv, &recv_len);
+
+ igt_debug("Detecting audio signal, t=%d msec\n", state->msec);
+
+ for (i = 0; i < state->playback.channels; i++) {
+ capture_chan = state->channel_mapping[i];
+ igt_assert(capture_chan >= 0);
+ igt_debug("Processing channel %zu (captured as "
+ "channel %d)\n", i, capture_chan);
+
+ channel_len = audio_extract_channel_s32_le(NULL, 0,
+ recv, recv_len,
+ state->capture.channels,
+ capture_chan);
+ channel = malloc(channel_len * sizeof(double));
+ audio_extract_channel_s32_le(channel, channel_len,
+ recv, recv_len,
+ state->capture.channels,
+ capture_chan);
+
+ if (detect_pulse_amplitude(channel, channel_len))
+ streak++;
+ else
+ streak = 0;
+
+ free(channel);
+ }
+
+ success = streak == MIN_STREAK * state->playback.channels;
+ }
+
+ audio_state_stop(state, success);
+
+ free(recv);
+
+ return success;
+}
+
static bool check_audio_configuration(struct alsa *alsa, snd_pcm_format_t format,
int channels, int sampling_rate)
{
@@ -1225,6 +1324,7 @@ test_display_audio(data_t *data, struct chamelium_port *port,
audio_state_init(&state, data, alsa, port,
format, channels, sampling_rate);
success &= test_audio_frequencies(&state);
+ success &= test_audio_pulse(&state);
audio_state_fini(&state);
alsa_close_output(alsa);
--
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] 10+ messages in thread
* [igt-dev] ✗ Fi.CI.BAT: failure for tests/kms_chamelium: add amplitude test
2019-05-24 8:07 [igt-dev] [PATCH i-g-t 0/8] tests/kms_chamelium: add amplitude test Simon Ser
` (7 preceding siblings ...)
2019-05-24 8:07 ` [igt-dev] [PATCH i-g-t 8/8] tests/kms_chamelium: add pulse audio test Simon Ser
@ 2019-05-24 10:41 ` Patchwork
8 siblings, 0 replies; 10+ messages in thread
From: Patchwork @ 2019-05-24 10:41 UTC (permalink / raw)
To: Ser, Simon; +Cc: igt-dev
== Series Details ==
Series: tests/kms_chamelium: add amplitude test
URL : https://patchwork.freedesktop.org/series/61087/
State : failure
== Summary ==
Applying: tests/kms_chamelium: refactor audio test
Applying: tests/kms_chamelium: introduce audio_state_receive
Applying: tests/kms_chamelium: rename do_test_display_audio and test_audio_configuration
Applying: tests/kms_chamelium: explain why 8-channel tests aren't performed
Applying: lib/igt_audio: introduce audio_convert_to
Patch failed at 0005 lib/igt_audio: introduce audio_convert_to
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev
^ permalink raw reply [flat|nested] 10+ messages in thread