Skip to content

Commit 5f74c00

Browse files
committed
test-case: add test jack detection while playback
Add a new test case to test jack detection during playback. The test checks all playback Jack PCM devices For unplug/plug headset jack is using a USB relay. https://github.com/darrylb123/usbrelay Signed-off-by: Artur Wilczak <arturx.wilczak@intel.com>
1 parent 5124961 commit 5f74c00

File tree

3 files changed

+250
-0
lines changed

3 files changed

+250
-0
lines changed

case-lib/relay.sh

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/bin/bash
2+
3+
# SPDX-License-Identifier: BSD-3-Clause
4+
# Copyright(c) 2021-2025 Intel Corporation. All rights reserved.
5+
6+
# test-mic_privacy.sh needs to control mic privacy settings (on/off)
7+
# needs usbrelay package: https://github.com/darrylb123/usbrelay
8+
# param1: switch name
9+
# param2: switch state
10+
usbrelay_switch()
11+
{
12+
# Declare a constant for the relay settle time
13+
USBRELAY_SETTLE_TIME=0.5
14+
15+
local switch_name=$1
16+
local state=$2
17+
18+
dlogi "Setting usbrelay switch $switch_name to $state."
19+
usbrelay "$switch_name=$state" > /dev/null || {
20+
# if not detect relays hw module, skip the test
21+
die "Failed to set usbrelay switch $switch_name to $state.
22+
The usbrelay hw module is not responding or no relays detected.
23+
Check hardware connection."
24+
}
25+
26+
# wait for the switch to settle
27+
sleep "$USBRELAY_SETTLE_TIME"
28+
29+
# Display current state of the switch
30+
current_state=$(usbrelay | awk -F= -v name="$switch_name" '$1 == name { print $2 }')
31+
32+
# Check if current_state is equal to the requested state
33+
[[ "$current_state" == "$state" ]] || {
34+
die "usbrelay switch $switch_name failed to set to $state (current: $current_state)"
35+
}
36+
37+
case "$current_state" in
38+
'1') dlogi "Current state of $switch_name is: on";;
39+
'0') dlogi "Current state of $switch_name is: off";;
40+
*) die "Invalid state for $switch_name: $current_state";;
41+
esac
42+
}

env-check.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ func_check_pkg aplay
8787
func_check_pkg sox
8888
func_check_pkg tinycap
8989
func_check_pkg tinyplay
90+
# MIC privacy / JACK Audio detection relay switch
91+
func_check_pkg usbrelay
9092
# JACK Audio Connection Kit
9193
func_check_pkg jackd
9294
func_check_pkg jack_iodelay
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
#!/bin/bash
2+
3+
# SPDX-License-Identifier: BSD-3-Clause
4+
# Copyright(c) 2025 Intel Corporation. All rights reserved.
5+
6+
##
7+
## Preconditions
8+
# 1. Runtime PM status is on.
9+
# 2. aplay (playback) is running.
10+
# 3. USB relay switch is available and configured.
11+
# Jack detection header should be connected to the USB relay switch
12+
# to the port HURTM_2 (NC) connector.
13+
14+
## Test Description
15+
# Verify jack detection functionality by simulating plugging and unplugging
16+
# of audio jack using a USB relay switch.
17+
# The unplugging and plugging of the jack will be during playback operations
18+
# to ensure the system can handle jack detection events correctly.
19+
# The test will check if the jack detection status is updated correctly
20+
# when the jack is plugged in and unplugged.
21+
22+
## Case Steps
23+
# 1. Ensure the USB relay switch is configured to control the jack detection header.
24+
# 2. Ensure the aplay (playback) command works properly.
25+
# 3. Set the USB relay switch to state on (1), simulate unplugging the headset from the jack.
26+
# 4. Check the jack detection status via amixer. The status should indicate **off**.
27+
# 5. Check if the aplay process is still running after unplugging the jack.
28+
# If the process is not running, the test fails.
29+
# If the process is still running, continue to the next step.
30+
# 6. Set the USB relay switch to state off (0), simulate plugging the headset.
31+
# 7. Check the jack detection status via amixer. The status should indicate **on**.
32+
# 8. Check if the aplay process is still running after plugging the jack.
33+
# If the process is not running, the test fails.
34+
# If the process is still running, continue to the next step.
35+
# 9. Terminate the aplay process.
36+
# 10. Check if the aplay process is terminated successfully.
37+
# If the process is still running, the test fails.
38+
# If the process is terminated successfully, the test passes.
39+
# 11. Check dmesg for any unexpected errors.
40+
#
41+
# Repeat steps 3-11 for all pcm jack playback devices.
42+
43+
TESTDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
44+
TESTLIB="${TESTDIR}/case-lib"
45+
46+
# shellcheck disable=SC1091 source=case-lib/lib.sh
47+
source "${TESTLIB}/lib.sh"
48+
# shellcheck disable=SC1091 source=case-lib/relay.sh
49+
source "${TESTLIB}/relay.sh"
50+
51+
# shellcheck disable=SC2153
52+
OPT_NAME['t']='tplg' OPT_DESC['t']="tplg file, default value is env TPLG: $TPLG"
53+
OPT_HAS_ARG['t']=1 OPT_VAL['t']="$TPLG"
54+
55+
OPT_NAME['l']='loop' OPT_DESC['l']='loop count'
56+
OPT_HAS_ARG['l']=1 OPT_VAL['l']=1
57+
58+
OPT_NAME['s']='sof-logger' OPT_DESC['s']="Open sof-logger trace the data will store at $LOG_ROOT"
59+
OPT_HAS_ARG['s']=0 OPT_VAL['s']=1
60+
61+
OPT_NAME['u']='relay' OPT_DESC['u']='name of usbrelay switch, default value is HURTM_2'
62+
OPT_HAS_ARG['u']=1 OPT_VAL['u']="HURTM_2"
63+
64+
func_opt_parse_option "$@"
65+
66+
tplg=${OPT_VAL['t']}
67+
relay=${OPT_VAL['u']}
68+
loop_cnt=${OPT_VAL['l']}
69+
70+
TWO_SECONDS=2
71+
72+
check_control_switch_state()
73+
{
74+
# Check the state of the switch using amixer.
75+
# The switch name is passed as the first argument, and the expected state (on/off)
76+
# is passed as the second argument.
77+
# Returns 0 if the state matches, 1 otherwise.
78+
local control_name="$1"
79+
local expected_control_state="$2"
80+
local control_state
81+
82+
control_state=$(amixer -c "$SOFCARD" contents | awk -v name="$control_name" '
83+
BEGIN {
84+
RS = "";
85+
IGNORECASE = 1;
86+
split(name, parts, " ");
87+
};
88+
$0 ~ parts[1] && $0 ~ parts[2] {
89+
if (match($0, /values=(on|off)/, m)) print m[1];
90+
}
91+
')
92+
dlogi "$control_name switch is: $control_state"
93+
94+
if [[ "$expected_control_state" == "$control_state" ]]; then
95+
return 0
96+
else
97+
return 1
98+
fi
99+
}
100+
101+
testing_one_pcm()
102+
{
103+
dlogi "===== Testing: (PCM: $pcm [$dev]<$type>) (Loop: $i/$loop_cnt) ====="
104+
dlogi "DEVICE: $dev, TYPE: $type, PCM: $pcm, RATE: $rate, CHANNEL: $channel"
105+
106+
dlogi "Command: aplay -Dplug$dev -q /dev/zero"
107+
# Start alsabat in background with longer duration
108+
dlogi "Starting aplay in background..."
109+
aplay "-Dplug$dev" -d10 -q /dev/zero & pid_playback=$! || {
110+
func_lib_lsof_error_dump "$snd"
111+
die "Failed to start aplay on PCM: $pcm"
112+
}
113+
# Wait briefly to ensure the device is ready and avoid read errors
114+
sleep 1
115+
dlogi "aplay started with PID: $pid_playback"
116+
117+
dlogi "Unplug jack audio."
118+
usbrelay_switch "$relay" 1
119+
120+
# Wait for a short period to allow the system to detect the unplug event
121+
sleep $TWO_SECONDS
122+
123+
# check if the aplay process is still running after unplugging the jack
124+
ps -p "$pid_playback" > /dev/null || {
125+
func_lib_lsof_error_dump "$snd"
126+
die "Playback process terminated unexpectedly after unplugging the jack."
127+
}
128+
129+
check_control_switch_state "headset" "off" || {
130+
die "unplug headset jack failed."
131+
}
132+
133+
check_control_switch_state "headphone" 'off' || {
134+
die "unplug headphone jack failed."
135+
}
136+
137+
dlogi "Plug jack audio."
138+
usbrelay_switch "$relay" 0
139+
140+
# Wait for a short period to allow the system to detect the plug event
141+
sleep $TWO_SECONDS
142+
143+
# check if the aplay process is still running after unplugging the jack
144+
ps -p "$pid_playback" > /dev/null || {
145+
func_lib_lsof_error_dump "$snd"
146+
die "Playback process terminated unexpectedly after unplugging the jack."
147+
}
148+
149+
check_control_switch_state "headset" "on" || {
150+
die "Plug headset jack failed."
151+
}
152+
153+
check_control_switch_state "headphone" "on" || {
154+
die "Plug headphone jack failed."
155+
}
156+
157+
kill -9 $pid_playback > /dev/null 2>&1
158+
wait $pid_playback 2>/dev/null || true
159+
ps -p "$pid_playback" > /dev/null && {
160+
dloge "Failed to kill playback process."
161+
func_lib_lsof_error_dump "$snd"
162+
die "Playback process did not terminate as expected."
163+
}
164+
dlogi "Playback process terminated."
165+
dlogi "===== Testing: PASSED ====="
166+
}
167+
168+
main()
169+
{
170+
func_pipeline_export "$tplg" "type:playback"
171+
172+
setup_kernel_check_point
173+
174+
start_test
175+
176+
logger_disabled || func_lib_start_log_collect
177+
178+
# Check if usbrelay tool is installed
179+
command -v usbrelay || {
180+
# If usbrelay package is not installed
181+
skip_test "usbrelay command not found. Please install usbrelay package."
182+
}
183+
184+
dlogi "Reset - plug jack audio"
185+
usbrelay_switch "$relay" 0
186+
187+
for idx in $(seq 0 $((PIPELINE_COUNT - 1)))
188+
do
189+
initialize_audio_params "$idx"
190+
191+
[[ "$pcm" == *Jack* ]] || {
192+
dlogi "PCM $pcm is not a Jack, skipping..."
193+
continue
194+
}
195+
196+
for i in $(seq 1 "$loop_cnt")
197+
do
198+
testing_one_pcm
199+
sof-kernel-log-check.sh "$KERNEL_CHECKPOINT"
200+
done
201+
done
202+
}
203+
204+
{
205+
main "$@"; exit "$?"
206+
}

0 commit comments

Comments
 (0)