tor-browser

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

rtcp_transceiver_unittest.cc (13137B)


      1 /*
      2 *  Copyright (c) 2017 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 "modules/rtp_rtcp/source/rtcp_transceiver.h"
     12 
     13 #include <cstdint>
     14 #include <memory>
     15 #include <utility>
     16 #include <vector>
     17 
     18 #include "api/array_view.h"
     19 #include "api/units/time_delta.h"
     20 #include "api/units/timestamp.h"
     21 #include "modules/rtp_rtcp/source/rtcp_packet.h"
     22 #include "modules/rtp_rtcp/source/rtcp_packet/remote_estimate.h"
     23 #include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
     24 #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
     25 #include "modules/rtp_rtcp/source/rtcp_transceiver_config.h"
     26 #include "rtc_base/buffer.h"
     27 #include "rtc_base/copy_on_write_buffer.h"
     28 #include "rtc_base/event.h"
     29 #include "rtc_base/task_queue_for_test.h"
     30 #include "system_wrappers/include/clock.h"
     31 #include "system_wrappers/include/ntp_time.h"
     32 #include "test/gmock.h"
     33 #include "test/gtest.h"
     34 #include "test/rtcp_packet_parser.h"
     35 
     36 namespace {
     37 
     38 using ::testing::_;
     39 using ::testing::AtLeast;
     40 using ::testing::InvokeWithoutArgs;
     41 using ::testing::IsNull;
     42 using ::testing::MockFunction;
     43 using ::testing::NiceMock;
     44 using ::webrtc::RtcpTransceiver;
     45 using ::webrtc::RtcpTransceiverConfig;
     46 using ::webrtc::SimulatedClock;
     47 using ::webrtc::TaskQueueForTest;
     48 using ::webrtc::Timestamp;
     49 using ::webrtc::rtcp::RemoteEstimate;
     50 using ::webrtc::rtcp::RtcpPacket;
     51 using ::webrtc::rtcp::TransportFeedback;
     52 using ::webrtc::test::RtcpPacketParser;
     53 
     54 class MockMediaReceiverRtcpObserver : public webrtc::MediaReceiverRtcpObserver {
     55 public:
     56  MOCK_METHOD(void,
     57              OnSenderReport,
     58              (uint32_t, webrtc::NtpTime, uint32_t),
     59              (override));
     60 };
     61 
     62 constexpr webrtc::TimeDelta kTimeout = webrtc::TimeDelta::Seconds(1);
     63 
     64 void WaitPostedTasks(TaskQueueForTest* queue) {
     65  webrtc::Event done;
     66  queue->PostTask([&done] { done.Set(); });
     67  ASSERT_TRUE(done.Wait(kTimeout));
     68 }
     69 
     70 TEST(RtcpTransceiverTest, SendsRtcpOnTaskQueueWhenCreatedOffTaskQueue) {
     71  SimulatedClock clock(0);
     72  MockFunction<void(webrtc::ArrayView<const uint8_t>)> outgoing_transport;
     73  TaskQueueForTest queue("rtcp");
     74  RtcpTransceiverConfig config;
     75  config.clock = &clock;
     76  config.rtcp_transport = outgoing_transport.AsStdFunction();
     77  config.task_queue = queue.Get();
     78  EXPECT_CALL(outgoing_transport, Call).WillRepeatedly(InvokeWithoutArgs([&] {
     79    EXPECT_TRUE(queue.IsCurrent());
     80    return true;
     81  }));
     82 
     83  RtcpTransceiver rtcp_transceiver(config);
     84  rtcp_transceiver.SendCompoundPacket();
     85  WaitPostedTasks(&queue);
     86 }
     87 
     88 TEST(RtcpTransceiverTest, SendsRtcpOnTaskQueueWhenCreatedOnTaskQueue) {
     89  SimulatedClock clock(0);
     90  MockFunction<void(webrtc::ArrayView<const uint8_t>)> outgoing_transport;
     91  TaskQueueForTest queue("rtcp");
     92  RtcpTransceiverConfig config;
     93  config.clock = &clock;
     94  config.rtcp_transport = outgoing_transport.AsStdFunction();
     95  config.task_queue = queue.Get();
     96  EXPECT_CALL(outgoing_transport, Call).WillRepeatedly(InvokeWithoutArgs([&] {
     97    EXPECT_TRUE(queue.IsCurrent());
     98    return true;
     99  }));
    100 
    101  std::unique_ptr<RtcpTransceiver> rtcp_transceiver;
    102  queue.PostTask([&] {
    103    rtcp_transceiver = std::make_unique<RtcpTransceiver>(config);
    104    rtcp_transceiver->SendCompoundPacket();
    105  });
    106  WaitPostedTasks(&queue);
    107 }
    108 
    109 TEST(RtcpTransceiverTest, CanBeDestroyedOnTaskQueue) {
    110  SimulatedClock clock(0);
    111  MockFunction<void(webrtc::ArrayView<const uint8_t>)> outgoing_transport;
    112  TaskQueueForTest queue("rtcp");
    113  RtcpTransceiverConfig config;
    114  config.clock = &clock;
    115  config.rtcp_transport = outgoing_transport.AsStdFunction();
    116  config.task_queue = queue.Get();
    117  auto rtcp_transceiver = std::make_unique<RtcpTransceiver>(config);
    118 
    119  queue.PostTask([&] {
    120    // Insert a packet just before destruction to test for races.
    121    rtcp_transceiver->SendCompoundPacket();
    122    rtcp_transceiver.reset();
    123  });
    124  WaitPostedTasks(&queue);
    125 }
    126 
    127 TEST(RtcpTransceiverTest, CanBeDestroyedWithoutBlocking) {
    128  SimulatedClock clock(0);
    129  TaskQueueForTest queue("rtcp");
    130  RtcpTransceiverConfig config;
    131  config.clock = &clock;
    132  config.task_queue = queue.Get();
    133  auto* rtcp_transceiver = new RtcpTransceiver(config);
    134  rtcp_transceiver->SendCompoundPacket();
    135 
    136  webrtc::Event done;
    137  webrtc::Event heavy_task;
    138  queue.PostTask([&] {
    139    EXPECT_TRUE(heavy_task.Wait(kTimeout));
    140    done.Set();
    141  });
    142  delete rtcp_transceiver;
    143 
    144  heavy_task.Set();
    145  EXPECT_TRUE(done.Wait(kTimeout));
    146 }
    147 
    148 TEST(RtcpTransceiverTest, MaySendPacketsAfterDestructor) {  // i.e. Be careful!
    149  SimulatedClock clock(0);
    150  // Must outlive queue below.
    151  NiceMock<MockFunction<void(webrtc::ArrayView<const uint8_t>)>> transport;
    152  TaskQueueForTest queue("rtcp");
    153  RtcpTransceiverConfig config;
    154  config.clock = &clock;
    155  config.rtcp_transport = transport.AsStdFunction();
    156  config.task_queue = queue.Get();
    157  auto* rtcp_transceiver = new RtcpTransceiver(config);
    158 
    159  webrtc::Event heavy_task;
    160  queue.PostTask([&] { EXPECT_TRUE(heavy_task.Wait(kTimeout)); });
    161  rtcp_transceiver->SendCompoundPacket();
    162  delete rtcp_transceiver;
    163 
    164  EXPECT_CALL(transport, Call);
    165  heavy_task.Set();
    166 
    167  WaitPostedTasks(&queue);
    168 }
    169 
    170 // Use rtp timestamp to distinguish different incoming sender reports.
    171 webrtc::CopyOnWriteBuffer CreateSenderReport(uint32_t ssrc, uint32_t rtp_time) {
    172  webrtc::rtcp::SenderReport sr;
    173  sr.SetSenderSsrc(ssrc);
    174  sr.SetRtpTimestamp(rtp_time);
    175  webrtc::Buffer buffer = sr.Build();
    176  // Switch to an efficient way creating CopyOnWriteBuffer from RtcpPacket when
    177  // there is one. Until then do not worry about extra memcpy in test.
    178  return webrtc::CopyOnWriteBuffer(buffer.data(), buffer.size());
    179 }
    180 
    181 TEST(RtcpTransceiverTest, DoesntPostToRtcpObserverAfterCallToRemove) {
    182  const uint32_t kRemoteSsrc = 1234;
    183  SimulatedClock clock(0);
    184  TaskQueueForTest queue("rtcp");
    185  RtcpTransceiverConfig config;
    186  config.clock = &clock;
    187  config.task_queue = queue.Get();
    188  RtcpTransceiver rtcp_transceiver(config);
    189  webrtc::Event observer_deleted;
    190 
    191  auto observer = std::make_unique<MockMediaReceiverRtcpObserver>();
    192  EXPECT_CALL(*observer, OnSenderReport(kRemoteSsrc, _, 1));
    193  EXPECT_CALL(*observer, OnSenderReport(kRemoteSsrc, _, 2)).Times(0);
    194 
    195  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc, observer.get());
    196  rtcp_transceiver.ReceivePacket(CreateSenderReport(kRemoteSsrc, 1));
    197  rtcp_transceiver.RemoveMediaReceiverRtcpObserver(kRemoteSsrc, observer.get(),
    198                                                   /*on_removed=*/[&] {
    199                                                     observer.reset();
    200                                                     observer_deleted.Set();
    201                                                   });
    202  rtcp_transceiver.ReceivePacket(CreateSenderReport(kRemoteSsrc, 2));
    203 
    204  EXPECT_TRUE(observer_deleted.Wait(kTimeout));
    205  WaitPostedTasks(&queue);
    206 }
    207 
    208 TEST(RtcpTransceiverTest, RemoveMediaReceiverRtcpObserverIsNonBlocking) {
    209  const uint32_t kRemoteSsrc = 1234;
    210  SimulatedClock clock(0);
    211  TaskQueueForTest queue("rtcp");
    212  RtcpTransceiverConfig config;
    213  config.clock = &clock;
    214  config.task_queue = queue.Get();
    215  RtcpTransceiver rtcp_transceiver(config);
    216  auto observer = std::make_unique<MockMediaReceiverRtcpObserver>();
    217  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc, observer.get());
    218 
    219  webrtc::Event queue_blocker;
    220  webrtc::Event observer_deleted;
    221  queue.PostTask([&] { EXPECT_TRUE(queue_blocker.Wait(kTimeout)); });
    222  rtcp_transceiver.RemoveMediaReceiverRtcpObserver(kRemoteSsrc, observer.get(),
    223                                                   /*on_removed=*/[&] {
    224                                                     observer.reset();
    225                                                     observer_deleted.Set();
    226                                                   });
    227 
    228  EXPECT_THAT(observer, Not(IsNull()));
    229  queue_blocker.Set();
    230  EXPECT_TRUE(observer_deleted.Wait(kTimeout));
    231 }
    232 
    233 TEST(RtcpTransceiverTest, CanCallSendCompoundPacketFromAnyThread) {
    234  SimulatedClock clock(0);
    235  MockFunction<void(webrtc::ArrayView<const uint8_t>)> outgoing_transport;
    236  TaskQueueForTest queue("rtcp");
    237  RtcpTransceiverConfig config;
    238  config.clock = &clock;
    239  config.rtcp_transport = outgoing_transport.AsStdFunction();
    240  config.task_queue = queue.Get();
    241 
    242  EXPECT_CALL(outgoing_transport, Call)
    243      // If test is slow, a periodic task may send an extra packet.
    244      .Times(AtLeast(3))
    245      .WillRepeatedly(InvokeWithoutArgs([&] {
    246        EXPECT_TRUE(queue.IsCurrent());
    247        return true;
    248      }));
    249 
    250  RtcpTransceiver rtcp_transceiver(config);
    251 
    252  // Call from the construction thread.
    253  rtcp_transceiver.SendCompoundPacket();
    254  // Call from the same queue transceiver use for processing.
    255  queue.PostTask([&] { rtcp_transceiver.SendCompoundPacket(); });
    256  // Call from unrelated task queue.
    257  TaskQueueForTest queue_send("send_packet");
    258  queue_send.PostTask([&] { rtcp_transceiver.SendCompoundPacket(); });
    259 
    260  WaitPostedTasks(&queue_send);
    261  WaitPostedTasks(&queue);
    262 }
    263 
    264 TEST(RtcpTransceiverTest, DoesntSendPacketsAfterStopCallback) {
    265  SimulatedClock clock(0);
    266  NiceMock<MockFunction<void(webrtc::ArrayView<const uint8_t>)>>
    267      outgoing_transport;
    268  TaskQueueForTest queue("rtcp");
    269  RtcpTransceiverConfig config;
    270  config.clock = &clock;
    271  config.rtcp_transport = outgoing_transport.AsStdFunction();
    272  config.task_queue = queue.Get();
    273  config.schedule_periodic_compound_packets = true;
    274 
    275  auto rtcp_transceiver = std::make_unique<RtcpTransceiver>(config);
    276  webrtc::Event done;
    277  rtcp_transceiver->SendCompoundPacket();
    278  rtcp_transceiver->Stop([&] {
    279    EXPECT_CALL(outgoing_transport, Call).Times(0);
    280    done.Set();
    281  });
    282  rtcp_transceiver = nullptr;
    283  EXPECT_TRUE(done.Wait(kTimeout));
    284 }
    285 
    286 TEST(RtcpTransceiverTest, SendsCombinedRtcpPacketOnTaskQueue) {
    287  static constexpr uint32_t kSenderSsrc = 12345;
    288 
    289  SimulatedClock clock(0);
    290  MockFunction<void(webrtc::ArrayView<const uint8_t>)> outgoing_transport;
    291  TaskQueueForTest queue("rtcp");
    292  RtcpTransceiverConfig config;
    293  config.clock = &clock;
    294  config.feedback_ssrc = kSenderSsrc;
    295  config.rtcp_transport = outgoing_transport.AsStdFunction();
    296  config.task_queue = queue.Get();
    297  config.schedule_periodic_compound_packets = false;
    298  RtcpTransceiver rtcp_transceiver(config);
    299 
    300  EXPECT_CALL(outgoing_transport, Call)
    301      .WillOnce([&](webrtc::ArrayView<const uint8_t> buffer) {
    302        EXPECT_TRUE(queue.IsCurrent());
    303        RtcpPacketParser rtcp_parser;
    304        rtcp_parser.Parse(buffer);
    305        EXPECT_EQ(rtcp_parser.transport_feedback()->num_packets(), 1);
    306        EXPECT_EQ(rtcp_parser.transport_feedback()->sender_ssrc(), kSenderSsrc);
    307        EXPECT_EQ(rtcp_parser.app()->num_packets(), 1);
    308        EXPECT_EQ(rtcp_parser.app()->sender_ssrc(), kSenderSsrc);
    309        return true;
    310      });
    311 
    312  // Create minimalistic transport feedback packet.
    313  std::vector<std::unique_ptr<RtcpPacket>> packets;
    314  auto transport_feedback = std::make_unique<TransportFeedback>();
    315  transport_feedback->AddReceivedPacket(321, Timestamp::Millis(10));
    316  packets.push_back(std::move(transport_feedback));
    317 
    318  auto remote_estimate = std::make_unique<RemoteEstimate>();
    319  packets.push_back(std::move(remote_estimate));
    320 
    321  rtcp_transceiver.SendCombinedRtcpPacket(std::move(packets));
    322  WaitPostedTasks(&queue);
    323 }
    324 
    325 TEST(RtcpTransceiverTest, SendFrameIntraRequestDefaultsToNewRequest) {
    326  static constexpr uint32_t kSenderSsrc = 12345;
    327 
    328  SimulatedClock clock(0);
    329  MockFunction<void(webrtc::ArrayView<const uint8_t>)> outgoing_transport;
    330  TaskQueueForTest queue("rtcp");
    331  RtcpTransceiverConfig config;
    332  config.clock = &clock;
    333  config.feedback_ssrc = kSenderSsrc;
    334  config.rtcp_transport = outgoing_transport.AsStdFunction();
    335  config.task_queue = queue.Get();
    336  config.schedule_periodic_compound_packets = false;
    337  RtcpTransceiver rtcp_transceiver(config);
    338 
    339  uint8_t first_seq_nr;
    340  EXPECT_CALL(outgoing_transport, Call)
    341      .WillOnce([&](webrtc::ArrayView<const uint8_t> buffer) {
    342        EXPECT_TRUE(queue.IsCurrent());
    343        RtcpPacketParser rtcp_parser;
    344        rtcp_parser.Parse(buffer);
    345        EXPECT_EQ(rtcp_parser.fir()->requests()[0].ssrc, kSenderSsrc);
    346        first_seq_nr = rtcp_parser.fir()->requests()[0].seq_nr;
    347        return true;
    348      })
    349      .WillOnce([&](webrtc::ArrayView<const uint8_t> buffer) {
    350        EXPECT_TRUE(queue.IsCurrent());
    351        RtcpPacketParser rtcp_parser;
    352        rtcp_parser.Parse(buffer);
    353        EXPECT_EQ(rtcp_parser.fir()->requests()[0].ssrc, kSenderSsrc);
    354        EXPECT_EQ(rtcp_parser.fir()->requests()[0].seq_nr, first_seq_nr + 1);
    355        return true;
    356      });
    357 
    358  // Send 2 FIR packets because the sequence numbers are incremented after,
    359  // sending. One wouldn't be able to differentiate the new_request.
    360  rtcp_transceiver.SendFullIntraRequest({kSenderSsrc});
    361  rtcp_transceiver.SendFullIntraRequest({kSenderSsrc});
    362 
    363  WaitPostedTasks(&queue);
    364 }
    365 
    366 }  // namespace