| Index: media/cast/transport/pacing/paced_sender.cc
|
| diff --git a/media/cast/transport/pacing/paced_sender.cc b/media/cast/transport/pacing/paced_sender.cc
|
| deleted file mode 100644
|
| index 20cbde85be9ffbb906c3841b3dea9c30362be725..0000000000000000000000000000000000000000
|
| --- a/media/cast/transport/pacing/paced_sender.cc
|
| +++ /dev/null
|
| @@ -1,260 +0,0 @@
|
| -// 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/transport/pacing/paced_sender.h"
|
| -
|
| -#include "base/big_endian.h"
|
| -#include "base/bind.h"
|
| -#include "base/message_loop/message_loop.h"
|
| -
|
| -namespace media {
|
| -namespace cast {
|
| -namespace transport {
|
| -
|
| -namespace {
|
| -
|
| -static const int64 kPacingIntervalMs = 10;
|
| -// Each frame will be split into no more than kPacingMaxBurstsPerFrame
|
| -// bursts of packets.
|
| -static const size_t kPacingMaxBurstsPerFrame = 3;
|
| -static const size_t kTargetBurstSize = 10;
|
| -static const size_t kMaxBurstSize = 20;
|
| -static const size_t kMaxDedupeWindowMs = 500;
|
| -
|
| -} // namespace
|
| -
|
| -// static
|
| -PacketKey PacedPacketSender::MakePacketKey(const base::TimeTicks& ticks,
|
| - uint32 ssrc,
|
| - uint16 packet_id) {
|
| - return std::make_pair(ticks, std::make_pair(ssrc, packet_id));
|
| -}
|
| -
|
| -PacedSender::PacedSender(
|
| - base::TickClock* clock,
|
| - LoggingImpl* logging,
|
| - PacketSender* transport,
|
| - const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner)
|
| - : clock_(clock),
|
| - logging_(logging),
|
| - transport_(transport),
|
| - transport_task_runner_(transport_task_runner),
|
| - audio_ssrc_(0),
|
| - video_ssrc_(0),
|
| - max_burst_size_(kTargetBurstSize),
|
| - next_max_burst_size_(kTargetBurstSize),
|
| - next_next_max_burst_size_(kTargetBurstSize),
|
| - current_burst_size_(0),
|
| - state_(State_Unblocked),
|
| - weak_factory_(this) {
|
| -}
|
| -
|
| -PacedSender::~PacedSender() {}
|
| -
|
| -void PacedSender::RegisterAudioSsrc(uint32 audio_ssrc) {
|
| - audio_ssrc_ = audio_ssrc;
|
| -}
|
| -
|
| -void PacedSender::RegisterVideoSsrc(uint32 video_ssrc) {
|
| - video_ssrc_ = video_ssrc;
|
| -}
|
| -
|
| -bool PacedSender::SendPackets(const SendPacketVector& packets) {
|
| - if (packets.empty()) {
|
| - return true;
|
| - }
|
| - for (size_t i = 0; i < packets.size(); i++) {
|
| - packet_list_[packets[i].first] =
|
| - make_pair(PacketType_Normal, packets[i].second);
|
| - }
|
| - if (state_ == State_Unblocked) {
|
| - SendStoredPackets();
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool PacedSender::ResendPackets(const SendPacketVector& packets,
|
| - base::TimeDelta dedupe_window) {
|
| - if (packets.empty()) {
|
| - return true;
|
| - }
|
| - base::TimeTicks now = clock_->NowTicks();
|
| - for (size_t i = 0; i < packets.size(); i++) {
|
| - std::map<PacketKey, base::TimeTicks>::const_iterator j =
|
| - sent_time_.find(packets[i].first);
|
| -
|
| - if (j != sent_time_.end() && now - j->second < dedupe_window) {
|
| - LogPacketEvent(packets[i].second->data, PACKET_RTX_REJECTED);
|
| - continue;
|
| - }
|
| -
|
| - packet_list_[packets[i].first] =
|
| - make_pair(PacketType_Resend, packets[i].second);
|
| - }
|
| - if (state_ == State_Unblocked) {
|
| - SendStoredPackets();
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool PacedSender::SendRtcpPacket(uint32 ssrc, PacketRef packet) {
|
| - if (state_ == State_TransportBlocked) {
|
| - packet_list_[PacedPacketSender::MakePacketKey(base::TimeTicks(), ssrc, 0)] =
|
| - make_pair(PacketType_RTCP, packet);
|
| - } else {
|
| - // We pass the RTCP packets straight through.
|
| - if (!transport_->SendPacket(
|
| - packet,
|
| - base::Bind(&PacedSender::SendStoredPackets,
|
| - weak_factory_.GetWeakPtr()))) {
|
| - state_ = State_TransportBlocked;
|
| - }
|
| -
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void PacedSender::CancelSendingPacket(const PacketKey& packet_key) {
|
| - packet_list_.erase(packet_key);
|
| -}
|
| -
|
| -PacketRef PacedSender::GetNextPacket(PacketType* packet_type,
|
| - PacketKey* packet_key) {
|
| - std::map<PacketKey, std::pair<PacketType, PacketRef> >::iterator i;
|
| - i = packet_list_.begin();
|
| - DCHECK(i != packet_list_.end());
|
| - *packet_type = i->second.first;
|
| - *packet_key = i->first;
|
| - PacketRef ret = i->second.second;
|
| - packet_list_.erase(i);
|
| - return ret;
|
| -}
|
| -
|
| -bool PacedSender::empty() const {
|
| - return packet_list_.empty();
|
| -}
|
| -
|
| -size_t PacedSender::size() const {
|
| - return packet_list_.size();
|
| -}
|
| -
|
| -// This function can be called from three places:
|
| -// 1. User called one of the Send* functions and we were in an unblocked state.
|
| -// 2. state_ == State_TransportBlocked and the transport is calling us to
|
| -// let us know that it's ok to send again.
|
| -// 3. state_ == State_BurstFull and there are still packets to send. In this
|
| -// case we called PostDelayedTask on this function to start a new burst.
|
| -void PacedSender::SendStoredPackets() {
|
| - State previous_state = state_;
|
| - state_ = State_Unblocked;
|
| - if (empty()) {
|
| - return;
|
| - }
|
| -
|
| - base::TimeTicks now = clock_->NowTicks();
|
| - // I don't actually trust that PostDelayTask(x - now) will mean that
|
| - // now >= x when the call happens, so check if the previous state was
|
| - // State_BurstFull too.
|
| - if (now >= burst_end_ || previous_state == State_BurstFull) {
|
| - // Start a new burst.
|
| - current_burst_size_ = 0;
|
| - burst_end_ = now + base::TimeDelta::FromMilliseconds(kPacingIntervalMs);
|
| -
|
| - // The goal here is to try to send out the queued packets over the next
|
| - // three bursts, while trying to keep the burst size below 10 if possible.
|
| - // We have some evidence that sending more than 12 packets in a row doesn't
|
| - // work very well, but we don't actually know why yet. Sending out packets
|
| - // sooner is better than sending out packets later as that gives us more
|
| - // time to re-send them if needed. So if we have less than 30 packets, just
|
| - // send 10 at a time. If we have less than 60 packets, send n / 3 at a time.
|
| - // if we have more than 60, we send 20 at a time. 20 packets is ~24Mbit/s
|
| - // which is more bandwidth than the cast library should need, and sending
|
| - // out more data per second is unlikely to be helpful.
|
| - size_t max_burst_size = std::min(
|
| - kMaxBurstSize,
|
| - std::max(kTargetBurstSize, size() / kPacingMaxBurstsPerFrame));
|
| -
|
| - // If the queue is long, issue a warning. Try to limit the number of
|
| - // warnings issued by only issuing the warning when the burst size
|
| - // grows. Otherwise we might get 100 warnings per second.
|
| - if (max_burst_size > next_next_max_burst_size_ && size() > 100) {
|
| - LOG(WARNING) << "Packet queue is very long:" << size();
|
| - }
|
| -
|
| - max_burst_size_ = std::max(next_max_burst_size_, max_burst_size);
|
| - next_max_burst_size_ = std::max(next_next_max_burst_size_, max_burst_size);
|
| - next_next_max_burst_size_ = max_burst_size;
|
| - }
|
| -
|
| - base::Closure cb = base::Bind(&PacedSender::SendStoredPackets,
|
| - weak_factory_.GetWeakPtr());
|
| - while (!empty()) {
|
| - if (current_burst_size_ >= max_burst_size_) {
|
| - transport_task_runner_->PostDelayedTask(FROM_HERE,
|
| - cb,
|
| - burst_end_ - now);
|
| - state_ = State_BurstFull;
|
| - return;
|
| - }
|
| - PacketType packet_type;
|
| - PacketKey packet_key;
|
| - PacketRef packet = GetNextPacket(&packet_type, &packet_key);
|
| - sent_time_[packet_key] = now;
|
| - sent_time_buffer_[packet_key] = now;
|
| -
|
| - switch (packet_type) {
|
| - case PacketType_Resend:
|
| - LogPacketEvent(packet->data, PACKET_RETRANSMITTED);
|
| - break;
|
| - case PacketType_Normal:
|
| - LogPacketEvent(packet->data, PACKET_SENT_TO_NETWORK);
|
| - break;
|
| - case PacketType_RTCP:
|
| - break;
|
| - }
|
| - if (!transport_->SendPacket(packet, cb)) {
|
| - state_ = State_TransportBlocked;
|
| - return;
|
| - }
|
| - current_burst_size_++;
|
| - }
|
| - // Keep ~0.5 seconds of data (1000 packets)
|
| - if (sent_time_buffer_.size() >=
|
| - kMaxBurstSize * kMaxDedupeWindowMs / kPacingIntervalMs) {
|
| - sent_time_.swap(sent_time_buffer_);
|
| - sent_time_buffer_.clear();
|
| - }
|
| - DCHECK_LE(sent_time_buffer_.size(),
|
| - kMaxBurstSize * kMaxDedupeWindowMs / kPacingIntervalMs);
|
| - DCHECK_LE(sent_time_.size(),
|
| - 2 * kMaxBurstSize * kMaxDedupeWindowMs / kPacingIntervalMs);
|
| - state_ = State_Unblocked;
|
| -}
|
| -
|
| -void PacedSender::LogPacketEvent(const Packet& packet, CastLoggingEvent event) {
|
| - // Get SSRC from packet and compare with the audio_ssrc / video_ssrc to see
|
| - // if the packet is audio or video.
|
| - DCHECK_GE(packet.size(), 12u);
|
| - base::BigEndianReader reader(reinterpret_cast<const char*>(&packet[8]), 4);
|
| - uint32 ssrc;
|
| - bool success = reader.ReadU32(&ssrc);
|
| - DCHECK(success);
|
| - bool is_audio;
|
| - if (ssrc == audio_ssrc_) {
|
| - is_audio = true;
|
| - } else if (ssrc == video_ssrc_) {
|
| - is_audio = false;
|
| - } else {
|
| - DVLOG(3) << "Got unknown ssrc " << ssrc << " when logging packet event";
|
| - return;
|
| - }
|
| -
|
| - EventMediaType media_type = is_audio ? AUDIO_EVENT : VIDEO_EVENT;
|
| - logging_->InsertSinglePacketEvent(clock_->NowTicks(), event, media_type,
|
| - packet);
|
| -}
|
| -
|
| -} // namespace transport
|
| -} // namespace cast
|
| -} // namespace media
|
|
|