• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PacedSender(scoped_refptr<CastEnvironment> cast_environment,PacketSender * transport)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 
~PacedSender()28 PacedSender::~PacedSender() {}
29 
SendPackets(const PacketList & packets)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 
ResendPackets(const PacketList & packets)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 
SendPacketsToTransport(const PacketList & packets,PacketList * packets_not_sent)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 
SendRtcpPacket(const Packet & packet)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 
ScheduleNextSend()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 
SendNextPacketBurst()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 
SendStoredPackets()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 
UpdateBurstSize(size_t packets_to_send)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