diff --git a/lib_com/options.h b/lib_com/options.h index 52201fffdc82dd7b3f4343a641e3e81fdbfff93a..0a1892dc0cf1d5c7d66342215d00c978f6ed2df3 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -175,6 +175,8 @@ #define NONBE_FIX_1180_HQMDCT_PHECU_LT_MUTING /* Ericsson: issue 1180, corrected long term mute loop attnuation after 200ms in PhECU-PLC */ #define NONBE_FIX_1297_SPAR_JBM_MEM_SAN /*Dolby: issue 1297, SPAR + JBM + BR switch memory sanitizer*/ #define NONBE_1289_STEREO_SW_TO_MONO /* VA: issue 1289: Fix glitch when stereo signal is decoded to mono n TD->DFT switching */ +#define NONBE_1122_JBM_FIX_PLAYOUT_DELAY_IN_DTX /* FhG: Avoid JBM ignoring safety margin and setting playout delay to 0 during DTX */ +#define NONBE_1122_KEEP_EVS_MODE_UNCHANGED /* FhG: Disables fix for issue 1122 in EVS mode to keep BE tests green. This switch should be removed once the 1122 fix is added to EVS via a CR. */ #define NONBE_1296_TDREND_ITD_OUT_OF_BOUNDS_ACCESS /* Eri: issue 1296: ITD resampling can occasionally read out of bounds, especially when the requested subframes are short (1.25 ms). Seen for headtracking+JBM. */ /* ##################### End NON-BE switches ########################### */ diff --git a/lib_dec/jbm_jb4_jmf.c b/lib_dec/jbm_jb4_jmf.c index 721a6937d0113ef4d7b2d2cf216a4f3843badb22..9abb3d97324e6fa939c77290f4e22e4774c16d33 100644 --- a/lib_dec/jbm_jb4_jmf.c +++ b/lib_dec/jbm_jb4_jmf.c @@ -208,7 +208,7 @@ int16_t JB4_JMF_PushPacket( rtpTimeDiff = (int32_t) ( rtpTimeStamp - h->lastRtpTimeStamp ); sysTimeDiff = sysTime - h->lastSysTime; - offset = sysTime - rtpTimeStamp; + offset = (int32_t) sysTime - (int32_t) rtpTimeStamp; /* get the delay (yes, signed!!!!) */ delay = sysTimeDiff - rtpTimeDiff + h->lastDelay; diff --git a/lib_dec/jbm_jb4sb.c b/lib_dec/jbm_jb4sb.c index c1e728e103f3ad24c9aaca783238674981aa87c2..ad3ba459a6c4f5209525ae9de41398cb13465765 100644 --- a/lib_dec/jbm_jb4sb.c +++ b/lib_dec/jbm_jb4sb.c @@ -199,6 +199,9 @@ struct JB4 JB4_DATAUNIT_HANDLE freeMemorySlots[MAX_JBM_SLOTS]; uint16_t nFreeMemorySlots; /*@} */ +#ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED + bool evsMode; +#endif }; /* JB4 */ @@ -293,6 +296,9 @@ ivas_error JB4_Create( h->freeMemorySlots[iter] = &h->memorySlots[iter]; } h->nFreeMemorySlots = MAX_JBM_SLOTS; +#ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED + h->evsMode = false; +#endif *ph = h; return IVAS_ERR_OK; @@ -369,6 +375,12 @@ ivas_error JB4_Init( return IVAS_ERR_OK; } +#ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED +void JB4_TMP_SetEvsCompatFlag( JB4_HANDLE h ) +{ + h->evsMode = true; +} +#endif /* Returns a memory slot to store a new data unit */ JB4_DATAUNIT_HANDLE JB4_AllocDataUnit( @@ -671,10 +683,22 @@ static void JB4_targetPlayoutDelay( *targetStartUp = ( *targetMin + *targetMax ) / 2; } +#ifdef NONBE_1122_JBM_FIX_PLAYOUT_DELAY_IN_DTX +#ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED + if ( !h->evsMode ) + { +#endif + *targetDtx = JB4_MAX( *targetDtx, (uint32_t) h->safetyMargin ); +#ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED + } +#endif + *targetStartUp = JB4_MAX( *targetStartUp, (uint32_t) h->safetyMargin ); +#else if ( *targetStartUp < 60 ) { *targetStartUp = 60; } +#endif return; } diff --git a/lib_dec/jbm_jb4sb.h b/lib_dec/jbm_jb4sb.h index 3d48723495cbf32fe3b37a358acda235a2a6d1af..8155d66ae9fafd953e854cb501aeab433b8fb28d 100644 --- a/lib_dec/jbm_jb4sb.h +++ b/lib_dec/jbm_jb4sb.h @@ -86,6 +86,10 @@ void JB4_Destroy( JB4_HANDLE *ph ); ivas_error JB4_Init( JB4_HANDLE h, const int16_t safetyMargin ); +#ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED +void JB4_TMP_SetEvsCompatFlag( JB4_HANDLE h ); +#endif + JB4_DATAUNIT_HANDLE JB4_AllocDataUnit( JB4_HANDLE h ); void JB4_FreeDataUnit( JB4_HANDLE h, JB4_DATAUNIT_HANDLE dataUnit ); diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index 7b4eb08f995ca85dec06ceb3c7af17a13fcd69e0..70036f9465e4ab4a661fa562d48030d49b35798f 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -793,6 +793,12 @@ ivas_error IVAS_DEC_EnableVoIP( { return IVAS_ERR_FAILED_ALLOC; } +#ifdef NONBE_1122_KEEP_EVS_MODE_UNCHANGED + if ( hIvasDec->mode == IVAS_DEC_MODE_EVS ) + { + JB4_TMP_SetEvsCompatFlag( hIvasDec->hVoIP->hJBM ); + } +#endif /* init flush buffer if necessary (only needed for binaural)*/ if ( hIvasDec->flushbuffer == NULL && ( hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL || hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR || hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ) diff --git a/scripts/config/self_test.prm b/scripts/config/self_test.prm index 5b3df2cf08b1e7962b1076ee4a65a748c408e5c3..f996b81602735cd20dcba0c9f06d77ef46139c22 100644 --- a/scripts/config/self_test.prm +++ b/scripts/config/self_test.prm @@ -1578,6 +1578,25 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_dec -non_diegetic_pan 80 STEREO 48 bit testv/stv1ISM48s.pcm_ISM_32000_48-48_STEREO_NON-DIEGETIC-PAN_80.tst +// stereo at 32 kbps, 48 kHz in, 32 kHz out, DTX on, JBM Prof 0 +../IVAS_cod -stereo -dtx 32000 48 testv/stvST48n.wav bit +networkSimulator_g192 ../scripts/dly_error_profiles/dly_error_profile_0.dat bit netsimoutput tracefile_sim 2 0 +../IVAS_dec -Tracefile tracefile_dec -VOIP STEREO 32 netsimoutput testv/stvST48n.wav_stereo_32000_48-32_DTX_JBM0.tst + +// 4 ISm with metadata at 64 kbps, 48 kHz in, 48 kHz out, DTX on, EXT out, JBM Prof 0 +../IVAS_cod -dtx -ism 4 testv/stvISM1.csv testv/stvISM2.csv testv/stvISM3.csv testv/stvISM4.csv 64000 48 testv/stv4ISM48n.wav bit +networkSimulator_g192 ../scripts/dly_error_profiles/dly_error_profile_0.dat bit netsimoutput tracefile_sim 2 0 +../IVAS_dec -Tracefile tracefile_dec -VOIP EXT 48 netsimoutput testv/stv4ISM48s.wav_64000_48-48_EXT_JBM0.tst + +// MASA 1dir 1TC at 13.2 kbps, 48kHz in, 32kHz out, DTX on, EXT out, JBM Prof 0 +../IVAS_cod -dtx -masa 1 testv/stv1MASA1TC48n.met 13200 48 testv/stv1MASA1TC48n.wav bit +networkSimulator_g192 ../scripts/dly_error_profiles/dly_error_profile_0.dat bit netsimoutput tracefile_sim 2 0 +../IVAS_dec -Tracefile tracefile_dec -VOIP EXT 32 netsimoutput testv/stv1MASA1TC48n.wav_sw_48-32_EXT_JBM0.tst + +// SBA at 24.4 kbps, 32kHz in, 32kHz out, DTX on, BINAURAL out, JBM 0 +../IVAS_cod -sba 3 -dtx 24400 32 testv/stv3OA32c_cut_.004.wav bit +networkSimulator_g192 ../scripts/dly_error_profiles/dly_error_profile_0.dat bit netsimoutput tracefile_sim 2 0 +../IVAS_dec -Tracefile tracefile_dec -VOIP BINAURAL 32 netsimoutput testv/stv3OA32c.wav_SBA_24400_32-32_DTX_Binaural_JBM0.tst // stereo at 48 kbps, 16 kHz in, 16 kHz out, DTX on, JBM Prof 5 ../IVAS_cod -stereo -dtx 48000 16 testv/stvST16n.wav bit diff --git a/tests/test_be_for_jbm_neutral_dly_profile.py b/tests/test_be_for_jbm_neutral_dly_profile.py index 61bb168a2fe0cc14a4c7adcce7522328db278e02..ec67ab22a3ae312d9ffbb9061b9c2338325259be 100644 --- a/tests/test_be_for_jbm_neutral_dly_profile.py +++ b/tests/test_be_for_jbm_neutral_dly_profile.py @@ -2,6 +2,7 @@ import pytest import pathlib import sys import re +import numpy as np from tempfile import TemporaryDirectory from .constants import TESTV_DIR, SCRIPTS_DIR @@ -14,69 +15,73 @@ DTX_ON = "DTX_ON" DTX_OFF = "DTX_OFF" -# TODO: Clarify if this should also be tested with DTX, see #1122 -TESTCASES = [ +# testcases where DTX is supported +TESTCASES_WITH_DTX = [ # stereo - ["stereo", 32000, "EXT", "DTX_OFF"], - ["stereo", 48000, "MONO", "DTX_OFF"], - ["stereo", 16400, "5_1", "DTX_OFF"], - ["stereo", 256000, "7_1_4", "DTX_OFF"], + ["stereo", 32000, "EXT"], + ["stereo", 48000, "MONO"], + ["stereo", 16400, "5_1"], + ["stereo", 256000, "7_1_4"], # 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"], + ["ISM4", 32000, "BINAURAL_ROOM_REVERB"], + ["ISM3", 24400, "STEREO"], + ["ISM4", 24400, "5_1_2"], + ["ISM3", 32000, "HOA2"], # 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"], + ["ISM3", 64000, "BINAURAL"], + ["ISM2", 96000, "7_1"], + ["ISM1", 80000, "MONO"], + ["ISM4", 128000, "FOA"], # 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"], + ["MASA1TC", 24400, "BINAURAL_ROOM_IR"], + ["MASA2TC", 80000, "stereo"], + ["MASA1TC", 16400, "7_1_4"], + ["MASA2TC", 256000, "HOA3"], + ["MASA1TC", 128000, "EXT"], + # SBA + ["HOA3", 64000, "BINAURAL"], + ["HOA2", 80000, "EXT"], + ["FOA", 13200, "stereo"], +] + +# testcases with no DTX support +TESTCASES_NO_DTX = [ + # SBA + ["FOA", 256000, "BINAURAL_ROOM_REVERB"], + ["HOA3", 512000, "5_1_4"], # 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"], + ["MC_5_1", 16400, "BINAURAL_ROOM_IR"], + ["MC_7_1_4", 80000, "mono"], + ["MC_5_1_2", 24400, "EXT"], # paramMC - ["MC_5_1_2", 48000, "BINAURAL", "DTX_OFF"], - ["MC_7_1", 80000, "EXT", "DTX_OFF"], - ["MC_7_1_4", 128000, "FOA", "DTX_OFF"], + ["MC_5_1_2", 48000, "BINAURAL"], + ["MC_7_1", 80000, "EXT"], + ["MC_7_1_4", 128000, "FOA"], # paramUpmix - ["MC_7_1_4", 160000, "stereo", "DTX_OFF"], + ["MC_7_1_4", 160000, "stereo"], # 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"], + ["MC_5_1_2", 512000, "BINAURAL_ROOM_REVERB"], + ["MC_7_1", 128000, "EXT"], + ["MC_7_1_4", 256000, "5_1"], # 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"], + ["OMASA_ISM1", 512000, "BINAURAL"], + ["OMASA_ISM2", 24400, "MONO"], + ["OMASA_ISM3", 80000, "7_1_4"], + ["OMASA_ISM4", 64000, "HOA3"], + ["OMASA_ISM2", 32000, "EXT"], # 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"], + ["OSBA_ISM2_HOA2", 64000, "BINAURAL_ROOM_IR"], + ["OSBA_ISM4_FOA", 512000, "BINAURAL_ROOM_REVERB"], + ["OSBA_ISM3_HOA3", 128000, "EXT"], + ["OSBA_ISM2_HOA3", 96000, "5_1"], + ["OSBA_ISM1_HOA2", 32000, "mono"], ] 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): +def get_options(in_format, dtx): options = list() if dtx: @@ -132,9 +137,9 @@ INPUT_FILES = { "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", + "FOA": "stvFOA48c_cut_.004.wav", + "HOA2": "stv2OA48c_cut_.004.wav", + "HOA3": "stv3OA48c_cut_.004.wav", "OMASA_ISM1": "stvOMASA_1ISM_2MASA2TC48c.wav", "OMASA_ISM2": "stvOMASA_2ISM_2MASA2TC48c.wav", "OMASA_ISM3": "stvOMASA_3ISM_2MASA2TC48c.wav", @@ -147,19 +152,98 @@ INPUT_FILES = { "OSBA_ISM1_HOA2": "stvOSBA_1ISM_2OA48c.wav", } +OUTPUT_FOLDER_IF_KEEP_FILES = pathlib.Path(__file__).parent.joinpath("output-jbm-be") +OUTPUT_FOLDER_IF_KEEP_FILES_NO_JBM = OUTPUT_FOLDER_IF_KEEP_FILES.joinpath("no-jbm") +OUTPUT_FOLDER_IF_KEEP_FILES_NEUTRAL = OUTPUT_FOLDER_IF_KEEP_FILES.joinpath( + "neutral-profile" +) + + +@pytest.mark.parametrize( + "in_format,bitrate,out_format", TESTCASES_NO_DTX + TESTCASES_WITH_DTX +) +def test_be_for_jbm_neutral_dly_profile_no_dtx( + in_format, + bitrate, + out_format, + dut_encoder_frontend, + dut_decoder_frontend, + keep_files, +): + run_test( + in_format, + bitrate, + out_format, + DTX_OFF, + dut_encoder_frontend, + dut_decoder_frontend, + keep_files, + ) + -@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 +@pytest.mark.parametrize("in_format,bitrate,out_format", TESTCASES_WITH_DTX) +def test_be_for_jbm_neutral_dly_profile_with_dtx( + in_format, + bitrate, + out_format, + dut_encoder_frontend, + dut_decoder_frontend, + keep_files, ): + run_test( + in_format, + bitrate, + out_format, + DTX_ON, + dut_encoder_frontend, + dut_decoder_frontend, + keep_files, + ) + + +def run_test( + in_format, + bitrate, + out_format, + dtx, + dut_encoder_frontend, + dut_decoder_frontend, + keep_files, +): + if keep_files: + OUTPUT_FOLDER_IF_KEEP_FILES_NEUTRAL.mkdir(exist_ok=True, parents=True) + OUTPUT_FOLDER_IF_KEEP_FILES_NO_JBM.mkdir(exist_ok=True, parents=True) + with TemporaryDirectory() as tmp_dir: tmp_dir = pathlib.Path(tmp_dir) + output_dir_no_jbm = ( + OUTPUT_FOLDER_IF_KEEP_FILES_NO_JBM if keep_files else tmp_dir + ) + output_dir_neutral = ( + OUTPUT_FOLDER_IF_KEEP_FILES_NEUTRAL if keep_files else 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) + + # for DTX cases append 5 frames of white noise to the file + # this should make sure that there is no DTX segment at the very end of the signal + # DTX at the end can still cause length differences which are fine to exist, but make the comparison hard to handle + # EXCEPTION (of course there is one...): MASA. We cant append to the signal without appending some MD. Luckily, this problem does not occur with the MASA testvectors + if dtx == DTX_ON and "MASA" not in in_format: + input_signal, fs = audiofile.readfile(input_file) + noise_len = fs // 50 * 5 + noise_amplitude = np.max(input_signal) + noise = ( + np.random.random((noise_len, input_signal.shape[1])) * noise_amplitude + ) + input_signal = np.concatenate([input_signal, noise]) + input_file = tmp_dir.joinpath(f"{input_file.stem}-plus-noise.wav") + audiofile.writefile(input_file, input_signal, fs) + + options = get_options(in_format, dtx == DTX_ON) dut_encoder_frontend.run( bitrate, sampling_rate_khz, @@ -170,11 +254,13 @@ def test_be_for_jbm_neutral_dly_profile( ) # run decoder without network simulation - output = tmp_dir.joinpath(f"{in_format}-{bitrate}-{out_format}.wav").absolute() + output = output_dir_no_jbm.joinpath( + f"{in_format}-{bitrate}-{out_format}-{dtx}.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") + output_jbm = output_dir_neutral.joinpath(output.with_suffix(".jbm-0.wav").name) dut_decoder_frontend.run( out_format, sampling_rate_khz, @@ -188,7 +274,6 @@ def test_be_for_jbm_neutral_dly_profile( 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, @@ -197,4 +282,6 @@ def test_be_for_jbm_neutral_dly_profile( test_start_offset_ms=JBM_NEUTRAL_DELAY_MS, ) if not cmp_result["bitexact"]: - pytest.fail(f"Difference between no jbm and zero-delay jbm decoding found! Max abs diff: {cmp_result['max_abs_diff']}") + pytest.fail( + f"Difference between no jbm and zero-delay jbm decoding found! Max abs diff: {cmp_result['max_abs_diff']}" + )