diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/audio.c | 193 | ||||
-rw-r--r-- | tests/kms_chamelium.c | 276 | ||||
-rw-r--r-- | tests/meson.build | 9 |
3 files changed, 271 insertions, 207 deletions
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 = [] |