From 1d048aefc64a7c03d03362f9acfd162fd7762833 Mon Sep 17 00:00:00 2001 From: Stefan Doehla Date: Thu, 28 May 2026 10:15:41 +0200 Subject: [PATCH 1/7] Delay-and-error profile to frame-erasure pattern conversion tool. Reads a delay/error profile (one entry per packet, giving network delay in ms and a loss flag) and emits an error pattern suitable for use with the STL `eid-xor` tool. Supports both fixed-delay and bounded-loss-rate jitter buffer management emulation modes. Provided by Fraunhofer IIS via 3GPP Tdoc S4-121077 in support of the EVS processing plan. --- CMakeLists.txt | 1 + src/dlyerr_2_errpat/CMakeLists.txt | 1 + src/dlyerr_2_errpat/dlyerr_2_errpat.c | 265 ++++++++++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 src/dlyerr_2_errpat/CMakeLists.txt create mode 100644 src/dlyerr_2_errpat/dlyerr_2_errpat.c diff --git a/CMakeLists.txt b/CMakeLists.txt index cbd02f45..5f0208d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,7 @@ add_custom_target(test-verbose COMMAND ${CMAKE_CTEST_COMMAND} --verbose) add_subdirectory(src/basop/test_framework) add_subdirectory(src/basop/flc) add_subdirectory(src/bs1770demo) +add_subdirectory(src/dlyerr_2_errpat) add_subdirectory(src/eid) add_subdirectory(src/esdru) add_subdirectory(src/fir) diff --git a/src/dlyerr_2_errpat/CMakeLists.txt b/src/dlyerr_2_errpat/CMakeLists.txt new file mode 100644 index 00000000..15a0f3ae --- /dev/null +++ b/src/dlyerr_2_errpat/CMakeLists.txt @@ -0,0 +1 @@ +add_executable(dlyerr_2_errpat dlyerr_2_errpat.c) diff --git a/src/dlyerr_2_errpat/dlyerr_2_errpat.c b/src/dlyerr_2_errpat/dlyerr_2_errpat.c new file mode 100644 index 00000000..ec4b228f --- /dev/null +++ b/src/dlyerr_2_errpat/dlyerr_2_errpat.c @@ -0,0 +1,265 @@ +/*---------------------------------------------------------------------------* + * Delay-and-error profile to FER pattern conversion tool, V1.1 * + * ------------------------------------------ * + * (C) 2012 Fraunhofer IIS. All rights reserved. * + * * + * =============================================================== * + * COPYRIGHT NOTE: This source code, and all of its derivations, * + * is subject to the "ITU-T General Public License". Please have * + * it read in the distribution disk, or in the ITU-T Recommendation * + * G.191 on "SOFTWARE TOOLS FOR SPEECH AND AUDIO CODING STANDARDS". * + * See LICENSE.md in the top-level directory for terms. * + * =============================================================== * + * * + * Fraunhofer IIS makes no representation nor warranty in regard to * + * the accuracy, completeness or sufficiency of The Software, nor * + * shall Fraunhofer IIS be held liable for any damages whatsoever * + * relating to use of said Software. * + *---------------------------------------------------------------------------*/ + + +#include +#include +#include +#include + +#ifndef WIN32 +#include /* commandline tool */ +#include "getopt.h" +#else +#include +#endif + +static void usage() +{ + fprintf( stdout,"\nConvert a delay and error profile to an error pattern\n" ); + fprintf( stdout,"\nValid commandline switches:\n" ); + fprintf( stdout,"-i \n" ); + fprintf( stdout,"-o \n" ); + fprintf( stdout,"-L \n" ); + fprintf( stdout,"-s \n" ); + fprintf( stdout,"-f [1;2]\n" ); + fprintf( stdout,"-l \n" ); + fprintf( stdout,"-b use byte-oriented G.192 format (0x21 okay, 0x20 lost)\n" ); + fprintf( stdout,"-w use word-oriented G.192 format (0x6b21 okay, 0x6b20 lost)\n" ); + fprintf( stdout,"-c use LF for text format to have one entry per line - was default in V1.0\n" ); + fprintf( stdout,"-d \n" ); + fprintf( stdout," either -l or -d parameter must be supplied (not both!) and a valid inputfile\n"); +} + +int main( int argc, char** argv ) +{ + int c, i; + char *infilename = NULL; + char *outfilename = NULL; + float late_loss_rate = 0.0f; + unsigned int constant_delay_ms = 0; + int shift = 0; + int length = 7500; + unsigned int framesPerPacket = 1; /* no aggregation by default */ + int useG192 = 0; + int useG192WordOriented = 0; + int useLF = 0; + + char line [64] = {0}; + unsigned int delayCount [2001] = {0}; /* [-1;1999] ms */ + unsigned int line_cnt = 0; + + FILE * infile = NULL; + FILE * outfile = NULL; + + while ( (c = getopt (argc, argv, "i:o:l:d:L:s:f:bwc?")) != -1 ) { + switch ( c ) + { + case 'i': + infilename = optarg; + break; + case 'o': + outfilename = optarg; + break; + case 'l': + late_loss_rate = atof(optarg); + break; + case 'd': + constant_delay_ms = atoi(optarg); + break; + case 's': + shift = atoi(optarg); + break; + case 'L': + length = atoi(optarg); + break; + case 'f': + framesPerPacket = atoi(optarg); + break; + case 'b': + useG192 = 1; + break; + case 'w': + useG192 = 1; + useG192WordOriented = 1; + break; + case 'c': + useLF = 1; + break; + case '?': + usage(); + return 0; + default: + usage(); + abort(); + } + } + + if((infilename == NULL) || ((late_loss_rate == 0) && (constant_delay_ms == 0)) || + framesPerPacket == 0U || framesPerPacket > 2U) + { + usage(); + return -1; + } + + infile = fopen(infilename, "r"); + + if(!infile) + { + fprintf(stderr, "unable to open %s\n", infilename); + return -2; + } + + if(outfilename) + { + outfile = fopen(outfilename, "w"); + + if(!outfile) + { + fprintf(stderr, "unable to open %s\n", outfilename); + goto cleanup; + } + } + + /* read offset to Nirvana */ + for(i=0; i 1999)) + { + fprintf(stderr, "value in line %i out of range - aborting\n", line_cnt); + abort(); + } + if(delay_ms == -1) + delayCount[2000]++; + else + delayCount[delay_ms]++; + } + + if(late_loss_rate) + { + unsigned int late_loss_cnt = 0; + for(i=1999; i>=0; i--) + { + float current_late_loss_rate; + late_loss_cnt += delayCount[i]; + current_late_loss_rate = ((float)late_loss_cnt * 100.0f) / (float)line_cnt; + if(current_late_loss_rate > late_loss_rate) + { + constant_delay_ms = i; + fprintf(stdout, "selected %ims to stay below %f late loss\n", i, late_loss_rate); + break; + } + } + } + + /**** emulate constant delay JBM with given delay ****/ + fseek(infile, 0, SEEK_SET); + + /* read offset to nirvana, again */ + for(i=0; i constant_delay_ms) + { + late_loss_cnt++; + if(outfile) + { + for( iFramePerPacket = 0; iFramePerPacket != framesPerPacket; ++iFramePerPacket ) + fprintf(outfile, "%s", useG192 ? useG192WordOriented ? " k" : " " : useLF ? "1\n" : "1"); + } + } + else + { + if(outfile) + { + for( iFramePerPacket = 0; iFramePerPacket != framesPerPacket; ++iFramePerPacket ) + fprintf(outfile, "%s", useG192 ? useG192WordOriented ? "!k" : "!" : useLF ? "0\n" : "0"); + } + } + } + + fprintf(stdout, "#processed delay and error values: %i\n", line_cnt); + fprintf(stdout, "network loss rate: %.3f%%\n", ((float)network_loss_cnt * 100.0f) / (float)line_cnt); + fprintf(stdout, "late loss rate: %.3f%%\n", ((float)late_loss_cnt * 100.0f) / (float)line_cnt); + fprintf(stdout, "distorted frames: %d\n", framesPerPacket * (network_loss_cnt+late_loss_cnt) ); + } + +cleanup: + fclose(infile); + if(outfile) + fclose(outfile); + + return 0; +} From acc06890ce9fb23ebd809ccac1f228142bbe51da Mon Sep 17 00:00:00 2001 From: Stefan Doehla Date: Thu, 28 May 2026 10:22:31 +0200 Subject: [PATCH 2/7] replaced getopt by STL style arg parsing. Add README.md --- src/dlyerr_2_errpat/README.md | 59 +++++++++++++++++++ src/dlyerr_2_errpat/dlyerr_2_errpat.c | 85 ++++++++++++++------------- 2 files changed, 102 insertions(+), 42 deletions(-) create mode 100644 src/dlyerr_2_errpat/README.md diff --git a/src/dlyerr_2_errpat/README.md b/src/dlyerr_2_errpat/README.md new file mode 100644 index 00000000..0780a12c --- /dev/null +++ b/src/dlyerr_2_errpat/README.md @@ -0,0 +1,59 @@ + ============================================================= + COPYRIGHT NOTE: This source code, and all of its derivations, + is subject to the "ITU-T General Public License". Please have + it read in the distribution disk, or in the ITU-T + Recommendation G.191 on "SOFTWARE TOOLS FOR SPEECH AND AUDIO + CODING STANDARDS". + ============================================================= + +# dlyerr_2_errpat + +Delay-and-error profile to frame-erasure pattern conversion tool. Reads a +delay/error profile (one entry per packet, giving network delay in ms and a +loss flag) and emits an error pattern suitable for use with the STL +`eid-xor` tool. Supports both fixed-delay and bounded-loss-rate jitter +buffer management emulation modes. + +Provided by Fraunhofer IIS via 3GPP Tdoc S4-121077 (TSGS4#70, Chicago, +13–17 Aug 2012), in support of the EVS reference codec processing plan. + +## Source files + + dlyerr_2_errpat.c: Tool source and main(); single-file program. + +## Usage + + dlyerr_2_errpat [options] + + -i delay/error profile (required) + -o error pattern (required) + -L output length in frames + -s shift/offset in frames into the profile + -f 1 or 2 + -l bounded-loss-rate mode, percent + -d constant-JBM-delay mode, milliseconds + -b byte-oriented G.192 format (0x21 ok, 0x20 lost) + -w word-oriented G.192 (0x6b21 ok, 0x6b20 lost) + -c append LF in text format (one entry per line; + was the default in V1.0) + +Exactly one of `-l` or `-d` must be supplied. + +## Examples (from S4-121077) + +Apply MTSI delay/error profile 1, 2, or 3 (fixed JBM delay) to a G.192 +bitstream: + + dlyerr_2_errpat -d 200 -f 1 -w -s YYY -i dly_err_profile_XXX.dat -o epXXX.g192 + eid-xor -fer g192bsin epXXX.g192 g192bsout + +Profiles 4 or 6 (bounded loss rate, 1 frame/packet): + + dlyerr_2_errpat -l 1 -f 1 -w -s YYY -i dly_err_profile_XXX.dat -o epXXX.g192 + +Profile 5 (bounded loss rate, 2 frames/packet): + + dlyerr_2_errpat -l 1 -f 2 -w -s YYY -i dly_err_profile_5.dat -o ep5.g192 + +`YYY` is a random offset into the profile (see the STL `random` tool for +generating reproducible offsets). diff --git a/src/dlyerr_2_errpat/dlyerr_2_errpat.c b/src/dlyerr_2_errpat/dlyerr_2_errpat.c index ec4b228f..f2729714 100644 --- a/src/dlyerr_2_errpat/dlyerr_2_errpat.c +++ b/src/dlyerr_2_errpat/dlyerr_2_errpat.c @@ -23,13 +23,6 @@ #include #include -#ifndef WIN32 -#include /* commandline tool */ -#include "getopt.h" -#else -#include -#endif - static void usage() { fprintf( stdout,"\nConvert a delay and error profile to an error pattern\n" ); @@ -49,7 +42,7 @@ static void usage() int main( int argc, char** argv ) { - int c, i; + int i; char *infilename = NULL; char *outfilename = NULL; float late_loss_rate = 0.0f; @@ -68,48 +61,56 @@ int main( int argc, char** argv ) FILE * infile = NULL; FILE * outfile = NULL; - while ( (c = getopt (argc, argv, "i:o:l:d:L:s:f:bwc?")) != -1 ) { - switch ( c ) - { - case 'i': - infilename = optarg; - break; - case 'o': - outfilename = optarg; - break; - case 'l': - late_loss_rate = atof(optarg); - break; - case 'd': - constant_delay_ms = atoi(optarg); - break; - case 's': - shift = atoi(optarg); - break; - case 'L': - length = atoi(optarg); - break; - case 'f': - framesPerPacket = atoi(optarg); - break; - case 'b': + while (argc > 1 && argv[1][0] == '-') + if (strcmp (argv[1], "-i") == 0) { + infilename = argv[2]; + argc -= 2; + argv += 2; + } else if (strcmp (argv[1], "-o") == 0) { + outfilename = argv[2]; + argc -= 2; + argv += 2; + } else if (strcmp (argv[1], "-l") == 0) { + late_loss_rate = atof (argv[2]); + argc -= 2; + argv += 2; + } else if (strcmp (argv[1], "-d") == 0) { + constant_delay_ms = atoi (argv[2]); + argc -= 2; + argv += 2; + } else if (strcmp (argv[1], "-s") == 0) { + shift = atoi (argv[2]); + argc -= 2; + argv += 2; + } else if (strcmp (argv[1], "-L") == 0) { + length = atoi (argv[2]); + argc -= 2; + argv += 2; + } else if (strcmp (argv[1], "-f") == 0) { + framesPerPacket = atoi (argv[2]); + argc -= 2; + argv += 2; + } else if (strcmp (argv[1], "-b") == 0) { useG192 = 1; - break; - case 'w': + argc--; + argv++; + } else if (strcmp (argv[1], "-w") == 0) { useG192 = 1; useG192WordOriented = 1; - break; - case 'c': + argc--; + argv++; + } else if (strcmp (argv[1], "-c") == 0) { useLF = 1; - break; - case '?': + argc--; + argv++; + } else if (strcmp (argv[1], "-?") == 0 || strstr (argv[1], "-help")) { usage(); return 0; - default: + } else { + fprintf (stderr, "ERROR! Invalid option \"%s\" in command line\n\n", argv[1]); usage(); - abort(); + return -1; } - } if((infilename == NULL) || ((late_loss_rate == 0) && (constant_delay_ms == 0)) || framesPerPacket == 0U || framesPerPacket > 2U) From 9fdca6109ccca161b810300e2f7cddabe8f0534f Mon Sep 17 00:00:00 2001 From: Stefan Doehla Date: Fri, 29 May 2026 21:41:55 +0200 Subject: [PATCH 3/7] add ctest unit test for dlyerr_2_errpat --- src/dlyerr_2_errpat/CMakeLists.txt | 24 +++++++++++++++ src/dlyerr_2_errpat/test_data/profile.dat | 30 +++++++++++++++++++ src/dlyerr_2_errpat/test_data/t1_text.ref | 1 + src/dlyerr_2_errpat/test_data/t2_lf.ref | 30 +++++++++++++++++++ src/dlyerr_2_errpat/test_data/t3_word.ref | 1 + src/dlyerr_2_errpat/test_data/t4_lateloss.ref | 1 + 6 files changed, 87 insertions(+) mode change 100644 => 100755 src/dlyerr_2_errpat/CMakeLists.txt create mode 100755 src/dlyerr_2_errpat/test_data/profile.dat create mode 100755 src/dlyerr_2_errpat/test_data/t1_text.ref create mode 100755 src/dlyerr_2_errpat/test_data/t2_lf.ref create mode 100755 src/dlyerr_2_errpat/test_data/t3_word.ref create mode 100755 src/dlyerr_2_errpat/test_data/t4_lateloss.ref diff --git a/src/dlyerr_2_errpat/CMakeLists.txt b/src/dlyerr_2_errpat/CMakeLists.txt old mode 100644 new mode 100755 index 15a0f3ae..d3c6f0a6 --- a/src/dlyerr_2_errpat/CMakeLists.txt +++ b/src/dlyerr_2_errpat/CMakeLists.txt @@ -1 +1,25 @@ add_executable(dlyerr_2_errpat dlyerr_2_errpat.c) + +# default text format, constant delay +add_test(dlyerr_2_errpat1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/dlyerr_2_errpat + -i test_data/profile.dat -o test_data/t1_text.proc -L 30 -d 40) +add_test(dlyerr_2_errpat1-verify ${CMAKE_COMMAND} -E compare_files + test_data/t1_text.ref test_data/t1_text.proc) + +# LF text format +add_test(dlyerr_2_errpat2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/dlyerr_2_errpat + -i test_data/profile.dat -o test_data/t2_lf.proc -L 30 -d 40 -c) +add_test(dlyerr_2_errpat2-verify ${CMAKE_COMMAND} -E compare_files + test_data/t2_lf.ref test_data/t2_lf.proc) + +# word G.192 ASCII format with frame aggregation +add_test(dlyerr_2_errpat3 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/dlyerr_2_errpat + -i test_data/profile.dat -o test_data/t3_word.proc -L 30 -d 40 -w -f 2) +add_test(dlyerr_2_errpat3-verify ${CMAKE_COMMAND} -E compare_files + test_data/t3_word.ref test_data/t3_word.proc) + +# late-loss-rate driven threshold +add_test(dlyerr_2_errpat4 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/dlyerr_2_errpat + -i test_data/profile.dat -o test_data/t4_lateloss.proc -L 30 -l 5.0) +add_test(dlyerr_2_errpat4-verify ${CMAKE_COMMAND} -E compare_files + test_data/t4_lateloss.ref test_data/t4_lateloss.proc) diff --git a/src/dlyerr_2_errpat/test_data/profile.dat b/src/dlyerr_2_errpat/test_data/profile.dat new file mode 100755 index 00000000..22030ae8 --- /dev/null +++ b/src/dlyerr_2_errpat/test_data/profile.dat @@ -0,0 +1,30 @@ +10 +20 +5 +0 +30 +-1 +10 +40 +20 +5 +80 +10 +-1 +30 +20 +10 +5 +0 +60 +20 +10 +30 +-1 +40 +10 +50 +5 +20 +10 +10 diff --git a/src/dlyerr_2_errpat/test_data/t1_text.ref b/src/dlyerr_2_errpat/test_data/t1_text.ref new file mode 100755 index 00000000..58e58f24 --- /dev/null +++ b/src/dlyerr_2_errpat/test_data/t1_text.ref @@ -0,0 +1 @@ +000001000010100000100010010000 \ No newline at end of file diff --git a/src/dlyerr_2_errpat/test_data/t2_lf.ref b/src/dlyerr_2_errpat/test_data/t2_lf.ref new file mode 100755 index 00000000..24460fff --- /dev/null +++ b/src/dlyerr_2_errpat/test_data/t2_lf.ref @@ -0,0 +1,30 @@ +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +1 +0 +1 +0 +0 +0 +0 +0 +1 +0 +0 +0 +1 +0 +0 +1 +0 +0 +0 +0 diff --git a/src/dlyerr_2_errpat/test_data/t3_word.ref b/src/dlyerr_2_errpat/test_data/t3_word.ref new file mode 100755 index 00000000..31848379 --- /dev/null +++ b/src/dlyerr_2_errpat/test_data/t3_word.ref @@ -0,0 +1 @@ +!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k k k!k!k k k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k k k!k!k!k!k k k!k!k!k!k!k!k!k!k \ No newline at end of file diff --git a/src/dlyerr_2_errpat/test_data/t4_lateloss.ref b/src/dlyerr_2_errpat/test_data/t4_lateloss.ref new file mode 100755 index 00000000..c49265e8 --- /dev/null +++ b/src/dlyerr_2_errpat/test_data/t4_lateloss.ref @@ -0,0 +1 @@ +000001000010100000000010000000 \ No newline at end of file From 32ea343f7224da8df69a8947604dd170cd426cd1 Mon Sep 17 00:00:00 2001 From: Ludovic Malfait Date: Tue, 2 Jun 2026 17:14:02 +0100 Subject: [PATCH 4/7] Integrate dlyerr_2_errpat into src/eid/ (from PR #180) Delay-and-error profile to frame-erasure pattern conversion tool. Provided by Fraunhofer IIS via 3GPP Tdoc S4-121077. Changes vs original PR: - Moved from src/dlyerr_2_errpat/ into src/eid/ (groups all EID tools) - Added argc bounds checks before argv[2] access - Replaced abort() with error return code - Error paths now return non-zero via retval - Fixed strstr("-help") to use exact strcmp - Added braces on while loop - No change to root CMakeLists.txt (already has src/eid) --- src/eid/CMakeLists.txt | 27 ++++ src/eid/dlyerr_2_errpat.c | 239 ++++++++++++++++++++++++++++++ src/eid/test_data/profile.dat | 30 ++++ src/eid/test_data/t1_text.ref | 1 + src/eid/test_data/t2_lf.ref | 30 ++++ src/eid/test_data/t3_word.ref | 1 + src/eid/test_data/t4_lateloss.ref | 1 + 7 files changed, 329 insertions(+) create mode 100644 src/eid/dlyerr_2_errpat.c create mode 100644 src/eid/test_data/profile.dat create mode 100644 src/eid/test_data/t1_text.ref create mode 100644 src/eid/test_data/t2_lf.ref create mode 100644 src/eid/test_data/t3_word.ref create mode 100644 src/eid/test_data/t4_lateloss.ref diff --git a/src/eid/CMakeLists.txt b/src/eid/CMakeLists.txt index a83eb223..2dbe61f8 100644 --- a/src/eid/CMakeLists.txt +++ b/src/eid/CMakeLists.txt @@ -103,3 +103,30 @@ add_test(eid-xor ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/eid-xor -fer -bs bit -ep g192 add_test(eid-xor ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/eid-xor -fer -bs bit -ep byte test_data/zero.src test_data/epf05g10.byt test_data/z_f05g10.bby) add_test(eid-xor ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/eid-xor -fer -bs bit -ep bit test_data/zero.src test_data/epf05g10.bit test_data/z_f05g10.bbi) + +#--- dlyerr_2_errpat: delay/error profile to frame-erasure pattern (from 3GPP S4-121077) +add_executable(dlyerr_2_errpat dlyerr_2_errpat.c) + +# default text format, constant delay +add_test(dlyerr_2_errpat1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/dlyerr_2_errpat + -i test_data/profile.dat -o test_data/t1_text.proc -L 30 -d 40) +add_test(dlyerr_2_errpat1-verify ${CMAKE_COMMAND} -E compare_files + test_data/t1_text.ref test_data/t1_text.proc) + +# LF text format +add_test(dlyerr_2_errpat2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/dlyerr_2_errpat + -i test_data/profile.dat -o test_data/t2_lf.proc -L 30 -d 40 -c) +add_test(dlyerr_2_errpat2-verify ${CMAKE_COMMAND} -E compare_files + test_data/t2_lf.ref test_data/t2_lf.proc) + +# word G.192 format with frame aggregation +add_test(dlyerr_2_errpat3 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/dlyerr_2_errpat + -i test_data/profile.dat -o test_data/t3_word.proc -L 30 -d 40 -w -f 2) +add_test(dlyerr_2_errpat3-verify ${CMAKE_COMMAND} -E compare_files + test_data/t3_word.ref test_data/t3_word.proc) + +# late-loss-rate driven threshold +add_test(dlyerr_2_errpat4 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/dlyerr_2_errpat + -i test_data/profile.dat -o test_data/t4_lateloss.proc -L 30 -l 5.0) +add_test(dlyerr_2_errpat4-verify ${CMAKE_COMMAND} -E compare_files + test_data/t4_lateloss.ref test_data/t4_lateloss.proc) diff --git a/src/eid/dlyerr_2_errpat.c b/src/eid/dlyerr_2_errpat.c new file mode 100644 index 00000000..204da8ca --- /dev/null +++ b/src/eid/dlyerr_2_errpat.c @@ -0,0 +1,239 @@ +/*---------------------------------------------------------------------------* + * Delay-and-error profile to FER pattern conversion tool, V1.1 * + * ------------------------------------------ * + * (C) 2012 Fraunhofer IIS. * + * * + * =============================================================== * + * COPYRIGHT NOTE: This source code, and all of its derivations, * + * is subject to the "ITU-T General Public License". Please have * + * it read in the distribution disk, or in the ITU-T Recommendation * + * G.191 on "SOFTWARE TOOLS FOR SPEECH AND AUDIO CODING STANDARDS". * + * See LICENSE.md in the top-level directory for terms. * + * =============================================================== * + * * + * Fraunhofer IIS makes no representation nor warranty in regard to * + * the accuracy, completeness or sufficiency of The Software, nor * + * shall Fraunhofer IIS be held liable for any damages whatsoever * + * relating to use of said Software. * + *---------------------------------------------------------------------------*/ + +#include +#include +#include +#include + +static void usage() { + fprintf(stdout, "\nConvert a delay and error profile to an error pattern\n"); + fprintf(stdout, "\nValid commandline switches:\n"); + fprintf(stdout, "-i \n"); + fprintf(stdout, "-o \n"); + fprintf(stdout, "-L \n"); + fprintf(stdout, "-s \n"); + fprintf(stdout, "-f [1;2]\n"); + fprintf(stdout, "-l \n"); + fprintf(stdout, "-b use byte-oriented G.192 format (0x21 okay, 0x20 lost)\n"); + fprintf(stdout, "-w use word-oriented G.192 format (0x6b21 okay, 0x6b20 lost)\n"); + fprintf(stdout, "-c use LF for text format to have one entry per line - was default in V1.0\n"); + fprintf(stdout, "-d \n"); + fprintf(stdout, " either -l or -d parameter must be supplied (not both!) and a valid inputfile\n"); +} + +int main(int argc, char **argv) { + int i; + char *infilename = NULL; + char *outfilename = NULL; + float late_loss_rate = 0.0f; + unsigned int constant_delay_ms = 0; + int shift = 0; + int length = 7500; + unsigned int framesPerPacket = 1; /* no aggregation by default */ + int useG192 = 0; + int useG192WordOriented = 0; + int useLF = 0; + int retval = 0; + + char line[64] = {0}; + unsigned int delayCount[2001] = {0}; /* [-1;1999] ms */ + unsigned int line_cnt = 0; + + FILE *infile = NULL; + FILE *outfile = NULL; + + while (argc > 1 && argv[1][0] == '-') { + if (strcmp(argv[1], "-i") == 0) { + if (argc < 3) { usage(); return -1; } + infilename = argv[2]; + argc -= 2; argv += 2; + } else if (strcmp(argv[1], "-o") == 0) { + if (argc < 3) { usage(); return -1; } + outfilename = argv[2]; + argc -= 2; argv += 2; + } else if (strcmp(argv[1], "-l") == 0) { + if (argc < 3) { usage(); return -1; } + late_loss_rate = (float)atof(argv[2]); + argc -= 2; argv += 2; + } else if (strcmp(argv[1], "-d") == 0) { + if (argc < 3) { usage(); return -1; } + constant_delay_ms = atoi(argv[2]); + argc -= 2; argv += 2; + } else if (strcmp(argv[1], "-s") == 0) { + if (argc < 3) { usage(); return -1; } + shift = atoi(argv[2]); + argc -= 2; argv += 2; + } else if (strcmp(argv[1], "-L") == 0) { + if (argc < 3) { usage(); return -1; } + length = atoi(argv[2]); + argc -= 2; argv += 2; + } else if (strcmp(argv[1], "-f") == 0) { + if (argc < 3) { usage(); return -1; } + framesPerPacket = atoi(argv[2]); + argc -= 2; argv += 2; + } else if (strcmp(argv[1], "-b") == 0) { + useG192 = 1; + argc--; argv++; + } else if (strcmp(argv[1], "-w") == 0) { + useG192 = 1; + useG192WordOriented = 1; + argc--; argv++; + } else if (strcmp(argv[1], "-c") == 0) { + useLF = 1; + argc--; argv++; + } else if (strcmp(argv[1], "-?") == 0 || strcmp(argv[1], "-help") == 0 || strcmp(argv[1], "--help") == 0) { + usage(); + return 0; + } else { + fprintf(stderr, "ERROR! Invalid option \"%s\" in command line\n\n", argv[1]); + usage(); + return -1; + } + } + + if ((infilename == NULL) || ((late_loss_rate == 0) && (constant_delay_ms == 0)) || + framesPerPacket == 0U || framesPerPacket > 2U) { + usage(); + return -1; + } + + infile = fopen(infilename, "r"); + if (!infile) { + fprintf(stderr, "unable to open %s\n", infilename); + return -2; + } + + if (outfilename) { + outfile = fopen(outfilename, "w"); + if (!outfile) { + fprintf(stderr, "unable to open %s\n", outfilename); + retval = -2; + goto cleanup; + } + } + + /* read offset to Nirvana */ + for (i = 0; i < shift; i++) { + if (!fgets(line, 63, infile)) { + fprintf(stderr, "shift out of range\n"); + retval = -3; + goto cleanup; + } + } + + /* create delay histogram */ + for (i = 0; i < length; i++) { + int delay_ms; + if (!fgets(line, 63, infile)) { + rewind(infile); + if (!fgets(line, 63, infile)) { + fprintf(stderr, "unable to rewind and read file\n"); + retval = -4; + goto cleanup; + } + } + line_cnt++; + delay_ms = atoi(line); + if ((delay_ms < -1) || (delay_ms > 1999)) { + fprintf(stderr, "value in line %u out of range - aborting\n", line_cnt); + retval = -5; + goto cleanup; + } + if (delay_ms == -1) + delayCount[2000]++; + else + delayCount[delay_ms]++; + } + + if (late_loss_rate) { + unsigned int late_loss_cnt = 0; + for (i = 1999; i >= 0; i--) { + float current_late_loss_rate; + late_loss_cnt += delayCount[i]; + current_late_loss_rate = ((float)late_loss_cnt * 100.0f) / (float)line_cnt; + if (current_late_loss_rate > late_loss_rate) { + constant_delay_ms = i; + fprintf(stdout, "selected %ims to stay below %f late loss\n", i, late_loss_rate); + break; + } + } + } + + /**** emulate constant delay JBM with given delay ****/ + fseek(infile, 0, SEEK_SET); + + /* read offset to nirvana, again */ + for (i = 0; i < shift; i++) { + if (!fgets(line, 63, infile)) { + fprintf(stderr, "shift out of range\n"); + retval = -3; + goto cleanup; + } + } + + if (constant_delay_ms) { + unsigned int late_loss_cnt = 0; + unsigned int network_loss_cnt = 0; + unsigned int iFramePerPacket; + for (i = 0; i < length; i++) { + int delay_ms; + if (!fgets(line, 63, infile)) { + rewind(infile); + if (!fgets(line, 63, infile)) { + fprintf(stderr, "unable to rewind and read file\n"); + retval = -4; + goto cleanup; + } + } + delay_ms = atoi(line); + + if (delay_ms == -1) { + network_loss_cnt++; + if (outfile) { + for (iFramePerPacket = 0; iFramePerPacket != framesPerPacket; ++iFramePerPacket) + fprintf(outfile, "%s", useG192 ? useG192WordOriented ? " k" : " " : useLF ? "1\n" : "1"); + } + } else if ((unsigned int)delay_ms > constant_delay_ms) { + late_loss_cnt++; + if (outfile) { + for (iFramePerPacket = 0; iFramePerPacket != framesPerPacket; ++iFramePerPacket) + fprintf(outfile, "%s", useG192 ? useG192WordOriented ? " k" : " " : useLF ? "1\n" : "1"); + } + } else { + if (outfile) { + for (iFramePerPacket = 0; iFramePerPacket != framesPerPacket; ++iFramePerPacket) + fprintf(outfile, "%s", useG192 ? useG192WordOriented ? "!k" : "!" : useLF ? "0\n" : "0"); + } + } + } + + fprintf(stdout, "#processed delay and error values: %u\n", line_cnt); + fprintf(stdout, "network loss rate: %.3f%%\n", ((float)network_loss_cnt * 100.0f) / (float)line_cnt); + fprintf(stdout, "late loss rate: %.3f%%\n", ((float)late_loss_cnt * 100.0f) / (float)line_cnt); + fprintf(stdout, "distorted frames: %u\n", framesPerPacket * (network_loss_cnt + late_loss_cnt)); + } + +cleanup: + fclose(infile); + if (outfile) + fclose(outfile); + + return retval; +} diff --git a/src/eid/test_data/profile.dat b/src/eid/test_data/profile.dat new file mode 100644 index 00000000..22030ae8 --- /dev/null +++ b/src/eid/test_data/profile.dat @@ -0,0 +1,30 @@ +10 +20 +5 +0 +30 +-1 +10 +40 +20 +5 +80 +10 +-1 +30 +20 +10 +5 +0 +60 +20 +10 +30 +-1 +40 +10 +50 +5 +20 +10 +10 diff --git a/src/eid/test_data/t1_text.ref b/src/eid/test_data/t1_text.ref new file mode 100644 index 00000000..58e58f24 --- /dev/null +++ b/src/eid/test_data/t1_text.ref @@ -0,0 +1 @@ +000001000010100000100010010000 \ No newline at end of file diff --git a/src/eid/test_data/t2_lf.ref b/src/eid/test_data/t2_lf.ref new file mode 100644 index 00000000..24460fff --- /dev/null +++ b/src/eid/test_data/t2_lf.ref @@ -0,0 +1,30 @@ +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +1 +0 +1 +0 +0 +0 +0 +0 +1 +0 +0 +0 +1 +0 +0 +1 +0 +0 +0 +0 diff --git a/src/eid/test_data/t3_word.ref b/src/eid/test_data/t3_word.ref new file mode 100644 index 00000000..31848379 --- /dev/null +++ b/src/eid/test_data/t3_word.ref @@ -0,0 +1 @@ +!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k k k!k!k k k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k k k!k!k!k!k k k!k!k!k!k!k!k!k!k \ No newline at end of file diff --git a/src/eid/test_data/t4_lateloss.ref b/src/eid/test_data/t4_lateloss.ref new file mode 100644 index 00000000..c49265e8 --- /dev/null +++ b/src/eid/test_data/t4_lateloss.ref @@ -0,0 +1 @@ +000001000010100000000010000000 \ No newline at end of file From 066d322345e11a49bb9a8513b0d95d3b4e64df64 Mon Sep 17 00:00:00 2001 From: Ludovic Malfait Date: Tue, 2 Jun 2026 17:54:15 +0100 Subject: [PATCH 5/7] Add dlyerr_2_errpat documentation (README + LaTeX manual) - src/eid/README.md: file listing entry + full usage/format/example section - doc/manual/eid.tex: new section with algorithm description (two-pass histogram + classification), input format spec, output formats, usage syntax, worked examples, and provenance --- doc/manual/eid.tex | 107 +++++++++++++++++++++++++++++++++++++++++++++ src/eid/README.md | 42 ++++++++++++++++++ 2 files changed, 149 insertions(+) diff --git a/doc/manual/eid.tex b/doc/manual/eid.tex index 8769dbe8..7b7594c4 100644 --- a/doc/manual/eid.tex +++ b/doc/manual/eid.tex @@ -1341,3 +1341,110 @@ \subsubsection{EID-EV G.192 Output frame examples } \label{fig:G192outputFrameLayer034ErrorIndividual} \end{center} \end{figure} + +%-------------------------------------- +\section {Delay/error profile to erasure pattern (dlyerr\_2\_errpat)} \label{DLYERR} +%-------------------------------------- + +\subsection{Description} + +The {\tt dlyerr\_2\_errpat} tool converts a delay-and-error profile into a +frame-erasure error pattern suitable for use with {\tt eid-xor}. This enables +simulation of jitter buffer management (JBM) behavior: packets that arrive +too late for playout are treated as lost, in addition to packets lost in +the network. + +The input profile contains one integer per line representing either: +\begin{itemize} +\item A network delay in milliseconds (0--1999), or +\item The value $-1$, indicating the packet was lost in the network. +\end{itemize} + +Two JBM emulation modes are supported: +\begin{itemize} +\item {\bf Constant-delay mode} ({\tt -d}): a fixed JBM delay in milliseconds. + Any packet with delay exceeding this threshold is marked as lost. +\item {\bf Bounded-loss-rate mode} ({\tt -l}): the tool automatically selects + the minimum JBM delay such that the combined late-loss rate stays + below the specified percentage. +\end{itemize} + +\subsection{Algorithm} + +Processing is performed in two passes over the input profile: + +\begin{enumerate} +\item {\bf Histogram pass}: reads the profile and builds a delay histogram + (counts per millisecond bin). In bounded-loss-rate mode, this histogram + is used to determine the JBM delay threshold by accumulating from the + highest delay downward until the target late-loss rate is exceeded. + +\item {\bf Output pass}: re-reads the profile and classifies each packet: + \begin{itemize} + \item delay $= -1$ (network loss) $\rightarrow$ frame erased + \item delay $>$ JBM threshold $\rightarrow$ frame erased (late loss) + \item otherwise $\rightarrow$ frame received (good) + \end{itemize} +\end{enumerate} + +If the profile is shorter than the requested output length ({\tt -L}), the +file is rewound and reused from the beginning. + +When {\tt -f~2} is specified, each packet decision produces two consecutive +frame-erasure flags in the output (for codecs sending two frames per packet). + +\subsection{Usage} + +{\tt\small +\begin{verbatim} +dlyerr_2_errpat [options] + + -i delay/error profile (required) + -o error pattern output (required) + -d constant-JBM-delay mode + -l bounded-loss-rate mode + -L output length (default: 7500) + -s skip initial frames in profile + -f <1|2> frames per packet (default: 1) + -w word-oriented G.192 output + -b byte-oriented G.192 output + -c text with LF (one entry per line) +\end{verbatim} +} + +Exactly one of {\tt -d} or {\tt -l} must be supplied. + +\subsection{Output formats} + +\begin{itemize} +\item {\bf Default text}: concatenated ASCII {\tt 0} (good) / {\tt 1} (erased) +\item {\bf Text with LF} ({\tt -c}): one digit per line +\item {\bf Byte G.192} ({\tt -b}): binary bytes 0x21 (good) / 0x20 (erased) +\item {\bf Word G.192} ({\tt -w}): binary 16-bit words 0x6B21 / 0x6B20 +\end{itemize} + +\subsection{Example} + +Apply MTSI delay/error profile with a fixed 200\,ms JBM delay, word-oriented +G.192 output, random offset into the profile: + +{\tt\small +\begin{verbatim} +dlyerr_2_errpat -d 200 -f 1 -w -s 1234 \ + -i dly_err_profile_1.dat -o ep1.g192 +eid-xor -fer -ep g192 bitstream.g192 ep1.g192 output.g192 +\end{verbatim} +} + +Bounded loss rate of 1\%, two frames per packet: + +{\tt\small +\begin{verbatim} +dlyerr_2_errpat -l 1 -f 2 -w -i dly_err_profile_5.dat -o ep5.g192 +\end{verbatim} +} + +\subsection{Origin} + +Provided by Fraunhofer IIS via 3GPP Tdoc S4-121077 (TSGS4\#70, Chicago, +13--17 Aug 2012), in support of the EVS reference codec processing plan. diff --git a/src/eid/README.md b/src/eid/README.md index 6918115c..10a01f10 100644 --- a/src/eid/README.md +++ b/src/eid/README.md @@ -20,6 +20,7 @@ The "Error Insertion Device" (EID) module is built of the following files: eid-int.c: .... Interpolates error patterns from a master EP eid-xor.c: .... Disturbs bits or erases frames based on error patterns + dlyerr_2_errpat.c: Delay/error profile to frame-erasure pattern converter ep-stats.c: ... Assesses and prints statistics about an error pattern file gen-patt.c: ... Generates error pattern files softbit.c: .... Library with softbit file I/O and format check @@ -263,5 +264,46 @@ little-endian computers (PC/VAX/Alpha) are: Has not been implemented yet. + +## dlyerr_2_errpat: Delay/error profile to frame-erasure pattern + +Converts a delay-and-error profile (one integer per line: network delay in ms, +or -1 for network loss) into a frame-erasure error pattern for use with +`eid-xor`. Supports two jitter buffer management emulation modes. + +Usage: + + dlyerr_2_errpat [options] + + -i delay/error profile (required) + -o error pattern output (required) + -d constant-JBM-delay mode (milliseconds) + -l bounded-loss-rate mode (percent) + -L output length in frames (default: 7500) + -s skip offset frames into the profile + -f <1|2> frames per packet (default: 1) + -w word-oriented G.192 output + -b byte-oriented G.192 output + -c text mode with LF (one entry per line) + +Exactly one of `-d` or `-l` must be supplied. + +Input format: one integer per line. Values 0--1999 represent network delay in +milliseconds; -1 indicates network loss (packet never arrived). If the input +file is shorter than `-L` frames, it wraps around. + +Output: `0` = good frame, `1` = lost frame (text mode); or G.192 binary +equivalent with `-w` or `-b` flags. + +Example (fixed JBM delay of 200ms, word G.192 output): + + dlyerr_2_errpat -d 200 -f 1 -w -s 100 -i profile.dat -o ep.g192 + eid-xor -fer -ep g192 bitstream.g192 ep.g192 output.g192 + +Originally provided by Fraunhofer IIS via 3GPP Tdoc S4-121077 +(TSGS4#70, Chicago, 13--17 Aug 2012), in support of the EVS codec +processing plan. + + Good luck! -- From 5d1d5a7d226be58112451f24ad212955944861b5 Mon Sep 17 00:00:00 2001 From: Ludovic Malfait Date: Tue, 2 Jun 2026 18:01:59 +0100 Subject: [PATCH 6/7] Use softbit save_g192/save_byte for G.192 output in dlyerr_2_errpat - Links softbit.c, includes ugstdemo.h and softbit.h - G.192 word mode now uses save_g192() (proper binary fwrite) - G.192 byte mode now uses save_byte() - Opens output in binary mode (WB) for G.192 formats - Uses G192_FER/G192_SYNC constants instead of ASCII tricks - Text modes unchanged (fprintf with '0'/'1') - Regenerated test references from updated tool --- src/eid/CMakeLists.txt | 3 ++- src/eid/dlyerr_2_errpat.c | 44 ++++++++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/eid/CMakeLists.txt b/src/eid/CMakeLists.txt index 2dbe61f8..8d76f753 100644 --- a/src/eid/CMakeLists.txt +++ b/src/eid/CMakeLists.txt @@ -105,7 +105,8 @@ add_test(eid-xor ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/eid-xor -fer -bs bit -ep bit #--- dlyerr_2_errpat: delay/error profile to frame-erasure pattern (from 3GPP S4-121077) -add_executable(dlyerr_2_errpat dlyerr_2_errpat.c) +add_executable(dlyerr_2_errpat dlyerr_2_errpat.c softbit.c) +target_link_libraries(dlyerr_2_errpat ${M_LIBRARY}) # default text format, constant delay add_test(dlyerr_2_errpat1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/dlyerr_2_errpat diff --git a/src/eid/dlyerr_2_errpat.c b/src/eid/dlyerr_2_errpat.c index 204da8ca..e139e36e 100644 --- a/src/eid/dlyerr_2_errpat.c +++ b/src/eid/dlyerr_2_errpat.c @@ -1,5 +1,5 @@ /*---------------------------------------------------------------------------* - * Delay-and-error profile to FER pattern conversion tool, V1.1 * + * Delay-and-error profile to FER pattern conversion tool, V1.2 * * ------------------------------------------ * * (C) 2012 Fraunhofer IIS. * * * @@ -20,7 +20,8 @@ #include #include #include -#include +#include "ugstdemo.h" +#include "softbit.h" static void usage() { fprintf(stdout, "\nConvert a delay and error profile to an error pattern\n"); @@ -38,6 +39,22 @@ static void usage() { fprintf(stdout, " either -l or -d parameter must be supplied (not both!) and a valid inputfile\n"); } +/* Write one frame erasure flag to output */ +static void write_flag(short flag, int useG192, int useG192WordOriented, int useLF, FILE *outfile) { + if (useG192) { + if (useG192WordOriented) + save_g192(&flag, 1, outfile); + else + save_byte(&flag, 1, outfile); + } else { + /* Text mode: 0 = good, 1 = erased */ + if (useLF) + fprintf(outfile, "%c\n", flag == G192_FER ? '1' : '0'); + else + fprintf(outfile, "%c", flag == G192_FER ? '1' : '0'); + } +} + int main(int argc, char **argv) { int i; char *infilename = NULL; @@ -121,7 +138,7 @@ int main(int argc, char **argv) { } if (outfilename) { - outfile = fopen(outfilename, "w"); + outfile = fopen(outfilename, useG192 ? WB : "w"); if (!outfile) { fprintf(stderr, "unable to open %s\n", outfilename); retval = -2; @@ -194,6 +211,7 @@ int main(int argc, char **argv) { unsigned int iFramePerPacket; for (i = 0; i < length; i++) { int delay_ms; + short flag; if (!fgets(line, 63, infile)) { rewind(infile); if (!fgets(line, 63, infile)) { @@ -206,21 +224,17 @@ int main(int argc, char **argv) { if (delay_ms == -1) { network_loss_cnt++; - if (outfile) { - for (iFramePerPacket = 0; iFramePerPacket != framesPerPacket; ++iFramePerPacket) - fprintf(outfile, "%s", useG192 ? useG192WordOriented ? " k" : " " : useLF ? "1\n" : "1"); - } + flag = G192_FER; } else if ((unsigned int)delay_ms > constant_delay_ms) { late_loss_cnt++; - if (outfile) { - for (iFramePerPacket = 0; iFramePerPacket != framesPerPacket; ++iFramePerPacket) - fprintf(outfile, "%s", useG192 ? useG192WordOriented ? " k" : " " : useLF ? "1\n" : "1"); - } + flag = G192_FER; } else { - if (outfile) { - for (iFramePerPacket = 0; iFramePerPacket != framesPerPacket; ++iFramePerPacket) - fprintf(outfile, "%s", useG192 ? useG192WordOriented ? "!k" : "!" : useLF ? "0\n" : "0"); - } + flag = G192_SYNC; + } + + if (outfile) { + for (iFramePerPacket = 0; iFramePerPacket != framesPerPacket; ++iFramePerPacket) + write_flag(flag, useG192, useG192WordOriented, useLF, outfile); } } From 482b9450da511fff8a0bcf592a988bfec85a64bd Mon Sep 17 00:00:00 2001 From: Ludovic Malfait Date: Tue, 2 Jun 2026 22:35:04 +0100 Subject: [PATCH 7/7] Fix Windows CRLF test failure: use compare_files --ignore-eol for text tests --- src/eid/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/eid/CMakeLists.txt b/src/eid/CMakeLists.txt index 8d76f753..a0eb28e0 100644 --- a/src/eid/CMakeLists.txt +++ b/src/eid/CMakeLists.txt @@ -111,13 +111,13 @@ target_link_libraries(dlyerr_2_errpat ${M_LIBRARY}) # default text format, constant delay add_test(dlyerr_2_errpat1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/dlyerr_2_errpat -i test_data/profile.dat -o test_data/t1_text.proc -L 30 -d 40) -add_test(dlyerr_2_errpat1-verify ${CMAKE_COMMAND} -E compare_files +add_test(dlyerr_2_errpat1-verify ${CMAKE_COMMAND} -E compare_files --ignore-eol test_data/t1_text.ref test_data/t1_text.proc) # LF text format add_test(dlyerr_2_errpat2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/dlyerr_2_errpat -i test_data/profile.dat -o test_data/t2_lf.proc -L 30 -d 40 -c) -add_test(dlyerr_2_errpat2-verify ${CMAKE_COMMAND} -E compare_files +add_test(dlyerr_2_errpat2-verify ${CMAKE_COMMAND} -E compare_files --ignore-eol test_data/t2_lf.ref test_data/t2_lf.proc) # word G.192 format with frame aggregation @@ -129,5 +129,5 @@ add_test(dlyerr_2_errpat3-verify ${CMAKE_COMMAND} -E compare_files # late-loss-rate driven threshold add_test(dlyerr_2_errpat4 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/dlyerr_2_errpat -i test_data/profile.dat -o test_data/t4_lateloss.proc -L 30 -l 5.0) -add_test(dlyerr_2_errpat4-verify ${CMAKE_COMMAND} -E compare_files +add_test(dlyerr_2_errpat4-verify ${CMAKE_COMMAND} -E compare_files --ignore-eol test_data/t4_lateloss.ref test_data/t4_lateloss.proc)