tor-browser

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

red_payload_splitter_unittest.cc (15609B)


      1 /*
      2 *  Copyright (c) 2012 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 // Unit tests for RedPayloadSplitter class.
     12 
     13 #include "modules/audio_coding/neteq/red_payload_splitter.h"
     14 
     15 #include <cstddef>
     16 #include <cstdint>
     17 #include <cstring>
     18 #include <optional>
     19 #include <utility>  // pair
     20 
     21 #include "api/audio_codecs/audio_format.h"
     22 #include "api/environment/environment.h"
     23 #include "api/environment/environment_factory.h"
     24 #include "api/make_ref_counted.h"
     25 #include "modules/audio_coding/neteq/decoder_database.h"
     26 #include "modules/audio_coding/neteq/packet.h"
     27 #include "rtc_base/checks.h"
     28 #include "rtc_base/numerics/safe_conversions.h"
     29 #include "test/gtest.h"
     30 #include "test/mock_audio_decoder_factory.h"
     31 
     32 using ::testing::Return;
     33 using ::testing::ReturnNull;
     34 
     35 namespace webrtc {
     36 
     37 static const int kRedPayloadType = 100;
     38 static const size_t kPayloadLength = 10;
     39 static const uint16_t kSequenceNumber = 0;
     40 static const uint32_t kBaseTimestamp = 0x12345678;
     41 
     42 // A possible Opus packet that contains FEC is the following.
     43 // The frame is 20 ms in duration.
     44 //
     45 // 0                   1                   2                   3
     46 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     47 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     48 // |0|0|0|0|1|0|0|0|x|1|x|x|x|x|x|x|x|                             |
     49 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                             |
     50 // |                    Compressed frame 1 (N-2 bytes)...          :
     51 // :                                                               |
     52 // |                                                               |
     53 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     54 void CreateOpusFecPayload(uint8_t* payload,
     55                          size_t payload_length,
     56                          uint8_t payload_value) {
     57  if (payload_length < 2) {
     58    return;
     59  }
     60  payload[0] = 0x08;
     61  payload[1] = 0x40;
     62  memset(&payload[2], payload_value, payload_length - 2);
     63 }
     64 
     65 // RED headers (according to RFC 2198):
     66 //
     67 //    0                   1                   2                   3
     68 //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     69 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     70 //   |F|   block PT  |  timestamp offset         |   block length    |
     71 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     72 //
     73 // Last RED header:
     74 //    0 1 2 3 4 5 6 7
     75 //   +-+-+-+-+-+-+-+-+
     76 //   |0|   Block PT  |
     77 //   +-+-+-+-+-+-+-+-+
     78 
     79 // Creates a RED packet, with `num_payloads` payloads, with payload types given
     80 // by the values in array `payload_types` (which must be of length
     81 // `num_payloads`). Each redundant payload is `timestamp_offset` samples
     82 // "behind" the the previous payload.
     83 Packet CreateRedPayload(size_t num_payloads,
     84                        uint8_t* payload_types,
     85                        int timestamp_offset,
     86                        bool embed_opus_fec = false) {
     87  Packet packet;
     88  packet.payload_type = kRedPayloadType;
     89  packet.timestamp = kBaseTimestamp;
     90  packet.sequence_number = kSequenceNumber;
     91  packet.payload.SetSize((kPayloadLength + 1) +
     92                         (num_payloads - 1) *
     93                             (kPayloadLength + kRedHeaderLength));
     94  uint8_t* payload_ptr = packet.payload.data();
     95  for (size_t i = 0; i < num_payloads; ++i) {
     96    // Write the RED headers.
     97    if (i == num_payloads - 1) {
     98      // Special case for last payload.
     99      *payload_ptr = payload_types[i] & 0x7F;  // F = 0;
    100      ++payload_ptr;
    101      break;
    102    }
    103    *payload_ptr = payload_types[i] & 0x7F;
    104    // Not the last block; set F = 1.
    105    *payload_ptr |= 0x80;
    106    ++payload_ptr;
    107    int this_offset =
    108        checked_cast<int>((num_payloads - i - 1) * timestamp_offset);
    109    *payload_ptr = this_offset >> 6;
    110    ++payload_ptr;
    111    RTC_DCHECK_LE(kPayloadLength, 1023);  // Max length described by 10 bits.
    112    *payload_ptr = ((this_offset & 0x3F) << 2) | (kPayloadLength >> 8);
    113    ++payload_ptr;
    114    *payload_ptr = kPayloadLength & 0xFF;
    115    ++payload_ptr;
    116  }
    117  for (size_t i = 0; i < num_payloads; ++i) {
    118    // Write `i` to all bytes in each payload.
    119    if (embed_opus_fec) {
    120      CreateOpusFecPayload(payload_ptr, kPayloadLength,
    121                           static_cast<uint8_t>(i));
    122    } else {
    123      memset(payload_ptr, static_cast<int>(i), kPayloadLength);
    124    }
    125    payload_ptr += kPayloadLength;
    126  }
    127  return packet;
    128 }
    129 
    130 // Create a packet with all payload bytes set to `payload_value`.
    131 Packet CreatePacket(uint8_t payload_type,
    132                    size_t payload_length,
    133                    uint8_t payload_value,
    134                    bool opus_fec = false) {
    135  Packet packet;
    136  packet.payload_type = payload_type;
    137  packet.timestamp = kBaseTimestamp;
    138  packet.sequence_number = kSequenceNumber;
    139  packet.payload.SetSize(payload_length);
    140  if (opus_fec) {
    141    CreateOpusFecPayload(packet.payload.data(), packet.payload.size(),
    142                         payload_value);
    143  } else {
    144    memset(packet.payload.data(), payload_value, packet.payload.size());
    145  }
    146  return packet;
    147 }
    148 
    149 // Checks that `packet` has the attributes given in the remaining parameters.
    150 void VerifyPacket(const Packet& packet,
    151                  size_t payload_length,
    152                  uint8_t payload_type,
    153                  uint16_t sequence_number,
    154                  uint32_t timestamp,
    155                  uint8_t payload_value,
    156                  Packet::Priority priority) {
    157  EXPECT_EQ(payload_length, packet.payload.size());
    158  EXPECT_EQ(payload_type, packet.payload_type);
    159  EXPECT_EQ(sequence_number, packet.sequence_number);
    160  EXPECT_EQ(timestamp, packet.timestamp);
    161  EXPECT_EQ(priority, packet.priority);
    162  ASSERT_FALSE(packet.payload.empty());
    163  for (size_t i = 0; i < packet.payload.size(); ++i) {
    164    ASSERT_EQ(payload_value, packet.payload.data()[i]);
    165  }
    166 }
    167 
    168 void VerifyPacket(const Packet& packet,
    169                  size_t payload_length,
    170                  uint8_t payload_type,
    171                  uint16_t sequence_number,
    172                  uint32_t timestamp,
    173                  uint8_t payload_value,
    174                  bool primary) {
    175  return VerifyPacket(packet, payload_length, payload_type, sequence_number,
    176                      timestamp, payload_value,
    177                      Packet::Priority{0, primary ? 0 : 1});
    178 }
    179 
    180 // Start of test definitions.
    181 
    182 TEST(RedPayloadSplitter, CreateAndDestroy) {
    183  RedPayloadSplitter* splitter = new RedPayloadSplitter;
    184  delete splitter;
    185 }
    186 
    187 // Packet A is split into A1 and A2.
    188 TEST(RedPayloadSplitter, OnePacketTwoPayloads) {
    189  uint8_t payload_types[] = {0, 0};
    190  const int kTimestampOffset = 160;
    191  PacketList packet_list;
    192  packet_list.push_back(CreateRedPayload(2, payload_types, kTimestampOffset));
    193  RedPayloadSplitter splitter;
    194  EXPECT_TRUE(splitter.SplitRed(&packet_list));
    195  ASSERT_EQ(2u, packet_list.size());
    196  // Check first packet. The first in list should always be the primary payload.
    197  VerifyPacket(packet_list.front(), kPayloadLength, payload_types[1],
    198               kSequenceNumber, kBaseTimestamp, 1, true);
    199  packet_list.pop_front();
    200  // Check second packet.
    201  VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
    202               kSequenceNumber, kBaseTimestamp - kTimestampOffset, 0, false);
    203 }
    204 
    205 // Packets A and B are not split at all. Only the RED header in each packet is
    206 // removed.
    207 TEST(RedPayloadSplitter, TwoPacketsOnePayload) {
    208  uint8_t payload_types[] = {0};
    209  const int kTimestampOffset = 160;
    210  // Create first packet, with a single RED payload.
    211  PacketList packet_list;
    212  packet_list.push_back(CreateRedPayload(1, payload_types, kTimestampOffset));
    213  // Create second packet, with a single RED payload.
    214  {
    215    Packet packet = CreateRedPayload(1, payload_types, kTimestampOffset);
    216    // Manually change timestamp and sequence number of second packet.
    217    packet.timestamp += kTimestampOffset;
    218    packet.sequence_number++;
    219    packet_list.push_back(std::move(packet));
    220  }
    221  RedPayloadSplitter splitter;
    222  EXPECT_TRUE(splitter.SplitRed(&packet_list));
    223  ASSERT_EQ(2u, packet_list.size());
    224  // Check first packet.
    225  VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
    226               kSequenceNumber, kBaseTimestamp, 0, true);
    227  packet_list.pop_front();
    228  // Check second packet.
    229  VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
    230               kSequenceNumber + 1, kBaseTimestamp + kTimestampOffset, 0, true);
    231 }
    232 
    233 // Packets A and B are split into packets A1, A2, A3, B1, B2, B3, with
    234 // attributes as follows:
    235 //
    236 //                  A1*   A2    A3    B1*   B2    B3
    237 // Payload type     0     1     2     0     1     2
    238 // Timestamp        b     b-o   b-2o  b+o   b     b-o
    239 // Sequence number  0     0     0     1     1     1
    240 //
    241 // b = kBaseTimestamp, o = kTimestampOffset, * = primary.
    242 TEST(RedPayloadSplitter, TwoPacketsThreePayloads) {
    243  uint8_t payload_types[] = {2, 1, 0};  // Primary is the last one.
    244  const int kTimestampOffset = 160;
    245  // Create first packet, with 3 RED payloads.
    246  PacketList packet_list;
    247  packet_list.push_back(CreateRedPayload(3, payload_types, kTimestampOffset));
    248  // Create first packet, with 3 RED payloads.
    249  {
    250    Packet packet = CreateRedPayload(3, payload_types, kTimestampOffset);
    251    // Manually change timestamp and sequence number of second packet.
    252    packet.timestamp += kTimestampOffset;
    253    packet.sequence_number++;
    254    packet_list.push_back(std::move(packet));
    255  }
    256  RedPayloadSplitter splitter;
    257  EXPECT_TRUE(splitter.SplitRed(&packet_list));
    258  ASSERT_EQ(6u, packet_list.size());
    259  // Check first packet, A1.
    260  VerifyPacket(packet_list.front(), kPayloadLength, payload_types[2],
    261               kSequenceNumber, kBaseTimestamp, 2, {0, 0});
    262  packet_list.pop_front();
    263  // Check second packet, A2.
    264  VerifyPacket(packet_list.front(), kPayloadLength, payload_types[1],
    265               kSequenceNumber, kBaseTimestamp - kTimestampOffset, 1, {0, 1});
    266  packet_list.pop_front();
    267  // Check third packet, A3.
    268  VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
    269               kSequenceNumber, kBaseTimestamp - 2 * kTimestampOffset, 0,
    270               {0, 2});
    271  packet_list.pop_front();
    272  // Check fourth packet, B1.
    273  VerifyPacket(packet_list.front(), kPayloadLength, payload_types[2],
    274               kSequenceNumber + 1, kBaseTimestamp + kTimestampOffset, 2,
    275               {0, 0});
    276  packet_list.pop_front();
    277  // Check fifth packet, B2.
    278  VerifyPacket(packet_list.front(), kPayloadLength, payload_types[1],
    279               kSequenceNumber + 1, kBaseTimestamp, 1, {0, 1});
    280  packet_list.pop_front();
    281  // Check sixth packet, B3.
    282  VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
    283               kSequenceNumber + 1, kBaseTimestamp - kTimestampOffset, 0,
    284               {0, 2});
    285 }
    286 
    287 // Creates a list with 4 packets with these payload types:
    288 // 0 = CNGnb
    289 // 1 = PCMu
    290 // 2 = DTMF (AVT)
    291 // 3 = PCMa
    292 // We expect the method CheckRedPayloads to discard the PCMa packet, since it
    293 // is a non-CNG, non-DTMF payload of another type than the first speech payload
    294 // found in the list (which is PCMu).
    295 TEST(RedPayloadSplitter, CheckRedPayloads) {
    296  const Environment env = CreateEnvironment();
    297  PacketList packet_list;
    298  for (uint8_t i = 0; i <= 3; ++i) {
    299    // Create packet with payload type `i`, payload length 10 bytes, all 0.
    300    packet_list.push_back(CreatePacket(i, 10, 0));
    301  }
    302 
    303  // Use a real DecoderDatabase object here instead of a mock, since it is
    304  // easier to just register the payload types and let the actual implementation
    305  // do its job.
    306  DecoderDatabase decoder_database(
    307      env, make_ref_counted<MockAudioDecoderFactory>(), std::nullopt);
    308  decoder_database.RegisterPayload(0, SdpAudioFormat("cn", 8000, 1));
    309  decoder_database.RegisterPayload(1, SdpAudioFormat("pcmu", 8000, 1));
    310  decoder_database.RegisterPayload(2,
    311                                   SdpAudioFormat("telephone-event", 8000, 1));
    312  decoder_database.RegisterPayload(1, SdpAudioFormat("pcma", 8000, 1));
    313 
    314  RedPayloadSplitter splitter;
    315  splitter.CheckRedPayloads(&packet_list, decoder_database);
    316 
    317  ASSERT_EQ(3u, packet_list.size());  // Should have dropped the last packet.
    318  // Verify packets. The loop verifies that payload types 0, 1, and 2 are in the
    319  // list.
    320  for (int i = 0; i <= 2; ++i) {
    321    VerifyPacket(packet_list.front(), 10, i, kSequenceNumber, kBaseTimestamp, 0,
    322                 true);
    323    packet_list.pop_front();
    324  }
    325  EXPECT_TRUE(packet_list.empty());
    326 }
    327 
    328 // This test creates a RED packet where the payloads also have the payload type
    329 // for RED. That is, some kind of weird nested RED packet. This is not supported
    330 // and the splitter should discard all packets.
    331 TEST(RedPayloadSplitter, CheckRedPayloadsRecursiveRed) {
    332  const Environment env = CreateEnvironment();
    333  PacketList packet_list;
    334  for (uint8_t i = 0; i <= 3; ++i) {
    335    // Create packet with RED payload type, payload length 10 bytes, all 0.
    336    packet_list.push_back(CreatePacket(kRedPayloadType, 10, 0));
    337  }
    338 
    339  // Use a real DecoderDatabase object here instead of a mock, since it is
    340  // easier to just register the payload types and let the actual implementation
    341  // do its job.
    342  DecoderDatabase decoder_database(
    343      env, make_ref_counted<MockAudioDecoderFactory>(), std::nullopt);
    344  decoder_database.RegisterPayload(kRedPayloadType,
    345                                   SdpAudioFormat("red", 8000, 1));
    346 
    347  RedPayloadSplitter splitter;
    348  splitter.CheckRedPayloads(&packet_list, decoder_database);
    349 
    350  EXPECT_TRUE(packet_list.empty());  // Should have dropped all packets.
    351 }
    352 
    353 // Packet A is split into A1, A2 and A3. But the length parameter is off, so
    354 // the last payloads should be discarded.
    355 TEST(RedPayloadSplitter, WrongPayloadLength) {
    356  uint8_t payload_types[] = {0, 0, 0};
    357  const int kTimestampOffset = 160;
    358  PacketList packet_list;
    359  {
    360    Packet packet = CreateRedPayload(3, payload_types, kTimestampOffset);
    361    // Manually tamper with the payload length of the packet.
    362    // This is one byte too short for the second payload (out of three).
    363    // We expect only the first payload to be returned.
    364    packet.payload.SetSize(packet.payload.size() - (kPayloadLength + 1));
    365    packet_list.push_back(std::move(packet));
    366  }
    367  RedPayloadSplitter splitter;
    368  EXPECT_FALSE(splitter.SplitRed(&packet_list));
    369  ASSERT_EQ(1u, packet_list.size());
    370  // Check first packet.
    371  VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
    372               kSequenceNumber, kBaseTimestamp - 2 * kTimestampOffset, 0,
    373               {0, 2});
    374  packet_list.pop_front();
    375 }
    376 
    377 // Test that we reject packets too short to contain a RED header.
    378 TEST(RedPayloadSplitter, RejectsIncompleteHeaders) {
    379  RedPayloadSplitter splitter;
    380 
    381  uint8_t payload_types[] = {0, 0};
    382  const int kTimestampOffset = 160;
    383 
    384  PacketList packet_list;
    385 
    386  // Truncate the packet such that the first block can not be parsed.
    387  packet_list.push_back(CreateRedPayload(2, payload_types, kTimestampOffset));
    388  packet_list.front().payload.SetSize(4);
    389  EXPECT_FALSE(splitter.SplitRed(&packet_list));
    390  EXPECT_FALSE(packet_list.empty());
    391 
    392  // Truncate the packet such that the first block can not be parsed.
    393  packet_list.front().payload.SetSize(3);
    394  EXPECT_FALSE(splitter.SplitRed(&packet_list));
    395  EXPECT_FALSE(packet_list.empty());
    396 }
    397 
    398 }  // namespace webrtc