|
| 1 | +# Audio_Playback (GStreamer) — Runner Test |
| 2 | + |
| 3 | +This directory contains the **Audio_Playback** validation test for Qualcomm Linux Testkit runners. |
| 4 | + |
| 5 | +It validates audio **playback** using **GStreamer (`gst-launch-1.0`)** with an auto-selected backend: |
| 6 | +- **PipeWire** |
| 7 | +- **PulseAudio** |
| 8 | +- **ALSA (direct)** |
| 9 | + |
| 10 | +The script is designed to be **CI/LAVA-friendly**: |
| 11 | +- Writes **PASS/FAIL/SKIP** into `Audio_Playback.res` |
| 12 | +- Always **exits 0** (even on FAIL/SKIP) to avoid terminating LAVA jobs early |
| 13 | +- Logs the **final `gst-launch-1.0` command** to console and to log files |
| 14 | + |
| 15 | +--- |
| 16 | + |
| 17 | +## Location in repo |
| 18 | + |
| 19 | +Expected path: |
| 20 | + |
| 21 | +``` |
| 22 | +Runner/suites/Multimedia/GSTreamer/Audio/Audio_Playback/run.sh |
| 23 | +``` |
| 24 | + |
| 25 | +Required shared utils (sourced from `Runner/utils` via `init_env`): |
| 26 | +- `functestlib.sh` |
| 27 | +- `lib_gstreamer.sh` |
| 28 | +- optional: `audio_common.sh` (wrapper/aliases if present) |
| 29 | + |
| 30 | +--- |
| 31 | + |
| 32 | +## What this test does |
| 33 | + |
| 34 | +At a high level, the test: |
| 35 | + |
| 36 | +1. Finds and sources `init_env` |
| 37 | +2. Sources: |
| 38 | + - `$TOOLS/functestlib.sh` |
| 39 | + - `$TOOLS/lib_gstreamer.sh` |
| 40 | + - optionally `$TOOLS/audio_common.sh` |
| 41 | +3. Resolves or accepts a clip path |
| 42 | +4. Ensures the clip is present locally (supports device-provided assets via `--assets` / `--clips-dir`, |
| 43 | + and optionally remote fetch via `--assets-url` if the helper exists) |
| 44 | +5. Builds a **backend chain** (auto: pipewire → pulseaudio → alsa) |
| 45 | +6. Selects a sink (optional `--sink`, optional `--null-sink`) |
| 46 | +7. Constructs a **multi-line** `gst-launch-1.0` playback pipeline |
| 47 | +8. Runs the pipeline for the requested duration (watchdog timeout) |
| 48 | +9. Applies **post-validation evidence** (streaming/path activity) and emits PASS/FAIL/SKIP |
| 49 | +10. Collects best-effort diagnostics: |
| 50 | + - mixer dump |
| 51 | + - dmesg scan |
| 52 | + |
| 53 | +--- |
| 54 | + |
| 55 | +## PASS / FAIL / SKIP criteria |
| 56 | + |
| 57 | +### PASS |
| 58 | +- `gst-launch-1.0` either: |
| 59 | + - exits `0`, or |
| 60 | + - is killed by watchdog timeout (`124` or `143`) **when a duration timeout is used** |
| 61 | +- **AND** evidence indicates the audio path was active, such as: |
| 62 | + - PipeWire stream RUNNING, or |
| 63 | + - PulseAudio stream/sink-input exists, or |
| 64 | + - ALSA PCM substream RUNNING, or |
| 65 | + - ASoC DAPM path shows `On` (fallback heuristic) |
| 66 | + |
| 67 | +### FAIL |
| 68 | +- A backend was attempted and the run did not meet PASS criteria (e.g., immediate pipeline failure, no evidence of activity) |
| 69 | + |
| 70 | +### SKIP |
| 71 | +- Missing required tools (`gst-launch-1.0`, `gst-inspect-1.0`) |
| 72 | +- No usable backend found |
| 73 | +- Clip missing and assets not available |
| 74 | +- Invalid arguments or required values missing |
| 75 | + |
| 76 | +**Note:** The test always exits `0` even for FAIL/SKIP. The `.res` file is the source of truth. |
| 77 | + |
| 78 | +--- |
| 79 | + |
| 80 | +## Logs and artifacts |
| 81 | + |
| 82 | +By default, logs are written relative to the script working directory: |
| 83 | + |
| 84 | +``` |
| 85 | +./Audio_Playback.res |
| 86 | +./logs/Audio_Playback/ |
| 87 | + gst.log |
| 88 | + mixers.txt |
| 89 | + clip_meta.txt |
| 90 | + dmesg/ |
| 91 | + (dmesg scan outputs) |
| 92 | +``` |
| 93 | + |
| 94 | +The final `gst-launch-1.0` command is always printed to the console. |
| 95 | + |
| 96 | +--- |
| 97 | + |
| 98 | +## Dependencies |
| 99 | + |
| 100 | +### Required |
| 101 | +- `gst-launch-1.0` |
| 102 | +- `gst-inspect-1.0` |
| 103 | + |
| 104 | +### Recommended (for best results) |
| 105 | +- `gst-discoverer-1.0` (for clip metadata and cap inference) |
| 106 | +- For PipeWire backend: |
| 107 | + - `pipewire` running |
| 108 | + - `wpctl` available |
| 109 | + - `pipewiresink` GStreamer plugin (preferred) |
| 110 | +- For PulseAudio backend: |
| 111 | + - `pulseaudio` or `pipewire-pulse` running |
| 112 | + - `pactl` available |
| 113 | + - `pulsesink` GStreamer plugin |
| 114 | +- For ALSA backend: |
| 115 | + - `alsasink` GStreamer plugin |
| 116 | + - proper hw device path (default `hw:0,0`) |
| 117 | + |
| 118 | +--- |
| 119 | + |
| 120 | +## Caps negotiation behavior (important) |
| 121 | + |
| 122 | +The pipeline only forces caps (`audio/x-raw,rate=...,channels=...`) when: |
| 123 | + |
| 124 | +- User explicitly sets `--rate` and/or `--channels`, **OR** |
| 125 | +- Inference succeeded via `gst-discoverer-1.0` |
| 126 | + |
| 127 | +Otherwise the test **does NOT force caps** and lets GStreamer negotiate. |
| 128 | +This reduces false failures on hardware with unusual constraints. |
| 129 | + |
| 130 | +--- |
| 131 | + |
| 132 | +## Usage |
| 133 | + |
| 134 | +Run: |
| 135 | + |
| 136 | +``` |
| 137 | +./run.sh [options] |
| 138 | +``` |
| 139 | + |
| 140 | +Help: |
| 141 | + |
| 142 | +``` |
| 143 | +./run.sh --help |
| 144 | +``` |
| 145 | + |
| 146 | +### Options |
| 147 | + |
| 148 | +- `--backend <auto|pipewire|pulseaudio|alsa>` |
| 149 | + - Default: `auto` (tries pipewire → pulseaudio → alsa) |
| 150 | + |
| 151 | +- `--stack <auto|base|overlay>` |
| 152 | + - Default: `auto` |
| 153 | + - `auto` : detect overlay (audioreach modules) and apply overlay setup only if detected |
| 154 | + - `base` : force base (do not run overlay setup even if audioreach modules are present) |
| 155 | + - `overlay` : force overlay setup (SKIP if overlay setup fails) |
| 156 | + |
| 157 | +- `--format <wav|aac|mp3|flac>` |
| 158 | + - Default: `wav` |
| 159 | + |
| 160 | +- `--duration <N|Ns|Nm|Nh|MM:SS|HH:MM:SS>` |
| 161 | + - Default: `${RUNTIMESEC:-10s}` |
| 162 | + |
| 163 | +- `--clipdur <short|medium|long>` |
| 164 | + - Used with `resolve_clip()` when `--clip` is not specified |
| 165 | + - Default: `short` |
| 166 | + |
| 167 | +- `--clip <path>` |
| 168 | + - Override resolved clip path |
| 169 | + |
| 170 | +- `--clips-dir <dir>` |
| 171 | + - Points to **already untarred** clips directory on device. |
| 172 | + - Sets `AUDIO_CLIPS_BASE_DIR` |
| 173 | + |
| 174 | +- `--assets <path>` |
| 175 | + - Device-provided assets (no network): |
| 176 | + - If directory: treated as `--clips-dir` |
| 177 | + - If file: `.tar` / `.tar.gz` extracted into `clips-dir` (or `AudioClips` under script dir) |
| 178 | + |
| 179 | +- `--assets-url <url>` |
| 180 | + - Optional remote tarball URL (used only if clip missing and helper exists) |
| 181 | + |
| 182 | +- `--rate <Hz>` |
| 183 | + - Forces output caps **rate** after decode/resample |
| 184 | + - Example: `48000` |
| 185 | + |
| 186 | +- `--channels <N>` |
| 187 | + - Forces output caps **channels** after decode/resample |
| 188 | + - Example: `1` or `2` |
| 189 | + |
| 190 | +- `--sink <idOrName>` |
| 191 | + - For PipeWire: numeric id or substring match in `wpctl status` |
| 192 | + - For PulseAudio: sink name or numeric index |
| 193 | + |
| 194 | +- `--null-sink` |
| 195 | + - Prefer null/dummy sink if available (useful for silent CI runs) |
| 196 | + |
| 197 | +- `--gst-debug <level>` |
| 198 | + - Sets `GST_DEBUG=<level>` (single numeric level) |
| 199 | + - Values: |
| 200 | + - `1` ERROR |
| 201 | + - `2` WARNING |
| 202 | + - `3` FIXME |
| 203 | + - `4` INFO |
| 204 | + - `5` DEBUG |
| 205 | + - `6` LOG |
| 206 | + - `7` TRACE |
| 207 | + - `9` MEMDUMP |
| 208 | + - Default: `2` |
| 209 | + |
| 210 | +--- |
| 211 | + |
| 212 | +## Examples |
| 213 | + |
| 214 | +### 1) Basic WAV playback (auto backend) |
| 215 | + |
| 216 | +``` |
| 217 | +./run.sh --format wav --clip /var/yesterday_48KHz.wav --duration 10s |
| 218 | +``` |
| 219 | + |
| 220 | +### 2) Base stack (force no overlay actions) |
| 221 | + |
| 222 | +``` |
| 223 | +./run.sh --stack base --format wav --clip /var/yesterday_48KHz.wav --duration 10s |
| 224 | +``` |
| 225 | + |
| 226 | +### 3) Overlay stack (force overlay setup) |
| 227 | + |
| 228 | +``` |
| 229 | +./run.sh --stack overlay --format wav --clip /var/yesterday_48KHz.wav --duration 10s |
| 230 | +``` |
| 231 | + |
| 232 | +### 4) AAC playback (matches your reference pipeline intent) |
| 233 | + |
| 234 | +Your reference pipeline: |
| 235 | + |
| 236 | +``` |
| 237 | +gst-launch-1.0 filesrc location=/opt/aac_48k_mono.aac ! aacparse ! avdec_aac ! audioconvert ! audioresample ! audio/x-raw,rate=48000,channels=1 ! alsasink device=hw:0,0 |
| 238 | +``` |
| 239 | + |
| 240 | +Equivalent test invocation: |
| 241 | + |
| 242 | +``` |
| 243 | +./run.sh --format aac --clip /opt/aac_48k_mono.aac --rate 48000 --channels 1 --duration 10s |
| 244 | +``` |
| 245 | + |
| 246 | +### 5) FLAC 48k stereo playback (reference intent) |
| 247 | + |
| 248 | +``` |
| 249 | +./run.sh --format flac --clip /opt/flac_48k_stereo.flac --rate 48000 --channels 2 --duration 10s |
| 250 | +``` |
| 251 | + |
| 252 | +### 6) MP3 44.1k stereo playback (reference intent) |
| 253 | + |
| 254 | +``` |
| 255 | +./run.sh --format mp3 --clip /opt/mp3_44k1_stereo.mp3 --rate 44100 --channels 2 --duration 10s |
| 256 | +``` |
| 257 | + |
| 258 | +### 7) Prefer a null/dummy sink for CI |
| 259 | + |
| 260 | +``` |
| 261 | +./run.sh --null-sink --format wav --clip /var/yesterday_48KHz.wav --duration 10s |
| 262 | +``` |
| 263 | + |
| 264 | +### 8) Choose a specific sink |
| 265 | + |
| 266 | +PipeWire example: |
| 267 | + |
| 268 | +``` |
| 269 | +./run.sh --backend pipewire --sink speaker --format wav --clip /var/yesterday_48KHz.wav --duration 10s |
| 270 | +``` |
| 271 | + |
| 272 | +PulseAudio example: |
| 273 | + |
| 274 | +``` |
| 275 | +./run.sh --backend pulseaudio --sink 0 --format wav --clip /var/yesterday_48KHz.wav --duration 10s |
| 276 | +``` |
| 277 | + |
| 278 | +### 9) Use device-provided local assets (tar.gz) |
| 279 | + |
| 280 | +``` |
| 281 | +./run.sh --assets /opt/audio_clips.tar.gz --format wav --clipdur short --duration 10s |
| 282 | +``` |
| 283 | + |
| 284 | +### 10) Use device-provided untar directory |
| 285 | + |
| 286 | +``` |
| 287 | +./run.sh --clips-dir /opt/AudioClips --format wav --clipdur short --duration 10s |
| 288 | +``` |
| 289 | + |
| 290 | +### 11) Increase GStreamer debug verbosity |
| 291 | + |
| 292 | +``` |
| 293 | +./run.sh --gst-debug 5 --format wav --clip /var/yesterday_48KHz.wav --duration 10s |
| 294 | +``` |
| 295 | + |
| 296 | +--- |
| 297 | + |
| 298 | +## Troubleshooting |
| 299 | + |
| 300 | +### A) “SKIP: Missing gstreamer runtime” |
| 301 | +- Ensure `gst-launch-1.0` and `gst-inspect-1.0` are installed in the image. |
| 302 | + |
| 303 | +### B) PipeWire/PulseAudio backend not used |
| 304 | +- Ensure the daemon is running: |
| 305 | + - PipeWire: `pgrep -x pipewire` |
| 306 | + - PulseAudio: `pgrep -x pulseaudio` or `pgrep -x pipewire-pulse` |
| 307 | +- Ensure control tools exist: |
| 308 | + - PipeWire: `wpctl` |
| 309 | + - PulseAudio: `pactl` |
| 310 | +- Ensure plugin exists: |
| 311 | + - PipeWire: `pipewiresink` |
| 312 | + - PulseAudio: `pulsesink` |
| 313 | + |
| 314 | +### C) ALSA backend fails |
| 315 | +- Confirm `alsasink` plugin exists: |
| 316 | + - `gst-inspect-1.0 alsasink` |
| 317 | +- Confirm device is correct (default `hw:0,0` in the test): |
| 318 | + - You can update the default in the test or extend args later if needed. |
| 319 | + |
| 320 | +### D) “FAIL: evidence=0” |
| 321 | +- If audio is routed through a sound server, ensure the sound server interfaces are accessible. |
| 322 | +- Check `logs/Audio_Playback/gst.log`, `mixers.txt`, and `dmesg/` outputs. |
| 323 | +- Try forcing `--gst-debug 5` for more detail. |
| 324 | + |
| 325 | +--- |
| 326 | + |
| 327 | +## Notes for CI / LAVA |
| 328 | + |
| 329 | +- The test always exits `0`. |
| 330 | +- Use the `.res` file for result: |
| 331 | + - `PASS` |
| 332 | + - `FAIL` |
| 333 | + - `SKIP` |
| 334 | + |
| 335 | +--- |
| 336 | + |
| 337 | +## Maintainers |
| 338 | + |
| 339 | +- This test is intended to be robust and easy to extend alongside: |
| 340 | + - `Audio_Record` |
| 341 | + - `Audio_Duplex_Loopback` |
| 342 | + - `Audio_Concurrency` |
| 343 | + |
| 344 | +Follow the same conventions: |
| 345 | +- Keep **usage in run.sh** |
| 346 | +- Use shared helpers in `Runner/utils/lib_gstreamer.sh` and `audio_common.sh` |
| 347 | +- Use `log_*` helpers from `functestlib.sh` |
| 348 | +- Always emit `.res` and exit `0` |
0 commit comments