Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / media / cast / net / cast_transport_sender_impl_unittest.cc
index b8a49cc..fa9ec47 100644 (file)
@@ -9,6 +9,7 @@
 #include "base/bind_helpers.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/test/simple_test_tick_clock.h"
+#include "base/values.h"
 #include "media/cast/cast_config.h"
 #include "media/cast/net/cast_transport_config.h"
 #include "media/cast/net/cast_transport_sender_impl.h"
 namespace media {
 namespace cast {
 
-static const int64 kStartMillisecond = INT64_C(12345678900000);
+namespace {
+const int64 kStartMillisecond = INT64_C(12345678900000);
+const uint32 kVideoSsrc = 1;
+const uint32 kAudioSsrc = 2;
+}  // namespace
 
 class FakePacketSender : public PacketSender {
  public:
-  FakePacketSender() {}
+  FakePacketSender()
+      : paused_(false), packets_sent_(0), bytes_sent_(0) {}
 
   virtual bool SendPacket(PacketRef packet, const base::Closure& cb) OVERRIDE {
+    if (paused_) {
+      stored_packet_ = packet;
+      callback_ = cb;
+      return false;
+    }
+    ++packets_sent_;
+    bytes_sent_ += packet->data.size();
     return true;
   }
+
+  virtual int64 GetBytesSent() OVERRIDE {
+    return bytes_sent_;
+  }
+
+  void SetPaused(bool paused) {
+    paused_ = paused;
+    if (!paused && stored_packet_.get()) {
+      SendPacket(stored_packet_, callback_);
+      callback_.Run();
+    }
+  }
+
+  int packets_sent() const { return packets_sent_; }
+
+ private:
+  bool paused_;
+  base::Closure callback_;
+  PacketRef stored_packet_;
+  int packets_sent_;
+  int64 bytes_sent_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakePacketSender);
 };
 
 class CastTransportSenderImplTest : public ::testing::Test {
@@ -46,6 +82,28 @@ class CastTransportSenderImplTest : public ::testing::Test {
         new CastTransportSenderImpl(NULL,
                                     &testing_clock_,
                                     net::IPEndPoint(),
+                                    make_scoped_ptr(new base::DictionaryValue),
+                                    base::Bind(&UpdateCastTransportStatus),
+                                    BulkRawEventsCallback(),
+                                    base::TimeDelta(),
+                                    task_runner_,
+                                    &transport_));
+    task_runner_->RunTasks();
+  }
+
+  void InitWithOptions() {
+    scoped_ptr<base::DictionaryValue> options(
+        new base::DictionaryValue);
+    options->SetBoolean("DHCP", true);
+    options->SetBoolean("disable_wifi_scan", true);
+    options->SetBoolean("media_streaming_mode", true);
+    options->SetInteger("pacer_target_burst_size", 20);
+    options->SetInteger("pacer_max_burst_size", 100);
+    transport_sender_.reset(
+        new CastTransportSenderImpl(NULL,
+                                    &testing_clock_,
+                                    net::IPEndPoint(),
+                                    options.Pass(),
                                     base::Bind(&UpdateCastTransportStatus),
                                     BulkRawEventsCallback(),
                                     base::TimeDelta(),
@@ -59,6 +117,7 @@ class CastTransportSenderImplTest : public ::testing::Test {
         NULL,
         &testing_clock_,
         net::IPEndPoint(),
+        make_scoped_ptr(new base::DictionaryValue),
         base::Bind(&UpdateCastTransportStatus),
         base::Bind(&CastTransportSenderImplTest::LogRawEvents,
                    base::Unretained(this)),
@@ -68,6 +127,26 @@ class CastTransportSenderImplTest : public ::testing::Test {
     task_runner_->RunTasks();
   }
 
+  void InitializeVideo() {
+    CastTransportRtpConfig rtp_config;
+    rtp_config.ssrc = kVideoSsrc;
+    rtp_config.feedback_ssrc = 2;
+    rtp_config.rtp_payload_type = 3;
+    transport_sender_->InitializeVideo(rtp_config,
+                                       RtcpCastMessageCallback(),
+                                       RtcpRttCallback());
+  }
+
+  void InitializeAudio() {
+    CastTransportRtpConfig rtp_config;
+    rtp_config.ssrc = kAudioSsrc;
+    rtp_config.feedback_ssrc = 3;
+    rtp_config.rtp_payload_type = 4;
+    transport_sender_->InitializeAudio(rtp_config,
+                                       RtcpCastMessageCallback(),
+                                       RtcpRttCallback());
+  }
+
   void LogRawEvents(const std::vector<PacketEvent>& packet_events,
                     const std::vector<FrameEvent>& frame_events) {
     num_times_callback_called_++;
@@ -95,5 +174,205 @@ TEST_F(CastTransportSenderImplTest, InitWithLogging) {
   EXPECT_EQ(5, num_times_callback_called_);
 }
 
+TEST_F(CastTransportSenderImplTest, InitWithOptions) {
+  InitWithOptions();
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(50));
+  EXPECT_EQ(0, num_times_callback_called_);
+}
+
+TEST_F(CastTransportSenderImplTest, NacksCancelRetransmits) {
+  InitWithoutLogging();
+  InitializeVideo();
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(50));
+
+  // A fake frame that will be decomposed into 4 packets.
+  EncodedFrame fake_frame;
+  fake_frame.frame_id = 1;
+  fake_frame.rtp_timestamp = 1;
+  fake_frame.dependency = EncodedFrame::KEY;
+  fake_frame.data.resize(5000, ' ');
+
+  transport_sender_->InsertFrame(kVideoSsrc, fake_frame);
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
+  EXPECT_EQ(4, transport_.packets_sent());
+
+  // Resend packet 0.
+  MissingFramesAndPacketsMap missing_packets;
+  missing_packets[1].insert(0);
+  missing_packets[1].insert(1);
+  missing_packets[1].insert(2);
+
+  transport_.SetPaused(true);
+  DedupInfo dedup_info;
+  dedup_info.resend_interval = base::TimeDelta::FromMilliseconds(10);
+  transport_sender_->ResendPackets(
+      kVideoSsrc, missing_packets, true, dedup_info);
+
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
+
+  RtcpCastMessage cast_message;
+  cast_message.media_ssrc = kVideoSsrc;
+  cast_message.ack_frame_id = 1;
+  cast_message.missing_frames_and_packets[1].insert(3);
+  transport_sender_->OnReceivedCastMessage(kVideoSsrc,
+                                           RtcpCastMessageCallback(),
+                                           cast_message);
+  transport_.SetPaused(false);
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
+
+  // Resend one packet in the socket when unpaused.
+  // Resend one more packet from NACK.
+  EXPECT_EQ(6, transport_.packets_sent());
+}
+
+TEST_F(CastTransportSenderImplTest, CancelRetransmits) {
+  InitWithoutLogging();
+  InitializeVideo();
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(50));
+
+  // A fake frame that will be decomposed into 4 packets.
+  EncodedFrame fake_frame;
+  fake_frame.frame_id = 1;
+  fake_frame.rtp_timestamp = 1;
+  fake_frame.dependency = EncodedFrame::KEY;
+  fake_frame.data.resize(5000, ' ');
+
+  transport_sender_->InsertFrame(kVideoSsrc, fake_frame);
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
+  EXPECT_EQ(4, transport_.packets_sent());
+
+  // Resend all packets for frame 1.
+  MissingFramesAndPacketsMap missing_packets;
+  missing_packets[1].insert(kRtcpCastAllPacketsLost);
+
+  transport_.SetPaused(true);
+  DedupInfo dedup_info;
+  dedup_info.resend_interval = base::TimeDelta::FromMilliseconds(10);
+  transport_sender_->ResendPackets(
+      kVideoSsrc, missing_packets, true, dedup_info);
+
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
+  std::vector<uint32> cancel_sending_frames;
+  cancel_sending_frames.push_back(1);
+  transport_sender_->CancelSendingFrames(kVideoSsrc,
+                                         cancel_sending_frames);
+  transport_.SetPaused(false);
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
+
+  // Resend one packet in the socket when unpaused.
+  EXPECT_EQ(5, transport_.packets_sent());
+}
+
+TEST_F(CastTransportSenderImplTest, Kickstart) {
+  InitWithoutLogging();
+  InitializeVideo();
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(50));
+
+  // A fake frame that will be decomposed into 4 packets.
+  EncodedFrame fake_frame;
+  fake_frame.frame_id = 1;
+  fake_frame.rtp_timestamp = 1;
+  fake_frame.dependency = EncodedFrame::KEY;
+  fake_frame.data.resize(5000, ' ');
+
+  transport_.SetPaused(true);
+  transport_sender_->InsertFrame(kVideoSsrc, fake_frame);
+  transport_sender_->ResendFrameForKickstart(kVideoSsrc, 1);
+  transport_.SetPaused(false);
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
+  EXPECT_EQ(4, transport_.packets_sent());
+
+  // Resend 2 packets for frame 1.
+  MissingFramesAndPacketsMap missing_packets;
+  missing_packets[1].insert(0);
+  missing_packets[1].insert(1);
+
+  transport_.SetPaused(true);
+  DedupInfo dedup_info;
+  dedup_info.resend_interval = base::TimeDelta::FromMilliseconds(10);
+  transport_sender_->ResendPackets(
+      kVideoSsrc, missing_packets, true, dedup_info);
+  transport_sender_->ResendFrameForKickstart(kVideoSsrc, 1);
+  transport_.SetPaused(false);
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
+
+  // Resend one packet in the socket when unpaused.
+  // Two more retransmission packets sent.
+  EXPECT_EQ(7, transport_.packets_sent());
+}
+
+TEST_F(CastTransportSenderImplTest, DedupRetransmissionWithAudio) {
+  InitWithoutLogging();
+  InitializeAudio();
+  InitializeVideo();
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(50));
+
+  // Send two audio frames.
+  EncodedFrame fake_audio;
+  fake_audio.frame_id = 1;
+  fake_audio.reference_time = testing_clock_.NowTicks();
+  fake_audio.dependency = EncodedFrame::KEY;
+  fake_audio.data.resize(100, ' ');
+  transport_sender_->InsertFrame(kAudioSsrc, fake_audio);
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(2));
+  fake_audio.frame_id = 2;
+  fake_audio.reference_time = testing_clock_.NowTicks();
+  transport_sender_->InsertFrame(kAudioSsrc, fake_audio);
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(2));
+  EXPECT_EQ(2, transport_.packets_sent());
+
+  // Ack the first audio frame.
+  RtcpCastMessage cast_message;
+  cast_message.media_ssrc = kAudioSsrc;
+  cast_message.ack_frame_id = 1;
+  transport_sender_->OnReceivedCastMessage(kAudioSsrc,
+                                           RtcpCastMessageCallback(),
+                                           cast_message);
+  task_runner_->RunTasks();
+  EXPECT_EQ(2, transport_.packets_sent());
+
+  // Send a fake video frame that will be decomposed into 4 packets.
+  EncodedFrame fake_video;
+  fake_video.frame_id = 1;
+  fake_video.dependency = EncodedFrame::KEY;
+  fake_video.data.resize(5000, ' ');
+  transport_sender_->InsertFrame(kVideoSsrc, fake_video);
+  task_runner_->RunTasks();
+  EXPECT_EQ(6, transport_.packets_sent());
+
+  // Retransmission is reject because audio is not acked yet.
+  cast_message.media_ssrc = kVideoSsrc;
+  cast_message.ack_frame_id = 0;
+  cast_message.missing_frames_and_packets[1].insert(3);
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
+  transport_sender_->OnReceivedCastMessage(kVideoSsrc,
+                                           RtcpCastMessageCallback(),
+                                           cast_message);
+  task_runner_->RunTasks();
+  EXPECT_EQ(6, transport_.packets_sent());
+
+  // Ack the second audio frame.
+  cast_message.media_ssrc = kAudioSsrc;
+  cast_message.ack_frame_id = 2;
+  cast_message.missing_frames_and_packets.clear();
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(2));
+  transport_sender_->OnReceivedCastMessage(kAudioSsrc,
+                                           RtcpCastMessageCallback(),
+                                           cast_message);
+  task_runner_->RunTasks();
+  EXPECT_EQ(6, transport_.packets_sent());
+
+  // Retransmission of video packet now accepted.
+  cast_message.media_ssrc = kVideoSsrc;
+  cast_message.ack_frame_id = 1;
+  cast_message.missing_frames_and_packets[1].insert(3);
+  task_runner_->Sleep(base::TimeDelta::FromMilliseconds(2));
+  transport_sender_->OnReceivedCastMessage(kVideoSsrc,
+                                           RtcpCastMessageCallback(),
+                                           cast_message);
+  task_runner_->RunTasks();
+  EXPECT_EQ(7, transport_.packets_sent());
+}
+
 }  // namespace cast
 }  // namespace media