From 128a0267c3083487f03c5f939941fe8adf3eda5c Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Sun, 19 Apr 2026 16:24:11 +0530 Subject: [PATCH 1/2] prefer offline generated OGG/MP3 clips while preserving clip path/url overrides Update audio clip provisioning to prefer locally generated GStreamer sample clips for OGG and MP3 when no external clip source is explicitly requested, making CI runs less dependent on network availability. This keeps backward compatibility by preserving existing --clip-path, --clip-url, AUDIO_CLIP_PATH, and AUDIO_CLIP_URL behavior. The run.sh changes now track whether an external source was explicitly requested and pass that state into provision_test_files(), while the provisioning logic can still fall back to user-provided clips or downloads when requested. Signed-off-by: Srikanth Muppandam --- .../Audio/Audio_Record_Playback/run.sh | 354 ++++++++++++++---- 1 file changed, 290 insertions(+), 64 deletions(-) diff --git a/Runner/suites/Multimedia/GSTreamer/Audio/Audio_Record_Playback/run.sh b/Runner/suites/Multimedia/GSTreamer/Audio/Audio_Record_Playback/run.sh index bd5df872..515369cd 100755 --- a/Runner/suites/Multimedia/GSTreamer/Audio/Audio_Record_Playback/run.sh +++ b/Runner/suites/Multimedia/GSTreamer/Audio/Audio_Record_Playback/run.sh @@ -112,6 +112,17 @@ fail_count=0 skip_count=0 total_tests=0 +# Track whether external clip provisioning was explicitly requested. +USER_CLIP_URL_SET=0 +USER_CLIP_PATH_SET=0 + +if [ "${AUDIO_CLIP_URL+x}" = "x" ] && [ -n "${AUDIO_CLIP_URL:-}" ]; then + USER_CLIP_URL_SET=1 +fi + +if [ "${AUDIO_CLIP_PATH+x}" = "x" ] && [ -n "${AUDIO_CLIP_PATH:-}" ]; then + USER_CLIP_PATH_SET=1 +fi # -------------------- Defaults (LAVA env vars -> defaults; CLI overrides) -------------------- testMode="${AUDIO_TEST_MODE:-all}" testName="${AUDIO_TEST_NAME:-}" @@ -217,20 +228,26 @@ while [ $# -gt 0 ]; do echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" exit 0 fi - [ -n "$2" ] && clipUrl="$2" + if [ -n "$2" ]; then + clipUrl="$2" + USER_CLIP_URL_SET=1 + fi shift 2 ;; - + --clip-path) if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then log_warn "Missing/invalid value for --clip-path" echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" exit 0 fi - [ -n "$2" ] && clipPath="$2" + if [ -n "$2" ]; then + clipPath="$2" + USER_CLIP_PATH_SET=1 + fi shift 2 ;; - + --test-name) if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then log_warn "Missing/invalid value for --test-name" @@ -452,6 +469,9 @@ run_record_test() { ext="$fmt" output_file="$RECORDED_DIR/${testname}.${ext}" test_log="$OUTDIR/${testname}.log" + + # Remove stale artifact from a previous rerun. + rm -f "$output_file" : >"$test_log" @@ -605,6 +625,9 @@ run_record_pulsesrc_test() { ext="$fmt" output_file="$RECORDED_DIR/${testname}.${ext}" test_log="$OUTDIR/${testname}.log" + + # Remove stale artifact from a previous rerun. + rm -f "$output_file" : >"$test_log" @@ -619,13 +642,16 @@ run_record_pulsesrc_test() { log_info "Pipeline: $pipeline" # Run recording with timeout - if gstreamer_run_gstlaunch_timeout "$duration" "$pipeline" >>"$test_log" 2>&1; then + if gstreamer_run_gstlaunch_timeout "$((duration + 10))" "$pipeline" >>"$test_log" 2>&1; then gstRc=0 else gstRc=$? fi log_info "Record exit code: $gstRc" + if [ "$gstRc" -eq 124 ]; then + log_info "$testname: timeout rc=124 is acceptable here if a valid output file was finalized" + fi # Check for GStreamer errors in log if ! gstreamer_validate_log "$test_log" "$testname"; then @@ -658,59 +684,71 @@ run_record_pulsesrc_test() { # -------------------- PulseSrc Playback test function -------------------- run_playback_pulsesrc_test() { fmt="$1" - + testname="playback_pulsesrc_${fmt}" log_info "==========================================" log_info "Running: $testname" log_info "==========================================" - + ext="$fmt" input_file="$RECORDED_DIR/record_pulsesrc_${fmt}.${ext}" - + if [ ! -f "$input_file" ]; then + if [ "$testMode" = "all" ]; then + log_fail "$testname: FAIL - expected recorded file is missing: $input_file (pulsesrc record testcase failed in same run)" + fail_count=$((fail_count + 1)) + return 1 + fi + log_warn "$testname: SKIP - recorded file not found: $input_file (run pulsesrc record first)" skip_count=$((skip_count + 1)) return 1 fi - - # Check if file has minimum content (same threshold as recording: 1000 bytes) + file_size="$(gstreamer_file_size_bytes "$input_file")" if [ "$file_size" -le 1000 ]; then + if [ "$testMode" = "all" ]; then + log_fail "$testname: FAIL - recorded file too small: $file_size bytes (pulsesrc recording failed in same run)" + fail_count=$((fail_count + 1)) + return 1 + fi + log_warn "$testname: SKIP - recorded file too small: $file_size bytes (pulsesrc recording likely failed)" skip_count=$((skip_count + 1)) return 1 fi - + test_log="$OUTDIR/${testname}.log" : >"$test_log" - + + # pulsesrc recordings are timeout-driven and can be longer than the nominal + # AUDIO_DURATION. Keep extra headroom here so valid same-run artifacts do not + # fail intermittently due to playback timeout racing EOS/finalization. + playback_timeout=$((duration + 20)) pipeline="$(gstreamer_build_audio_playback_pipeline "$fmt" "$input_file")" - + if [ -z "$pipeline" ]; then log_fail "$testname: FAIL (could not build playback pipeline)" fail_count=$((fail_count + 1)) return 1 fi - + log_info "Pipeline: $pipeline" - - # Run playback - if gstreamer_run_gstlaunch_timeout "$((duration + 10))" "$pipeline" >>"$test_log" 2>&1; then + + if gstreamer_run_gstlaunch_timeout "$playback_timeout" "$pipeline" >>"$test_log" 2>&1; then gstRc=0 else gstRc=$? fi - - log_info "Playback exit code: $gstRc" - - # Check for GStreamer errors in log + + log_info "$testname: playback timeout budget=${playback_timeout}s" + if ! gstreamer_validate_log "$test_log" "$testname"; then log_fail "$testname: FAIL (GStreamer errors detected)" fail_count=$((fail_count + 1)) return 1 fi - - # Check for successful completion + if [ "$gstRc" -eq 0 ]; then log_pass "$testname: PASS" pass_count=$((pass_count + 1)) @@ -721,7 +759,6 @@ run_playback_pulsesrc_test() { return 1 fi } - # -------------------- Test file playback test function (OGG/MP3) -------------------- run_playback_ogg_mp3_test() { fmt="$1" @@ -806,70 +843,259 @@ export GST_DEBUG_NO_COLOR=1 export GST_DEBUG="$gstDebugLevel" export GST_DEBUG_FILE="$GST_LOG" +audio_record_get_valid_duration_secs() { + duration_secs="$1" + + if [ -z "$duration_secs" ]; then + echo 10 + return 0 + fi + + case "$duration_secs" in + ''|*[!0-9]*) + log_warn "Invalid duration_secs '$duration_secs' for sample generation, defaulting to 10" + echo 10 + return 0 + ;; + esac + + if [ "$duration_secs" -le 0 ] 2>/dev/null; then + log_warn "Non-positive duration_secs '$duration_secs' for sample generation, defaulting to 10" + echo 10 + return 0 + fi + + echo "$duration_secs" + return 0 +} + +# Refresh sample availability flags for the current OUTDIR. +# Note: have_ogg / have_mp3 are intentionally shared global state in this +# POSIX sh flow so subsequent provisioning stages can make decisions based on +# the latest discovered/generated/copied samples. +audio_record_mark_existing_samples() { + outdir="$1" + + sample_ogg="$outdir/sample_audio.ogg" + sample_mp3="$outdir/sample_audio.mp3" + + have_ogg=0 + have_mp3=0 + + if [ -f "$sample_ogg" ]; then + ogg_size="$(gstreamer_file_size_bytes "$sample_ogg")" + if [ "$ogg_size" -gt 1000 ]; then + have_ogg=1 + log_info "OGG Test file available (size: $ogg_size bytes)" + fi + fi + + if [ -f "$sample_mp3" ]; then + mp3_size="$(gstreamer_file_size_bytes "$sample_mp3")" + if [ "$mp3_size" -gt 1000 ]; then + have_mp3=1 + log_info "MP3 Test file available (size: $mp3_size bytes)" + fi + fi + + return 0 +} + +audio_record_copy_sample_from_path() { + src_file="$1" + dst_file="$2" + label="$3" + + if [ ! -f "$src_file" ]; then + return 1 + fi + + if cp "$src_file" "$dst_file"; then + log_info "$label copied from local path" + return 0 + fi + + log_warn "Failed to copy $label from local path: $src_file -> $dst_file" + return 1 +} + +audio_record_generate_local_ogg_sample() { + outdir="$1" + num_buffers="$2" + duration_secs="$3" + + duration_secs="$(audio_record_get_valid_duration_secs "$duration_secs")" + sample_ogg="$outdir/sample_audio.ogg" + test_log="$outdir/provision_sample_ogg.log" + + : >"$test_log" + + pipeline="audiotestsrc wave=sine freq=440 volume=1.0 num-buffers=$num_buffers ! audioconvert ! audioresample ! vorbisenc ! oggmux ! filesink location=$sample_ogg" + + log_info "Generating local OGG sample from audiotestsrc..." + log_info "Pipeline: $pipeline" + + if gstreamer_run_gstlaunch_timeout "$((duration_secs + 10))" "$pipeline" >>"$test_log" 2>&1; then + gstRc=0 + else + gstRc=$? + fi + + log_info "OGG generation exit code: $gstRc" + + if ! gstreamer_validate_log "$test_log" "provision_sample_ogg"; then + log_warn "Local OGG sample generation reported GStreamer errors" + return 1 + fi + + if [ -f "$sample_ogg" ] && [ -s "$sample_ogg" ]; then + ogg_size="$(gstreamer_file_size_bytes "$sample_ogg")" + if [ "$ogg_size" -gt 1000 ]; then + log_pass "Local OGG sample generated successfully (size: $ogg_size bytes)" + return 0 + fi + log_warn "Generated OGG sample is too small: $ogg_size bytes" + return 1 + fi + + log_warn "Local OGG sample was not created" + return 1 +} + +audio_record_generate_local_mp3_sample() { + outdir="$1" + num_buffers="$2" + duration_secs="$3" + + duration_secs="$(audio_record_get_valid_duration_secs "$duration_secs")" + sample_mp3="$outdir/sample_audio.mp3" + test_log="$outdir/provision_sample_mp3.log" + + : >"$test_log" + + pipeline="audiotestsrc wave=sine freq=440 volume=1.0 num-buffers=$num_buffers ! audioconvert ! audioresample ! lamemp3enc ! filesink location=$sample_mp3" + + log_info "Generating local MP3 sample from audiotestsrc..." + log_info "Pipeline: $pipeline" + + if gstreamer_run_gstlaunch_timeout "$((duration_secs + 10))" "$pipeline" >>"$test_log" 2>&1; then + gstRc=0 + else + gstRc=$? + fi + + log_info "MP3 generation exit code: $gstRc" + + if ! gstreamer_validate_log "$test_log" "provision_sample_mp3"; then + log_warn "Local MP3 sample generation reported GStreamer errors" + return 1 + fi + + if [ -f "$sample_mp3" ] && [ -s "$sample_mp3" ]; then + mp3_size="$(gstreamer_file_size_bytes "$sample_mp3")" + if [ "$mp3_size" -gt 1000 ]; then + log_pass "Local MP3 sample generated successfully (size: $mp3_size bytes)" + return 0 + fi + log_warn "Generated MP3 sample is too small: $mp3_size bytes" + return 1 + fi + + log_warn "Local MP3 sample was not created" + return 1 +} # -------------------- Test file provisioning (OGG/MP3) -------------------- provision_test_files() { log_info "==========================================" log_info "TEST FILE PROVISIONING" log_info "==========================================" - + sample_ogg="$OUTDIR/sample_audio.ogg" sample_mp3="$OUTDIR/sample_audio.mp3" - # Check if Test files already exist - if [ -f "$sample_ogg" ] && [ -f "$sample_mp3" ]; then - log_info "Test files already exist" - else - # Try to get Test files from provided path or URL - if [ -n "$clipPath" ]; then - log_info "Attempting to get Test files from local path: $clipPath" - if [ -f "$clipPath/sample_audio.ogg" ]; then - cp "$clipPath/sample_audio.ogg" "$sample_ogg" 2>/dev/null || true - log_info "Sample OGG file copied from local path" + # Refresh once at each provisioning stage boundary. + # This is intentional: later stages depend on the latest have_ogg/have_mp3 + # values after local-path copy, URL extraction, or best-effort generation. + audio_record_mark_existing_samples "$OUTDIR" + + # If user explicitly gave --clip-path (or AUDIO_CLIP_PATH), honor it first. + if [ "$have_ogg" -eq 0 ] || [ "$have_mp3" -eq 0 ]; then + if [ "${USER_CLIP_PATH_SET:-0}" -eq 1 ] && [ -n "$clipPath" ]; then + log_info "Using user-provided clip path: $clipPath" + + if [ "$have_ogg" -eq 0 ]; then + audio_record_copy_sample_from_path \ + "$clipPath/sample_audio.ogg" \ + "$sample_ogg" \ + "Sample OGG file" fi - if [ -f "$clipPath/sample_audio.mp3" ]; then - cp "$clipPath/sample_audio.mp3" "$sample_mp3" 2>/dev/null || true - log_info "Sample MP3 file copied from local path" + + if [ "$have_mp3" -eq 0 ]; then + audio_record_copy_sample_from_path \ + "$clipPath/sample_audio.mp3" \ + "$sample_mp3" \ + "Sample MP3 file" fi + + audio_record_mark_existing_samples "$OUTDIR" fi - - # If not found locally, try URL download - if [ ! -f "$sample_ogg" ] || [ ! -f "$sample_mp3" ]; then - log_info "Test files not found locally; attempting download from URL..." + fi + + # If user explicitly gave --clip-url (or AUDIO_CLIP_URL), honor it next. + if [ "$have_ogg" -eq 0 ] || [ "$have_mp3" -eq 0 ]; then + if [ "${USER_CLIP_URL_SET:-0}" -eq 1 ] && [ -n "$clipUrl" ]; then + log_info "Using user-provided clip URL: $clipUrl" if extract_tar_from_url "$clipUrl" "$OUTDIR"; then log_pass "Test files downloaded and extracted successfully" else log_warn "Test file download failed (offline or URL issue)" fi + + audio_record_mark_existing_samples "$OUTDIR" fi - fi - - # Check what we have AFTER all provisioning attempts - have_ogg=0 - have_mp3=0 - - if [ -f "$sample_ogg" ]; then - size=$(gstreamer_file_size_bytes "$sample_ogg") - if [ "$size" -gt 1000 ]; then - have_ogg=1 - log_info "OGG Test file available (size: $size bytes)" + + # If user did NOT explicitly request clip-path or clip-url, prefer local generation. + if [ "${USER_CLIP_PATH_SET:-0}" -eq 0 ] && [ "${USER_CLIP_URL_SET:-0}" -eq 0 ]; then + if [ "$have_ogg" -eq 0 ]; then + if has_element vorbisenc && has_element oggmux; then + audio_record_generate_local_ogg_sample "$OUTDIR" "$NUM_BUFFERS" "$duration" || true + else + log_warn "OGG sample generation skipped: vorbisenc or oggmux plugin not available" + fi + fi + + if [ "$have_mp3" -eq 0 ]; then + if has_element lamemp3enc; then + audio_record_generate_local_mp3_sample "$OUTDIR" "$NUM_BUFFERS" "$duration" || true + else + log_warn "MP3 sample generation skipped: lamemp3enc plugin not available" + fi fi fi - - if [ -f "$sample_mp3" ]; then - size=$(gstreamer_file_size_bytes "$sample_mp3") - if [ "$size" -gt 1000 ]; then - have_mp3=1 - log_info "MP3 Test file available (size: $size bytes)" + + # If user explicitly requested an external source but it was incomplete, + # local generation can still fill in missing files as best effort. + if [ "${USER_CLIP_PATH_SET:-0}" -eq 1 ] || [ "${USER_CLIP_URL_SET:-0}" -eq 1 ]; then + if [ "$have_ogg" -eq 0 ]; then + if has_element vorbisenc && has_element oggmux; then + audio_record_generate_local_ogg_sample "$OUTDIR" "$NUM_BUFFERS" "$duration" || true + fi + fi + + if [ "$have_mp3" -eq 0 ]; then + if has_element lamemp3enc; then + audio_record_generate_local_mp3_sample "$OUTDIR" "$NUM_BUFFERS" "$duration" || true + fi fi fi - - # Only warn if BOTH files are missing after all attempts + + audio_record_mark_existing_samples "$OUTDIR" + if [ "$have_ogg" -eq 0 ] && [ "$have_mp3" -eq 0 ]; then log_warn "No Test files (OGG/MP3) available for playback tests" fi } - # -------------------- Main test execution -------------------- log_info "Starting audio record/playback tests..." @@ -889,7 +1115,7 @@ if [ -n "$testName" ]; then # Only provision test files if running OGG/MP3 playback tests case "$testName" in playback_sample_ogg|playback_sample_mp3) - provision_test_files + provision_test_files "$OUTDIR" "$NUM_BUFFERS" "$duration" "$clipPath" "$clipUrl" "$USER_CLIP_PATH_SET" "$USER_CLIP_URL_SET" ;; esac log_info "==========================================" @@ -957,7 +1183,7 @@ else # Run ALL playback/decode tests after recording (6 tests total) if [ "$testMode" = "all" ] || [ "$testMode" = "playback" ]; then # Provision test files only when running playback tests - provision_test_files + provision_test_files "$OUTDIR" "$NUM_BUFFERS" "$duration" "$clipPath" "$clipUrl" "$USER_CLIP_PATH_SET" "$USER_CLIP_URL_SET" log_info "==========================================" log_info "PLAYBACK TESTS" From cc5e9b0a5f5b9aedba548327ea2281d22db4e70c Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Tue, 21 Apr 2026 07:15:21 +0530 Subject: [PATCH 2/2] Add audioresample between audioconvert and the shared audio record encoders in gstreamer_build_audio_record_pipeline(). This makes pulsesrc-based recording paths, especially FLAC, more robust across platforms by improving caps/rate negotiation before encoding and reducing intermittent file-generation failures seen in CI/LAVA runs. Signed-off-by: Srikanth Muppandam --- Runner/utils/lib_gstreamer.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Runner/utils/lib_gstreamer.sh b/Runner/utils/lib_gstreamer.sh index 0e312528..fe6f34ad 100755 --- a/Runner/utils/lib_gstreamer.sh +++ b/Runner/utils/lib_gstreamer.sh @@ -592,7 +592,7 @@ gstreamer_build_audio_record_pipeline() { esac # Construct complete pipeline - printf '%s\n' "${source_elem} ! audioconvert ! ${encoder_elem} ! filesink location=${output_file}" + printf '%s\n' "${source_elem} ! audioconvert ! audioresample ! ${encoder_elem} ! filesink location=${output_file}" return 0 }