1/*
2 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
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.
9 */
10
11/*
12 * test_iSACfixfloat.c
13 *
14 * Test compatibility and quality between floating- and fixed-point code
15 * */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20
21/* include API */
22#include "isac.h"
23#include "isacfix.h"
24#include "webrtc/base/format_macros.h"
25
26/* max number of samples per frame (= 60 ms frame) */
27#define MAX_FRAMESAMPLES 960
28/* number of samples per 10ms frame */
29#define FRAMESAMPLES_10ms 160
30/* sampling frequency (Hz) */
31#define FS 16000
32
33/* Runtime statistics */
34#include <time.h>
35#define CLOCKS_PER_SEC 1000
36
37// FILE *histfile, *ratefile;
38
39/* function for reading audio data from PCM file */
40int readframe(int16_t* data, FILE* inp, int length) {
41  short k, rlen, status = 0;
42
43  rlen = fread(data, sizeof(int16_t), length, inp);
44  if (rlen < length) {
45    for (k = rlen; k < length; k++)
46      data[k] = 0;
47    status = 1;
48  }
49
50  return status;
51}
52
53typedef struct {
54  uint32_t send_time;    /* samples */
55  uint32_t arrival_time; /* samples */
56  uint32_t sample_count; /* samples */
57  uint16_t rtp_number;
58} BottleNeckModel;
59
60void get_arrival_time(int current_framesamples, /* samples */
61                      size_t packet_size,       /* bytes */
62                      int bottleneck,           /* excluding headers; bits/s */
63                      BottleNeckModel* BN_data) {
64  const int HeaderSize = 35;
65  int HeaderRate;
66
67  HeaderRate = HeaderSize * 8 * FS / current_framesamples; /* bits/s */
68
69  /* everything in samples */
70  BN_data->sample_count = BN_data->sample_count + current_framesamples;
71
72  BN_data->arrival_time += (uint32_t)
73      (((packet_size + HeaderSize) * 8 * FS) / (bottleneck + HeaderRate));
74  BN_data->send_time += current_framesamples;
75
76  if (BN_data->arrival_time < BN_data->sample_count)
77    BN_data->arrival_time = BN_data->sample_count;
78
79  BN_data->rtp_number++;
80}
81
82int main(int argc, char* argv[]) {
83  char inname[50], outname[50], bottleneck_file[50], bitfilename[60],
84      bitending[10] = "_bits.pcm";
85  FILE* inp, *outp, *f_bn, *bitsp;
86  int framecnt, endfile;
87
88  int i, j, errtype, plc = 0;
89  int16_t CodingMode;
90  int16_t bottleneck;
91
92  int framesize = 30; /* ms */
93  // int framesize = 60; /* To invoke cisco complexity case at frame 2252 */
94
95  int cur_framesmpls, err;
96
97  /* Runtime statistics */
98  double starttime;
99  double runtime;
100  double length_file;
101
102  size_t stream_len = 0;
103  int declen;
104
105  int16_t shortdata[FRAMESAMPLES_10ms];
106  int16_t decoded[MAX_FRAMESAMPLES];
107  uint16_t streamdata[600];
108  int16_t speechType[1];
109
110  // int16_t* iSACstruct;
111
112  char version_number[20];
113  int mode = -1, tmp, nbTest = 0; /*,sss;*/
114
115#if !defined(NDEBUG)
116  FILE* fy;
117  double kbps;
118  size_t totalbits = 0;
119  int totalsmpls = 0;
120#endif
121
122  /* only one structure used for ISAC encoder */
123  ISAC_MainStruct* ISAC_main_inst;
124  ISACFIX_MainStruct* ISACFIX_main_inst;
125
126  BottleNeckModel BN_data;
127  f_bn = NULL;
128
129#if !defined(NDEBUG)
130  fy = fopen("bit_rate.dat", "w");
131  fclose(fy);
132  fy = fopen("bytes_frames.dat", "w");
133  fclose(fy);
134#endif
135
136  // histfile = fopen("histo.dat", "ab");
137  // ratefile = fopen("rates.dat", "ab");
138
139  /* handling wrong input arguments in the command line */
140  if ((argc < 6) || (argc > 10)) {
141    printf("\n\nWrong number of arguments or flag values.\n\n");
142
143    printf("\n");
144    WebRtcIsacfix_version(version_number);
145    printf("iSAC version %s \n\n", version_number);
146
147    printf("Usage:\n\n");
148    printf("./kenny.exe [-I] bottleneck_value infile outfile \n\n");
149    printf("with:\n");
150
151    printf("[-I]            : If -I option is specified, the coder will use\n");
152    printf("                  an instantaneous Bottleneck value. If not, it\n");
153    printf("                  will be an adaptive Bottleneck value.\n\n");
154    printf("bottleneck_value: The value of the bottleneck provided either\n");
155    printf("                  as a fixed value (e.g. 25000) or\n");
156    printf("                  read from a file (e.g. bottleneck.txt)\n\n");
157    printf("[-m] mode       : Mode (encoder - decoder):\n");
158    printf("                    0 - float - float\n");
159    printf("                    1 - float - fix\n");
160    printf("                    2 - fix - float\n");
161    printf("                    3 - fix - fix\n\n");
162    printf("[-PLC]          : Test PLC packetlosses\n\n");
163    printf("[-NB] num       : Test NB interfaces:\n");
164    printf("                    1 - encNB\n");
165    printf("                    2 - decNB\n\n");
166    printf("infile          : Normal speech input file\n\n");
167    printf("outfile         : Speech output file\n\n");
168    printf("Example usage:\n\n");
169    printf("./kenny.exe -I bottleneck.txt -m 1 speechIn.pcm speechOut.pcm\n\n");
170    exit(0);
171  }
172
173  printf("--------------------START---------------------\n\n");
174  WebRtcIsac_version(version_number);
175  printf("iSAC FLOAT version %s \n", version_number);
176  WebRtcIsacfix_version(version_number);
177  printf("iSAC FIX version   %s \n\n", version_number);
178
179  CodingMode = 0;
180  tmp = 1;
181  for (i = 1; i < argc; i++) {
182    if (!strcmp("-I", argv[i])) {
183      printf("\nInstantaneous BottleNeck\n");
184      CodingMode = 1;
185      i++;
186      tmp = 0;
187    }
188
189    if (!strcmp("-m", argv[i])) {
190      mode = atoi(argv[i + 1]);
191      i++;
192    }
193
194    if (!strcmp("-PLC", argv[i])) {
195      plc = 1;
196    }
197
198    if (!strcmp("-NB", argv[i])) {
199      nbTest = atoi(argv[i + 1]);
200      i++;
201    }
202  }
203
204  if (mode < 0) {
205    printf("\nError! Mode must be set: -m 0 \n");
206    exit(0);
207  }
208
209  if (CodingMode == 0) {
210    printf("\nAdaptive BottleNeck\n");
211  }
212
213  /* Get Bottleneck value */
214  bottleneck = atoi(argv[2 - tmp]);
215  if (bottleneck == 0) {
216    sscanf(argv[2 - tmp], "%s", bottleneck_file);
217    f_bn = fopen(bottleneck_file, "rb");
218    if (f_bn == NULL) {
219      printf("No value provided for BottleNeck and cannot read file %s.\n",
220             bottleneck_file);
221      exit(0);
222    } else {
223      printf("reading bottleneck rates from file %s\n\n", bottleneck_file);
224      if (fscanf(f_bn, "%d", &bottleneck) == EOF) {
225        /* Set pointer to beginning of file */
226        fseek(f_bn, 0L, SEEK_SET);
227        fscanf(f_bn, "%d", &bottleneck);
228      }
229
230      /* Bottleneck is a cosine function
231       * Matlab code for writing the bottleneck file:
232       * BottleNeck_10ms = 20e3 + 10e3 * cos((0:5999)/5999*2*pi);
233       * fid = fopen('bottleneck.txt', 'wb');
234       * fprintf(fid, '%d\n', BottleNeck_10ms); fclose(fid);
235       */
236    }
237  } else {
238    printf("\nfixed bottleneck rate of %d bits/s\n\n", bottleneck);
239  }
240
241  /* Get Input and Output files */
242  sscanf(argv[argc - 2], "%s", inname);
243  sscanf(argv[argc - 1], "%s", outname);
244
245  if ((inp = fopen(inname, "rb")) == NULL) {
246    printf("  iSAC: Cannot read file %s.\n", inname);
247    exit(1);
248  }
249  if ((outp = fopen(outname, "wb")) == NULL) {
250    printf("  iSAC: Cannot write file %s.\n", outname);
251    exit(1);
252  }
253  printf("\nInput:%s\nOutput:%s\n", inname, outname);
254
255  i = 0;
256  while (outname[i] != '\0') {
257    bitfilename[i] = outname[i];
258    i++;
259  }
260  i -= 4;
261  for (j = 0; j < 9; j++, i++)
262    bitfilename[i] = bitending[j];
263  bitfilename[i] = '\0';
264  if ((bitsp = fopen(bitfilename, "wb")) == NULL) {
265    printf("  iSAC: Cannot read file %s.\n", bitfilename);
266    exit(1);
267  }
268  printf("Bitstream:%s\n\n", bitfilename);
269
270  starttime = clock() / (double)CLOCKS_PER_SEC; /* Runtime statistics */
271
272  /* Initialize the ISAC and BN structs */
273  WebRtcIsac_create(&ISAC_main_inst);
274  WebRtcIsacfix_Create(&ISACFIX_main_inst);
275
276  BN_data.send_time = 0;
277  BN_data.arrival_time = 0;
278  BN_data.sample_count = 0;
279  BN_data.rtp_number = 0;
280
281  /* Initialize encoder and decoder */
282  framecnt = 0;
283  endfile = 0;
284
285  if (mode == 0) { /* Encode using FLOAT, decode using FLOAT */
286
287    printf("Coding mode: Encode using FLOAT, decode using FLOAT \n\n");
288
289    /* Init iSAC FLOAT */
290    WebRtcIsac_EncoderInit(ISAC_main_inst, CodingMode);
291    WebRtcIsac_DecoderInit(ISAC_main_inst);
292    if (CodingMode == 1) {
293      err = WebRtcIsac_Control(ISAC_main_inst, bottleneck, framesize);
294      if (err < 0) {
295        /* exit if returned with error */
296        errtype = WebRtcIsac_GetErrorCode(ISAC_main_inst);
297        printf("\n\n Error in initialization: %d.\n\n", errtype);
298        // exit(EXIT_FAILURE);
299      }
300    }
301
302  } else if (mode == 1) { /* Encode using FLOAT, decode using FIX */
303
304    printf("Coding mode: Encode using FLOAT, decode using FIX \n\n");
305
306    /* Init iSAC FLOAT */
307    WebRtcIsac_EncoderInit(ISAC_main_inst, CodingMode);
308    WebRtcIsac_DecoderInit(ISAC_main_inst);
309    if (CodingMode == 1) {
310      err = WebRtcIsac_Control(ISAC_main_inst, bottleneck, framesize);
311      if (err < 0) {
312        /* exit if returned with error */
313        errtype = WebRtcIsac_GetErrorCode(ISAC_main_inst);
314        printf("\n\n Error in initialization: %d.\n\n", errtype);
315        // exit(EXIT_FAILURE);
316      }
317    }
318
319    /* Init iSAC FIX */
320    WebRtcIsacfix_EncoderInit(ISACFIX_main_inst, CodingMode);
321    WebRtcIsacfix_DecoderInit(ISACFIX_main_inst);
322    if (CodingMode == 1) {
323      err = WebRtcIsacfix_Control(ISACFIX_main_inst, bottleneck, framesize);
324      if (err < 0) {
325        /* exit if returned with error */
326        errtype = WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst);
327        printf("\n\n Error in initialization: %d.\n\n", errtype);
328        // exit(EXIT_FAILURE);
329      }
330    }
331  } else if (mode == 2) { /* Encode using FIX, decode using FLOAT */
332
333    printf("Coding mode: Encode using FIX, decode using FLOAT \n\n");
334
335    /* Init iSAC FLOAT */
336    WebRtcIsac_EncoderInit(ISAC_main_inst, CodingMode);
337    WebRtcIsac_DecoderInit(ISAC_main_inst);
338    if (CodingMode == 1) {
339      err = WebRtcIsac_Control(ISAC_main_inst, bottleneck, framesize);
340      if (err < 0) {
341        /* exit if returned with error */
342        errtype = WebRtcIsac_GetErrorCode(ISAC_main_inst);
343        printf("\n\n Error in initialization: %d.\n\n", errtype);
344        // exit(EXIT_FAILURE);
345      }
346    }
347
348    /* Init iSAC FIX */
349    WebRtcIsacfix_EncoderInit(ISACFIX_main_inst, CodingMode);
350    WebRtcIsacfix_DecoderInit(ISACFIX_main_inst);
351    if (CodingMode == 1) {
352      err = WebRtcIsacfix_Control(ISACFIX_main_inst, bottleneck, framesize);
353      if (err < 0) {
354        /* exit if returned with error */
355        errtype = WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst);
356        printf("\n\n Error in initialization: %d.\n\n", errtype);
357        // exit(EXIT_FAILURE);
358      }
359    }
360  } else if (mode == 3) {
361    printf("Coding mode: Encode using FIX, decode using FIX \n\n");
362
363    WebRtcIsacfix_EncoderInit(ISACFIX_main_inst, CodingMode);
364    WebRtcIsacfix_DecoderInit(ISACFIX_main_inst);
365    if (CodingMode == 1) {
366      err = WebRtcIsacfix_Control(ISACFIX_main_inst, bottleneck, framesize);
367      if (err < 0) {
368        /* exit if returned with error */
369        errtype = WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst);
370        printf("\n\n Error in initialization: %d.\n\n", errtype);
371        // exit(EXIT_FAILURE);
372      }
373    }
374
375  } else
376    printf("Mode must be value between 0 and 3\n");
377  *speechType = 1;
378
379//#define BI_TEST 1
380#ifdef BI_TEST
381  err = WebRtcIsacfix_SetMaxPayloadSize(ISACFIX_main_inst, 300);
382  if (err < 0) {
383    /* exit if returned with error */
384    errtype = WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst);
385    printf("\n\n Error in setMaxPayloadSize: %d.\n\n", errtype);
386    fclose(inp);
387    fclose(outp);
388    fclose(bitsp);
389    return (EXIT_FAILURE);
390  }
391#endif
392
393  while (endfile == 0) {
394    cur_framesmpls = 0;
395    while (1) {
396      int stream_len_int;
397
398      /* Read 10 ms speech block */
399      if (nbTest != 1)
400        endfile = readframe(shortdata, inp, FRAMESAMPLES_10ms);
401      else
402        endfile = readframe(shortdata, inp, (FRAMESAMPLES_10ms / 2));
403
404      /* iSAC encoding */
405
406      if (mode == 0 || mode == 1) {
407        stream_len_int =
408            WebRtcIsac_Encode(ISAC_main_inst, shortdata, (uint8_t*)streamdata);
409        if (stream_len_int < 0) {
410          /* exit if returned with error */
411          errtype = WebRtcIsac_GetErrorCode(ISAC_main_inst);
412          printf("\n\nError in encoder: %d.\n\n", errtype);
413          // exit(EXIT_FAILURE);
414        }
415      } else if (mode == 2 || mode == 3) {
416        /* iSAC encoding */
417        if (nbTest != 1) {
418          stream_len_int = WebRtcIsacfix_Encode(ISACFIX_main_inst, shortdata,
419                                                (uint8_t*)streamdata);
420        } else {
421          stream_len_int =
422              WebRtcIsacfix_EncodeNb(ISACFIX_main_inst, shortdata, streamdata);
423        }
424
425        if (stream_len_int < 0) {
426          /* exit if returned with error */
427          errtype = WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst);
428          printf("\n\nError in encoder: %d.\n\n", errtype);
429          // exit(EXIT_FAILURE);
430        }
431      }
432      stream_len = (size_t)stream_len_int;
433
434      cur_framesmpls += FRAMESAMPLES_10ms;
435
436      /* read next bottleneck rate */
437      if (f_bn != NULL) {
438        if (fscanf(f_bn, "%d", &bottleneck) == EOF) {
439          /* Set pointer to beginning of file */
440          fseek(f_bn, 0L, SEEK_SET);
441          fscanf(f_bn, "%d", &bottleneck);
442        }
443        if (CodingMode == 1) {
444          if (mode == 0 || mode == 1)
445            WebRtcIsac_Control(ISAC_main_inst, bottleneck, framesize);
446          else if (mode == 2 || mode == 3)
447            WebRtcIsacfix_Control(ISACFIX_main_inst, bottleneck, framesize);
448        }
449      }
450
451      /* exit encoder loop if the encoder returned a bitstream */
452      if (stream_len != 0)
453        break;
454    }
455
456    fwrite(streamdata, 1, stream_len, bitsp); /* NOTE! Writes bytes to file */
457
458    /* simulate packet handling through NetEq and the modem */
459    get_arrival_time(cur_framesmpls, stream_len, bottleneck, &BN_data);
460    //*****************************
461    if (1) {
462      if (mode == 0) {
463        err = WebRtcIsac_UpdateBwEstimate(ISAC_main_inst, streamdata,
464                                          stream_len, BN_data.rtp_number,
465                                          BN_data.arrival_time);
466
467        if (err < 0) {
468          /* exit if returned with error */
469          errtype = WebRtcIsac_GetErrorCode(ISAC_main_inst);
470          printf("\n\nError in decoder: %d.\n\n", errtype);
471          // exit(EXIT_FAILURE);
472        }
473        /* iSAC decoding */
474        declen = WebRtcIsac_Decode(ISAC_main_inst, streamdata, stream_len,
475                                   decoded, speechType);
476        if (declen <= 0) {
477          /* exit if returned with error */
478          errtype = WebRtcIsac_GetErrorCode(ISAC_main_inst);
479          printf("\n\nError in decoder: %d.\n\n", errtype);
480          // exit(EXIT_FAILURE);
481        }
482      } else if (mode == 1) {
483        err = WebRtcIsac_UpdateBwEstimate(ISAC_main_inst, streamdata,
484                                          stream_len, BN_data.rtp_number,
485                                          BN_data.arrival_time);
486        err = WebRtcIsacfix_UpdateBwEstimate1(ISACFIX_main_inst, streamdata,
487                                              stream_len, BN_data.rtp_number,
488                                              BN_data.arrival_time);
489        if (err < 0) {
490          /* exit if returned with error */
491          errtype = WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst);
492          printf("\n\nError in decoder: %d.\n\n", errtype);
493          // exit(EXIT_FAILURE);
494        }
495
496        declen = WebRtcIsac_Decode(ISAC_main_inst, streamdata, stream_len,
497                                   decoded, speechType);
498
499        /* iSAC decoding */
500        if (plc && (framecnt + 1) % 10 == 0) {
501          if (nbTest != 2) {
502            declen =
503                (int)WebRtcIsacfix_DecodePlc(ISACFIX_main_inst, decoded, 1);
504          } else {
505            declen =
506                (int)WebRtcIsacfix_DecodePlcNb(ISACFIX_main_inst, decoded, 1);
507          }
508        } else {
509          if (nbTest != 2)
510            declen = WebRtcIsacfix_Decode(ISACFIX_main_inst, streamdata,
511                                          stream_len, decoded, speechType);
512          else
513            declen = WebRtcIsacfix_DecodeNb(ISACFIX_main_inst, streamdata,
514                                            stream_len, decoded, speechType);
515        }
516
517        if (declen <= 0) {
518          /* exit if returned with error */
519          errtype = WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst);
520          printf("\n\nError in decoder: %d.\n\n", errtype);
521          // exit(EXIT_FAILURE);
522        }
523      } else if (mode == 2) {
524        err = WebRtcIsacfix_UpdateBwEstimate1(ISACFIX_main_inst, streamdata,
525                                              stream_len, BN_data.rtp_number,
526                                              BN_data.arrival_time);
527
528        err = WebRtcIsac_UpdateBwEstimate(ISAC_main_inst, streamdata,
529                                          stream_len, BN_data.rtp_number,
530                                          BN_data.arrival_time);
531
532        if (err < 0) {
533          /* exit if returned with error */
534          errtype = WebRtcIsac_GetErrorCode(ISAC_main_inst);
535          printf("\n\nError in decoder: %d.\n\n", errtype);
536          // exit(EXIT_FAILURE);
537        }
538        /* iSAC decoding */
539        declen = WebRtcIsac_Decode(ISAC_main_inst, streamdata, stream_len,
540                                   decoded, speechType);
541        if (declen <= 0) {
542          /* exit if returned with error */
543          errtype = WebRtcIsac_GetErrorCode(ISAC_main_inst);
544          printf("\n\nError in decoder: %d.\n\n", errtype);
545          // exit(EXIT_FAILURE);
546        }
547      } else if (mode == 3) {
548        err = WebRtcIsacfix_UpdateBwEstimate(
549            ISACFIX_main_inst, streamdata, stream_len, BN_data.rtp_number,
550            BN_data.send_time, BN_data.arrival_time);
551
552        if (err < 0) {
553          /* exit if returned with error */
554          errtype = WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst);
555          printf("\n\nError in decoder: %d.\n\n", errtype);
556          // exit(EXIT_FAILURE);
557        }
558        /* iSAC decoding */
559
560        if (plc && (framecnt + 1) % 10 == 0) {
561          if (nbTest != 2) {
562            declen =
563                (int)WebRtcIsacfix_DecodePlc(ISACFIX_main_inst, decoded, 1);
564          } else {
565            declen =
566                (int)WebRtcIsacfix_DecodePlcNb(ISACFIX_main_inst, decoded, 1);
567          }
568        } else {
569          if (nbTest != 2) {
570            declen = WebRtcIsacfix_Decode(ISACFIX_main_inst, streamdata,
571                                          stream_len, decoded, speechType);
572          } else {
573            declen = WebRtcIsacfix_DecodeNb(ISACFIX_main_inst, streamdata,
574                                            stream_len, decoded, speechType);
575          }
576        }
577        if (declen <= 0) {
578          /* exit if returned with error */
579          errtype = WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst);
580          printf("\n\nError in decoder: %d.\n\n", errtype);
581          // exit(EXIT_FAILURE);
582        }
583      }
584
585      /* Write decoded speech frame to file */
586      fwrite(decoded, sizeof(int16_t), declen, outp);
587    }
588
589    fprintf(stderr, "  \rframe = %d", framecnt);
590    framecnt++;
591
592#if !defined(NDEBUG)
593
594    totalsmpls += declen;
595    totalbits += 8 * stream_len;
596    kbps = (double)FS / (double)cur_framesmpls * 8.0 * stream_len / 1000.0;
597    fy = fopen("bit_rate.dat", "a");
598    fprintf(fy, "Frame %i = %0.14f\n", framecnt, kbps);
599    fclose(fy);
600
601#endif
602  }
603
604#if !defined(NDEBUG)
605  printf("\n\ntotal bits               = %" PRIuS " bits", totalbits);
606  printf("\nmeasured average bitrate = %0.3f kbits/s",
607         (double)totalbits * (FS / 1000) / totalsmpls);
608  printf("\n");
609#endif
610
611  /* Runtime statistics */
612  runtime = (double)(clock() / (double)CLOCKS_PER_SEC - starttime);
613  length_file = ((double)framecnt * (double)declen / FS);
614  printf("\n\nLength of speech file: %.1f s\n", length_file);
615  printf("Time to run iSAC:      %.2f s (%.2f %% of realtime)\n\n", runtime,
616         (100 * runtime / length_file));
617  printf("---------------------END----------------------\n");
618
619  fclose(inp);
620  fclose(outp);
621
622  WebRtcIsac_Free(ISAC_main_inst);
623  WebRtcIsacfix_Free(ISACFIX_main_inst);
624
625  // fclose(histfile);
626  // fclose(ratefile);
627
628  return 0;
629}
630