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