tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

opus_fec_test.cc (8128B)


      1 /*
      2 *  Copyright (c) 2014 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 #include <cstddef>
     12 #include <cstdint>
     13 #include <cstdio>
     14 #include <cstdlib>
     15 #include <cstring>
     16 #include <memory>
     17 #include <string>
     18 #include <tuple>
     19 
     20 #include "modules/audio_coding/codecs/opus/opus_interface.h"
     21 #include "test/gtest.h"
     22 #include "test/testsupport/file_utils.h"
     23 
     24 using std::get;
     25 using std::string;
     26 using std::tuple;
     27 using ::testing::TestWithParam;
     28 
     29 namespace webrtc {
     30 
     31 // Define coding parameter as <channels, bit_rate, filename, extension>.
     32 typedef tuple<size_t, int, string, string> coding_param;
     33 typedef struct mode mode;
     34 
     35 struct mode {
     36  bool fec;
     37  uint8_t target_packet_loss_rate;
     38 };
     39 
     40 constexpr int kOpusBlockDurationMs = 20;
     41 constexpr int kOpusSamplingKhz = 48;
     42 
     43 class OpusFecTest : public TestWithParam<coding_param> {
     44 protected:
     45  OpusFecTest();
     46 
     47  void SetUp() override;
     48  void TearDown() override;
     49 
     50  virtual void EncodeABlock();
     51 
     52  virtual void DecodeABlock(bool lost_previous, bool lost_current);
     53 
     54  int block_duration_ms_;
     55  int sampling_khz_;
     56  size_t block_length_sample_;
     57 
     58  size_t channels_;
     59  int bit_rate_;
     60 
     61  size_t data_pointer_;
     62  size_t loop_length_samples_;
     63  size_t max_bytes_;
     64  size_t encoded_bytes_;
     65 
     66  WebRtcOpusEncInst* opus_encoder_;
     67  WebRtcOpusDecInst* opus_decoder_;
     68 
     69  string in_filename_;
     70 
     71  std::unique_ptr<int16_t[]> in_data_;
     72  std::unique_ptr<int16_t[]> out_data_;
     73  std::unique_ptr<uint8_t[]> bit_stream_;
     74 };
     75 
     76 void OpusFecTest::SetUp() {
     77  channels_ = get<0>(GetParam());
     78  bit_rate_ = get<1>(GetParam());
     79  printf("Coding %zu channel signal at %d bps.\n", channels_, bit_rate_);
     80 
     81  in_filename_ = test::ResourcePath(get<2>(GetParam()), get<3>(GetParam()));
     82 
     83  FILE* fp = fopen(in_filename_.c_str(), "rb");
     84  ASSERT_FALSE(fp == nullptr);
     85 
     86  // Obtain file size.
     87  fseek(fp, 0, SEEK_END);
     88  loop_length_samples_ = ftell(fp) / sizeof(int16_t);
     89  rewind(fp);
     90 
     91  // Allocate memory to contain the whole file.
     92  in_data_.reset(
     93      new int16_t[loop_length_samples_ + block_length_sample_ * channels_]);
     94 
     95  // Copy the file into the buffer.
     96  ASSERT_EQ(fread(&in_data_[0], sizeof(int16_t), loop_length_samples_, fp),
     97            loop_length_samples_);
     98  fclose(fp);
     99 
    100  // The audio will be used in a looped manner. To ease the acquisition of an
    101  // audio frame that crosses the end of the excerpt, we add an extra block
    102  // length of samples to the end of the array, starting over again from the
    103  // beginning of the array. Audio frames cross the end of the excerpt always
    104  // appear as a continuum of memory.
    105  memcpy(&in_data_[loop_length_samples_], &in_data_[0],
    106         block_length_sample_ * channels_ * sizeof(int16_t));
    107 
    108  // Maximum number of bytes in output bitstream.
    109  max_bytes_ = block_length_sample_ * channels_ * sizeof(int16_t);
    110 
    111  out_data_.reset(new int16_t[2 * block_length_sample_ * channels_]);
    112  bit_stream_.reset(new uint8_t[max_bytes_]);
    113 
    114  // If channels_ == 1, use Opus VOIP mode, otherwise, audio mode.
    115  int app = channels_ == 1 ? 0 : 1;
    116 
    117  // Create encoder memory.
    118  EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, app, 48000));
    119  EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_, 48000));
    120  // Set bitrate.
    121  EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, bit_rate_));
    122 }
    123 
    124 void OpusFecTest::TearDown() {
    125  // Free memory.
    126  EXPECT_EQ(0, WebRtcOpus_EncoderFree(opus_encoder_));
    127  EXPECT_EQ(0, WebRtcOpus_DecoderFree(opus_decoder_));
    128 }
    129 
    130 OpusFecTest::OpusFecTest()
    131    : block_duration_ms_(kOpusBlockDurationMs),
    132      sampling_khz_(kOpusSamplingKhz),
    133      block_length_sample_(
    134          static_cast<size_t>(block_duration_ms_ * sampling_khz_)),
    135      data_pointer_(0),
    136      max_bytes_(0),
    137      encoded_bytes_(0),
    138      opus_encoder_(nullptr),
    139      opus_decoder_(nullptr) {}
    140 
    141 void OpusFecTest::EncodeABlock() {
    142  int value =
    143      WebRtcOpus_Encode(opus_encoder_, &in_data_[data_pointer_],
    144                        block_length_sample_, max_bytes_, &bit_stream_[0]);
    145  EXPECT_GT(value, 0);
    146 
    147  encoded_bytes_ = static_cast<size_t>(value);
    148 }
    149 
    150 void OpusFecTest::DecodeABlock(bool lost_previous, bool lost_current) {
    151  int16_t audio_type;
    152  int value_1 = 0, value_2 = 0;
    153 
    154  if (lost_previous) {
    155    // Decode previous frame.
    156    if (!lost_current &&
    157        WebRtcOpus_PacketHasFec(&bit_stream_[0], encoded_bytes_) == 1) {
    158      value_1 =
    159          WebRtcOpus_DecodeFec(opus_decoder_, &bit_stream_[0], encoded_bytes_,
    160                               &out_data_[0], &audio_type);
    161    } else {
    162      // Call decoder PLC.
    163      while (value_1 < static_cast<int>(block_length_sample_)) {
    164        int ret = WebRtcOpus_Decode(opus_decoder_, nullptr, 0,
    165                                    &out_data_[value_1], &audio_type);
    166        EXPECT_EQ(ret, sampling_khz_ * 10);  // Should return 10 ms of samples.
    167        value_1 += ret;
    168      }
    169    }
    170    EXPECT_EQ(static_cast<int>(block_length_sample_), value_1);
    171  }
    172 
    173  if (!lost_current) {
    174    // Decode current frame.
    175    value_2 = WebRtcOpus_Decode(opus_decoder_, &bit_stream_[0], encoded_bytes_,
    176                                &out_data_[value_1 * channels_], &audio_type);
    177    EXPECT_EQ(static_cast<int>(block_length_sample_), value_2);
    178  }
    179 }
    180 
    181 TEST_P(OpusFecTest, RandomPacketLossTest) {
    182  const int kDurationMs = 200000;
    183  int time_now_ms, fec_frames;
    184  int actual_packet_loss_rate;
    185  bool lost_current, lost_previous;
    186  mode mode_set[3] = {{true, 0}, {false, 0}, {true, 50}};
    187 
    188  lost_current = false;
    189  for (int i = 0; i < 3; i++) {
    190    if (mode_set[i].fec) {
    191      EXPECT_EQ(0, WebRtcOpus_EnableFec(opus_encoder_));
    192      EXPECT_EQ(0, WebRtcOpus_SetPacketLossRate(
    193                       opus_encoder_, mode_set[i].target_packet_loss_rate));
    194      printf("FEC is ON, target at packet loss rate %d percent.\n",
    195             mode_set[i].target_packet_loss_rate);
    196    } else {
    197      EXPECT_EQ(0, WebRtcOpus_DisableFec(opus_encoder_));
    198      printf("FEC is OFF.\n");
    199    }
    200    // In this test, we let the target packet loss rate match the actual rate.
    201    actual_packet_loss_rate = mode_set[i].target_packet_loss_rate;
    202    // Run every mode a certain time.
    203    time_now_ms = 0;
    204    fec_frames = 0;
    205    while (time_now_ms < kDurationMs) {
    206      // Encode & decode.
    207      EncodeABlock();
    208 
    209      // Check if payload has FEC.
    210      int fec = WebRtcOpus_PacketHasFec(&bit_stream_[0], encoded_bytes_);
    211 
    212      // If FEC is disabled or the target packet loss rate is set to 0, there
    213      // should be no FEC in the bit stream.
    214      if (!mode_set[i].fec || mode_set[i].target_packet_loss_rate == 0) {
    215        EXPECT_EQ(fec, 0);
    216      } else if (fec == 1) {
    217        fec_frames++;
    218      }
    219 
    220      lost_previous = lost_current;
    221      lost_current = rand() < actual_packet_loss_rate * (RAND_MAX / 100);
    222      DecodeABlock(lost_previous, lost_current);
    223 
    224      time_now_ms += block_duration_ms_;
    225 
    226      // `data_pointer_` is incremented and wrapped across
    227      // `loop_length_samples_`.
    228      data_pointer_ = (data_pointer_ + block_length_sample_ * channels_) %
    229                      loop_length_samples_;
    230    }
    231    if (mode_set[i].fec) {
    232      printf("%.2f percent frames has FEC.\n",
    233             static_cast<float>(fec_frames) * block_duration_ms_ / 2000);
    234    }
    235  }
    236 }
    237 
    238 const coding_param param_set[] = {
    239    std::make_tuple(1,
    240                    64000,
    241                    string("audio_coding/testfile32kHz"),
    242                    string("pcm")),
    243    std::make_tuple(1,
    244                    32000,
    245                    string("audio_coding/testfile32kHz"),
    246                    string("pcm")),
    247    std::make_tuple(2,
    248                    64000,
    249                    string("audio_coding/teststereo32kHz"),
    250                    string("pcm"))};
    251 
    252 // 64 kbps, stereo
    253 INSTANTIATE_TEST_SUITE_P(AllTest, OpusFecTest, ::testing::ValuesIn(param_set));
    254 
    255 }  // namespace webrtc