1b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org/*
2b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org *
4b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org *  Use of this source code is governed by a BSD-style license
5b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org *  that can be found in the LICENSE file in the root of the source
6b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org *  tree. An additional intellectual property rights grant can be found
7b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org *  in the file PATENTS.  All contributing project authors may
8b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org */
10b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org
116568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org#include <math.h>
12b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org#include <stdio.h>
1383b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin#include "webrtc/base/checks.h"
149c55f0f957534144d2b8a64154f0a479249b34behenrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.h"
1583b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin#include "webrtc/modules/audio_coding/neteq/tools/output_audio_file.h"
1683b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin#include "webrtc/modules/audio_coding/neteq/tools/output_wav_file.h"
1783b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin#include "webrtc/modules/audio_coding/neteq/tools/resample_input_audio_file.h"
1883b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin#include "webrtc/test/testsupport/fileutils.h"
1983b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin
2083b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundinusing std::string;
21b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org
22b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.orgnamespace webrtc {
23b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.orgnamespace test {
24b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org
25b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.orgconst uint8_t kPayloadType = 95;
26b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.orgconst int kOutputSizeMs = 10;
276568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgconst int kInitSeed = 0x12345678;
286568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgconst int kPacketLossTimeUnitMs = 10;
296568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
3083b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin// Common validator for file names.
3183b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundinstatic bool ValidateFilename(const string& value, bool write) {
3283b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  FILE* fid = write ? fopen(value.c_str(), "wb") : fopen(value.c_str(), "rb");
3383b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  if (fid == nullptr)
3483b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin    return false;
3583b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  fclose(fid);
3683b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  return true;
3783b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin}
3883b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin
3983b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin// Define switch for input file name.
4083b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundinstatic bool ValidateInFilename(const char* flagname, const string& value) {
4183b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  if (!ValidateFilename(value, false)) {
4283b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin    printf("Invalid input filename.");
4383b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin    return false;
4483b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  }
4583b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  return true;
4683b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin}
4783b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin
4883b5c053b9687813c5fc9c08b3beee4d464f7950Henrik LundinDEFINE_string(
4983b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin    in_filename,
5083b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin    ResourcePath("audio_coding/speech_mono_16kHz", "pcm"),
51f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li    "Filename for input audio (specify sample rate with --input_sample_rate ,"
52f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li    "and channels with --channels).");
5383b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin
5483b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundinstatic const bool in_filename_dummy =
5583b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin    RegisterFlagValidator(&FLAGS_in_filename, &ValidateInFilename);
5683b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin
5783b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin// Define switch for sample rate.
5883b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundinstatic bool ValidateSampleRate(const char* flagname, int32_t value) {
5983b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  if (value == 8000 || value == 16000 || value == 32000 || value == 48000)
6083b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin    return true;
6183b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  printf("Invalid sample rate should be 8000, 16000, 32000 or 48000 Hz.");
6283b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  return false;
6383b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin}
6483b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin
6583b5c053b9687813c5fc9c08b3beee4d464f7950Henrik LundinDEFINE_int32(input_sample_rate, 16000, "Sample rate of input file in Hz.");
6683b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin
6783b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundinstatic const bool sample_rate_dummy =
6883b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin    RegisterFlagValidator(&FLAGS_input_sample_rate, &ValidateSampleRate);
6983b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin
70f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li// Define switch for channels.
71f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Listatic bool ValidateChannels(const char* flagname, int32_t value) {
72f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li  if (value == 1)
73f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li    return true;
74f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li  printf("Invalid number of channels, current support only 1.");
75f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li  return false;
76f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li}
77f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li
78f761d10393ae47283c6170387fcb8cce4aadbd59Minyue LiDEFINE_int32(channels, 1, "Number of channels in input audio.");
79f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li
80f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Listatic const bool channels_dummy =
81f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li    RegisterFlagValidator(&FLAGS_channels, &ValidateChannels);
82f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li
8383b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin// Define switch for output file name.
8483b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundinstatic bool ValidateOutFilename(const char* flagname, const string& value) {
8583b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  if (!ValidateFilename(value, true)) {
8683b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin    printf("Invalid output filename.");
8783b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin    return false;
8883b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  }
8983b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  return true;
9083b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin}
9183b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin
9283b5c053b9687813c5fc9c08b3beee4d464f7950Henrik LundinDEFINE_string(out_filename,
9383b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin              OutputPath() + "neteq_quality_test_out.pcm",
9483b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin              "Name of output audio file.");
9583b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin
9683b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundinstatic const bool out_filename_dummy =
9783b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin    RegisterFlagValidator(&FLAGS_out_filename, &ValidateOutFilename);
9883b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin
996568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org// Define switch for packet loss rate.
1006568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgstatic bool ValidatePacketLossRate(const char* /* flag_name */, int32_t value) {
1016568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  if (value >= 0 && value <= 100)
1026568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    return true;
1036568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  printf("Invalid packet loss percentile, should be between 0 and 100.");
1046568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  return false;
1056568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org}
1066568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
107e5ff00a1c65750e7d30a25c4f1da91f0c035d07fHenrik Lundin// Define switch for runtime.
108e5ff00a1c65750e7d30a25c4f1da91f0c035d07fHenrik Lundinstatic bool ValidateRuntime(const char* flagname, int32_t value) {
109e5ff00a1c65750e7d30a25c4f1da91f0c035d07fHenrik Lundin  if (value > 0)
110e5ff00a1c65750e7d30a25c4f1da91f0c035d07fHenrik Lundin    return true;
111e5ff00a1c65750e7d30a25c4f1da91f0c035d07fHenrik Lundin  printf("Invalid runtime, should be greater than 0.");
112e5ff00a1c65750e7d30a25c4f1da91f0c035d07fHenrik Lundin  return false;
113e5ff00a1c65750e7d30a25c4f1da91f0c035d07fHenrik Lundin}
114e5ff00a1c65750e7d30a25c4f1da91f0c035d07fHenrik Lundin
115e5ff00a1c65750e7d30a25c4f1da91f0c035d07fHenrik LundinDEFINE_int32(runtime_ms, 10000, "Simulated runtime (milliseconds).");
116e5ff00a1c65750e7d30a25c4f1da91f0c035d07fHenrik Lundin
117e5ff00a1c65750e7d30a25c4f1da91f0c035d07fHenrik Lundinstatic const bool runtime_dummy =
118e5ff00a1c65750e7d30a25c4f1da91f0c035d07fHenrik Lundin    RegisterFlagValidator(&FLAGS_runtime_ms, &ValidateRuntime);
119e5ff00a1c65750e7d30a25c4f1da91f0c035d07fHenrik Lundin
1206568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgDEFINE_int32(packet_loss_rate, 10, "Percentile of packet loss.");
1216568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
1226568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgstatic const bool packet_loss_rate_dummy =
1236568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    RegisterFlagValidator(&FLAGS_packet_loss_rate, &ValidatePacketLossRate);
1246568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
1256568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org// Define switch for random loss mode.
1266568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgstatic bool ValidateRandomLossMode(const char* /* flag_name */, int32_t value) {
1276568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  if (value >= 0 && value <= 2)
1286568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    return true;
1296568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  printf("Invalid random packet loss mode, should be between 0 and 2.");
1306568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  return false;
1316568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org}
1326568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
1336568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgDEFINE_int32(random_loss_mode, 1,
1346568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    "Random loss mode: 0--no loss, 1--uniform loss, 2--Gilbert Elliot loss.");
1356568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgstatic const bool random_loss_mode_dummy =
1366568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    RegisterFlagValidator(&FLAGS_random_loss_mode, &ValidateRandomLossMode);
1376568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
1386568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org// Define switch for burst length.
1396568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgstatic bool ValidateBurstLength(const char* /* flag_name */, int32_t value) {
1406568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  if (value >= kPacketLossTimeUnitMs)
1416568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    return true;
1426568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  printf("Invalid burst length, should be greater than %d ms.",
1436568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org         kPacketLossTimeUnitMs);
1446568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  return false;
1456568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org}
1466568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
1476568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgDEFINE_int32(burst_length, 30,
1486568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    "Burst length in milliseconds, only valid for Gilbert Elliot loss.");
1496568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
1506568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgstatic const bool burst_length_dummy =
1516568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    RegisterFlagValidator(&FLAGS_burst_length, &ValidateBurstLength);
1526568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
1536568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org// Define switch for drift factor.
1546568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgstatic bool ValidateDriftFactor(const char* /* flag_name */, double value) {
1556568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  if (value > -0.1)
1566568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    return true;
1576568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  printf("Invalid drift factor, should be greater than -0.1.");
1586568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  return false;
1596568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org}
1606568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
1616568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgDEFINE_double(drift_factor, 0.0, "Time drift factor.");
1626568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
1636568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgstatic const bool drift_factor_dummy =
1646568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    RegisterFlagValidator(&FLAGS_drift_factor, &ValidateDriftFactor);
1656568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
1666568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org// ProbTrans00Solver() is to calculate the transition probability from no-loss
1676568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org// state to itself in a modified Gilbert Elliot packet loss model. The result is
1686568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org// to achieve the target packet loss rate |loss_rate|, when a packet is not
1696568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org// lost only if all |units| drawings within the duration of the packet result in
1706568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org// no-loss.
1716568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgstatic double ProbTrans00Solver(int units, double loss_rate,
1726568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org                                double prob_trans_10) {
1736568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  if (units == 1)
1746568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    return prob_trans_10 / (1.0f - loss_rate) - prob_trans_10;
1756568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org// 0 == prob_trans_00 ^ (units - 1) + (1 - loss_rate) / prob_trans_10 *
1766568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org//     prob_trans_00 - (1 - loss_rate) * (1 + 1 / prob_trans_10).
1776568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org// There is a unique solution between 0.0 and 1.0, due to the monotonicity and
1786568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org// an opposite sign at 0.0 and 1.0.
1796568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org// For simplicity, we reformulate the equation as
1806568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org//     f(x) = x ^ (units - 1) + a x + b.
1816568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org// Its derivative is
1826568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org//     f'(x) = (units - 1) x ^ (units - 2) + a.
1836568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org// The derivative is strictly greater than 0 when x is between 0 and 1.
1846568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org// We use Newton's method to solve the equation, iteration is
1856568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org//     x(k+1) = x(k) - f(x) / f'(x);
1866568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  const double kPrecision = 0.001f;
1876568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  const int kIterations = 100;
1886568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  const double a = (1.0f - loss_rate) / prob_trans_10;
1896568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  const double b = (loss_rate - 1.0f) * (1.0f + 1.0f / prob_trans_10);
1906568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  double x = 0.0f;  // Starting point;
1916568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  double f = b;
1926568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  double f_p;
1936568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  int iter = 0;
1946568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  while ((f >= kPrecision || f <= -kPrecision) && iter < kIterations) {
1956568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    f_p = (units - 1.0f) * pow(x, units - 2) + a;
1966568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    x -= f / f_p;
1976568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    if (x > 1.0f) {
1986568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      x = 1.0f;
1996568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    } else if (x < 0.0f) {
2006568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      x = 0.0f;
2016568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    }
2026568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    f = pow(x, units - 1) + a * x + b;
2036568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    iter ++;
2046568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  }
2056568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  return x;
2066568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org}
207b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org
208b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.orgNetEqQualityTest::NetEqQualityTest(int block_duration_ms,
209b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org                                   int in_sampling_khz,
210b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org                                   int out_sampling_khz,
211ee1879ca40ffe4af9bb9613e03eacc5c2c4881fckwiberg                                   NetEqDecoder decoder_type)
212f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li    : decoder_type_(decoder_type),
2136955870806624479723addfae6dcf5d13968796cPeter Kasting      channels_(static_cast<size_t>(FLAGS_channels)),
214f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li      decoded_time_ms_(0),
215b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org      decodable_time_ms_(0),
2166568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      drift_factor_(FLAGS_drift_factor),
2176568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      packet_loss_rate_(FLAGS_packet_loss_rate),
218b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org      block_duration_ms_(block_duration_ms),
219b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org      in_sampling_khz_(in_sampling_khz),
220b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org      out_sampling_khz_(out_sampling_khz),
221dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting      in_size_samples_(
222dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting          static_cast<size_t>(in_sampling_khz_ * block_duration_ms_)),
223dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting      out_size_samples_(static_cast<size_t>(out_sampling_khz_ * kOutputSizeMs)),
224b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org      payload_size_bytes_(0),
225b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org      max_payload_bytes_(0),
22683b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin      in_file_(new ResampleInputAudioFile(FLAGS_in_filename,
22783b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin                                          FLAGS_input_sample_rate,
22883b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin                                          in_sampling_khz * 1000)),
22983b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin      rtp_generator_(
23083b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin          new RtpGenerator(in_sampling_khz_, 0, 0, decodable_time_ms_)),
2316568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      total_payload_size_bytes_(0) {
23283b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  const std::string out_filename = FLAGS_out_filename;
23383b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  const std::string log_filename = out_filename + ".log";
234f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li  log_file_.open(log_filename.c_str(), std::ofstream::out);
23591d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_CHECK(log_file_.is_open());
23683b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin
23783b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  if (out_filename.size() >= 4 &&
23883b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin      out_filename.substr(out_filename.size() - 4) == ".wav") {
23983b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin    // Open a wav file.
24083b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin    output_.reset(
24183b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin        new webrtc::test::OutputWavFile(out_filename, 1000 * out_sampling_khz));
24283b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  } else {
24383b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin    // Open a pcm file.
24483b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin    output_.reset(new webrtc::test::OutputAudioFile(out_filename));
24583b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin  }
24683b5c053b9687813c5fc9c08b3beee4d464f7950Henrik Lundin
24735ead381f8dff68ba2f6b7ff163ede6cf4bccc24henrik.lundin@webrtc.org  NetEq::Config config;
24835ead381f8dff68ba2f6b7ff163ede6cf4bccc24henrik.lundin@webrtc.org  config.sample_rate_hz = out_sampling_khz_ * 1000;
24935ead381f8dff68ba2f6b7ff163ede6cf4bccc24henrik.lundin@webrtc.org  neteq_.reset(NetEq::Create(config));
250b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org  max_payload_bytes_ = in_size_samples_ * channels_ * sizeof(int16_t);
251b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org  in_data_.reset(new int16_t[in_size_samples_ * channels_]);
252b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org  payload_.reset(new uint8_t[max_payload_bytes_]);
253b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org  out_data_.reset(new int16_t[out_size_samples_ * channels_]);
254b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org}
255b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org
256f761d10393ae47283c6170387fcb8cce4aadbd59Minyue LiNetEqQualityTest::~NetEqQualityTest() {
257f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li  log_file_.close();
258f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li}
259f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li
2606568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgbool NoLoss::Lost() {
2616568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  return false;
2626568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org}
2636568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
264194fea7640f6aa8598f1bc454f7350a4b6f22808minyue@webrtc.orgUniformLoss::UniformLoss(double loss_rate)
2656568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    : loss_rate_(loss_rate) {
2666568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org}
2676568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
2686568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgbool UniformLoss::Lost() {
2696568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  int drop_this = rand();
2706568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  return (drop_this < loss_rate_ * RAND_MAX);
2716568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org}
2726568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
2736568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgGilbertElliotLoss::GilbertElliotLoss(double prob_trans_11, double prob_trans_01)
2746568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    : prob_trans_11_(prob_trans_11),
2756568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      prob_trans_01_(prob_trans_01),
2766568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      lost_last_(false),
2776568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      uniform_loss_model_(new UniformLoss(0)) {
2786568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org}
2796568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
2806568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgbool GilbertElliotLoss::Lost() {
2816568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  // Simulate bursty channel (Gilbert model).
2826568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  // (1st order) Markov chain model with memory of the previous/last
2836568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  // packet state (lost or received).
2846568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  if (lost_last_) {
2856568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    // Previous packet was not received.
2866568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    uniform_loss_model_->set_loss_rate(prob_trans_11_);
2876568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    return lost_last_ = uniform_loss_model_->Lost();
2886568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  } else {
2896568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    uniform_loss_model_->set_loss_rate(prob_trans_01_);
2906568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    return lost_last_ = uniform_loss_model_->Lost();
2916568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  }
2926568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org}
2936568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
294b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.orgvoid NetEqQualityTest::SetUp() {
2954cf61dd116288e9f119209c59e07f1d9439d8d05henrik.lundin  ASSERT_EQ(0,
2964cf61dd116288e9f119209c59e07f1d9439d8d05henrik.lundin            neteq_->RegisterPayloadType(decoder_type_, "noname", kPayloadType));
297b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org  rtp_generator_->set_drift_factor(drift_factor_);
2986568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
2996568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  int units = block_duration_ms_ / kPacketLossTimeUnitMs;
3006568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  switch (FLAGS_random_loss_mode) {
3016568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    case 1: {
3026568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // |unit_loss_rate| is the packet loss rate for each unit time interval
3036568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // (kPacketLossTimeUnitMs). Since a packet loss event is generated if any
3046568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // of |block_duration_ms_ / kPacketLossTimeUnitMs| unit time intervals of
3056568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // a full packet duration is drawn with a loss, |unit_loss_rate| fulfills
3066568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // (1 - unit_loss_rate) ^ (block_duration_ms_ / kPacketLossTimeUnitMs) ==
3076568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // 1 - packet_loss_rate.
3086568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      double unit_loss_rate = (1.0f - pow(1.0f - 0.01f * packet_loss_rate_,
3096568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org          1.0f / units));
3106568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      loss_model_.reset(new UniformLoss(unit_loss_rate));
3116568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      break;
3126568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    }
3136568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    case 2: {
3146568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // |FLAGS_burst_length| should be integer times of kPacketLossTimeUnitMs.
3156568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      ASSERT_EQ(0, FLAGS_burst_length % kPacketLossTimeUnitMs);
3166568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
3176568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // We do not allow 100 percent packet loss in Gilbert Elliot model, which
3186568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // makes no sense.
3196568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      ASSERT_GT(100, packet_loss_rate_);
3206568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
3216568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // To guarantee the overall packet loss rate, transition probabilities
3226568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // need to satisfy:
3236568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // pi_0 * (1 - prob_trans_01_) ^ units +
3246568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      //     pi_1 * prob_trans_10_ ^ (units - 1) == 1 - loss_rate
3256568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // pi_0 = prob_trans_10 / (prob_trans_10 + prob_trans_01_)
3266568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      //     is the stationary state probability of no-loss
3276568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // pi_1 = prob_trans_01_ / (prob_trans_10 + prob_trans_01_)
3286568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      //     is the stationary state probability of loss
3296568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // After a derivation prob_trans_00 should satisfy:
3306568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // prob_trans_00 ^ (units - 1) = (loss_rate - 1) / prob_trans_10 *
3316568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      //     prob_trans_00 + (1 - loss_rate) * (1 + 1 / prob_trans_10).
3326568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      double loss_rate = 0.01f * packet_loss_rate_;
3336568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      double prob_trans_10 = 1.0f * kPacketLossTimeUnitMs / FLAGS_burst_length;
3346568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      double prob_trans_00 = ProbTrans00Solver(units, loss_rate, prob_trans_10);
3356568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      loss_model_.reset(new GilbertElliotLoss(1.0f - prob_trans_10,
3366568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org                                              1.0f - prob_trans_00));
3376568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      break;
3386568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    }
3396568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    default: {
3406568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      loss_model_.reset(new NoLoss);
3416568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      break;
3426568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    }
3436568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  }
3446568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
3456568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  // Make sure that the packet loss profile is same for all derived tests.
3466568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  srand(kInitSeed);
347b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org}
348b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org
349f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Listd::ofstream& NetEqQualityTest::Log() {
350f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li  return log_file_;
351f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li}
352f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li
3536568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.orgbool NetEqQualityTest::PacketLost() {
3546568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  int cycles = block_duration_ms_ / kPacketLossTimeUnitMs;
3556568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
3566568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  // The loop is to make sure that codecs with different block lengths share the
3576568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  // same packet loss profile.
3586568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  bool lost = false;
3596568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  for (int idx = 0; idx < cycles; idx ++) {
3606568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    if (loss_model_->Lost()) {
3616568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // The packet will be lost if any of the drawings indicates a loss, but
3626568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // the loop has to go on to make sure that codecs with different block
3636568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      // lengths keep the same pace.
3646568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      lost = true;
3656568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    }
3666568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  }
3676568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  return lost;
3686568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org}
3696568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org
370b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.orgint NetEqQualityTest::Transmit() {
371b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org  int packet_input_time_ms =
372b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org      rtp_generator_->GetRtpHeader(kPayloadType, in_size_samples_,
373b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org                                   &rtp_header_);
374f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li  Log() << "Packet of size "
375f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li        << payload_size_bytes_
376f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li        << " bytes, for frame at "
377f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li        << packet_input_time_ms
378f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li        << " ms ";
3796568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org  if (payload_size_bytes_ > 0) {
3806568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    if (!PacketLost()) {
381ee2bac26dd3eb4463126098f87701ff66098b288kwiberg      int ret = neteq_->InsertPacket(
382ee2bac26dd3eb4463126098f87701ff66098b288kwiberg          rtp_header_,
383ee2bac26dd3eb4463126098f87701ff66098b288kwiberg          rtc::ArrayView<const uint8_t>(payload_.get(), payload_size_bytes_),
384ee2bac26dd3eb4463126098f87701ff66098b288kwiberg          packet_input_time_ms * in_sampling_khz_);
3856568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      if (ret != NetEq::kOK)
3866568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org        return -1;
387f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li      Log() << "was sent.";
3886568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    } else {
389f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li      Log() << "was lost.";
3906568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    }
391b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org  }
392f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li  Log() << std::endl;
393b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org  return packet_input_time_ms;
394b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org}
395b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org
396b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.orgint NetEqQualityTest::DecodeBlock() {
3976955870806624479723addfae6dcf5d13968796cPeter Kasting  size_t channels;
398dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting  size_t samples;
399b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org  int ret = neteq_->GetAudio(out_size_samples_ * channels_, &out_data_[0],
400b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org                             &samples, &channels, NULL);
401b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org
402b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org  if (ret != NetEq::kOK) {
403b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org    return -1;
404b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org  } else {
405b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org    assert(channels == channels_);
406dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting    assert(samples == static_cast<size_t>(kOutputSizeMs * out_sampling_khz_));
40791d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg    RTC_CHECK(output_->WriteArray(out_data_.get(), samples * channels));
408dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting    return static_cast<int>(samples);
409b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org  }
410b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org}
411b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org
412e5ff00a1c65750e7d30a25c4f1da91f0c035d07fHenrik Lundinvoid NetEqQualityTest::Simulate() {
413b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org  int audio_size_samples;
414b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org
415e5ff00a1c65750e7d30a25c4f1da91f0c035d07fHenrik Lundin  while (decoded_time_ms_ < FLAGS_runtime_ms) {
4166568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    // Assume 10 packets in packets buffer.
4176568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org    while (decodable_time_ms_ - 10 * block_duration_ms_ < decoded_time_ms_) {
418b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org      ASSERT_TRUE(in_file_->Read(in_size_samples_ * channels_, &in_data_[0]));
419b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org      payload_size_bytes_ = EncodeBlock(&in_data_[0],
420b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org                                        in_size_samples_, &payload_[0],
421b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org                                        max_payload_bytes_);
4226568e97d108dffbf10af04a764287f3d1589691fminyue@webrtc.org      total_payload_size_bytes_ += payload_size_bytes_;
423b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org      decodable_time_ms_ = Transmit() + block_duration_ms_;
424b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org    }
425b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org    audio_size_samples = DecodeBlock();
426b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org    if (audio_size_samples > 0) {
427b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org      decoded_time_ms_ += audio_size_samples / out_sampling_khz_;
428b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org    }
429b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org  }
430f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li  Log() << "Average bit rate was "
431f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li        << 8.0f * total_payload_size_bytes_ / FLAGS_runtime_ms
432f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li        << " kbps"
433f761d10393ae47283c6170387fcb8cce4aadbd59Minyue Li        << std::endl;
434b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org}
435b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org
436b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org}  // namespace test
437b28bfa7efcffa3800f64ebd6aeb54face45c180dminyue@webrtc.org}  // namespace webrtc
438