Skip to content

Commit 9fecb79

Browse files
committed
test-case: Add ALSA conformance tests
Add ALSA conformance tests from ChromeOS Audio Test package. The new test case `check-alsa-conformance.sh` executes `alsa_conformnance_test` and compose its results into a JSON file. Signed-off-by: Dmitrii Golovanov <dmitrii.golovanov@intel.com>
1 parent 4a5a1d9 commit 9fecb79

File tree

1 file changed

+284
-0
lines changed

1 file changed

+284
-0
lines changed
Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
#!/bin/bash
2+
3+
# Copyright(c) 2025 Intel Corporation.
4+
# SPDX-License-Identifier: BSD-3-Clause
5+
6+
##
7+
## Case Name: Execute ALSA conformance tests.
8+
##
9+
## Preconditions:
10+
## - ChromeOS Audio Test package is installed
11+
## https://chromium.googlesource.com/chromiumos/platform/audiotest
12+
##
13+
## Description:
14+
## Run `alsa_conformance_test.py` for the playback device
15+
## and the capture devices with the test suite paramenters given.
16+
## Pass multiple values of the test parameters enclosing them in quotes,
17+
## eg. `-F 'U8 S16_LE'`
18+
## Compose resulting JSON reports.
19+
##
20+
## Case steps:
21+
## 0. Set ALSA parameters.
22+
## 1. Try to start `alsa_conformance_test` in device info mode.
23+
## 2. Start `alsa conformance_test.py` for playback device.
24+
## 3. Start `alsa conformance_test.py` for capture device.
25+
## 4. Compose the resulting JSON report.
26+
##
27+
## Expect result:
28+
## ALSA conformance results collected and saved in `test_result.json` file.
29+
## Exit status 0.
30+
##
31+
32+
TESTDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
33+
TESTLIB="${TESTDIR}/case-lib"
34+
35+
# shellcheck source=case-lib/lib.sh
36+
source "${TESTLIB}/lib.sh"
37+
38+
OPT_NAME['d']='device' OPT_DESC['d']='ALSA pcm device for playback and capture. Example: hw:0'
39+
OPT_HAS_ARG['d']=1 OPT_VAL['d']=''
40+
41+
OPT_NAME['p']='pcm_p' OPT_DESC['p']='ALSA pcm device for playback only. Example: hw:soundwire,0'
42+
OPT_HAS_ARG['p']=1 OPT_VAL['p']=''
43+
44+
OPT_NAME['c']='pcm_c' OPT_DESC['c']='ALSA pcm device for capture only. Example: hw:soundwire,1'
45+
OPT_HAS_ARG['c']=1 OPT_VAL['c']=''
46+
47+
OPT_NAME['r']='rates' OPT_DESC['r']='Sample ratis to try. Default: check all available rates.'
48+
OPT_HAS_ARG['r']=1 OPT_VAL['r']=''
49+
50+
OPT_NAME['F']='formats' OPT_DESC['F']='Data formats to try. Default: check all available formats.'
51+
OPT_HAS_ARG['F']=1 OPT_VAL['F']=''
52+
53+
OPT_NAME['s']='sof-logger' OPT_DESC['s']="Open sof-logger trace the data will store at $LOG_ROOT"
54+
OPT_HAS_ARG['s']=0 OPT_VAL['s']=1
55+
56+
OPT_NAME['v']='verbose' OPT_DESC['v']='Verbose logging.'
57+
OPT_HAS_ARG['v']=0 OPT_VAL['v']=0
58+
59+
OPT_NAME['E']='rate-diff' OPT_DESC['E']="ALSA conformance --rate-criteria-diff-pct (difference, %)."
60+
OPT_HAS_ARG['E']=1 OPT_VAL['E']=''
61+
62+
OPT_NAME['e']='rate-err' OPT_DESC['e']="ALSA conformance --rate-err-criteria (max rate error)."
63+
OPT_HAS_ARG['e']=1 OPT_VAL['e']=''
64+
65+
OPT_NAME['a']='avail-delay' OPT_DESC['a']="ALSA conformance --avail-delay"
66+
OPT_HAS_ARG['a']=0 OPT_VAL['a']=0
67+
68+
OPT_NAME['T']='test-suites' OPT_DESC['T']="ALSA conformance --test-suites (Default: all)."
69+
OPT_HAS_ARG['T']=1 OPT_VAL['T']=''
70+
71+
func_opt_parse_option "$@"
72+
73+
# Options for the ALSA conformance test script call
74+
CMD_OPTS=()
75+
76+
# Recompose OPT_VAL[$1] option as ALSA test script option $2
77+
add_cmd_option()
78+
{
79+
local opt_val="${OPT_VAL[$1]}"
80+
local prefix=$2
81+
82+
if [ -n "${opt_val}" ]; then
83+
# Split list parameters to separate values
84+
opt_val=("${opt_val//[ ,]/ }")
85+
# shellcheck disable=SC2206
86+
CMD_OPTS+=("${prefix}" ${opt_val[@]})
87+
fi
88+
}
89+
90+
init_globals()
91+
{
92+
add_cmd_option 'r' '--allow-rates'
93+
add_cmd_option 'F' '--allow-formats'
94+
add_cmd_option 'E' '--rate-criteria-diff-pct'
95+
add_cmd_option 'e' '--rate-err-criteria'
96+
add_cmd_option 'T' '--test-suites'
97+
98+
run_verbose=0
99+
if [[ "${OPT_VAL['v']}" -eq 1 ]]; then
100+
run_verbose=1
101+
CMD_OPTS+=("--log-file" "/dev/stdout")
102+
fi
103+
104+
if [[ "${OPT_VAL['a']}" -eq 1 ]]; then
105+
CMD_OPTS+=('--avail-delay')
106+
fi
107+
108+
AUDIOTEST_OUT="${LOG_ROOT}/alsa_conformance"
109+
RESULT_JSON="${LOG_ROOT}/test_result.json"
110+
111+
ALSA_CONFORMANCE_PATH=$([ -n "$ALSA_CONFORMANCE_PATH" ] || realpath "${TESTDIR}/../audiotest")
112+
ALSA_CONFORMANCE_TEST="${ALSA_CONFORMANCE_PATH}/alsa_conformance_test"
113+
}
114+
115+
check_alsa_conformance_suite()
116+
{
117+
if [ -d "${ALSA_CONFORMANCE_PATH}" ]; then
118+
if [ -x "${ALSA_CONFORMANCE_TEST}" ] && [ -x "${ALSA_CONFORMANCE_TEST}.py" ]; then
119+
dlogi "Use ALSA conformance test suite: ${ALSA_CONFORMANCE_TEST}"
120+
return
121+
fi
122+
fi
123+
skip_test "ALSA conformance test suite is missing at: ${ALSA_CONFORMANCE_PATH}"
124+
}
125+
126+
check_options()
127+
{
128+
alsa_device=${OPT_VAL['d']}
129+
pcm_p=${OPT_VAL['p']}
130+
pcm_c=${OPT_VAL['c']}
131+
132+
PLAYBACK_DEVICE="${pcm_p}"
133+
CAPTURE_DEVICE="${pcm_c}"
134+
PLAYBACK_OPTIONS=()
135+
CAPTURE_OPTIONS=()
136+
137+
if [ -n "${alsa_device}" ]; then
138+
if [ -n "${pcm_p}" ] || [ -n "${pcm_c}" ]; then
139+
die "Give either ALSA device, or ALSA playback/capture PCMs."
140+
fi
141+
PLAYBACK_DEVICE="${alsa_device}"
142+
PLAYBACK_OPTIONS=("-P" "${alsa_device}")
143+
CAPTURE_DEVICE="${alsa_device}"
144+
CAPTURE_OPTIONS=("-C" "${alsa_device}")
145+
elif [ -z "${pcm_p}" ] && [ -z "${pcm_c}" ]; then
146+
skip_test "Neither playback, nor capture ALSA PCM is specified."
147+
else
148+
[ -n "${pcm_p}" ] && PLAYBACK_OPTIONS=("-P" "${pcm_p}")
149+
[ -n "${pcm_c}" ] && CAPTURE_OPTIONS=("-C" "${pcm_c}")
150+
fi
151+
}
152+
153+
set_alsa()
154+
{
155+
reset_sof_volume
156+
157+
# If MODEL is defined, set proper gain for the platform
158+
if [ -z "$MODEL" ]; then
159+
dlogw "No MODEL is defined. Please define MODEL to run alsa_settings/\${MODEL}.sh"
160+
else
161+
set_alsa_settings "$MODEL"
162+
fi
163+
}
164+
165+
alsa_conformance_device_info()
166+
{
167+
local run_cmd=("${ALSA_CONFORMANCE_TEST}" "${PLAYBACK_OPTIONS[@]}" "${CAPTURE_OPTIONS[@]}" "--dev_info_only")
168+
dlogc "${run_cmd[@]}"
169+
local rc=1
170+
"${run_cmd[@]}" ; rc=$?
171+
[[ "${rc}" -ne 0 ]] && die "Failed to get device info, rc=${rc}"
172+
}
173+
174+
alsa_conformance_test_playback()
175+
{
176+
if [ -n "${PLAYBACK_OPTIONS[*]}" ]; then
177+
local run_prefix=("export" "PATH=${ALSA_CONFORMANCE_PATH}:${PATH}")
178+
local run_cmd=()
179+
run_cmd+=("${ALSA_CONFORMANCE_TEST}.py" "${CMD_OPTS[@]}" "${PLAYBACK_OPTIONS[@]}")
180+
run_cmd+=("--json-file" "${AUDIOTEST_OUT}_playback.json")
181+
dlogc "${run_cmd[@]}"
182+
local rc=1
183+
"${run_prefix[@]}" && "${run_cmd[@]}" ; rc=$?
184+
[[ "${rc}" -ne 0 ]] && dloge "Failed PLAYBACK TESTS, rc=${rc}"
185+
fi
186+
}
187+
188+
alsa_conformance_test_capture()
189+
{
190+
if [ -n "${CAPTURE_OPTIONS[*]}" ]; then
191+
local run_prefix=("export" "PATH=${ALSA_CONFORMANCE_PATH}:${PATH}")
192+
local run_cmd=()
193+
run_cmd+=("${ALSA_CONFORMANCE_TEST}.py" "${CMD_OPTS[@]}" "${CAPTURE_OPTIONS[@]}")
194+
run_cmd+=("--json-file" "${AUDIOTEST_OUT}_capture.json")
195+
dlogc "${run_cmd[@]}"
196+
local rc=1
197+
"${run_prefix[@]}" && "${run_cmd[@]}" ; rc=$?
198+
[[ "${rc}" -ne 0 ]] && dloge "Failed CAPTURE TESTS, rc=${rc}"
199+
fi
200+
}
201+
202+
report_start()
203+
{
204+
dlogi "Compose ${RESULT_JSON}"
205+
printf '{"options":{%s}, "alsa_conformance":[' "$(options2json)" > "${RESULT_JSON}"
206+
}
207+
208+
json_next_sep=""
209+
210+
report_conformance()
211+
{
212+
local report_type=$1
213+
local report_device=$2
214+
local report_file="${AUDIOTEST_OUT}_${report_type}.json"
215+
if [ -s "${report_file}" ]; then
216+
printf '%s{"device":"%s","%s":' \
217+
"${json_next_sep}" "${report_device}" "${report_type}" >> "${RESULT_JSON}"
218+
jq --compact-output . "${report_file}" >> "${RESULT_JSON}" && rm "${report_file}"
219+
printf '}' >> "${RESULT_JSON}"
220+
json_next_sep=","
221+
else
222+
dlogw "No conformance report for ${report_type}"
223+
fi
224+
}
225+
226+
report_end()
227+
{
228+
printf ']}\n' >> "${RESULT_JSON}"
229+
[[ "${run_verbose}" -ne 0 ]] && cat "${RESULT_JSON}"
230+
}
231+
232+
assert_failures()
233+
{
234+
local report_type=$1
235+
local report_device=$2
236+
[ -z "${report_device}" ] && return
237+
238+
local report_key="alsa_conformance[].${report_type}.fail"
239+
local failures=""
240+
241+
failures=$(jq ".${report_key} // 0" "${RESULT_JSON}")
242+
if [ -z "${failures}" ] || [ "${failures}" -ne "${failures}" ]; then
243+
die "Invalid ${RESULT_JSON}"
244+
fi
245+
if [ "${failures}" -ne 0 ]; then
246+
die "${report_type} has ${failures} failures."
247+
fi
248+
}
249+
250+
main()
251+
{
252+
init_globals
253+
254+
setup_kernel_check_point
255+
256+
start_test
257+
258+
check_alsa_conformance_suite
259+
260+
check_options
261+
262+
logger_disabled || func_lib_start_log_collect
263+
264+
set_alsa
265+
266+
alsa_conformance_device_info
267+
268+
report_start
269+
270+
alsa_conformance_test_playback
271+
report_conformance 'playback' "${PLAYBACK_DEVICE}"
272+
273+
alsa_conformance_test_capture
274+
report_conformance 'capture' "${CAPTURE_DEVICE}"
275+
276+
report_end
277+
278+
assert_failures 'playback' "${PLAYBACK_DEVICE}"
279+
assert_failures 'capture' "${CAPTURE_DEVICE}"
280+
}
281+
282+
{
283+
main "$@"; exit "$?"
284+
}

0 commit comments

Comments
 (0)