diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 13df7886bcdd1678d0be052d206f90b1832ce253..1b192ec44d0b4c9f6bc07597492b9c5a1664331d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1012,11 +1012,13 @@ voip-be-on-merge-request: - .test-job-linux-needs-testv-dir - .rules-merge-request stage: test - needs: ["build-codec-linux-make", "codec-smoke-test"] + needs: ["build-codec-linux-make"] timeout: "10 minutes" script: - *print-common-info - - bash ci/ivas_voip_be_test.sh + - make clean + - make -j + - python3 -m pytest tests/test_be_for_jbm_neutral_dly_profile.py clang-format-check: extends: @@ -2205,7 +2207,7 @@ coverage-test-on-main-scheduled: - python3 -m pytest $TESTS_DIR_CODEC_BE_ON_MR/test_param_file.py -v -n auto --update_ref 1 -m create_ref --param_file scripts/config/self_test_evs.prm --ref_encoder_path ./IVAS_cod --ref_decoder_path ./IVAS_dec - bash ci/smoke_test.sh coverage - python3 -m pytest $TESTS_DIR_CODEC_BE_ON_MR/test_param_file.py -v -n auto --update_ref 1 -m create_ref --param_file scripts/config/self_test_ltv.prm --ref_encoder_path ./IVAS_cod --ref_decoder_path ./IVAS_dec - - bash ci/ivas_voip_be_test.sh coverage + - python3 -m pytest tests/test_be_for_jbm_neutral_dly_profile.py - lcov -c -d obj -o coverage.info # remove apps and lib_util files from coverage - lcov -r coverage.info "*apps*" -o coverage.info diff --git a/ci/ivas_voip_be_test.sh b/ci/ivas_voip_be_test.sh deleted file mode 100755 index 7c5c8344192521ccf3d3c3761c25a9d43af6d8e4..0000000000000000000000000000000000000000 --- a/ci/ivas_voip_be_test.sh +++ /dev/null @@ -1,145 +0,0 @@ -#! /usr/bin/bash - -# (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, -# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., -# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, -# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other -# contributors to this repository. All Rights Reserved. - -# This software is protected by copyright law and by international treaties. -# The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, -# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., -# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, -# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other -# contributors to this repository retain full ownership rights in their respective contributions in -# the software. This notice grants no license of any kind, including but not limited to patent -# license, nor is any license granted by implication, estoppel or otherwise. - -# Contributors are required to enter into the IVAS codec Public Collaboration agreement before making -# contributions. - -# This software is provided "AS IS", without any express or implied warranties. The software is in the -# development stage. It is intended exclusively for experts who have experience with such software and -# solely for the purpose of inspection. All implied warranties of non-infringement, merchantability -# and fitness for a particular purpose are hereby disclaimed and excluded. - -# Any dispute, controversy or claim arising under or in relation to providing this software shall be -# submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in -# accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and -# the United Nations Convention on Contracts on the International Sales of Goods. - -function usage { - echo - echo "Usage:" - echo " ivas_voip_be_test.sh [MODE]" - echo - echo " MODE - test (default) or coverage" - exit -} - -if [ ! -d "lib_com" ]; then - echo "not in root directory! - please run in IVAS root" - exit 1 -fi - -if [ -z "$1" ] || [ "$1" == "test" ]; then - WORKERS="" - BUILD=1 - COVERAGE=0 -elif [ "$1" == "coverage" ]; then - WORKERS="-t 1" - BUILD=0 - COVERAGE=1 -else - usage -fi - -if [ $BUILD -eq 1 ];then - make clean - make all -j -fi - -# Configuration -modes=('HOA3_b128_wb_cbr' 'MC_7_1_b96_fb_cbr' 'ISM2_b48_fb_cbr') -output_formats=('STEREO' 'FOA' '7_1' 'HOA3') -limit_input_to_x_seconds=30 -verbosity_cmd="-z console" - -cfg=./scripts/config/ci_linux.json -dly_profile=./scripts/dly_error_profiles/dly_error_profile_0.dat - -output_dir_default="out" -output_dir_voip="out_voip" - -# Run the same modes in VoIP and non-VoIP mode with a neutral delay profile -./scripts/runIvasCodec.py $verbosity_cmd -p $cfg $WORKERS -U $limit_input_to_x_seconds -m "${modes[@]}" --oc "${output_formats[@]}" -o $output_dir_default | tee voip_be_test_output.txt -./scripts/runIvasCodec.py $verbosity_cmd -p $cfg $WORKERS -U $limit_input_to_x_seconds -m "${modes[@]}" --oc "${output_formats[@]}" -o $output_dir_voip -J "$dly_profile" | tee -a voip_be_test_output.txt - -# Check if Python scripts above failed. They return status 0 even when running a mode fails, so we have to parse log file -if grep -iq failed voip_be_test_output.txt ; then - echo "Run errors in runIvasCodec.py" - exit 1 -fi - -if [ $COVERAGE -eq 1 ];then - # Coverage analysis requires only running the codec and may exit before the comparison part - exit 0 -fi - -# Set up Python path -python_audio_module_path=$(pwd)/scripts -export PYTHONPATH=$python_audio_module_path:$PYTHONPATH -python_audiofile_script_path=$python_audio_module_path/pyaudio3dtools/audiofile.py - -# Trim JBM delay from VoIP output files -output_dir_voip_dec="$output_dir_voip"/dec -output_dir_voip_dec_trimmed="$output_dir_voip"/dec_trimmed - -if [[ ! -d $output_dir_voip_dec_trimmed ]]; then - mkdir $output_dir_voip_dec_trimmed -fi - -for cut in "$output_dir_voip_dec"/*.wav; do - output_path=${cut/$output_dir_voip_dec/$output_dir_voip_dec_trimmed} - output_path=${output_path/".wav"/".raw"} - python3 "$python_audiofile_script_path" pre-trim 60 "$cut" "$output_path" | tee -a voip_be_test_output.txt -done - -# Convert non-VoIP output from wav to pcm (comparison script doesn't support wav) -output_dir_default_dec="$output_dir_default"/dec -output_dir_default_dec_pcm="$output_dir_default"/dec_pcm - -if [[ ! -d $output_dir_default_dec_pcm ]]; then - mkdir $output_dir_default_dec_pcm -fi - -for ref in "$output_dir_default_dec"/*.wav; do - output_path=${ref/$output_dir_default_dec/$output_dir_default_dec_pcm} - output_path=${output_path/".wav"/".raw"} - python3 "$python_audiofile_script_path" convert "$ref" "$output_path" | tee -a voip_be_test_output.txt -done - -# Assert BE between non-VoIP and VoIP modes -all_be=1 - -cmp_tool_path=$(pwd)/tests/cmp_pcm.py - -for ref in "$output_dir_default_dec_pcm"/*; do - cut=${ref/$output_dir_default_dec_pcm/$output_dir_voip_dec_trimmed} - cut=${cut/".dec."/"_jbm_dly_error_profile_0_dat.dec."} - - # Print paths of compared files, since the script doesn't do it - printf "\nComparing %s and %s\n" "$ref" "$cut" | tee -a voip_be_test_output.txt - printout=$($cmp_tool_path "$ref" "$cut") - if [ $? -ne 0 ]; then - all_be=0 - fi - printf "%s\n" "$printout" | tee -a voip_be_test_output.txt -done - -if [ $all_be -eq 1 ]; then - printf "\n\nAll tested conditions are bit-exact\n" | tee -a voip_be_test_output.txt -else - printf "\n\nBitexactness problems found!\n" | tee -a voip_be_test_output.txt - exit 1; -fi diff --git a/scripts/batch_comp_audio.py b/scripts/batch_comp_audio.py index ce1f380c568c4bd1073686371490d7714722cf29..56a6b7d5023c2962f4a522d7170592a00275e455 100755 --- a/scripts/batch_comp_audio.py +++ b/scripts/batch_comp_audio.py @@ -49,16 +49,21 @@ SEG_SNR_EXPR = r"Seg. SNR\s+=(.+)dB" DIFF_EXPR = r"Max Diff\s+=\s+(\d+)" DIFF_STR = { "CompAudio": "{label} Max. diff (PCM) for file {f}: {diff}", + "pyaudio3dtools": "{label} Max. diff (PCM) for file {f}: {diff}", "mld": "{label} MLD diff for file {f}: {diff}", } def main(args): tool = args.tool - if shutil.which(tool) is None: + if tool != "pyaudio3dtools" and shutil.which(tool) is None: print(f"{tool} not in PATH - abort.") sys.exit(-1) + test_offset_ms = args.test_offset_ms + if tool != "pyaudio3dtools": + test_offset_ms = 0 + num_files_diff = 0 with OutFileManager(args.out_file) as out_file: @@ -77,7 +82,7 @@ def main(args): # if only one thread is passed, do everything in the main thread # to allow for meaningful debugging if needed for f in common_files: - compare_files(f, fol1, fol2, outputs, tool) + compare_files(f, fol1, fol2, outputs, tool, test_offset_ms) else: with concurrent.futures.ThreadPoolExecutor( max_workers=args.num_threads @@ -89,6 +94,7 @@ def main(args): repeat(fol2), repeat(outputs), repeat(tool), + repeat(test_offset_ms) ) if args.sort: @@ -98,7 +104,7 @@ def main(args): # write csv header if out_file is not None: - if tool == "CompAudio": + if tool == "CompAudio" or tool == "pyaudio3dtools": out_file.write("filename,diff\n") elif tool == "mld": out_file.write("filename,mld\n") @@ -106,7 +112,7 @@ def main(args): for f, tool_output in out.items(): if tool == "CompAudio": diff, snr, gain, seg_snr = tool_output - elif tool == "mld": + elif tool == "mld" or tool == "pyaudio3dtools": diff = tool_output if diff > 0: @@ -133,8 +139,10 @@ def main(args): else: print("All files are bitexact") + return num_files_diff + -def compare_files(f, fol1, fol2, outputs_dict, tool): +def compare_files(f, fol1, fol2, outputs_dict, tool, test_offset_ms): """ Compare file f in both folders fol1 and fol2 using the given tool and store the parsed difference in outputs_dict. @@ -155,6 +163,11 @@ def compare_files(f, fol1, fol2, outputs_dict, tool): s2, fs2 = readfile(f2, outdtype="int16") cmp_result = compare(s1, s2, fs1, per_frame=False, get_mld=True) tool_output = cmp_result["MLD"] + elif tool == "pyaudio3dtools": + s1, fs1 = readfile(f1, outdtype="int16") + s2, fs2 = readfile(f2, outdtype="int16") + cmp_result = compare(s1, s2, fs1, per_frame=False, test_start_offset_ms=test_offset_ms) + tool_output = cmp_result["max_abs_diff"] with threading.Lock(): outputs_dict.update({f: tool_output}) @@ -284,10 +297,16 @@ if __name__ == "__main__": ) parser.add_argument( "--tool", - choices=["mld", "CompAudio"], + choices=["mld", "CompAudio", "pyaudio3dtools"], default="CompAudio", help="Compare tool to run", ) + parser.add_argument( + "--test_offset_ms", + type=int, + default=0, + help="Offset in miliseconds that is ignored at the start of the files in folder2 (only used if tool=pyaudio3dtools)" + ) args = parser.parse_args() - main(args) + sys.exit(main(args)) diff --git a/scripts/pyaudio3dtools/audioarray.py b/scripts/pyaudio3dtools/audioarray.py index 0c313c4c91da056c46df90bba2a43361d6140da3..be950aaf6013ae5d24034e0346608c7a05edf001 100644 --- a/scripts/pyaudio3dtools/audioarray.py +++ b/scripts/pyaudio3dtools/audioarray.py @@ -237,6 +237,7 @@ def compare( ssnr_thresh_low: float = -np.inf, ssnr_thresh_high: float = np.inf, apply_thresholds_to_ref_only: bool = False, + test_start_offset_ms: int = 0, ) -> dict: """Compare two audio arrays @@ -264,12 +265,23 @@ def compare( Set to True to only apply the threshold comparison for the reference signal for whether to include a segment in the ssnr computation. Use this to align behaviour with the MPEG-D conformance specification. + test_start_offset_ms: (non-negative) int + offset in miliseconds for test signal. If > 0, the corresponding number of samples + will be removed from the test array like so: test = test[sample_offset:, :]. Returns ------- result: dict Comparison results """ + + if test_start_offset_ms < 0: + raise ValueError( + f"Test_start_offset_ms has to be non-negative, but {test_start_offset_ms} was given." + ) + test_start_offset_samples = int(fs * test_start_offset_ms / 1000) + test = test[test_start_offset_samples:, :] + framesize = fs // 50 diff = abs(test - ref) max_diff = int(diff.max()) diff --git a/scripts/pyaudio3dtools/audiofile.py b/scripts/pyaudio3dtools/audiofile.py index e614bfbd49fa3a72209ef10cb6f4791c52ba8204..bbee88ca9c52f570489858bf5c779c5ed4a06984 100644 --- a/scripts/pyaudio3dtools/audiofile.py +++ b/scripts/pyaudio3dtools/audiofile.py @@ -780,5 +780,25 @@ if __name__ == "__main__": parser_convert.add_argument("output_file") parser_convert.set_defaults(func=convert_wrapper) + def compare_wrapper(compare_args): + if not compare_args.ref_file.endswith(".wav") or not compare_args.test_file.endswith(".wav"): + print("Convert currently only supported with WAV file input") + exit(-1) + + s1, fs1 = readfile(compare_args.ref_file, outdtype="int16") + s2, fs2 = readfile(compare_args.test_file, outdtype="int16") + if fs1 != fs2: + print("Can only compare signals of same sampling rate") + exit(-1) + + cmp_result = audioarray.compare(s1, s2, fs1, per_frame=False, test_start_offset_ms=compare_args.test_start_offset_ms) + exit(cmp_result["max_abs_diff"]) + + parser_compare = subparsers.add_parser("compare", help="Compare two wav files for bitexactness") + parser_compare.add_argument("ref_file") + parser_compare.add_argument("test_file") + parser_compare.add_argument("test_start_offset_ms", default=0, type=int) + parser_compare.set_defaults(func=compare_wrapper) + args = parser.parse_args() args.func(args) diff --git a/tests/conftest.py b/tests/conftest.py index 52b32c7704f98ac37dc6a5d65e46321c1798a7fa..24446c9678fa25d0475979f71ccd65aa21ea2e49 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -508,6 +508,7 @@ class DecoderFrontend: output_path: Path, quiet_mode: Optional[bool] = True, plc_file: Optional[Path] = None, + netsim_profile: Optional[Path] = None, add_option_list: Optional[list] = None, run_dir: Optional[Path] = None, ) -> None: @@ -546,11 +547,43 @@ class DecoderFrontend: try: if not os.path.exists(str(input_bitstream_path) + eid_output_suffix): result = run(eid_command, check=True, cwd=run_dir) - except Exception: - pytest.fail("eid-xor operation failed!") + except Exception as e: + pytest.fail(f"eid-xor operation failed! - {e}") input_bitstream_path += eid_output_suffix + if netsim_profile is not None: + system = platform.system() + + # TODO: centralize this in a utils file + if system == "Windows": + netsim_path = "./scripts/tools/Win32/networkSimulator_g192.exe" + elif system == "Linux": + netsim_path = "./scripts/tools/Linux/networkSimulator_g192" + elif system == "Darwin": + netsim_path = "./scripts/tools/Darwin/networkSimulator_g192" + else: + raise ValueError(f'Wrong system "{system}"!') + + if not os.path.isfile(netsim_path): + raise FileNotFoundError(f"network simulator binary {netsim_path} not found!\n") + netsim_bitstream_path = input_bitstream_path.with_suffix(".netsimout") + tracefile_path = input_bitstream_path.with_suffix(".netsimtrace") + # TODO: need to check if the "1" works with every profile + netsim_command = [netsim_path, netsim_profile, input_bitstream_path, netsim_bitstream_path, tracefile_path, "1"] + print(netsim_command) + try: + run(netsim_command, check=True, cwd=run_dir) + except Exception as e: + pytest.fail(f"netsim operation failed! - {e}") + + input_bitstream_path = netsim_bitstream_path + voip_opt = ["-voip"] + if add_option_list is None: + add_option_list = voip_opt + elif "-voip" not in add_option_list: + add_option_list.extend(voip_opt) + if add_option_list is not None: command.extend(add_option_list) diff --git a/tests/constants.py b/tests/constants.py index 5bce5ac4e32ce795737ec68fdf166740799a36b6..0f985d0b567057b5ad7cd074fd4c7ebb1502ddf5 100644 --- a/tests/constants.py +++ b/tests/constants.py @@ -1,3 +1,9 @@ +import pathlib + +HERE = pathlib.Path(__file__).parent.absolute() +SCRIPTS_DIR = HERE.parent.joinpath("scripts") +TESTV_DIR = SCRIPTS_DIR.joinpath("testv") + # regex patterns for parsing the output from cmp_pcm -> mainly for BASOP ci MLD_PATTERN = r"MLD: ([\d\.]*)" MAX_DIFF_PATTERN = r"MAXIMUM ABS DIFF: (\d*)" diff --git a/tests/test_be_for_jbm_neutral_dly_profile.py b/tests/test_be_for_jbm_neutral_dly_profile.py new file mode 100644 index 0000000000000000000000000000000000000000..64e7773a60f3d2be8fdfdc3dc02d1e7aa0fdc90c --- /dev/null +++ b/tests/test_be_for_jbm_neutral_dly_profile.py @@ -0,0 +1,200 @@ +import pytest +import pathlib +import sys +import re +from tempfile import TemporaryDirectory + +from .constants import TESTV_DIR, SCRIPTS_DIR + +sys.path.append(str(SCRIPTS_DIR)) +from pyaudio3dtools import audiofile, audioarray + + +DTX_ON = "DTX_ON" +DTX_OFF = "DTX_OFF" + + +# TODO: Clarify if this should also be tested with DTX, see #1122 +TESTCASES = [ + # stereo + ["stereo", 32000, "EXT", "DTX_OFF"], + ["stereo", 48000, "MONO", "DTX_OFF"], + ["stereo", 16400, "5_1", "DTX_OFF"], + ["stereo", 256000, "7_1_4", "DTX_OFF"], + # param ISM + ["ISM4", 32000, "BINAURAL_ROOM_REVERB", "DTX_OFF"], + ["ISM3", 24400, "STEREO", "DTX_OFF"], + ["ISM4", 24400, "5_1_2", "DTX_OFF"], + ["ISM3", 32000, "HOA2", "DTX_OFF"], + # discrete ISM + ["ISM3", 64000, "BINAURAL", "DTX_OFF"], + ["ISM1", 32000, "BINAURAL_ROOM_IR", "DTX_OFF"], + ["ISM2", 96000, "7_1", "DTX_OFF"], + ["ISM1", 80000, "MONO", "DTX_OFF"], + ["ISM4", 128000, "FOA", "DTX_OFF"], + # MASA + ["MASA1TC", 24400, "BINAURAL_ROOM_IR", "DTX_OFF"], + ["MASA2TC", 80000, "stereo", "DTX_OFF"], + ["MASA1TC", 16400, "7_1_4", "DTX_OFF"], + ["MASA2TC", 256000, "HOA3", "DTX_OFF"], + ["MASA1TC", 128000, "EXT", "DTX_OFF"], + # MC + # McMasa + ["MC_5_1", 16400, "BINAURAL_ROOM_IR", "DTX_OFF"], + ["MC_7_1_4", 80000, "mono", "DTX_OFF"], + ["MC_5_1_2", 24400, "EXT", "DTX_OFF"], + # paramMC + ["MC_5_1_2", 48000, "BINAURAL", "DTX_OFF"], + ["MC_7_1", 80000, "EXT", "DTX_OFF"], + ["MC_7_1_4", 128000, "FOA", "DTX_OFF"], + # paramUpmix + ["MC_7_1_4", 160000, "stereo", "DTX_OFF"], + # discrete MC + ["MC_5_1_2", 512000, "BINAURAL_ROOM_REVERB", "DTX_OFF"], + ["MC_7_1", 128000, "EXT", "DTX_OFF"], + ["MC_7_1_4", 256000, "5_1", "DTX_OFF"], + # SBA + ["HOA3", 64000, "BINAURAL", "DTX_OFF"], + ["FOA", 256000, "BINAURAL_ROOM_REVERB", "DTX_OFF"], + ["HOA2", 80000, "EXT", "DTX_OFF"], + ["HOA3", 512000, "5_1_4", "DTX_OFF"], + ["FOA", 80000, "stereo", "DTX_OFF"], + # OMASA + ["OMASA_ISM1", 512000, "BINAURAL", "DTX_OFF"], + ["OMASA_ISM2", 24400, "MONO", "DTX_OFF"], + ["OMASA_ISM3", 80000, "7_1_4", "DTX_OFF"], + ["OMASA_ISM4", 64000, "HOA3", "DTX_OFF"], + ["OMASA_ISM2", 32000, "EXT", "DTX_OFF"], + # OSBA + ["OSBA_ISM2_HOA2", 64000, "BINAURAL_ROOM_IR", "DTX_OFF"], + ["OSBA_ISM4_FOA", 512000, "BINAURAL_ROOM_REVERB", "DTX_OFF"], + ["OSBA_ISM3_HOA3", 128000, "EXT", "DTX_OFF"], + ["OSBA_ISM2_HOA3", 96000, "5_1", "DTX_OFF"], + ["OSBA_ISM1_HOA2", 32000, "mono", "DTX_OFF"], +] +DLY_PROFILE = SCRIPTS_DIR.joinpath("dly_error_profiles/dly_error_profile_0.dat") +JBM_NEUTRAL_DELAY_MS = 60 + + +def get_options(in_format, bitrate, dtx): + options = list() + + if dtx: + options.append("-dtx") + + SBA_FORMATS = ["FOA", "HOA2", "HOA3"] + if in_format == "stereo": + options.append("-stereo") + elif (match := re.fullmatch(r"ISM(\d)", in_format)) is not None: + n_ism = int(match.groups()[0]) + options.extend(f"-ism {n_ism}".split()) + for i in range(1, n_ism + 1): + options.append(str(TESTV_DIR.joinpath(f"stvISM{i}.csv"))) + elif (match := re.fullmatch(r"MASA(\d)TC", in_format)) is not None: + n_tcs = int(match.groups()[0]) + options.extend(f"-masa {n_tcs}".split()) + options.append(str(TESTV_DIR.joinpath(f"stv2MASA{n_tcs}TC48c.met"))) + elif (match := re.fullmatch(r"MC_(.*)", in_format)) is not None: + mc_format = match.groups()[0] + options.extend(f"-mc {mc_format}".split()) + elif in_format in SBA_FORMATS: + options.extend(f"-sba {SBA_FORMATS.index(in_format) + 1}".split()) + elif (match := re.fullmatch(r"OMASA_ISM(\d)", in_format)) is not None: + n_ism = int(match.groups()[0]) + n_tcs = 2 + options.extend(f"-ism_masa {n_ism} {n_tcs}".split()) + for i in range(1, n_ism + 1): + options.append(str(TESTV_DIR.joinpath(f"stvISM{i}.csv"))) + options.append( + str(TESTV_DIR.joinpath(f"stvOMASA_{n_ism}ISM_1MASA{n_tcs}TC48c.met")) + ) + elif (match := re.fullmatch(r"OSBA_ISM(\d)_(.*)", in_format)) is not None: + n_ism = int(match.groups()[0]) + sba_order_str = match.groups()[1] + n_sba = 1 if sba_order_str == "FOA" else str(sba_order_str[-1]) + options.extend(f"-ism_sba {n_ism}, -{n_sba}".split()) + for i in range(1, n_ism + 1): + options.append(str(TESTV_DIR.joinpath(f"stvISM{i}.csv"))) + + return options + + +INPUT_FILES = { + "stereo": "stvST48n.wav", + "ISM1": "stv1ISM48s.wav", + "ISM2": "stv2ISM48s.wav", + "ISM3": "stv3ISM48s.wav", + "ISM4": "stv4ISM48n.wav", + "MASA1TC": "stv2MASA1TC48c.wav", + "MASA2TC": "stv2MASA2TC48c.wav", + "MC_5_1": "stv51MC48c.wav", + "MC_5_1_2": "stv512MC48c.wav", + "MC_5_1_4": "stv514MC48c.wav", + "MC_7_1": "stv71MC48c.wav", + "MC_7_1_4": "stv714MC48c.wav", + "FOA": "stvFOA48c.wav", + "HOA2": "stv2OA48c.wav", + "HOA3": "stv3OA48c.wav", + "OMASA_ISM1": "stvOMASA_1ISM_2MASA2TC48c.wav", + "OMASA_ISM2": "stvOMASA_2ISM_2MASA2TC48c.wav", + "OMASA_ISM3": "stvOMASA_3ISM_2MASA2TC48c.wav", + "OMASA_ISM4": "stvOMASA_4ISM_2MASA2TC48c.wav", + "OSBA_ISM2_HOA2": "stvOSBA_2ISM_2OA48c.wav", + "OSBA_ISM4_HOA2": "stvOSBA_4ISM_2OA48c.wav", + "OSBA_ISM4_FOA": "stvOSBA_4ISM_FOA48c.wav", + "OSBA_ISM3_HOA3": "stvOSBA_3ISM_3OA48c.wav", + "OSBA_ISM2_HOA3": "stvOSBA_2ISM_3OA48c.wav", + "OSBA_ISM1_HOA2": "stvOSBA_1ISM_2OA48c.wav", +} + + +@pytest.mark.parametrize("in_format,bitrate,out_format,dtx", TESTCASES) +def test_be_for_jbm_neutral_dly_profile( + in_format, bitrate, out_format, dtx, dut_encoder_frontend, dut_decoder_frontend +): + with TemporaryDirectory() as tmp_dir: + tmp_dir = pathlib.Path(tmp_dir) + + # run encoder + bitstream_file = tmp_dir.joinpath(f"{in_format}.192").absolute() + sampling_rate_khz = 48 + input_file = TESTV_DIR.joinpath(INPUT_FILES[in_format]) + options = get_options(in_format, bitrate, dtx == DTX_ON) + dut_encoder_frontend.run( + bitrate, + sampling_rate_khz, + input_file, + bitstream_file, + add_option_list=options, + run_dir=tmp_dir, + ) + + # run decoder without network simulation + output = tmp_dir.joinpath(f"{in_format}-{bitrate}-{out_format}.wav").absolute() + dut_decoder_frontend.run(out_format, sampling_rate_khz, bitstream_file, output) + + # run decoder with network simulation + output_jbm = output.with_suffix(".jbm-0.wav") + dut_decoder_frontend.run( + out_format, + sampling_rate_khz, + bitstream_file, + output_jbm, + netsim_profile=DLY_PROFILE, + ) + + # compare no-jbm and jbm output + x, _ = audiofile.readfile(output) + x_jbm, _ = audiofile.readfile(output_jbm) + + # strip jbm delay + # TODO: this may need to be adapted to handle variable offsets based on outcome of #1122 + cmp_result = audioarray.compare( + x, + x_jbm, + fs=sampling_rate_khz * 1000, + per_frame=False, + test_start_offset_ms=JBM_NEUTRAL_DELAY_MS, + ) + if not cmp_result["bitexact"]: + pytest.fail("Difference between no jbm and zero-delay jbm decoding!")