From 21606a207d87be0897e8ea858ee901400b3caf41 Mon Sep 17 00:00:00 2001 From: Teja Swaroop Moida Date: Wed, 3 Jun 2026 16:18:43 +0530 Subject: [PATCH] Add Audio_Hamoa: ALSA-based audio playback and recording tests for Hamoa platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #454 This PR introduces comprehensive audio testing for Qualcomm Hamoa platforms using ALSA-based mixer configurations. The implementation provides automated validation of audio playback and recording capabilities across multiple devices. Tests audio playback on two output devices: - Handset (plughw:0,1): 4-way speaker system using WSA2/WSA amplifiers * Audio path: AIF1_PB → WSA2/WSA RX0/RX1 → WooferLeft/Right + TweeterLeft/Right * 44 mixer controls configured * Dual WSA codec support with compressor and boost - Headset (plughw:0,0): Stereo headphones using RX codec * Audio path: AIF1_PB → RX_MACRO RX0/RX1 → RX INT0/INT1 → HPHL/HPHR * 22 mixer controls configured * Class-H High Fidelity mode for optimal audio quality Tests audio recording on two input devices: - Handset (plughw:0,3): Built-in VA_DMIC (Voice Activation DMIC) * Audio path: DMIC0/DMIC1 → VA DMIC MUX0/MUX1 → VA DEC0/DEC1 → VA_AIF1_CAP * 8 mixer controls configured * Dual DMIC support with volume control - Headset (plughw:0,2): SoundWire microphone (SWR_MIC) * Audio path: SWR_MIC → ADC2 → TX SMIC MUX0 (SWR_MIC0) → TX DEC0 → TX_AIF1_CAP * 10 mixer controls configured - **Dual device support**: Test handset, headset, or both devices - **Mixer validation**: Verifies all mixer settings before audio operations - **Clip/config-based testing**: Auto-discovery of audio clips and configurations - **Skip mode**: Test mixer configuration without actual audio playback/recording - **CI/LAVA integration**: * Unique result file suffixes prevent file collisions in parallel runs * Unique testcase IDs prevent LAVA testcase ID collisions * Enables running multiple configurations simultaneously - **Comprehensive logging**: Mixer dumps, playback/recording logs per test case - **Recording validation**: File size and format verification Comprehensive README files included for both test suites: - Complete usage examples (basic, mixer-only, verbose, CI/LAVA) - Command line options and environment variables tables - Audio clip/config configuration tables - Test execution flow diagrams - Sample output examples - Known limitations and workarounds - CI/LAVA integration guidelines Signed-off-by: Teja Swaroop Moida --- .../AudioPlayback_Hamoa_Handset.yaml | 24 ++ .../AudioPlayback_Hamoa_Headset.yaml | 24 ++ .../Audio/Audio_Hamoa/AudioPlayback/README.md | 271 ++++++++++++ .../Audio/Audio_Hamoa/AudioPlayback/run.sh | 368 ++++++++++++++++ .../AudioRecord_Hamoa_Handset.yaml | 24 ++ .../AudioRecord_Hamoa_Headset.yaml | 24 ++ .../Audio/Audio_Hamoa/AudioRecord/README.md | 300 +++++++++++++ .../Audio/Audio_Hamoa/AudioRecord/run.sh | 403 ++++++++++++++++++ Runner/utils/audio/alsa_common.sh | 347 +++++++++++++++ 9 files changed, 1785 insertions(+) create mode 100644 Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/AudioPlayback_Hamoa_Handset.yaml create mode 100644 Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/AudioPlayback_Hamoa_Headset.yaml create mode 100644 Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/README.md create mode 100755 Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/run.sh create mode 100644 Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/AudioRecord_Hamoa_Handset.yaml create mode 100644 Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/AudioRecord_Hamoa_Headset.yaml create mode 100644 Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/README.md create mode 100755 Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/run.sh create mode 100755 Runner/utils/audio/alsa_common.sh diff --git a/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/AudioPlayback_Hamoa_Handset.yaml b/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/AudioPlayback_Hamoa_Handset.yaml new file mode 100644 index 00000000..264a371a --- /dev/null +++ b/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/AudioPlayback_Hamoa_Handset.yaml @@ -0,0 +1,24 @@ +metadata: + name: audio-playback-hamoa-handset + format: "Lava-Test Test Definition 1.0" + description: "Audio Hamoa handset playback validation (4-way speaker system)" + os: + - linux + scope: + - functional + +params: + DEVICE: "handset" # Device to test: handset, headset, or all, default: handset + CLIP_NAMES: "playback_config1" # Clip configuration name for auto-discovery, default: playback_config1 + AUDIO_CLIPS_BASE_DIR: "/home/AudioClips" # Path to audio clips directory, default: /home/AudioClips + SKIP_ACTUAL_PLAYBACK: 0 # Skip actual audio playback, only test mixer configuration (0=play audio, 1=skip), default: 0 + VERBOSE: 0 # Enable verbose logging, default: 0 + RES_SUFFIX: "Handset" # Suffix for unique result file, default: Handset + LAVA_TESTCASE_ID: "AudioPlayback_Hamoa_Handset" # Unique testcase ID for LAVA, default: AudioPlayback_Hamoa_Handset + +run: + steps: + - REPO_PATH=$PWD + - cd Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/ + - ./run.sh --device "${DEVICE}" --clip-name "${CLIP_NAMES}" --audio-clips-path "${AUDIO_CLIPS_BASE_DIR}" --skip-actual-playback "${SKIP_ACTUAL_PLAYBACK}" --verbose "${VERBOSE}" --res-suffix "${RES_SUFFIX}" --lava-testcase-id "${LAVA_TESTCASE_ID}" || true + - $REPO_PATH/Runner/utils/send-to-lava.sh AudioPlayback_Hamoa${RES_SUFFIX:+_${RES_SUFFIX}}.res diff --git a/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/AudioPlayback_Hamoa_Headset.yaml b/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/AudioPlayback_Hamoa_Headset.yaml new file mode 100644 index 00000000..d065c0e9 --- /dev/null +++ b/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/AudioPlayback_Hamoa_Headset.yaml @@ -0,0 +1,24 @@ +metadata: + name: audio-playback-hamoa-headset + format: "Lava-Test Test Definition 1.0" + description: "Audio Hamoa headset playback validation (stereo headphones)" + os: + - linux + scope: + - functional + +params: + DEVICE: "headset" # Device to test: handset, headset, or all, default: headset + CLIP_NAMES: "playback_config1" # Clip configuration name for auto-discovery, default: playback_config1 + AUDIO_CLIPS_BASE_DIR: "/home/AudioClips" # Path to audio clips directory, default: /home/AudioClips + SKIP_ACTUAL_PLAYBACK: 0 # Skip actual audio playback, only test mixer configuration (0=play audio, 1=skip), default: 0 + VERBOSE: 0 # Enable verbose logging, default: 0 + RES_SUFFIX: "Headset" # Suffix for unique result file, default: Headset + LAVA_TESTCASE_ID: "AudioPlayback_Hamoa_Headset" # Unique testcase ID for LAVA, default: AudioPlayback_Hamoa_Headset + +run: + steps: + - REPO_PATH=$PWD + - cd Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/ + - ./run.sh --device "${DEVICE}" --clip-name "${CLIP_NAMES}" --audio-clips-path "${AUDIO_CLIPS_BASE_DIR}" --skip-actual-playback "${SKIP_ACTUAL_PLAYBACK}" --verbose "${VERBOSE}" --res-suffix "${RES_SUFFIX}" --lava-testcase-id "${LAVA_TESTCASE_ID}" || true + - $REPO_PATH/Runner/utils/send-to-lava.sh AudioPlayback_Hamoa${RES_SUFFIX:+_${RES_SUFFIX}}.res diff --git a/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/README.md b/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/README.md new file mode 100644 index 00000000..1ae74c2e --- /dev/null +++ b/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/README.md @@ -0,0 +1,271 @@ +# Audio Hamoa Playback Validation Script + +## Overview + +This suite automates the validation of audio playback capabilities on Qualcomm Hamoa platforms using ALSA-based mixer configurations. It provides comprehensive testing for handset (speakers) and headset (headphones) audio output devices with robust mixer configuration validation and diagnostic logging. + +## Features + +- **ALSA-based audio playback** using direct mixer control +- **Dual device support**: Handset (4-way speakers) and Headset (stereo headphones) +- **Clip-based testing**: Uses pre-configured audio clips for validation +- **Mixer configuration validation**: Verifies all mixer settings before playback +- **CI/LAVA integration**: + - Unique result file suffixes prevent file collisions in parallel test runs + - Unique testcase IDs prevent LAVA testcase ID collisions + - Enables running multiple AudioPlayback_Hamoa configurations simultaneously in CI +- **Flexible device selection**: Test handset, headset, or both devices +- **Skip playback mode**: Test mixer configuration without actual audio playback +- Diagnostic logs: mixer dumps, playback logs per test case +- Generates `.res` result file for CI/LAVA integration + +## Test Coverage + +The test validates playback on two audio output devices: + +### 1. Handset Playback (Speakers) - `plughw:0,1` +- **4-way speaker system** using WSA2 and WSA amplifiers +- **Audio path**: AIF1_PB → WSA2/WSA RX0/RX1 → WooferLeft/Right + TweeterLeft/Right +- **Mixer commands**: 44 controls configured +- **Features**: + - Dual WSA codec support (WSA + WSA2) + - Compressor and boost enabled + - Maximum volume levels + - Speaker protection (PBR) enabled + +### 2. Headset Playback (Headphones) - `plughw:0,0` +- **Stereo headphone output** using RX codec +- **Class-H High Fidelity mode** for optimal audio quality +- **Audio path**: AIF1_PB → RX_MACRO RX0/RX1 → RX INT0/INT1 → HPHL/HPHR +- **Mixer commands**: 22 controls configured +- **Features**: + - Class-H amplifier mode + - Compressor enabled + - Optimized volume levels + - Low-distortion output + +## Audio Clip Configurations + +The test uses pre-configured audio clips for validation: + +``` +| Config Name | Sample Rate | Bit Depth | Channels | Duration | +|-------------------|-------------|-----------|----------|----------| +| playback_config1 | 8 KHz | 8-bit | 1ch | 30s | +| playback_config2 | 16 KHz | 8-bit | 6ch | 30s | +| playback_config3 | 16 KHz | 16-bit | 2ch | 30s | +| playback_config4 | 22.05 KHz | 8-bit | 1ch | 30s | +| playback_config5 | 24 KHz | 24-bit | 6ch | 30s | +| playback_config6 | 24 KHz | 32-bit | 1ch | 30s | +| playback_config7 | 32 KHz | 8-bit | 8ch | 30s | +| playback_config8 | 32 KHz | 16-bit | 2ch | 30s | +| playback_config9 | 44.1 KHz | 16-bit | 1ch | 30s | +| playback_config10 | 48 KHz | 8-bit | 2ch | 30s | +``` + +## Prerequisites + +Ensure the following components are present on the target platform: + +- ALSA utilities: `aplay`, `amixer` +- Audio clips directory: `/home/AudioClips/` (or custom path) +- Hamoa audio drivers and codecs loaded +- Required mixer controls available + +## Directory Structure + +```bash +Runner/ +├── run-test.sh +├── utils/ +│ ├── functestlib.sh +│ └── audio/ +│ └── alsa_common.sh +└── suites/ + └── Multimedia/ + └── Audio/ + └── Audio_Hamoa/ + └── AudioPlayback/ + ├── run.sh + ├── README.md + ├── AudioPlayback_Hamoa_Handset.yaml + └── AudioPlayback_Hamoa_Headset.yaml +``` + +## Usage + +Instructions: +1. Copy repo to Target Device: Use scp to transfer the scripts from the host to the target device +2. Verify Transfer: Ensure that the repo has been successfully copied to the target device +3. Run Scripts: Navigate to the directory and execute the scripts as needed + +### Basic Usage + +```bash +cd Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback + +# Test both handset and headset (default) +./run.sh --device all --clip-name playback_config1 --audio-clips-path /home/AudioClips + +# Test handset only +./run.sh --device handset --clip-name playback_config1 --audio-clips-path /home/AudioClips + +# Test headset only +./run.sh --device headset --clip-name playback_config1 --audio-clips-path /home/AudioClips +``` + +### Mixer Configuration Only (No Playback) + +```bash +# Test mixer configuration without actual playback +./run.sh --device handset --skip-actual-playback +``` + +### With Verbose Logging + +```bash +./run.sh --device all --clip-name playback_config1 --audio-clips-path /home/AudioClips --verbose +``` + +### CI/LAVA Workflow with Unique Result Files + +```bash +# Using --res-suffix prevents file collisions in parallel CI runs +./run.sh --device handset --clip-name playback_config1 --audio-clips-path /home/AudioClips --res-suffix "Handset" --lava-testcase-id "AudioPlayback_Hamoa_Handset" + +# Result file: AudioPlayback_Hamoa_Handset.res +# Log directory: results/AudioPlayback_Hamoa_Handset/ + +./run.sh --device headset --clip-name playback_config1 --audio-clips-path /home/AudioClips --res-suffix "Headset" --lava-testcase-id "AudioPlayback_Hamoa_Headset" + +# Result file: AudioPlayback_Hamoa_Headset.res +# Log directory: results/AudioPlayback_Hamoa_Headset/ +``` + +## Command Line Options + +| Option | Description | Default | +|--------|-------------|---------| +| `--device ` | Device to test: handset, headset, or all | all | +| `--clip-name ` | Clip configuration name (playback_config1-10) | playback_config1 | +| `--audio-clips-path ` | Path to audio clips directory | /home/AudioClips | +| `--skip-actual-playback` | Skip actual playback, only test mixer configuration | Disabled | +| `--verbose` | Enable verbose logging | Disabled | +| `--res-suffix ` | Suffix for unique result file (e.g., "Handset") | Empty | +| `--lava-testcase-id ` | Unique testcase ID for LAVA (e.g., "AudioPlayback_Hamoa_Handset") | AudioPlayback_Hamoa | +| `--help`, `-h` | Show help message | - | + +## Environment Variables + +| Variable | Description | Default | +|----------|-------------|---------| +| DEVICE | Device to test: handset, headset, or all | all | +| CLIP_NAMES | Clip configuration name | playback_config1 | +| AUDIO_CLIPS_BASE_DIR | Path to audio clips directory | /home/AudioClips | +| SKIP_ACTUAL_PLAYBACK | Skip actual playback (0=play, 1=skip) | 0 | +| VERBOSE | Enable verbose logging (0=disabled, 1=enabled) | 0 | +| RES_SUFFIX | Suffix for unique result file | Empty | +| LAVA_TESTCASE_ID | Unique testcase ID for LAVA | AudioPlayback_Hamoa | + +## Test Execution Flow + +### Handset Playback Test +1. Configure handset playback mixer (44 commands) +2. Validate mixer state +3. Play audio clip on plughw:0,1 (if not skipped) +4. Report results + +### Headset Playback Test +1. Configure headset playback mixer (22 commands) +2. Validate mixer state +3. Play audio clip on plughw:0,0 (if not skipped) +4. Report results + +## Sample Output + +**Example 1: Testing handset playback** +``` +[INFO] 2026-04-20 21:35:23 - Using unique result file: /tmp/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/AudioPlayback_Hamoa_Handset.res +[INFO] 2026-04-20 21:35:23 - ------------------- Starting AudioPlayback_Hamoa Testcase -------------------------- +[INFO] 2026-04-20 21:35:23 - Platform: machine='Qualcomm Technologies, Inc. Hamoa IoT EVK' target='unknown' +[INFO] 2026-04-20 21:35:23 - Configuration: +[INFO] 2026-04-20 21:35:23 - Device: handset +[INFO] 2026-04-20 21:35:23 - Clip Names: playback_config1 +[INFO] 2026-04-20 21:35:23 - Audio Clips Path: /home/AudioClips +[INFO] 2026-04-20 21:35:23 - Discovered Clips: 1 +[INFO] 2026-04-20 21:35:23 - ========================================== +[INFO] 2026-04-20 21:35:23 - TEST 1: Handset Playback (Speakers) +[INFO] 2026-04-20 21:35:23 - ========================================== +[INFO] 2026-04-20 21:35:23 - Configuring mixer for handset playback (speakers)... +[INFO] 2026-04-20 21:35:23 - Handset playback mixer configured successfully +[INFO] 2026-04-20 21:35:23 - Validating mixer state for: handset_playback +[INFO] 2026-04-20 21:35:23 - Mixer state validation passed +[INFO] 2026-04-20 21:35:23 - Playing clip: yesterday_16KHz_30s_16b_2ch.wav on device: plughw:0,1 +Playing WAVE '/home/AudioClips/yesterday_16KHz_30s_16b_2ch.wav' : Signed 16 bit Little Endian, Rate 16000 Hz, Stereo +[PASS] 2026-04-20 21:35:53 - Handset playback test PASSED +[PASS] 2026-04-20 21:35:53 - AudioPlayback_Hamoa_Handset : PASS +``` + +**Example 2: Testing both devices** +``` +[INFO] 2026-04-20 18:47:27 - Device: all +[INFO] 2026-04-20 18:47:27 - TEST 1: Handset Playback (Speakers) +[PASS] 2026-04-20 18:47:57 - Handset playback test PASSED +[INFO] 2026-04-20 18:47:57 - TEST 2: Headset Playback (Headphones) +[PASS] 2026-04-20 18:48:27 - Headset playback test PASSED +[PASS] 2026-04-20 18:48:27 - AudioPlayback_Hamoa : PASS +``` + +**Example 3: Mixer-only test (no playback)** +``` +[INFO] 2026-04-20 18:48:59 - Skip Actual Playback: 1 +[INFO] 2026-04-20 18:48:59 - Configuring mixer for handset playback (speakers)... +[INFO] 2026-04-20 18:48:59 - Handset playback mixer configured successfully +[INFO] 2026-04-20 18:48:59 - Validating mixer state for: handset_playback +[INFO] 2026-04-20 18:48:59 - Mixer state validation passed +[INFO] 2026-04-20 18:48:59 - Skipping actual playback (mixer configuration verified) +[PASS] 2026-04-20 18:48:59 - Handset playback test PASSED +``` + +## Expected Results + +- **PASS**: All selected device tests succeed (mixer configuration and playback) +- **FAIL**: One or more device tests fail + +## Results + +- Results are stored in: `results/AudioPlayback_Hamoa/` (or `results/AudioPlayback_Hamoa_/` when using --res-suffix) +- Summary result file: `AudioPlayback_Hamoa.res` (or `AudioPlayback_Hamoa_.res` when using --res-suffix) +- Diagnostic logs: mixer dumps per test case +- **Note**: When using --res-suffix, both result files AND log directories are unique per invocation, preventing log collisions in CI/LAVA workflows + +## Dependencies + +- ALSA utilities (`aplay`, `amixer`) +- `Runner/utils/audio/alsa_common.sh` library +- `functestlib.sh` framework library +- Audio clips in `/home/AudioClips/` or custom path + +## Notes + +- Mixer configurations are based on verified Hamoa commands for the platform +- If no audio clips are found, the test will fail with an error message +- Mixer validation ensures all controls are set correctly before playback +- The test supports parallel execution with unique result files using --res-suffix +- Use --lava-testcase-id to prevent testcase ID collisions in LAVA +- Logs include complete mixer state dumps for debugging + +## Known Limitations + +- 8kHz mono recordings cannot be played back directly with `aplay` on this platform +- Use `sox` to convert for playback: `sox input.wav -r 48000 output.wav` +- Or play on a different device that supports 8kHz mono + +## Related Tests + +- **AudioRecord_Hamoa**: Tests audio capture functionality + +## License + +SPDX-License-Identifier: BSD-3-Clause +Copyright (C) Qualcomm Technologies, Inc. and/or its subsidiaries. \ No newline at end of file diff --git a/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/run.sh b/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/run.sh new file mode 100755 index 00000000..a76279de --- /dev/null +++ b/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioPlayback/run.sh @@ -0,0 +1,368 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause +# +# Audio Hamoa Playback Test +# Tests audio playback on handset speakers and headset (headphones) +# using ALSA mixer configurations verified on X1E80100-EVK platform. +# +# Devices tested: +# - Handset: plughw:0,1 (4-way speaker system) +# - Headset: plughw:0,0 (stereo headphones) + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +INIT_ENV="" +SEARCH="$SCRIPT_DIR" + +while [ "$SEARCH" != "/" ]; do + if [ -f "$SEARCH/init_env" ]; then + INIT_ENV="$SEARCH/init_env" + break + fi + SEARCH=$(dirname "$SEARCH") +done + +if [ -z "$INIT_ENV" ]; then + echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2 + exit 1 +fi + +if [ -z "${__INIT_ENV_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" + __INIT_ENV_LOADED=1 +fi + +# shellcheck disable=SC1091 +. "$TOOLS/functestlib.sh" +# shellcheck disable=SC1091 +. "$TOOLS/audio_common.sh" +# shellcheck disable=SC1091 +. "$TOOLS/audio/alsa_common.sh" + +TESTNAME="AudioPlayback_Hamoa" +RESULT_TESTNAME="$TESTNAME" +RES_SUFFIX="" + +# Pre-parse --res-suffix and --lava-testcase-id for early failure handling +prev_arg="" +for arg in "$@"; do + case "$prev_arg" in + --res-suffix) + RES_SUFFIX="$arg" + ;; + --lava-testcase-id) + RESULT_TESTNAME="$arg" + ;; + esac + prev_arg="$arg" +done + +AUDIO_FILE="${AUDIO_FILE:-}" +SKIP_ACTUAL_PLAYBACK="${SKIP_ACTUAL_PLAYBACK:-0}" +DEVICE="${DEVICE:-all}" +VERBOSE="${VERBOSE:-0}" +CLIP_NAMES="${CLIP_NAMES:-}" +AUDIO_CLIPS_BASE_DIR="${AUDIO_CLIPS_BASE_DIR:-AudioClips}" + +usage() { + cat <&2 + exit 1 + fi + AUDIO_FILE="$2" + shift 2 + ;; + --skip-actual-playback) + SKIP_ACTUAL_PLAYBACK=1 + shift + ;; + --device) + if [ $# -lt 2 ]; then + echo "[ERROR] --device requires an argument" >&2 + exit 1 + fi + DEVICE="$2" + if [ "$DEVICE" != "handset" ] && [ "$DEVICE" != "headset" ] && [ "$DEVICE" != "all" ]; then + echo "[ERROR] --device must be 'handset', 'headset', or 'all'" >&2 + exit 1 + fi + shift 2 + ;; + --res-suffix) + # Already parsed above + shift 2 + ;; + --lava-testcase-id) + # Already parsed above + shift 2 + ;; + --clip-name) + if [ $# -lt 2 ]; then + echo "[ERROR] --clip-name requires an argument" >&2 + exit 1 + fi + CLIP_NAMES="$2" + shift 2 + ;; + --audio-clips-path) + if [ $# -lt 2 ]; then + echo "[ERROR] --audio-clips-path requires an argument" >&2 + exit 1 + fi + AUDIO_CLIPS_BASE_DIR="$2" + shift 2 + ;; + --verbose) + VERBOSE=1 + export VERBOSE + shift + ;; + --help|-h) + usage + exit 0 + ;; + *) + echo "[WARN] Unknown option: $1" >&2 + shift + ;; + esac +done + +test_path="$(find_test_case_by_name "$TESTNAME" 2>/dev/null || echo "$SCRIPT_DIR")" +if ! cd "$test_path"; then + log_fail "cd failed: $test_path" + exit 1 +fi + +# Setup result file and log directory (with optional suffix) +if [ -n "$RES_SUFFIX" ]; then + RES_FILE="$SCRIPT_DIR/${TESTNAME}_${RES_SUFFIX}.res" + LOGDIR="$SCRIPT_DIR/results/${TESTNAME}_${RES_SUFFIX}" + log_info "Using unique result file: $RES_FILE" +else + RES_FILE="$SCRIPT_DIR/$TESTNAME.res" + LOGDIR="$SCRIPT_DIR/results/$TESTNAME" +fi + +mkdir -p "$LOGDIR" 2>/dev/null || true +: > "$RES_FILE" + +log_info "--------------------------------------------------------------------------" +log_info "------------------- Starting $TESTNAME Testcase --------------------------" +log_info "--------------------------------------------------------------------------" + +if command -v detect_platform >/dev/null 2>&1; then + detect_platform >/dev/null 2>&1 || true + log_info "Platform: machine='${PLATFORM_MACHINE:-unknown}' target='${PLATFORM_TARGET:-unknown}'" +fi + +log_info "Configuration:" +log_info " Audio File: ${AUDIO_FILE:-}" +log_info " Skip Actual Playback: $SKIP_ACTUAL_PLAYBACK" +log_info " Device: $DEVICE" + +# Discover clips if CLIP_NAMES provided +CLIPS_TO_TEST="" +if [ -n "$CLIP_NAMES" ]; then + log_info " Clip Names: $CLIP_NAMES" + log_info " Audio Clips Path: $AUDIO_CLIPS_BASE_DIR" + + # Export for clip discovery functions + export AUDIO_CLIPS_BASE_DIR + + # Discover and filter clips + CLIPS_TO_TEST="$(discover_and_filter_clips "$CLIP_NAMES" "")" || { + log_error "Failed to discover clips for: $CLIP_NAMES" + log_fail "$RESULT_TESTNAME FAIL - Clip discovery failed" + echo "$RESULT_TESTNAME FAIL" > "$RES_FILE" + exit 1 + } + + # Count clips + clip_count=0 + for clip_file in $CLIPS_TO_TEST; do + clip_count=$((clip_count + 1)) + done + log_info " Discovered Clips: $clip_count" +elif [ -n "$AUDIO_FILE" ]; then + # Single file mode + CLIPS_TO_TEST="$AUDIO_FILE" +fi + +test_handset_playback() { + log_info "==========================================" + log_info "TEST 1: Handset Playback (Speakers)" + log_info "==========================================" + + if ! setup_handset_playback_mixer; then + log_fail "Failed to configure handset playback mixer" + return 1 + fi + + if ! validate_mixer_state "handset_playback"; then + log_fail "Handset playback mixer validation failed" + return 1 + fi + + if [ "$SKIP_ACTUAL_PLAYBACK" -eq 0 ] && [ -n "$CLIPS_TO_TEST" ]; then + device=$(get_alsa_device "handset_playback") + + # Test each clip + for clip_file in $CLIPS_TO_TEST; do + # Resolve full path + clip_path="$AUDIO_CLIPS_BASE_DIR/$clip_file" + + if [ ! -f "$clip_path" ]; then + log_warn "Audio file not found: $clip_path" + continue + fi + + log_info "Playing clip: $clip_file on device: $device" + + if ! aplay -D "$device" "$clip_path"; then + log_fail "Handset playback failed for: $clip_file" + return 1 + fi + done + else + log_info "Skipping actual playback (mixer configuration verified)" + fi + + log_pass "Handset playback test PASSED" + return 0 +} + +test_headset_playback() { + log_info "==========================================" + log_info "TEST 2: Headset Playback (Headphones)" + log_info "==========================================" + + if ! setup_headset_playback_mixer; then + log_fail "Failed to configure headset playback mixer" + return 1 + fi + + if ! validate_mixer_state "headset_playback"; then + log_fail "Headset playback mixer validation failed" + return 1 + fi + + if [ "$SKIP_ACTUAL_PLAYBACK" -eq 0 ] && [ -n "$CLIPS_TO_TEST" ]; then + device=$(get_alsa_device "headset_playback") + + # Test each clip + for clip_file in $CLIPS_TO_TEST; do + # Resolve full path + clip_path="$AUDIO_CLIPS_BASE_DIR/$clip_file" + + if [ ! -f "$clip_path" ]; then + log_warn "Audio file not found: $clip_path" + continue + fi + + log_info "Playing clip: $clip_file on device: $device" + + if ! aplay -D "$device" "$clip_path"; then + log_fail "Headset playback failed for: $clip_file" + return 1 + fi + done + else + log_info "Skipping actual playback (mixer configuration verified)" + fi + + log_pass "Headset playback test PASSED" + return 0 +} + +test_failed=0 + +# Run tests based on device selection +if [ "$DEVICE" = "handset" ] || [ "$DEVICE" = "all" ]; then + if ! test_handset_playback; then + log_fail "Handset playback test FAILED" + test_failed=1 + fi + echo "" +fi + +if [ "$DEVICE" = "headset" ] || [ "$DEVICE" = "all" ]; then + if ! test_headset_playback; then + log_fail "Headset playback test FAILED" + test_failed=1 + fi + echo "" +fi + +log_info "==========================================" + +if [ "$test_failed" -eq 0 ]; then + log_pass "$RESULT_TESTNAME : PASS" + echo "$RESULT_TESTNAME PASS" > "$RES_FILE" +else + log_fail "$RESULT_TESTNAME : FAIL" + echo "$RESULT_TESTNAME FAIL" > "$RES_FILE" +fi + +log_info "------------------- Completed $RESULT_TESTNAME Testcase --------------------------" +exit 0 \ No newline at end of file diff --git a/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/AudioRecord_Hamoa_Handset.yaml b/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/AudioRecord_Hamoa_Handset.yaml new file mode 100644 index 00000000..4a45a6be --- /dev/null +++ b/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/AudioRecord_Hamoa_Handset.yaml @@ -0,0 +1,24 @@ +metadata: + name: audio-record-hamoa-handset + format: "Lava-Test Test Definition 1.0" + description: "Audio Hamoa handset recording validation (built-in microphone)" + os: + - linux + scope: + - functional + +params: + DEVICE: "handset" # Device to test: handset, headset, or all, default: handset + CONFIG_NAME: "record_config1" # Record configuration name (e.g., record_config1), default: record_config1 + DURATION: 5 # Recording duration in seconds, default: 5 + SKIP_ACTUAL_RECORDING: 0 # Skip actual audio recording, only test mixer configuration (0=record audio, 1=skip), default: 0 + VERBOSE: 0 # Enable verbose logging, default: 0 + RES_SUFFIX: "Handset" # Suffix for unique result file, default: Handset + LAVA_TESTCASE_ID: "AudioRecord_Hamoa_Handset" # Unique testcase ID for LAVA, default: AudioRecord_Hamoa_Handset + +run: + steps: + - REPO_PATH=$PWD + - cd Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/ + - ./run.sh --device "${DEVICE}" --config-name "${CONFIG_NAME}" --duration "${DURATION}" --skip-actual-recording "${SKIP_ACTUAL_RECORDING}" --verbose "${VERBOSE}" --res-suffix "${RES_SUFFIX}" --lava-testcase-id "${LAVA_TESTCASE_ID}" || true + - $REPO_PATH/Runner/utils/send-to-lava.sh AudioRecord_Hamoa${RES_SUFFIX:+_${RES_SUFFIX}}.res diff --git a/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/AudioRecord_Hamoa_Headset.yaml b/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/AudioRecord_Hamoa_Headset.yaml new file mode 100644 index 00000000..fbdae478 --- /dev/null +++ b/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/AudioRecord_Hamoa_Headset.yaml @@ -0,0 +1,24 @@ +metadata: + name: audio-record-hamoa-headset + format: "Lava-Test Test Definition 1.0" + description: "Audio Hamoa headset recording validation (headset microphone)" + os: + - linux + scope: + - functional + +params: + DEVICE: "headset" # Device to test: handset, headset, or all, default: headset + CONFIG_NAME: "record_config1" # Record configuration name (e.g., record_config1), default: record_config1 + DURATION: 5 # Recording duration in seconds, default: 5 + SKIP_ACTUAL_RECORDING: 0 # Skip actual audio recording, only test mixer configuration (0=record audio, 1=skip), default: 0 + VERBOSE: 0 # Enable verbose logging, default: 0 + RES_SUFFIX: "Headset" # Suffix for unique result file, default: Headset + LAVA_TESTCASE_ID: "AudioRecord_Hamoa_Headset" # Unique testcase ID for LAVA, default: AudioRecord_Hamoa_Headset + +run: + steps: + - REPO_PATH=$PWD + - cd Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/ + - ./run.sh --device "${DEVICE}" --config-name "${CONFIG_NAME}" --duration "${DURATION}" --skip-actual-recording "${SKIP_ACTUAL_RECORDING}" --verbose "${VERBOSE}" --res-suffix "${RES_SUFFIX}" --lava-testcase-id "${LAVA_TESTCASE_ID}" || true + - $REPO_PATH/Runner/utils/send-to-lava.sh AudioRecord_Hamoa${RES_SUFFIX:+_${RES_SUFFIX}}.res diff --git a/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/README.md b/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/README.md new file mode 100644 index 00000000..31e05a5a --- /dev/null +++ b/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/README.md @@ -0,0 +1,300 @@ +# Audio Hamoa Record Validation Script + +## Overview + +This suite automates the validation of audio recording (capture) capabilities on Qualcomm Hamoa platforms using ALSA-based mixer configurations. It provides comprehensive testing for handset (built-in microphone) and headset (headset microphone) audio input devices with robust mixer configuration validation and diagnostic logging. + +## Features + +- **ALSA-based audio recording** using direct mixer control +- **Dual device support**: Handset (built-in DMIC) and Headset (SoundWire mic) +- **Config-based testing**: Uses pre-configured audio parameters for validation +- **Mixer configuration validation**: Verifies all mixer settings before recording +- **CI/LAVA integration**: + - Unique result file suffixes prevent file collisions in parallel test runs + - Unique testcase IDs prevent LAVA testcase ID collisions + - Enables running multiple AudioRecord_Hamoa configurations simultaneously in CI +- **Flexible device selection**: Test handset, headset, or both devices +- **Skip recording mode**: Test mixer configuration without actual audio recording +- **Recording validation**: Verifies file size and format +- Diagnostic logs: mixer dumps, recording logs per test case +- Generates `.res` result file for CI/LAVA integration + +## Test Coverage + +The test validates recording on two audio input devices: + +### 1. Handset Capture (Built-in Microphone) - `plughw:0,3` +- **VA_DMIC** (Voice Activation DMIC - built-in digital microphone) +- **Audio path**: DMIC0/DMIC1 → VA DMIC MUX0/MUX1 → VA DEC0/DEC1 → VA_AIF1_CAP +- **Mixer commands**: 8 controls configured +- **Features**: + - Dual DMIC support (DMIC0 + DMIC1) + - Voice activation codec + - Optimized for built-in microphones + - Volume control per channel + +### 2. Headset Capture (Headset Microphone) - `plughw:0,2` +- **SWR_MIC** (SoundWire microphone - headset mic) +- **Audio path**: SWR_MIC → ADC2 → TX SMIC MUX0 (SWR_MIC0) → TX DEC0 → TX_AIF1_CAP +- **Mixer commands**: 10 controls configured +- **Features**: + - SoundWire interface + - ADC2 with volume control + - TX codec path + - Optimized for external microphones +- **Critical Fix**: TX SMIC MUX0 set to 'SWR_MIC0' (not 'ADC1') + +## Audio Record Configurations + +The test uses pre-configured audio parameters for validation: + +``` +| Config Name | Sample Rate | Channels | Format | +|------------------|-------------|----------|---------| +| record_config1 | 8 KHz | 1ch | S16_LE | +| record_config2 | 16 KHz | 1ch | S16_LE | +| record_config3 | 16 KHz | 2ch | S16_LE | +| record_config4 | 24 KHz | 1ch | S16_LE | +| record_config5 | 32 KHz | 2ch | S16_LE | +| record_config6 | 44.1 KHz | 2ch | S16_LE | +| record_config7 | 48 KHz | 2ch | S16_LE | +| record_config8 | 48 KHz | 6ch | S16_LE | +| record_config9 | 96 KHz | 2ch | S16_LE | +| record_config10 | 96 KHz | 6ch | S16_LE | +``` + +## Prerequisites + +Ensure the following components are present on the target platform: + +- ALSA utilities: `arecord`, `amixer` +- Hamoa audio drivers and codecs loaded +- Required mixer controls available +- Sufficient disk space for recordings + +## Directory Structure + +```bash +Runner/ +├── run-test.sh +├── utils/ +│ ├── functestlib.sh +│ └── audio/ +│ └── alsa_common.sh +└── suites/ + └── Multimedia/ + └── Audio/ + └── Audio_Hamoa/ + └── AudioRecord/ + ├── run.sh + ├── README.md + ├── AudioRecord_Hamoa_Handset.yaml + └── AudioRecord_Hamoa_Headset.yaml +``` + +## Usage + +Instructions: +1. Copy repo to Target Device: Use scp to transfer the scripts from the host to the target device +2. Verify Transfer: Ensure that the repo has been successfully copied to the target device +3. Run Scripts: Navigate to the directory and execute the scripts as needed + +### Basic Usage (5 second recording) + +```bash +cd Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord + +# Test both handset and headset (default) +./run.sh --device all --config-name record_config1 --duration 5 + +# Test handset only +./run.sh --device handset --config-name record_config1 --duration 5 + +# Test headset only +./run.sh --device headset --config-name record_config1 --duration 5 +``` + +### Custom Duration + +```bash +# Record for 10 seconds +./run.sh --device handset --config-name record_config1 --duration 10 +``` + +### Mixer Configuration Only (No Recording) + +```bash +# Test mixer configuration without actual recording +./run.sh --device handset --skip-actual-recording +``` + +### With Verbose Logging + +```bash +./run.sh --device all --config-name record_config1 --duration 5 --verbose +``` + +### CI/LAVA Workflow with Unique Result Files + +```bash +# Using --res-suffix prevents file collisions in parallel CI runs +./run.sh --device handset --config-name record_config1 --duration 5 --res-suffix "Handset" --lava-testcase-id "AudioRecord_Hamoa_Handset" + +# Result file: AudioRecord_Hamoa_Handset.res +# Log directory: results/AudioRecord_Hamoa_Handset/ + +./run.sh --device headset --config-name record_config1 --duration 5 --res-suffix "Headset" --lava-testcase-id "AudioRecord_Hamoa_Headset" + +# Result file: AudioRecord_Hamoa_Headset.res +# Log directory: results/AudioRecord_Hamoa_Headset/ +``` + +## Command Line Options + +| Option | Description | Default | +|--------|-------------|---------| +| `--device ` | Device to test: handset, headset, or all | all | +| `--config-name ` | Config name (record_config1-10) | record_config1 | +| `--duration ` | Recording duration in seconds | 5 | +| `--skip-actual-recording` | Skip actual recording, only test mixer configuration | Disabled | +| `--verbose` | Enable verbose logging | Disabled | +| `--res-suffix ` | Suffix for unique result file (e.g., "Handset") | Empty | +| `--lava-testcase-id ` | Unique testcase ID for LAVA (e.g., "AudioRecord_Hamoa_Handset") | AudioRecord_Hamoa | +| `--help`, `-h` | Show help message | - | + +## Environment Variables + +| Variable | Description | Default | +|----------|-------------|---------| +| DEVICE | Device to test: handset, headset, or all | all | +| CONFIG_NAME | Config name (record_config1-10) | record_config1 | +| DURATION | Recording duration in seconds | 5 | +| SKIP_ACTUAL_RECORDING | Skip actual recording (0=record, 1=skip) | 0 | +| VERBOSE | Enable verbose logging (0=disabled, 1=enabled) | 0 | +| RES_SUFFIX | Suffix for unique result file | Empty | +| LAVA_TESTCASE_ID | Unique testcase ID for LAVA | AudioRecord_Hamoa | + +## Test Execution Flow + +### Handset Capture Test +1. Configure handset capture mixer (8 commands) +2. Validate mixer state +3. Record audio on plughw:0,3 for specified duration (if not skipped) +4. Validate recording file size +5. Report results + +### Headset Capture Test +1. Configure headset capture mixer (10 commands) +2. Validate mixer state +3. Record audio on plughw:0,2 for specified duration (if not skipped) +4. Validate recording file size +5. Report results + +## Sample Output + +**Example 1: Testing handset recording** +``` +[INFO] 2026-04-20 21:42:47 - Using unique result file: /tmp/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/AudioRecord_Hamoa_Handset.res +[INFO] 2026-04-20 21:42:47 - ------------------- Starting AudioRecord_Hamoa Testcase -------------------------- +[INFO] 2026-04-20 21:42:47 - Platform: machine='Qualcomm Technologies, Inc. Hamoa IoT EVK' target='unknown' +[INFO] 2026-04-20 21:42:47 - Config Name: record_config1 +[INFO] 2026-04-20 21:42:47 - Config applied: Rate=8000 Hz, Channels=1 +[INFO] 2026-04-20 21:42:47 - Configuration: +[INFO] 2026-04-20 21:42:47 - Duration: 5s +[INFO] 2026-04-20 21:42:48 - Format: S16_LE +[INFO] 2026-04-20 21:42:48 - Rate: 8000 Hz +[INFO] 2026-04-20 21:42:48 - Channels: 1 +[INFO] 2026-04-20 21:42:48 - ========================================== +[INFO] 2026-04-20 21:42:48 - TEST 1: Handset Capture (Built-in Mic) +[INFO] 2026-04-20 21:42:48 - ========================================== +[INFO] 2026-04-20 21:42:48 - Configuring mixer for handset capture (built-in mic)... +[INFO] 2026-04-20 21:42:48 - Handset capture mixer configured successfully +[INFO] 2026-04-20 21:42:48 - Validating mixer state for: handset_capture +[INFO] 2026-04-20 21:42:48 - Mixer state validation passed +[INFO] 2026-04-20 21:42:48 - Recording from device: plughw:0,3 +[INFO] 2026-04-20 21:42:48 - Output file: /tmp/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/results/AudioRecord_Hamoa_Handset/handset_recording.wav +Recording WAVE '/tmp/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/results/AudioRecord_Hamoa_Handset/handset_recording.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Mono +[INFO] 2026-04-20 21:42:53 - Audio file validated: /tmp/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/results/AudioRecord_Hamoa_Handset/handset_recording.wav (80044 bytes) +[INFO] 2026-04-20 21:42:53 - Recording validated: /tmp/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/results/AudioRecord_Hamoa_Handset/handset_recording.wav (80044 bytes) +[PASS] 2026-04-20 21:42:53 - Handset capture test PASSED +[PASS] 2026-04-20 21:42:53 - AudioRecord_Hamoa_Handset : PASS +``` + +**Example 2: Testing both devices** +``` +[INFO] 2026-04-20 18:34:24 - Device: all +[INFO] 2026-04-20 18:34:24 - TEST 1: Handset Capture (Built-in Mic) +[PASS] 2026-04-20 18:34:29 - Handset capture test PASSED +[INFO] 2026-04-20 18:34:29 - TEST 2: Headset Capture (Headset Mic) +[PASS] 2026-04-20 18:34:34 - Headset capture test PASSED +[PASS] 2026-04-20 18:34:34 - AudioRecord_Hamoa : PASS +``` + +**Example 3: Mixer-only test (no recording)** +``` +[INFO] 2026-04-20 19:06:12 - Skip Actual Recording: 1 +[INFO] 2026-04-20 19:06:12 - Configuring mixer for handset capture (built-in mic)... +[INFO] 2026-04-20 19:06:12 - Handset capture mixer configured successfully +[INFO] 2026-04-20 19:06:12 - Validating mixer state for: handset_capture +[INFO] 2026-04-20 19:06:12 - Mixer state validation passed +[INFO] 2026-04-20 19:06:12 - Skipping actual recording (mixer configuration verified) +[PASS] 2026-04-20 19:06:12 - Handset capture test PASSED +``` + +## Expected Results + +- **PASS**: All selected device tests succeed (mixer configuration and recording) +- **FAIL**: One or more device tests fail + +## Output Files + +Recorded audio files are saved to: +- `results/AudioRecord_Hamoa/handset_recording.wav` (or `results/AudioRecord_Hamoa_/handset_recording.wav`) +- `results/AudioRecord_Hamoa/headset_recording.wav` (or `results/AudioRecord_Hamoa_/headset_recording.wav`) + +## Results + +- Results are stored in: `results/AudioRecord_Hamoa/` (or `results/AudioRecord_Hamoa_/` when using --res-suffix) +- Summary result file: `AudioRecord_Hamoa.res` (or `AudioRecord_Hamoa_.res` when using --res-suffix) +- Diagnostic logs: mixer dumps, recording files per test case +- **Note**: When using --res-suffix, both result files AND log directories are unique per invocation, preventing log collisions in CI/LAVA workflows + +## Dependencies + +- ALSA utilities (`arecord`, `amixer`) +- `Runner/utils/audio/alsa_common.sh` library +- `functestlib.sh` framework library + +## Notes + +- Mixer configurations are based on verified Hamoa commands for the platform +- Recording validation checks for minimum file size to ensure audio was captured +- Mixer validation ensures all controls are set correctly before recording +- The test supports parallel execution with unique result files using --res-suffix +- Use --lava-testcase-id to prevent testcase ID collisions in LAVA +- Logs include complete mixer state dumps for debugging +- Recording files can be played back on compatible devices + +## Important Fix + +The headset capture mixer includes a critical fix: +- **TX SMIC MUX0** must be set to **'SWR_MIC0'** (not 'ADC1') +- This ensures proper routing for SoundWire microphone input +- Without this fix, headset recording will not work correctly + +## Known Limitations + +- 8kHz mono recordings cannot be played back directly with `aplay` on this platform +- Use `sox` to convert for playback: `sox input.wav -r 48000 output.wav` +- Or play on a different device that supports 8kHz mono +- Recording validation is based on file size; actual audio quality should be verified manually + +## Related Tests + +- **AudioPlayback_Hamoa**: Tests audio playback functionality + +## License + +SPDX-License-Identifier: BSD-3-Clause +Copyright (C) Qualcomm Technologies, Inc. and/or its subsidiaries. \ No newline at end of file diff --git a/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/run.sh b/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/run.sh new file mode 100755 index 00000000..e2119679 --- /dev/null +++ b/Runner/suites/Multimedia/Audio/Audio_Hamoa/AudioRecord/run.sh @@ -0,0 +1,403 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause +# +# Audio Hamoa Record Test +# Tests audio recording on handset microphone and headset microphone +# using ALSA mixer configurations verified on X1E80100-EVK platform. +# +# Devices tested: +# - Handset: plughw:0,3 (built-in microphone MSM_DMIC) +# - Headset: plughw:0,2 (headset microphone SWR_MIC) + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +INIT_ENV="" +SEARCH="$SCRIPT_DIR" + +while [ "$SEARCH" != "/" ]; do + if [ -f "$SEARCH/init_env" ]; then + INIT_ENV="$SEARCH/init_env" + break + fi + SEARCH=$(dirname "$SEARCH") +done + +if [ -z "$INIT_ENV" ]; then + echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2 + exit 1 +fi + +if [ -z "${__INIT_ENV_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" + __INIT_ENV_LOADED=1 +fi + +# shellcheck disable=SC1091 +. "$TOOLS/functestlib.sh" +# shellcheck disable=SC1091 +. "$TOOLS/audio_common.sh" +# shellcheck disable=SC1091 +. "$TOOLS/audio/alsa_common.sh" + +TESTNAME="AudioRecord_Hamoa" +RESULT_TESTNAME="$TESTNAME" +RES_SUFFIX="" + +# Pre-parse --res-suffix and --lava-testcase-id for early failure handling +prev_arg="" +for arg in "$@"; do + case "$prev_arg" in + --res-suffix) + RES_SUFFIX="$arg" + ;; + --lava-testcase-id) + RESULT_TESTNAME="$arg" + ;; + esac + prev_arg="$arg" +done + +CONFIG_NAME="${CONFIG_NAME:-}" +RECORD_DURATION="${RECORD_DURATION:-5}" +RECORD_FORMAT="${RECORD_FORMAT:-S16_LE}" +RECORD_RATE="${RECORD_RATE:-48000}" +RECORD_CHANNELS="${RECORD_CHANNELS:-2}" +DEVICE="${DEVICE:-all}" +SKIP_ACTUAL_RECORDING="${SKIP_ACTUAL_RECORDING:-0}" +VERBOSE="${VERBOSE:-0}" + +usage() { + cat <&2 + exit 1 + fi + RECORD_DURATION="$2" + shift 2 + ;; + --format) + if [ $# -lt 2 ]; then + echo "[ERROR] --format requires an argument" >&2 + exit 1 + fi + RECORD_FORMAT="$2" + shift 2 + ;; + --rate) + if [ $# -lt 2 ]; then + echo "[ERROR] --rate requires an argument" >&2 + exit 1 + fi + RECORD_RATE="$2" + shift 2 + ;; + --channels) + if [ $# -lt 2 ]; then + echo "[ERROR] --channels requires an argument" >&2 + exit 1 + fi + RECORD_CHANNELS="$2" + shift 2 + ;; + --config-name) + if [ $# -lt 2 ]; then + echo "[ERROR] --config-name requires an argument" >&2 + exit 1 + fi + CONFIG_NAME="$2" + shift 2 + ;; + --device) + if [ $# -lt 2 ]; then + echo "[ERROR] --device requires an argument" >&2 + exit 1 + fi + DEVICE="$2" + if [ "$DEVICE" != "handset" ] && [ "$DEVICE" != "headset" ] && [ "$DEVICE" != "all" ]; then + echo "[ERROR] --device must be 'handset', 'headset', or 'all'" >&2 + exit 1 + fi + shift 2 + ;; + --skip-actual-recording) + SKIP_ACTUAL_RECORDING=1 + shift + ;; + --res-suffix) + # Already parsed above + shift 2 + ;; + --lava-testcase-id) + # Already parsed above + shift 2 + ;; + --verbose) + VERBOSE=1 + export VERBOSE + shift + ;; + --help|-h) + usage + exit 0 + ;; + *) + echo "[WARN] Unknown option: $1" >&2 + shift + ;; + esac +done + +test_path="$(find_test_case_by_name "$TESTNAME" 2>/dev/null || echo "$SCRIPT_DIR")" +if ! cd "$test_path"; then + log_fail "cd failed: $test_path" + exit 1 +fi + +# Setup result file and log directory (with optional suffix) +if [ -n "$RES_SUFFIX" ]; then + RES_FILE="$SCRIPT_DIR/${TESTNAME}_${RES_SUFFIX}.res" + LOGDIR="$SCRIPT_DIR/results/${TESTNAME}_${RES_SUFFIX}" + log_info "Using unique result file: $RES_FILE" +else + RES_FILE="$SCRIPT_DIR/$TESTNAME.res" + LOGDIR="$SCRIPT_DIR/results/$TESTNAME" +fi + +mkdir -p "$LOGDIR" 2>/dev/null || true +: > "$RES_FILE" + +log_info "--------------------------------------------------------------------------" +log_info "------------------- Starting $TESTNAME Testcase --------------------------" +log_info "--------------------------------------------------------------------------" + +if command -v detect_platform >/dev/null 2>&1; then + detect_platform >/dev/null 2>&1 || true + log_info "Platform: machine='${PLATFORM_MACHINE:-unknown}' target='${PLATFORM_TARGET:-unknown}'" +fi + +# Apply config if CONFIG_NAME provided +if [ -n "$CONFIG_NAME" ]; then + log_info " Config Name: $CONFIG_NAME" + + # Get config parameters (rate channels) + config_params="$(get_record_config_params "$CONFIG_NAME")" || { + log_error "Invalid config name: $CONFIG_NAME" + log_fail "$RESULT_TESTNAME FAIL - Invalid config" + echo "$RESULT_TESTNAME FAIL" > "$RES_FILE" + exit 1 + } + + # Parse rate and channels + RECORD_RATE="$(echo "$config_params" | awk '{print $1}')" + RECORD_CHANNELS="$(echo "$config_params" | awk '{print $2}')" + + log_info " Config applied: Rate=$RECORD_RATE Hz, Channels=$RECORD_CHANNELS" +fi + +log_info "Configuration:" +log_info " Duration: ${RECORD_DURATION}s" +log_info " Format: $RECORD_FORMAT" +log_info " Rate: $RECORD_RATE Hz" +log_info " Channels: $RECORD_CHANNELS" +log_info " Skip Actual Recording: $SKIP_ACTUAL_RECORDING" + +test_handset_capture() { + log_info "==========================================" + log_info "TEST 1: Handset Capture (Built-in Mic)" + log_info "==========================================" + + if ! setup_handset_capture_mixer; then + log_fail "Failed to configure handset capture mixer" + return 1 + fi + + if ! validate_mixer_state "handset_capture"; then + log_fail "Handset capture mixer validation failed" + return 1 + fi + + if [ "$SKIP_ACTUAL_RECORDING" -eq 0 ]; then + device=$(get_alsa_device "handset_capture") + output_file="$LOGDIR/handset_recording.wav" + log_info "Recording from device: $device" + log_info "Output file: $output_file" + + if ! arecord -D "$device" -f "$RECORD_FORMAT" -r "$RECORD_RATE" -c "$RECORD_CHANNELS" -d "$RECORD_DURATION" "$output_file"; then + log_fail "Handset recording failed" + return 1 + fi + + if ! validate_recording "$output_file"; then + log_fail "Handset recording validation failed" + return 1 + fi + else + log_info "Skipping actual recording (mixer configuration verified)" + fi + + log_pass "Handset capture test PASSED" + return 0 +} + +test_headset_capture() { + log_info "==========================================" + log_info "TEST 2: Headset Capture (Headset Mic)" + log_info "==========================================" + + if ! setup_headset_capture_mixer; then + log_fail "Failed to configure headset capture mixer" + return 1 + fi + + if ! validate_mixer_state "headset_capture"; then + log_fail "Headset capture mixer validation failed" + return 1 + fi + + if [ "$SKIP_ACTUAL_RECORDING" -eq 0 ]; then + device=$(get_alsa_device "headset_capture") + output_file="$LOGDIR/headset_recording.wav" + log_info "Recording from device: $device" + log_info "Output file: $output_file" + + if ! arecord -D "$device" -f "$RECORD_FORMAT" -r "$RECORD_RATE" -c "$RECORD_CHANNELS" -d "$RECORD_DURATION" "$output_file"; then + log_fail "Headset recording failed" + return 1 + fi + + if ! validate_recording "$output_file"; then + log_fail "Headset recording validation failed" + return 1 + fi + else + log_info "Skipping actual recording (mixer configuration verified)" + fi + + log_pass "Headset capture test PASSED" + return 0 +} + +test_failed=0 + +# Run tests based on device selection +case "$DEVICE" in + handset) + if ! test_handset_capture; then + log_fail "Handset capture test FAILED" + test_failed=1 + fi + ;; + headset) + if ! test_headset_capture; then + log_fail "Headset capture test FAILED" + test_failed=1 + fi + ;; + all) + if ! test_handset_capture; then + log_fail "Handset capture test FAILED" + test_failed=1 + fi + + echo "" + + if ! test_headset_capture; then + log_fail "Headset capture test FAILED" + test_failed=1 + fi + ;; + *) + log_error "Invalid device: $DEVICE (must be handset, headset, or all)" + log_fail "$RESULT_TESTNAME FAIL - Invalid device" + echo "$RESULT_TESTNAME FAIL" > "$RES_FILE" + exit 1 + ;; +esac + +echo "" +log_info "==========================================" + +if [ "$test_failed" -eq 0 ]; then + log_pass "$RESULT_TESTNAME : PASS" + echo "$RESULT_TESTNAME PASS" > "$RES_FILE" +else + log_fail "$RESULT_TESTNAME : FAIL" + echo "$RESULT_TESTNAME FAIL" > "$RES_FILE" +fi + +log_info "------------------- Completed $RESULT_TESTNAME Testcase --------------------------" +exit 0 diff --git a/Runner/utils/audio/alsa_common.sh b/Runner/utils/audio/alsa_common.sh new file mode 100755 index 00000000..97c88678 --- /dev/null +++ b/Runner/utils/audio/alsa_common.sh @@ -0,0 +1,347 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause +# +# ALSA audio helpers for Hamoa test scenarios on X1E80100-EVK platform. +# Provides mixer configuration and device management for ALSA-based audio tests. +# +# This library assumes functestlib.sh has been sourced by the calling script, +# which provides log_info, log_warn, log_error, log_pass, and log_fail functions. + +# ALSA device mappings for X1E80100-EVK audio hardware +# These map logical device names to ALSA plughw device identifiers +ALSA_DEVICE_HANDSET_PLAYBACK="plughw:0,1" # 4-way speaker system (WSA2 + WSA) +ALSA_DEVICE_HEADSET_PLAYBACK="plughw:0,0" # Stereo headphones (RX codec) +ALSA_DEVICE_HANDSET_CAPTURE="plughw:0,3" # Built-in microphone (MSM_DMIC) +ALSA_DEVICE_HEADSET_CAPTURE="plughw:0,2" # Headset microphone (SWR_MIC) + +# Retrieve ALSA device identifier by logical name +# Args: $1 - device name (handset_playback, headset_playback, handset_capture, headset_capture) +# Returns: device identifier on stdout, 0 on success, 1 if unknown device +get_alsa_device() { + case "$1" in + handset_playback) printf '%s\n' "$ALSA_DEVICE_HANDSET_PLAYBACK"; return 0 ;; + headset_playback) printf '%s\n' "$ALSA_DEVICE_HEADSET_PLAYBACK"; return 0 ;; + handset_capture) printf '%s\n' "$ALSA_DEVICE_HANDSET_CAPTURE"; return 0 ;; + headset_capture) printf '%s\n' "$ALSA_DEVICE_HEADSET_CAPTURE"; return 0 ;; + *) log_error "Unknown ALSA device name: $1"; return 1 ;; + esac +} + +# Verify that an ALSA device exists and is accessible +# Args: $1 - ALSA device identifier (e.g., plughw:0,1) +# Returns: 0 if device exists, 1 otherwise +check_alsa_device() { + device="$1" + if [ -z "$device" ]; then + log_error "check_alsa_device: device parameter is empty" + return 1 + fi + + if aplay -l 2>/dev/null | grep -q "card 0"; then + log_info "ALSA device accessible: $device" + return 0 + else + log_error "ALSA device not found: $device" + return 1 + fi +} + +# Validate that an audio file exists and has non-zero size +# Args: $1 - path to audio file +# Returns: 0 if valid, 1 otherwise +validate_audio_file() { + file="$1" + if [ ! -f "$file" ]; then + log_error "Audio file not found: $file" + return 1 + fi + + size=$(stat -c%s "$file" 2>/dev/null || stat -f%z "$file" 2>/dev/null || echo 0) + if [ "$size" -eq 0 ]; then + log_error "Audio file is empty: $file" + return 1 + fi + + log_info "Audio file validated: $file ($size bytes)" + return 0 +} + +# Validate that a recorded audio file meets minimum size requirements +# Args: $1 - path to recording file +# $2 - minimum size in bytes (default: 1024 bytes, same as AudioRecord) +# Returns: 0 if valid, 1 otherwise +validate_recording() { + file="$1" + min_size="${2:-1024}" + + validate_audio_file "$file" || return 1 + + size=$(stat -c%s "$file" 2>/dev/null || stat -f%z "$file" 2>/dev/null || echo 0) + if [ "$size" -lt "$min_size" ]; then + log_error "Recording file too small: $size bytes (expected >= $min_size)" + return 1 + fi + + log_info "Recording validated: $file ($size bytes)" + return 0 +} + +# Verify that a specific ALSA mixer control is set to the expected value +# Args: $1 - mixer control name (e.g., 'WSA2 WSA RX0 MUX') +# $2 - expected value (e.g., 'AIF1_PB' or 'on' or '1') +# Returns: 0 if control matches expected value, 1 otherwise +check_mixer_control() { + control="$1" + expected_value="$2" + + if [ -z "$control" ]; then + log_error "check_mixer_control: control name is empty" + return 1 + fi + + # Get the full control output to check both enum index and string value + control_output=$(amixer -c 0 cget iface=MIXER,name="$control" 2>/dev/null) + + if [ -z "$control_output" ]; then + log_error "Mixer control not found: $control" + return 1 + fi + + # For enum controls, check if the expected value appears in the selected item line + # For boolean/integer controls, check the values= line + if echo "$control_output" | grep -q "type=ENUMERATED"; then + # For enum, check if expected value is in the output (handles both index and string) + if echo "$control_output" | grep -q "$expected_value"; then + return 0 + fi + else + # For boolean/integer, check the values= line + actual_value=$(echo "$control_output" | grep ": values=" | cut -d'=' -f2) + case "$actual_value" in + *"$expected_value"*) + return 0 + ;; + esac + fi + + log_error "Mixer control validation failed: $control" + log_error " Expected: $expected_value" + return 1 +} + +# Validate complete mixer state for a specific device type +# Checks key mixer controls to ensure audio path is configured correctly +# Args: $1 - device type (handset_playback, headset_playback, handset_capture, headset_capture) +# Returns: 0 if mixer state is valid, 1 otherwise +validate_mixer_state() { + device_type="$1" + + log_info "Validating mixer state for: $device_type" + + case "$device_type" in + handset_playback) + check_mixer_control "WSA2 WSA RX0 MUX" "AIF1_PB" || return 1 + check_mixer_control "WSA2 WSA RX1 MUX" "AIF1_PB" || return 1 + ;; + headset_playback) + check_mixer_control "HPHL_RDAC Switch" "on" || return 1 + check_mixer_control "HPHR_RDAC Switch" "on" || return 1 + ;; + handset_capture) + check_mixer_control "VA DEC0 MUX" "VA_DMIC" || return 1 + check_mixer_control "VA DMIC MUX0" "DMIC0" || return 1 + ;; + headset_capture) + check_mixer_control "TX DEC0 MUX" "SWR_MIC" || return 1 + check_mixer_control "TX SMIC MUX0" "SWR_MIC0" || return 1 + ;; + *) + log_error "Unknown device type: $device_type" + return 1 + ;; + esac + + log_info "Mixer state validation passed" + return 0 +} + +# Configure ALSA mixer for handset playback (built-in speakers) +# Sets up 4-way speaker system using WSA2 and WSA amplifiers +# Audio path: AIF1_PB -> WSA2/WSA RX0/RX1 -> WooferLeft/Right + TweeterLeft/Right +# Returns: 0 on success, 1 on failure +setup_handset_playback_mixer() { + log_info "Configuring mixer for handset playback (speakers)..." + + # Create mixer log file if LOGDIR is set + if [ -n "$LOGDIR" ]; then + mkdir -p "$LOGDIR" 2>/dev/null || true + mixer_log="$LOGDIR/mixer_handset_playback.log" + else + mixer_log="./mixer_handset_playback.log" + fi + + # WSA2 Configuration + amixer -c 0 cset iface=MIXER,name='WSA2 WSA RX0 MUX' 'AIF1_PB' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WSA2 WSA RX1 MUX' 'AIF1_PB' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WSA2 WSA_RX0 INP0' 'RX0' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WSA2 WSA_RX1 INP0' 'RX1' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WSA2 WSA_COMP1 Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WSA2 WSA_COMP2 Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WSA2 WSA_RX0 Digital Volume' 84 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WSA2 WSA_RX1 Digital Volume' 84 >> "$mixer_log" 2>&1 || return 1 + + # WSA Configuration + amixer -c 0 cset iface=MIXER,name='WSA WSA RX0 MUX' 'AIF1_PB' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WSA WSA RX1 MUX' 'AIF1_PB' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WSA WSA_RX0 INP0' 'RX0' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WSA WSA_RX1 INP0' 'RX1' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WSA WSA_COMP1 Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WSA WSA_COMP2 Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WSA WSA_RX0 Digital Volume' 84 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WSA WSA_RX1 Digital Volume' 84 >> "$mixer_log" 2>&1 || return 1 + + # WooferLeft Configuration + amixer -c 0 cset iface=MIXER,name='WooferLeft COMP Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WooferLeft BOOST Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WooferLeft DAC Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WooferLeft PBR Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WooferLeft VISENSE Switch' 0 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WooferLeft WSA MODE' 0 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WooferLeft PA Volume' 12 >> "$mixer_log" 2>&1 || return 1 + + # TweeterLeft Configuration + amixer -c 0 cset iface=MIXER,name='TweeterLeft COMP Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='TweeterLeft BOOST Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='TweeterLeft DAC Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='TweeterLeft PBR Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='TweeterLeft VISENSE Switch' 0 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='TweeterLeft WSA MODE' 0 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='TweeterLeft PA Volume' 12 >> "$mixer_log" 2>&1 || return 1 + + # WooferRight Configuration + amixer -c 0 cset iface=MIXER,name='WooferRight COMP Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WooferRight BOOST Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WooferRight DAC Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WooferRight PBR Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WooferRight VISENSE Switch' 0 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WooferRight WSA MODE' 0 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='WooferRight PA Volume' 12 >> "$mixer_log" 2>&1 || return 1 + + # TweeterRight Configuration + amixer -c 0 cset iface=MIXER,name='TweeterRight COMP Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='TweeterRight BOOST Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='TweeterRight DAC Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='TweeterRight PBR Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='TweeterRight VISENSE Switch' 0 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='TweeterRight WSA MODE' 0 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='TweeterRight PA Volume' 12 >> "$mixer_log" 2>&1 || return 1 + + log_info "Handset playback mixer configured successfully" + return 0 +} + +# Configure ALSA mixer for headset playback (headphones) +# Sets up stereo headphone output using RX codec in Class-H High Fidelity mode +# Audio path: AIF1_PB -> RX_MACRO RX0/RX1 -> RX INT0/INT1 -> HPHL/HPHR +# Returns: 0 on success, 1 on failure +setup_headset_playback_mixer() { + log_info "Configuring mixer for headset playback (headphones)..." + + # Create mixer log file if LOGDIR is set + if [ -n "$LOGDIR" ]; then + mkdir -p "$LOGDIR" 2>/dev/null || true + mixer_log="$LOGDIR/mixer_headset_playback.log" + else + mixer_log="./mixer_headset_playback.log" + fi + + amixer -c 0 cset iface=MIXER,name='HPHL_RDAC Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='HPHR_RDAC Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='HPHL Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='HPHR Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='HPHR_COMP Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='HPHL_COMP Switch' 1 >> "$mixer_log" 2>&1 || return 1 + + amixer -c 0 cset iface=MIXER,name='RX HPH Mode' 'CLS_H_HIFI' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='RX_HPH PWR Mode' 'LOHIFI' >> "$mixer_log" 2>&1 || return 1 + + amixer -c 0 cset iface=MIXER,name='RX_MACRO RX0 MUX' 'AIF1_PB' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='RX_MACRO RX1 MUX' 'AIF1_PB' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='RX INT0_1 MIX1 INP0' 'RX0' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='RX INT1_1 MIX1 INP0' 'RX1' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='RX INT0 DEM MUX' 'CLSH_DSM_OUT' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='RX INT1 DEM MUX' 'CLSH_DSM_OUT' >> "$mixer_log" 2>&1 || return 1 + + amixer -c 0 cset iface=MIXER,name='RX_COMP1 Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='RX_COMP2 Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='RX_RX0 Digital Volume' 60 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='RX_RX1 Digital Volume' 60 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='HPHL Volume' 20 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='HPHR Volume' 20 >> "$mixer_log" 2>&1 || return 1 + + amixer -c 0 cset iface=MIXER,name='CLSH Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='LO Switch' 1 >> "$mixer_log" 2>&1 || return 1 + + log_info "Headset playback mixer configured successfully" + return 0 +} + +# Configure ALSA mixer for handset capture (built-in microphone) +# Sets up VA_DMIC (Voice Activation DMIC) routing through VA decimators +# Audio path: DMIC0/DMIC1 -> VA DMIC MUX0/MUX1 -> VA DEC0/DEC1 -> VA_AIF1_CAP +# Returns: 0 on success, 1 on failure +setup_handset_capture_mixer() { + log_info "Configuring mixer for handset capture (built-in mic)..." + + # Create mixer log file if LOGDIR is set + if [ -n "$LOGDIR" ]; then + mkdir -p "$LOGDIR" 2>/dev/null || true + mixer_log="$LOGDIR/mixer_handset_capture.log" + else + mixer_log="./mixer_handset_capture.log" + fi + + amixer -c 0 cset iface=MIXER,name='VA DEC0 MUX' 'VA_DMIC' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='VA DMIC MUX0' 'DMIC0' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='VA_AIF1_CAP Mixer DEC0' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='VA_DEC0 Volume' 100 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='VA DEC1 MUX' 'VA_DMIC' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='VA DMIC MUX1' 'DMIC1' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='VA_AIF1_CAP Mixer DEC1' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='VA_DEC1 Volume' 100 >> "$mixer_log" 2>&1 || return 1 + + log_info "Handset capture mixer configured successfully" + return 0 +} + +# Configure ALSA mixer for headset capture (headset microphone) +# Sets up SWR_MIC (headset microphone) routing through SoundWire interface +# Audio path: SWR_MIC -> ADC2 -> TX SMIC MUX0 (SWR_MIC0) -> TX DEC0 -> TX_AIF1_CAP +# Note: TX SMIC MUX0 must be set to 'SWR_MIC0' (not 'ADC1') for proper routing +# Returns: 0 on success, 1 on failure +setup_headset_capture_mixer() { + log_info "Configuring mixer for headset capture (headset mic)..." + + # Create mixer log file if LOGDIR is set + if [ -n "$LOGDIR" ]; then + mkdir -p "$LOGDIR" 2>/dev/null || true + mixer_log="$LOGDIR/mixer_headset_capture.log" + else + mixer_log="./mixer_headset_capture.log" + fi + + amixer -c 0 cset iface=MIXER,name='TX DEC0 MUX' 'SWR_MIC' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='TX SMIC MUX0' 'SWR_MIC0' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='TX_AIF1_CAP Mixer DEC0' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='TX1 MODE' 'ADC_NORMAL' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='ADC2 Volume' 20 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='TX_DEC0 Volume' 84 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='ADC2_MIXER Switch' 1 >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='HDR12 MUX' 'NO_HDR12' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='ADC2 MUX' 'INP2' >> "$mixer_log" 2>&1 || return 1 + amixer -c 0 cset iface=MIXER,name='ADC2 Switch' 1 >> "$mixer_log" 2>&1 || return 1 + + log_info "Headset capture mixer configured successfully" + return 0 +}