2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
17 #include "webrtc/modules/audio_coding/codecs/isac/fix/interface/isacfix.h"
18 #include "webrtc/test/testsupport/perf_test.h"
20 // TODO(kma): Clean up the code and change benchmarking the whole codec to
21 // separate encoder and decoder.
24 #define SEED_FILE "randseed.txt" /* Used when running decoder on garbage data */
25 #define MAX_FRAMESAMPLES 960 /* max number of samples per frame (= 60 ms frame) */
26 #define FRAMESAMPLES_10ms 160 /* number of samples per 10ms frame */
27 #define FS 16000 /* sampling frequency (Hz) */
29 /* Function for reading audio data from PCM file */
30 int readframe(int16_t *data, FILE *inp, int length) {
32 short k, rlen, status = 0;
34 rlen = fread(data, sizeof(int16_t), length, inp);
36 for (k = rlen; k < length; k++)
44 /* Struct for bottleneck model */
46 uint32_t send_time; /* samples */
47 uint32_t arrival_time; /* samples */
48 uint32_t sample_count; /* samples */
52 void get_arrival_time(int current_framesamples, /* samples */
53 int packet_size, /* bytes */
54 int bottleneck, /* excluding headers; bits/s */
55 BottleNeckModel *BN_data)
57 const int HeaderSize = 35;
60 HeaderRate = HeaderSize * 8 * FS / current_framesamples; /* bits/s */
62 /* everything in samples */
63 BN_data->sample_count = BN_data->sample_count + current_framesamples;
65 BN_data->arrival_time += ((packet_size + HeaderSize) * 8 * FS) / (bottleneck + HeaderRate);
66 BN_data->send_time += current_framesamples;
68 if (BN_data->arrival_time < BN_data->sample_count)
69 BN_data->arrival_time = BN_data->sample_count;
71 BN_data->rtp_number++;
74 void get_arrival_time2(int current_framesamples,
76 BottleNeckModel *BN_data)
78 if (current_delay == -1)
81 BN_data->arrival_time += current_framesamples;
83 else if (current_delay != -2)
86 BN_data->arrival_time += (current_framesamples + ((FS/1000) * current_delay));
89 //current packet has same timestamp as previous packet
91 BN_data->rtp_number++;
94 int main(int argc, char* argv[])
97 char inname[100], outname[100], outbitsname[100], bottleneck_file[100];
98 FILE *inp, *outp, *f_bn, *outbits;
101 int i, errtype, h = 0, k, packetLossPercent = 0;
104 int16_t framesize = 30; /* ms */
105 int cur_framesmpls, err = 0, lostPackets = 0;
107 /* Runtime statistics */
108 double starttime, runtime, length_file;
110 int16_t stream_len = 0;
111 int16_t framecnt, declen = 0;
112 int16_t shortdata[FRAMESAMPLES_10ms];
113 int16_t decoded[MAX_FRAMESAMPLES];
114 uint16_t streamdata[500];
115 int16_t speechType[1];
116 int16_t prevFrameSize = 1;
119 int16_t payloadSize = 0;
120 int32_t payloadRate = 0;
121 int setControlBWE = 0;
125 char version_number[20];
126 char tmpBit[5] = ".bit";
130 int16_t testNum, testCE;
139 float scale = (float)0.7;
140 /* only one structure used for ISAC encoder */
141 ISACFIX_MainStruct *ISAC_main_inst = NULL;
143 /* For fault test 10, garbage data */
145 unsigned int random_seed = (unsigned int) time(NULL);//1196764538
147 BottleNeckModel BN_data;
151 packetLossPercent = 0;
153 /* Handling wrong input arguments in the command line */
154 if ((argc<3) || (argc>21)) {
155 printf("\n\nWrong number of arguments or flag values.\n\n");
158 WebRtcIsacfix_version(version_number);
159 printf("iSAC version %s \n\n", version_number);
161 printf("Usage:\n\n");
162 printf("./kenny.exe [-F num][-I] bottleneck_value infile outfile \n\n");
164 printf("[-I] :if -I option is specified, the coder will use\n");
165 printf(" an instantaneous Bottleneck value. If not, it\n");
166 printf(" will be an adaptive Bottleneck value.\n\n");
167 printf("bottleneck_value :the value of the bottleneck provided either\n");
168 printf(" as a fixed value (e.g. 25000) or\n");
169 printf(" read from a file (e.g. bottleneck.txt)\n\n");
170 printf("[-INITRATE num] :Set a new value for initial rate. Note! Only used"
171 " in adaptive mode.\n\n");
172 printf("[-FL num] :Set (initial) frame length in msec. Valid length"
173 " are 30 and 60 msec.\n\n");
174 printf("[-FIXED_FL] :Frame length to be fixed to initial value.\n\n");
175 printf("[-MAX num] :Set the limit for the payload size of iSAC"
177 printf(" Minimum 100, maximum 400.\n\n");
178 printf("[-MAXRATE num] :Set the maxrate for iSAC in bits per second. \n");
179 printf(" Minimum 32000, maximum 53400.\n\n");
180 printf("[-F num] :if -F option is specified, the test function\n");
181 printf(" will run the iSAC API fault scenario specified"
183 printf(" supplied number.\n");
184 printf(" F 1 - Call encoder prior to init encoder call\n");
185 printf(" F 2 - Call decoder prior to init decoder call\n");
186 printf(" F 3 - Call decoder prior to encoder call\n");
187 printf(" F 4 - Call decoder with a too short coded"
189 printf(" F 5 - Call decoder with a too long coded"
191 printf(" F 6 - Call decoder with random bit stream\n");
192 printf(" F 7 - Call init encoder/decoder at random"
194 printf(" F 8 - Call encoder/decoder without having"
195 " allocated memory for \n");
196 printf(" encoder/decoder instance\n");
197 printf(" F 9 - Call decodeB without calling decodeA\n");
198 printf(" F 10 - Call decodeB with garbage data\n");
199 printf("[-PL num] : if -PL option is specified 0<num<100 will "
201 printf(" percentage of packet loss\n\n");
202 printf("[-G file] : if -G option is specified the file given is"
204 printf(" that represents a network profile\n\n");
205 printf("[-NB num] : if -NB option, use the narrowband interfaces\n");
206 printf(" num=1 => encode with narrowband encoder"
207 " (infile is narrowband)\n");
208 printf(" num=2 => decode with narrowband decoder"
209 " (outfile is narrowband)\n\n");
210 printf("[-CE num] : Test of APIs used by Conference Engine.\n");
211 printf(" CE 1 - createInternal, freeInternal,"
212 " getNewBitstream \n");
213 printf(" CE 2 - transcode, getBWE \n");
214 printf(" CE 3 - getSendBWE, setSendBWE. \n\n");
215 printf("[-RTP_INIT num] : if -RTP_INIT option is specified num will be"
217 printf(" value of the rtp sequence number.\n\n");
218 printf("infile : Normal speech input file\n\n");
219 printf("outfile : Speech output file\n\n");
220 printf("Example usage : \n\n");
221 printf("./kenny.exe -I bottleneck.txt speechIn.pcm speechOut.pcm\n\n");
226 /* Print version number */
227 WebRtcIsacfix_version(version_number);
228 printf("iSAC version %s \n\n", version_number);
230 /* Loop over all command line arguments */
234 for (i = 1; i < argc-2;i++) {
235 /* Instantaneous mode */
236 if (!strcmp ("-I", argv[i])) {
237 printf("\nInstantaneous BottleNeck\n");
242 /* Set (initial) bottleneck value */
243 if (!strcmp ("-INITRATE", argv[i])) {
244 rateBPS = atoi(argv[i + 1]);
246 if ((rateBPS < 10000) || (rateBPS > 32000)) {
247 printf("\n%d is not a initial rate. "
248 "Valid values are in the range 10000 to 32000.\n", rateBPS);
251 printf("\nNew initial rate: %d\n", rateBPS);
255 /* Set (initial) framelength */
256 if (!strcmp ("-FL", argv[i])) {
257 framesize = atoi(argv[i + 1]);
258 if ((framesize != 30) && (framesize != 60)) {
259 printf("\n%d is not a valid frame length. "
260 "Valid length are 30 and 60 msec.\n", framesize);
263 printf("\nFrame Length: %d\n", framesize);
267 /* Fixed frame length */
268 if (!strcmp ("-FIXED_FL", argv[i])) {
273 /* Set maximum allowed payload size in bytes */
274 if (!strcmp ("-MAX", argv[i])) {
275 payloadSize = atoi(argv[i + 1]);
276 printf("Maximum Payload Size: %d\n", payloadSize);
280 /* Set maximum rate in bytes */
281 if (!strcmp ("-MAXRATE", argv[i])) {
282 payloadRate = atoi(argv[i + 1]);
283 printf("Maximum Rate in kbps: %d\n", payloadRate);
287 /* Test of fault scenarious */
288 if (!strcmp ("-F", argv[i])) {
289 testNum = atoi(argv[i + 1]);
290 printf("\nFault test: %d\n", testNum);
291 if (testNum < 1 || testNum > 10) {
292 printf("\n%d is not a valid Fault Scenario number."
293 " Valid Fault Scenarios are numbered 1-10.\n", testNum);
299 /* Packet loss test */
300 if (!strcmp ("-PL", argv[i])) {
301 if( isdigit( *argv[i+1] ) ) {
302 packetLossPercent = atoi( argv[i+1] );
303 if( (packetLossPercent < 0) | (packetLossPercent > 100) ) {
304 printf( "\nInvalid packet loss perentage \n" );
307 if( packetLossPercent > 0 ) {
308 printf( "\nSimulating %d %% of independent packet loss\n",
311 printf( "\nNo Packet Loss Is Simulated \n" );
316 plFile = fopen( argv[i+1], "rb" );
317 if( plFile == NULL ) {
318 printf( "\n couldn't open the frameloss file: %s\n", argv[i+1] );
321 printf( "\nSimulating packet loss through the given "
322 "channel file: %s\n", argv[i+1] );
327 /* Random packetlosses */
328 if (!strcmp ("-rnd", argv[i])) {
330 printf( "\n Random pattern in lossed packets \n" );
334 if (!strcmp ("-G", argv[i])) {
335 sscanf(argv[i + 1], "%s", gns_file);
336 fp_gns = fopen(gns_file, "rb");
337 if (fp_gns == NULL) {
338 printf("Cannot read file %s.\n", gns_file);
345 /* Run Narrowband interfaces (either encoder or decoder) */
346 if (!strcmp ("-NB", argv[i])) {
347 nbTest = atoi(argv[i + 1]);
351 /* Run Conference Engine APIs */
352 if (!strcmp ("-CE", argv[i])) {
353 testCE = atoi(argv[i + 1]);
354 if (testCE==1 || testCE==2) {
356 scale = (float)atof( argv[i+1] );
357 } else if (testCE < 1 || testCE > 3) {
358 printf("\n%d is not a valid CE-test number, valid Fault "
359 "Scenarios are numbered 1-3\n", testCE);
365 /* Set initial RTP number */
366 if (!strcmp ("-RTP_INIT", argv[i])) {
371 /* Get Bottleneck value */
372 /* Gns files and bottleneck should not and can not be used simultaneously */
373 bottleneck = atoi(argv[CodingMode+1]);
374 if (bottleneck == 0 && gns == 0) {
375 sscanf(argv[CodingMode+1], "%s", bottleneck_file);
376 f_bn = fopen(bottleneck_file, "rb");
378 printf("No value provided for BottleNeck and cannot read file %s\n",
383 printf("reading bottleneck rates from file %s\n\n",bottleneck_file);
384 if (fscanf(f_bn, "%d", &aux_var) == EOF) {
385 /* Set pointer to beginning of file */
386 fseek(f_bn, 0L, SEEK_SET);
387 if (fscanf(f_bn, "%d", &aux_var) == EOF) {
391 bottleneck = (int16_t)aux_var;
392 /* Bottleneck is a cosine function
393 * Matlab code for writing the bottleneck file:
394 * BottleNeck_10ms = 20e3 + 10e3 * cos((0:5999)/5999*2*pi);
395 * fid = fopen('bottleneck.txt', 'wb');
396 * fprintf(fid, '%d\n', BottleNeck_10ms); fclose(fid);
401 printf("\nfixed bottleneck rate of %d bits/s\n\n", bottleneck);
404 if (CodingMode == 0) {
405 printf("\nAdaptive BottleNeck\n");
408 /* Get Input and Output files */
409 sscanf(argv[argc-2], "%s", inname);
410 sscanf(argv[argc-1], "%s", outname);
412 /* Add '.bit' to output bitstream file */
413 while ((int)outname[h] != 0) {
414 outbitsname[h] = outname[h];
417 for (k=0; k<5; k++) {
418 outbitsname[h] = tmpBit[k];
421 if ((inp = fopen(inname,"rb")) == NULL) {
422 printf(" iSAC: Cannot read file %s\n", inname);
425 if ((outp = fopen(outname,"wb")) == NULL) {
426 printf(" iSAC: Cannot write file %s\n", outname);
430 if ((outbits = fopen(outbitsname,"wb")) == NULL) {
431 printf(" iSAC: Cannot write file %s\n", outbitsname);
434 printf("\nInput:%s\nOutput:%s\n\n", inname, outname);
436 /* Error test number 10, garbage data */
438 /* Test to run decoder with garbage data */
441 if ( (seedfile = fopen(SEED_FILE, "a+t") ) == NULL ) {
442 printf("Error: Could not open file %s\n", SEED_FILE);
445 fprintf(seedfile, "%u\n", random_seed);
450 /* Runtime statistics */
451 starttime = clock()/(double)CLOCKS_PER_SEC;
453 /* Initialize the ISAC and BN structs */
457 err =WebRtcIsacfix_Create(&ISAC_main_inst);
459 /* Test the Assign functions */
462 err =WebRtcIsacfix_AssignSize(&sss);
464 err =WebRtcIsacfix_Assign(&ISAC_main_inst,ppp);
468 printf("\n\n Error in create.\n\n");
471 err = WebRtcIsacfix_CreateInternal(ISAC_main_inst);
474 printf("\n\n Error in createInternal.\n\n");
479 /* Init of bandwidth data */
480 BN_data.send_time = 0;
481 BN_data.arrival_time = 0;
482 BN_data.sample_count = 0;
483 BN_data.rtp_number = 0;
485 /* Initialize encoder and decoder */
489 WebRtcIsacfix_EncoderInit(ISAC_main_inst, CodingMode);
492 WebRtcIsacfix_DecoderInit(ISAC_main_inst);
495 if (CodingMode == 1) {
496 err = WebRtcIsacfix_Control(ISAC_main_inst, bottleneck, framesize);
498 /* exit if returned with error */
499 errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst);
500 printf("\n\n Error in control: %d.\n\n", errtype);
502 } else if(setControlBWE == 1) {
503 err = WebRtcIsacfix_ControlBwe(ISAC_main_inst, rateBPS, framesize, fixedFL);
506 if (payloadSize != 0) {
507 err = WebRtcIsacfix_SetMaxPayloadSize(ISAC_main_inst, payloadSize);
509 /* exit if returned with error */
510 errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst);
511 printf("\n\n Error in SetMaxPayloadSize: %d.\n\n", errtype);
515 if (payloadRate != 0) {
516 err = WebRtcIsacfix_SetMaxRate(ISAC_main_inst, payloadRate);
518 /* exit if returned with error */
519 errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst);
520 printf("\n\n Error in SetMaxRateInBytes: %d.\n\n", errtype);
528 while (endfile == 0) {
530 if(testNum == 7 && (rand()%2 == 0)) {
531 err = WebRtcIsacfix_EncoderInit(ISAC_main_inst, CodingMode);
534 errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst);
535 printf("\n\n Error in encoderinit: %d.\n\n", errtype);
538 err = WebRtcIsacfix_DecoderInit(ISAC_main_inst);
541 errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst);
542 printf("\n\n Error in decoderinit: %d.\n\n", errtype);
549 /* Read 10 ms speech block */
551 endfile = readframe(shortdata, inp, FRAMESAMPLES_10ms);
553 endfile = readframe(shortdata, inp, (FRAMESAMPLES_10ms/2));
561 if (!(testNum == 3 && framecnt == 0)) {
566 stream_len = WebRtcIsacfix_Encode(ISAC_main_inst,
568 (uint8_t*)streamdata);
570 /* If packet is ready, and CE testing, call the different API
571 functions from the internal API. */
574 err = WebRtcIsacfix_ReadBwIndex((int16_t*)streamdata, &bwe);
575 stream_len = WebRtcIsacfix_GetNewBitStream(
579 (int16_t*)streamdata);
580 } else if (testCE == 2) {
581 /* transcode function not supported */
582 } else if (testCE == 3) {
583 /* Only for Function testing. The functions should normally
584 not be used in this way */
586 err = WebRtcIsacfix_GetDownLinkBwIndex(ISAC_main_inst, &bwe);
589 errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst);
590 printf("\nError in getSendBWE: %d.\n", errtype);
593 err = WebRtcIsacfix_UpdateUplinkBw(ISAC_main_inst, bwe);
596 errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst);
597 printf("\nError in setBWE: %d.\n", errtype);
603 #ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED
604 stream_len = WebRtcIsacfix_EncodeNb(ISAC_main_inst,
617 if (stream_len < 0 || err < 0) {
618 /* exit if returned with error */
619 errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst);
620 printf("\nError in encoder: %d.\n", errtype);
622 if (fwrite(streamdata, sizeof(char),
623 stream_len, outbits) != (size_t)stream_len) {
628 cur_framesmpls += FRAMESAMPLES_10ms;
630 /* read next bottleneck rate */
633 if (fscanf(f_bn, "%d", &aux_var) == EOF) {
634 /* Set pointer to beginning of file */
635 fseek(f_bn, 0L, SEEK_SET);
636 if (fscanf(f_bn, "%d", &aux_var) == EOF) {
640 bottleneck = (int16_t)aux_var;
641 if (CodingMode == 1) {
642 WebRtcIsacfix_Control(ISAC_main_inst, bottleneck, framesize);
646 /* exit encoder loop if the encoder returned a bitstream */
647 if (stream_len != 0) break;
650 /* make coded sequence to short be inreasing */
651 /* the length the decoder expects */
656 /* make coded sequence to long be decreasing */
657 /* the length the decoder expects */
664 for (i = 0; i < stream_len; i++ ) {
665 streamdata[i] = rand();
669 /* set pointer to beginning of file */
670 if (fp_gns != NULL) {
671 if (fscanf(fp_gns, "%d", &cur_delay) == EOF) {
672 fseek(fp_gns, 0L, SEEK_SET);
673 if (fscanf(fp_gns, "%d", &cur_delay) == EOF) {
679 /* simulate packet handling through NetEq and the modem */
680 if (!(testNum == 3 && framecnt == 0)) {
682 get_arrival_time(cur_framesmpls, stream_len, bottleneck,
685 get_arrival_time2(cur_framesmpls, cur_delay, &BN_data);
689 /* packet not dropped */
690 if (cur_delay != -1) {
692 /* Error test number 10, garbage data */
694 for ( i = 0; i < stream_len; i++) {
695 streamdata[i] = (short) (streamdata[i] + (short) rand());
700 err = WebRtcIsacfix_UpdateBwEstimate(ISAC_main_inst,
705 BN_data.arrival_time);
708 /* exit if returned with error */
709 errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst);
710 printf("\nError in decoder: %d.\n", errtype);
714 if( readLoss == 1 ) {
715 if( fread( &lostFrame, sizeof(int16_t), 1, plFile ) != 1 ) {
718 lostFrame = !lostFrame;
720 lostFrame = (rand()%100 < packetLossPercent);
726 if( lostFrame && framecnt > 0) {
728 declen = WebRtcIsacfix_DecodePlc(ISAC_main_inst,
729 decoded, prevFrameSize );
731 #ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED
732 declen = WebRtcIsacfix_DecodePlcNb(ISAC_main_inst, decoded,
742 /* Call getFramelen, only used here for function test */
743 err = WebRtcIsacfix_ReadFrameLen((int16_t*)streamdata, &FL);
744 declen = WebRtcIsacfix_Decode( ISAC_main_inst, streamdata, stream_len,
745 decoded, speechType );
747 if (err<0 || declen<0 || FL!=declen) {
748 errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst);
749 printf("\nError in decode_B/or getFrameLen: %d.\n", errtype);
751 prevFrameSize = declen/480;
754 #ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED
755 declen = WebRtcIsacfix_DecodeNb( ISAC_main_inst, streamdata,
756 stream_len, decoded, speechType );
760 prevFrameSize = declen/240;
765 /* exit if returned with error */
766 errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst);
767 printf("\nError in decoder: %d.\n", errtype);
770 /* Write decoded speech frame to file */
771 if (fwrite(decoded, sizeof(int16_t),
772 declen, outp) != (size_t)declen) {
775 // fprintf( ratefile, "%f \n", stream_len / ( ((double)declen)/
776 // ((double)FS) ) * 8 );
782 totalsmpls += declen;
783 totalbits += 8 * stream_len;
785 /* Error test number 10, garbage data */
787 if ( (seedfile = fopen(SEED_FILE, "a+t") ) == NULL ) {
788 printf( "Error: Could not open file %s\n", SEED_FILE);
791 fprintf(seedfile, "ok\n\n");
796 printf("\nLost Frames %d ~ %4.1f%%\n", lostPackets,
797 (double)lostPackets/(double)framecnt*100.0 );
798 printf("\n\ntotal bits = %d bits", totalbits);
799 printf("\nmeasured average bitrate = %0.3f kbits/s",
800 (double)totalbits *(FS/1000) / totalsmpls);
803 /* Runtime statistics */
806 runtime = (double)(((double)clock()/(double)CLOCKS_PER_SEC)-starttime);
807 length_file = ((double)framecnt*(double)declen/FS);
808 printf("\n\nLength of speech file: %.1f s\n", length_file);
809 printf("Time to run iSAC: %.2f s (%.2f %% of realtime)\n\n",
810 runtime, (100*runtime/length_file));
811 printf("\n\n_______________________________________________\n");
813 // Record the results with Perf test tools.
814 webrtc::test::PrintResult("isac", "", "time_per_10ms_frame",
815 (runtime * 10000) / length_file, "us", false);
822 WebRtcIsacfix_FreeInternal(ISAC_main_inst);
824 WebRtcIsacfix_Free(ISAC_main_inst);