| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "media/cast/pacing/paced_sender.h" |
| |
| #include "base/bind.h" |
| #include "base/message_loop/message_loop.h" |
| |
| namespace media { |
| namespace cast { |
| |
| static const int64 kPacingIntervalMs = 10; |
| // Each frame will be split into no more than kPacingMaxBurstsPerFrame |
| // bursts of packets. |
| static const size_t kPacingMaxBurstsPerFrame = 3; |
| |
| PacedSender::PacedSender(scoped_refptr<CastEnvironment> cast_environment, |
| PacketSender* transport) |
| : cast_environment_(cast_environment), |
| burst_size_(1), |
| packets_sent_in_burst_(0), |
| transport_(transport), |
| weak_factory_(this) { |
| ScheduleNextSend(); |
| } |
| |
| PacedSender::~PacedSender() {} |
| |
| bool PacedSender::SendPackets(const PacketList& packets) { |
| return SendPacketsToTransport(packets, &packet_list_); |
| } |
| |
| bool PacedSender::ResendPackets(const PacketList& packets) { |
| return SendPacketsToTransport(packets, &resend_packet_list_); |
| } |
| |
| bool PacedSender::SendPacketsToTransport(const PacketList& packets, |
| PacketList* packets_not_sent) { |
| UpdateBurstSize(packets.size()); |
| |
| if (!packets_not_sent->empty()) { |
| packets_not_sent->insert(packets_not_sent->end(), |
| packets.begin(), packets.end()); |
| return true; |
| } |
| PacketList packets_to_send; |
| PacketList::const_iterator first_to_store_it = packets.begin(); |
| |
| size_t max_packets_to_send_now = burst_size_ - packets_sent_in_burst_; |
| if (max_packets_to_send_now > 0) { |
| size_t packets_to_send_now = std::min(max_packets_to_send_now, |
| packets.size()); |
| |
| std::advance(first_to_store_it, packets_to_send_now); |
| packets_to_send.insert(packets_to_send.begin(), |
| packets.begin(), first_to_store_it); |
| } |
| packets_not_sent->insert(packets_not_sent->end(), |
| first_to_store_it, packets.end()); |
| packets_sent_in_burst_ += packets_to_send.size(); |
| if (packets_to_send.empty()) return true; |
| |
| return transport_->SendPackets(packets_to_send); |
| } |
| |
| bool PacedSender::SendRtcpPacket(const Packet& packet) { |
| // We pass the RTCP packets straight through. |
| return transport_->SendPacket(packet); |
| } |
| |
| void PacedSender::ScheduleNextSend() { |
| base::TimeDelta time_to_next = time_last_process_ - |
| cast_environment_->Clock()->NowTicks() + |
| base::TimeDelta::FromMilliseconds(kPacingIntervalMs); |
| |
| time_to_next = std::max(time_to_next, base::TimeDelta()); |
| |
| cast_environment_->PostDelayedTask(CastEnvironment::MAIN, FROM_HERE, |
| base::Bind(&PacedSender::SendNextPacketBurst, weak_factory_.GetWeakPtr()), |
| time_to_next); |
| } |
| |
| void PacedSender::SendNextPacketBurst() { |
| SendStoredPackets(); |
| time_last_process_ = cast_environment_->Clock()->NowTicks(); |
| ScheduleNextSend(); |
| } |
| |
| void PacedSender::SendStoredPackets() { |
| if (packet_list_.empty() && resend_packet_list_.empty()) return; |
| |
| size_t packets_to_send = burst_size_; |
| PacketList packets_to_resend; |
| |
| // Send our re-send packets first. |
| if (!resend_packet_list_.empty()) { |
| PacketList::iterator it = resend_packet_list_.begin(); |
| size_t packets_to_send_now = std::min(packets_to_send, |
| resend_packet_list_.size()); |
| std::advance(it, packets_to_send_now); |
| packets_to_resend.insert(packets_to_resend.begin(), |
| resend_packet_list_.begin(), it); |
| resend_packet_list_.erase(resend_packet_list_.begin(), it); |
| packets_to_send -= packets_to_resend.size(); |
| } |
| if (!packet_list_.empty() && packets_to_send > 0) { |
| PacketList::iterator it = packet_list_.begin(); |
| size_t packets_to_send_now = std::min(packets_to_send, |
| packet_list_.size()); |
| |
| std::advance(it, packets_to_send_now); |
| packets_to_resend.insert(packets_to_resend.end(), |
| packet_list_.begin(), it); |
| packet_list_.erase(packet_list_.begin(), it); |
| |
| if (packet_list_.empty()) { |
| burst_size_ = 1; // Reset burst size after we sent the last stored packet |
| packets_sent_in_burst_ = 0; |
| } |
| } |
| transport_->SendPackets(packets_to_resend); |
| } |
| |
| void PacedSender::UpdateBurstSize(size_t packets_to_send) { |
| packets_to_send = std::max(packets_to_send, |
| resend_packet_list_.size() + packet_list_.size()); |
| |
| packets_to_send += (kPacingMaxBurstsPerFrame - 1); // Round up. |
| burst_size_ = std::max(packets_to_send / kPacingMaxBurstsPerFrame, |
| burst_size_); |
| } |
| |
| } // namespace cast |
| } // namespace media |