Home | History | Annotate | Download | only in pacing
      1 // Copyright 2013 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 "media/cast/net/pacing/paced_sender.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/message_loop/message_loop.h"
      9 
     10 namespace media {
     11 namespace cast {
     12 
     13 static const int64 kPacingIntervalMs = 10;
     14 // Each frame will be split into no more than kPacingMaxBurstsPerFrame
     15 // bursts of packets.
     16 static const size_t kPacingMaxBurstsPerFrame = 3;
     17 
     18 PacedSender::PacedSender(scoped_refptr<CastEnvironment> cast_environment,
     19                          PacketSender* transport)
     20     : cast_environment_(cast_environment),
     21       burst_size_(1),
     22       packets_sent_in_burst_(0),
     23       transport_(transport),
     24       weak_factory_(this) {
     25   ScheduleNextSend();
     26 }
     27 
     28 PacedSender::~PacedSender() {}
     29 
     30 bool PacedSender::SendPackets(const PacketList& packets) {
     31   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
     32   cast_environment_->Logging()->InsertPacketListEvent(kPacketSentToPacer,
     33                                                       packets);
     34   return SendPacketsToTransport(packets, &packet_list_);
     35 }
     36 
     37 bool PacedSender::ResendPackets(const PacketList& packets) {
     38   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
     39   cast_environment_->Logging()->InsertPacketListEvent(kPacketRetransmited,
     40                                                       packets);
     41   return SendPacketsToTransport(packets, &resend_packet_list_);
     42 }
     43 
     44 bool PacedSender::SendPacketsToTransport(const PacketList& packets,
     45                                          PacketList* packets_not_sent) {
     46   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
     47   UpdateBurstSize(packets.size());
     48 
     49   if (!packets_not_sent->empty()) {
     50     packets_not_sent->insert(packets_not_sent->end(),
     51                              packets.begin(), packets.end());
     52     return true;
     53   }
     54   PacketList packets_to_send;
     55   PacketList::const_iterator first_to_store_it = packets.begin();
     56 
     57   size_t max_packets_to_send_now = burst_size_ - packets_sent_in_burst_;
     58   if (max_packets_to_send_now > 0) {
     59     size_t packets_to_send_now = std::min(max_packets_to_send_now,
     60                                           packets.size());
     61 
     62     std::advance(first_to_store_it, packets_to_send_now);
     63     packets_to_send.insert(packets_to_send.begin(),
     64                            packets.begin(), first_to_store_it);
     65   }
     66   packets_not_sent->insert(packets_not_sent->end(),
     67                          first_to_store_it, packets.end());
     68   packets_sent_in_burst_ += packets_to_send.size();
     69   if (packets_to_send.empty()) return true;
     70 
     71   cast_environment_->Logging()->InsertPacketListEvent(kPacketSentToNetwork,
     72                                                       packets);
     73   return transport_->SendPackets(packets_to_send);
     74 }
     75 
     76 bool PacedSender::SendRtcpPacket(const Packet& packet) {
     77   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
     78   // We pass the RTCP packets straight through.
     79   return transport_->SendPacket(packet);
     80 }
     81 
     82 void PacedSender::ScheduleNextSend() {
     83   base::TimeDelta time_to_next = time_last_process_ -
     84       cast_environment_->Clock()->NowTicks() +
     85       base::TimeDelta::FromMilliseconds(kPacingIntervalMs);
     86 
     87   time_to_next = std::max(time_to_next, base::TimeDelta());
     88 
     89   cast_environment_->PostDelayedTask(CastEnvironment::MAIN, FROM_HERE,
     90       base::Bind(&PacedSender::SendNextPacketBurst, weak_factory_.GetWeakPtr()),
     91                  time_to_next);
     92 }
     93 
     94 void PacedSender::SendNextPacketBurst() {
     95   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
     96   SendStoredPackets();
     97   time_last_process_ = cast_environment_->Clock()->NowTicks();
     98   ScheduleNextSend();
     99 }
    100 
    101 void PacedSender::SendStoredPackets() {
    102   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
    103   if (packet_list_.empty() && resend_packet_list_.empty()) return;
    104 
    105   size_t packets_to_send = burst_size_;
    106   PacketList packets_to_resend;
    107 
    108   // Send our re-send packets first.
    109   if (!resend_packet_list_.empty()) {
    110     PacketList::iterator it = resend_packet_list_.begin();
    111     size_t packets_to_send_now = std::min(packets_to_send,
    112                                           resend_packet_list_.size());
    113     std::advance(it, packets_to_send_now);
    114     packets_to_resend.insert(packets_to_resend.begin(),
    115                              resend_packet_list_.begin(), it);
    116     resend_packet_list_.erase(resend_packet_list_.begin(), it);
    117     packets_to_send -= packets_to_resend.size();
    118   }
    119   if (!packet_list_.empty() && packets_to_send > 0) {
    120     PacketList::iterator it = packet_list_.begin();
    121     size_t packets_to_send_now = std::min(packets_to_send,
    122                                           packet_list_.size());
    123 
    124     std::advance(it, packets_to_send_now);
    125     packets_to_resend.insert(packets_to_resend.end(),
    126                              packet_list_.begin(), it);
    127     packet_list_.erase(packet_list_.begin(), it);
    128 
    129     if (packet_list_.empty()) {
    130       burst_size_ = 1;  // Reset burst size after we sent the last stored packet
    131       packets_sent_in_burst_ = 0;
    132     }
    133   }
    134   transport_->SendPackets(packets_to_resend);
    135 }
    136 
    137 void PacedSender::UpdateBurstSize(size_t packets_to_send) {
    138   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
    139   packets_to_send = std::max(packets_to_send,
    140       resend_packet_list_.size() + packet_list_.size());
    141 
    142   packets_to_send += (kPacingMaxBurstsPerFrame - 1);  // Round up.
    143   burst_size_ = std::max(packets_to_send / kPacingMaxBurstsPerFrame,
    144                          burst_size_);
    145 }
    146 
    147 }  // namespace cast
    148 }  // namespace media
    149