1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <gtest/gtest.h>
6#include <stdint.h>
7
8#include "base/bind.h"
9#include "base/bind_helpers.h"
10#include "base/memory/scoped_ptr.h"
11#include "base/test/simple_test_tick_clock.h"
12#include "base/values.h"
13#include "media/cast/cast_config.h"
14#include "media/cast/net/cast_transport_config.h"
15#include "media/cast/net/cast_transport_sender_impl.h"
16#include "media/cast/net/rtcp/rtcp.h"
17#include "media/cast/test/fake_single_thread_task_runner.h"
18#include "testing/gtest/include/gtest/gtest.h"
19
20namespace media {
21namespace cast {
22
23namespace {
24const int64 kStartMillisecond = INT64_C(12345678900000);
25const uint32 kVideoSsrc = 1;
26const uint32 kAudioSsrc = 2;
27}  // namespace
28
29class FakePacketSender : public PacketSender {
30 public:
31  FakePacketSender()
32      : paused_(false), packets_sent_(0), bytes_sent_(0) {}
33
34  virtual bool SendPacket(PacketRef packet, const base::Closure& cb) OVERRIDE {
35    if (paused_) {
36      stored_packet_ = packet;
37      callback_ = cb;
38      return false;
39    }
40    ++packets_sent_;
41    bytes_sent_ += packet->data.size();
42    return true;
43  }
44
45  virtual int64 GetBytesSent() OVERRIDE {
46    return bytes_sent_;
47  }
48
49  void SetPaused(bool paused) {
50    paused_ = paused;
51    if (!paused && stored_packet_.get()) {
52      SendPacket(stored_packet_, callback_);
53      callback_.Run();
54    }
55  }
56
57  int packets_sent() const { return packets_sent_; }
58
59 private:
60  bool paused_;
61  base::Closure callback_;
62  PacketRef stored_packet_;
63  int packets_sent_;
64  int64 bytes_sent_;
65
66  DISALLOW_COPY_AND_ASSIGN(FakePacketSender);
67};
68
69class CastTransportSenderImplTest : public ::testing::Test {
70 protected:
71  CastTransportSenderImplTest()
72      : num_times_callback_called_(0) {
73    testing_clock_.Advance(
74        base::TimeDelta::FromMilliseconds(kStartMillisecond));
75    task_runner_ = new test::FakeSingleThreadTaskRunner(&testing_clock_);
76  }
77
78  virtual ~CastTransportSenderImplTest() {}
79
80  void InitWithoutLogging() {
81    transport_sender_.reset(
82        new CastTransportSenderImpl(NULL,
83                                    &testing_clock_,
84                                    net::IPEndPoint(),
85                                    make_scoped_ptr(new base::DictionaryValue),
86                                    base::Bind(&UpdateCastTransportStatus),
87                                    BulkRawEventsCallback(),
88                                    base::TimeDelta(),
89                                    task_runner_,
90                                    &transport_));
91    task_runner_->RunTasks();
92  }
93
94  void InitWithOptions() {
95    scoped_ptr<base::DictionaryValue> options(
96        new base::DictionaryValue);
97    options->SetBoolean("DHCP", true);
98    options->SetBoolean("disable_wifi_scan", true);
99    options->SetBoolean("media_streaming_mode", true);
100    options->SetInteger("pacer_target_burst_size", 20);
101    options->SetInteger("pacer_max_burst_size", 100);
102    transport_sender_.reset(
103        new CastTransportSenderImpl(NULL,
104                                    &testing_clock_,
105                                    net::IPEndPoint(),
106                                    options.Pass(),
107                                    base::Bind(&UpdateCastTransportStatus),
108                                    BulkRawEventsCallback(),
109                                    base::TimeDelta(),
110                                    task_runner_,
111                                    &transport_));
112    task_runner_->RunTasks();
113  }
114
115  void InitWithLogging() {
116    transport_sender_.reset(new CastTransportSenderImpl(
117        NULL,
118        &testing_clock_,
119        net::IPEndPoint(),
120        make_scoped_ptr(new base::DictionaryValue),
121        base::Bind(&UpdateCastTransportStatus),
122        base::Bind(&CastTransportSenderImplTest::LogRawEvents,
123                   base::Unretained(this)),
124        base::TimeDelta::FromMilliseconds(10),
125        task_runner_,
126        &transport_));
127    task_runner_->RunTasks();
128  }
129
130  void InitializeVideo() {
131    CastTransportRtpConfig rtp_config;
132    rtp_config.ssrc = kVideoSsrc;
133    rtp_config.feedback_ssrc = 2;
134    rtp_config.rtp_payload_type = 3;
135    transport_sender_->InitializeVideo(rtp_config,
136                                       RtcpCastMessageCallback(),
137                                       RtcpRttCallback());
138  }
139
140  void InitializeAudio() {
141    CastTransportRtpConfig rtp_config;
142    rtp_config.ssrc = kAudioSsrc;
143    rtp_config.feedback_ssrc = 3;
144    rtp_config.rtp_payload_type = 4;
145    transport_sender_->InitializeAudio(rtp_config,
146                                       RtcpCastMessageCallback(),
147                                       RtcpRttCallback());
148  }
149
150  void LogRawEvents(const std::vector<PacketEvent>& packet_events,
151                    const std::vector<FrameEvent>& frame_events) {
152    num_times_callback_called_++;
153  }
154
155  static void UpdateCastTransportStatus(CastTransportStatus status) {
156  }
157
158  base::SimpleTestTickClock testing_clock_;
159  scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
160  scoped_ptr<CastTransportSenderImpl> transport_sender_;
161  FakePacketSender transport_;
162  int num_times_callback_called_;
163};
164
165TEST_F(CastTransportSenderImplTest, InitWithoutLogging) {
166  InitWithoutLogging();
167  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(50));
168  EXPECT_EQ(0, num_times_callback_called_);
169}
170
171TEST_F(CastTransportSenderImplTest, InitWithLogging) {
172  InitWithLogging();
173  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(50));
174  EXPECT_EQ(5, num_times_callback_called_);
175}
176
177TEST_F(CastTransportSenderImplTest, InitWithOptions) {
178  InitWithOptions();
179  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(50));
180  EXPECT_EQ(0, num_times_callback_called_);
181}
182
183TEST_F(CastTransportSenderImplTest, NacksCancelRetransmits) {
184  InitWithoutLogging();
185  InitializeVideo();
186  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(50));
187
188  // A fake frame that will be decomposed into 4 packets.
189  EncodedFrame fake_frame;
190  fake_frame.frame_id = 1;
191  fake_frame.rtp_timestamp = 1;
192  fake_frame.dependency = EncodedFrame::KEY;
193  fake_frame.data.resize(5000, ' ');
194
195  transport_sender_->InsertFrame(kVideoSsrc, fake_frame);
196  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
197  EXPECT_EQ(4, transport_.packets_sent());
198
199  // Resend packet 0.
200  MissingFramesAndPacketsMap missing_packets;
201  missing_packets[1].insert(0);
202  missing_packets[1].insert(1);
203  missing_packets[1].insert(2);
204
205  transport_.SetPaused(true);
206  DedupInfo dedup_info;
207  dedup_info.resend_interval = base::TimeDelta::FromMilliseconds(10);
208  transport_sender_->ResendPackets(
209      kVideoSsrc, missing_packets, true, dedup_info);
210
211  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
212
213  RtcpCastMessage cast_message;
214  cast_message.media_ssrc = kVideoSsrc;
215  cast_message.ack_frame_id = 1;
216  cast_message.missing_frames_and_packets[1].insert(3);
217  transport_sender_->OnReceivedCastMessage(kVideoSsrc,
218                                           RtcpCastMessageCallback(),
219                                           cast_message);
220  transport_.SetPaused(false);
221  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
222
223  // Resend one packet in the socket when unpaused.
224  // Resend one more packet from NACK.
225  EXPECT_EQ(6, transport_.packets_sent());
226}
227
228TEST_F(CastTransportSenderImplTest, CancelRetransmits) {
229  InitWithoutLogging();
230  InitializeVideo();
231  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(50));
232
233  // A fake frame that will be decomposed into 4 packets.
234  EncodedFrame fake_frame;
235  fake_frame.frame_id = 1;
236  fake_frame.rtp_timestamp = 1;
237  fake_frame.dependency = EncodedFrame::KEY;
238  fake_frame.data.resize(5000, ' ');
239
240  transport_sender_->InsertFrame(kVideoSsrc, fake_frame);
241  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
242  EXPECT_EQ(4, transport_.packets_sent());
243
244  // Resend all packets for frame 1.
245  MissingFramesAndPacketsMap missing_packets;
246  missing_packets[1].insert(kRtcpCastAllPacketsLost);
247
248  transport_.SetPaused(true);
249  DedupInfo dedup_info;
250  dedup_info.resend_interval = base::TimeDelta::FromMilliseconds(10);
251  transport_sender_->ResendPackets(
252      kVideoSsrc, missing_packets, true, dedup_info);
253
254  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
255  std::vector<uint32> cancel_sending_frames;
256  cancel_sending_frames.push_back(1);
257  transport_sender_->CancelSendingFrames(kVideoSsrc,
258                                         cancel_sending_frames);
259  transport_.SetPaused(false);
260  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
261
262  // Resend one packet in the socket when unpaused.
263  EXPECT_EQ(5, transport_.packets_sent());
264}
265
266TEST_F(CastTransportSenderImplTest, Kickstart) {
267  InitWithoutLogging();
268  InitializeVideo();
269  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(50));
270
271  // A fake frame that will be decomposed into 4 packets.
272  EncodedFrame fake_frame;
273  fake_frame.frame_id = 1;
274  fake_frame.rtp_timestamp = 1;
275  fake_frame.dependency = EncodedFrame::KEY;
276  fake_frame.data.resize(5000, ' ');
277
278  transport_.SetPaused(true);
279  transport_sender_->InsertFrame(kVideoSsrc, fake_frame);
280  transport_sender_->ResendFrameForKickstart(kVideoSsrc, 1);
281  transport_.SetPaused(false);
282  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
283  EXPECT_EQ(4, transport_.packets_sent());
284
285  // Resend 2 packets for frame 1.
286  MissingFramesAndPacketsMap missing_packets;
287  missing_packets[1].insert(0);
288  missing_packets[1].insert(1);
289
290  transport_.SetPaused(true);
291  DedupInfo dedup_info;
292  dedup_info.resend_interval = base::TimeDelta::FromMilliseconds(10);
293  transport_sender_->ResendPackets(
294      kVideoSsrc, missing_packets, true, dedup_info);
295  transport_sender_->ResendFrameForKickstart(kVideoSsrc, 1);
296  transport_.SetPaused(false);
297  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
298
299  // Resend one packet in the socket when unpaused.
300  // Two more retransmission packets sent.
301  EXPECT_EQ(7, transport_.packets_sent());
302}
303
304TEST_F(CastTransportSenderImplTest, DedupRetransmissionWithAudio) {
305  InitWithoutLogging();
306  InitializeAudio();
307  InitializeVideo();
308  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(50));
309
310  // Send two audio frames.
311  EncodedFrame fake_audio;
312  fake_audio.frame_id = 1;
313  fake_audio.reference_time = testing_clock_.NowTicks();
314  fake_audio.dependency = EncodedFrame::KEY;
315  fake_audio.data.resize(100, ' ');
316  transport_sender_->InsertFrame(kAudioSsrc, fake_audio);
317  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(2));
318  fake_audio.frame_id = 2;
319  fake_audio.reference_time = testing_clock_.NowTicks();
320  transport_sender_->InsertFrame(kAudioSsrc, fake_audio);
321  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(2));
322  EXPECT_EQ(2, transport_.packets_sent());
323
324  // Ack the first audio frame.
325  RtcpCastMessage cast_message;
326  cast_message.media_ssrc = kAudioSsrc;
327  cast_message.ack_frame_id = 1;
328  transport_sender_->OnReceivedCastMessage(kAudioSsrc,
329                                           RtcpCastMessageCallback(),
330                                           cast_message);
331  task_runner_->RunTasks();
332  EXPECT_EQ(2, transport_.packets_sent());
333
334  // Send a fake video frame that will be decomposed into 4 packets.
335  EncodedFrame fake_video;
336  fake_video.frame_id = 1;
337  fake_video.dependency = EncodedFrame::KEY;
338  fake_video.data.resize(5000, ' ');
339  transport_sender_->InsertFrame(kVideoSsrc, fake_video);
340  task_runner_->RunTasks();
341  EXPECT_EQ(6, transport_.packets_sent());
342
343  // Retransmission is reject because audio is not acked yet.
344  cast_message.media_ssrc = kVideoSsrc;
345  cast_message.ack_frame_id = 0;
346  cast_message.missing_frames_and_packets[1].insert(3);
347  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
348  transport_sender_->OnReceivedCastMessage(kVideoSsrc,
349                                           RtcpCastMessageCallback(),
350                                           cast_message);
351  task_runner_->RunTasks();
352  EXPECT_EQ(6, transport_.packets_sent());
353
354  // Ack the second audio frame.
355  cast_message.media_ssrc = kAudioSsrc;
356  cast_message.ack_frame_id = 2;
357  cast_message.missing_frames_and_packets.clear();
358  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(2));
359  transport_sender_->OnReceivedCastMessage(kAudioSsrc,
360                                           RtcpCastMessageCallback(),
361                                           cast_message);
362  task_runner_->RunTasks();
363  EXPECT_EQ(6, transport_.packets_sent());
364
365  // Retransmission of video packet now accepted.
366  cast_message.media_ssrc = kVideoSsrc;
367  cast_message.ack_frame_id = 1;
368  cast_message.missing_frames_and_packets[1].insert(3);
369  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(2));
370  transport_sender_->OnReceivedCastMessage(kVideoSsrc,
371                                           RtcpCastMessageCallback(),
372                                           cast_message);
373  task_runner_->RunTasks();
374  EXPECT_EQ(7, transport_.packets_sent());
375}
376
377}  // namespace cast
378}  // namespace media
379