OLD | NEW |
| (Empty) |
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 transport_(transport), | |
22 burst_size_(1), | |
23 packets_sent_in_burst_(0), | |
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 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | |
33 cast_environment_->Logging()->InsertPacketListEvent(now, kPacketSentToPacer, | |
34 packets); | |
35 return SendPacketsToTransport(packets, &packet_list_); | |
36 } | |
37 | |
38 bool PacedSender::ResendPackets(const PacketList& packets) { | |
39 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
40 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | |
41 cast_environment_->Logging()->InsertPacketListEvent(now, kPacketRetransmited, | |
42 packets); | |
43 return SendPacketsToTransport(packets, &resend_packet_list_); | |
44 } | |
45 | |
46 bool PacedSender::SendPacketsToTransport(const PacketList& packets, | |
47 PacketList* packets_not_sent) { | |
48 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
49 UpdateBurstSize(packets.size()); | |
50 | |
51 if (!packets_not_sent->empty()) { | |
52 packets_not_sent->insert(packets_not_sent->end(), | |
53 packets.begin(), packets.end()); | |
54 return true; | |
55 } | |
56 PacketList packets_to_send; | |
57 PacketList::const_iterator first_to_store_it = packets.begin(); | |
58 | |
59 size_t max_packets_to_send_now = burst_size_ - packets_sent_in_burst_; | |
60 if (max_packets_to_send_now > 0) { | |
61 size_t packets_to_send_now = std::min(max_packets_to_send_now, | |
62 packets.size()); | |
63 | |
64 std::advance(first_to_store_it, packets_to_send_now); | |
65 packets_to_send.insert(packets_to_send.begin(), | |
66 packets.begin(), first_to_store_it); | |
67 } | |
68 packets_not_sent->insert(packets_not_sent->end(), | |
69 first_to_store_it, packets.end()); | |
70 packets_sent_in_burst_ += packets_to_send.size(); | |
71 if (packets_to_send.empty()) return true; | |
72 | |
73 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | |
74 cast_environment_->Logging()->InsertPacketListEvent(now, kPacketSentToNetwork, | |
75 packets); | |
76 return transport_->SendPackets(packets_to_send); | |
77 } | |
78 | |
79 bool PacedSender::SendRtcpPacket(const Packet& packet) { | |
80 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
81 // We pass the RTCP packets straight through. | |
82 return transport_->SendPacket(packet); | |
83 } | |
84 | |
85 void PacedSender::ScheduleNextSend() { | |
86 base::TimeDelta time_to_next = time_last_process_ - | |
87 cast_environment_->Clock()->NowTicks() + | |
88 base::TimeDelta::FromMilliseconds(kPacingIntervalMs); | |
89 | |
90 time_to_next = std::max(time_to_next, base::TimeDelta()); | |
91 | |
92 cast_environment_->PostDelayedTask(CastEnvironment::MAIN, FROM_HERE, | |
93 base::Bind(&PacedSender::SendNextPacketBurst, weak_factory_.GetWeakPtr()), | |
94 time_to_next); | |
95 } | |
96 | |
97 void PacedSender::SendNextPacketBurst() { | |
98 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
99 SendStoredPackets(); | |
100 time_last_process_ = cast_environment_->Clock()->NowTicks(); | |
101 ScheduleNextSend(); | |
102 } | |
103 | |
104 void PacedSender::SendStoredPackets() { | |
105 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
106 if (packet_list_.empty() && resend_packet_list_.empty()) return; | |
107 | |
108 size_t packets_to_send = burst_size_; | |
109 PacketList packets_to_resend; | |
110 | |
111 // Send our re-send packets first. | |
112 if (!resend_packet_list_.empty()) { | |
113 PacketList::iterator it = resend_packet_list_.begin(); | |
114 size_t packets_to_send_now = std::min(packets_to_send, | |
115 resend_packet_list_.size()); | |
116 std::advance(it, packets_to_send_now); | |
117 packets_to_resend.insert(packets_to_resend.begin(), | |
118 resend_packet_list_.begin(), it); | |
119 resend_packet_list_.erase(resend_packet_list_.begin(), it); | |
120 packets_to_send -= packets_to_resend.size(); | |
121 } | |
122 if (!packet_list_.empty() && packets_to_send > 0) { | |
123 PacketList::iterator it = packet_list_.begin(); | |
124 size_t packets_to_send_now = std::min(packets_to_send, | |
125 packet_list_.size()); | |
126 | |
127 std::advance(it, packets_to_send_now); | |
128 packets_to_resend.insert(packets_to_resend.end(), | |
129 packet_list_.begin(), it); | |
130 packet_list_.erase(packet_list_.begin(), it); | |
131 | |
132 if (packet_list_.empty()) { | |
133 burst_size_ = 1; // Reset burst size after we sent the last stored packet | |
134 packets_sent_in_burst_ = 0; | |
135 } | |
136 } | |
137 transport_->SendPackets(packets_to_resend); | |
138 } | |
139 | |
140 void PacedSender::UpdateBurstSize(size_t packets_to_send) { | |
141 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
142 packets_to_send = std::max(packets_to_send, | |
143 resend_packet_list_.size() + packet_list_.size()); | |
144 | |
145 packets_to_send += (kPacingMaxBurstsPerFrame - 1); // Round up. | |
146 burst_size_ = std::max(packets_to_send / kPacingMaxBurstsPerFrame, | |
147 burst_size_); | |
148 } | |
149 | |
150 } // namespace cast | |
151 } // namespace media | |
OLD | NEW |