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" 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 }