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/transport/rtp_sender/rtp_sender.h" 6 7 #include "base/big_endian.h" 8 #include "base/logging.h" 9 #include "base/rand_util.h" 10 #include "media/cast/transport/cast_transport_defines.h" 11 #include "media/cast/transport/pacing/paced_sender.h" 12 13 namespace media { 14 namespace cast { 15 namespace transport { 16 17 namespace { 18 19 // If there is only one referecne to the packet then copy the 20 // reference and return. 21 // Otherwise return a deep copy of the packet. 22 PacketRef FastCopyPacket(const PacketRef& packet) { 23 if (packet->HasOneRef()) 24 return packet; 25 return make_scoped_refptr(new base::RefCountedData<Packet>(packet->data)); 26 } 27 28 } // namespace 29 30 RtpSender::RtpSender( 31 base::TickClock* clock, 32 const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner, 33 PacedSender* const transport) 34 : clock_(clock), 35 transport_(transport), 36 transport_task_runner_(transport_task_runner), 37 weak_factory_(this) { 38 // Randomly set sequence number start value. 39 config_.sequence_number = base::RandInt(0, 65535); 40 } 41 42 RtpSender::~RtpSender() {} 43 44 bool RtpSender::InitializeAudio(const CastTransportAudioConfig& config) { 45 storage_.reset(new PacketStorage(config.rtp.max_outstanding_frames)); 46 if (!storage_->IsValid()) { 47 return false; 48 } 49 config_.audio = true; 50 config_.ssrc = config.rtp.config.ssrc; 51 config_.payload_type = config.rtp.config.payload_type; 52 config_.frequency = config.frequency; 53 config_.audio_codec = config.codec; 54 packetizer_.reset(new RtpPacketizer(transport_, storage_.get(), config_)); 55 return true; 56 } 57 58 bool RtpSender::InitializeVideo(const CastTransportVideoConfig& config) { 59 storage_.reset(new PacketStorage(config.rtp.max_outstanding_frames)); 60 if (!storage_->IsValid()) { 61 return false; 62 } 63 config_.audio = false; 64 config_.ssrc = config.rtp.config.ssrc; 65 config_.payload_type = config.rtp.config.payload_type; 66 config_.frequency = kVideoFrequency; 67 config_.video_codec = config.codec; 68 packetizer_.reset(new RtpPacketizer(transport_, storage_.get(), config_)); 69 return true; 70 } 71 72 void RtpSender::SendFrame(const EncodedFrame& frame) { 73 DCHECK(packetizer_); 74 packetizer_->SendFrameAsPackets(frame); 75 } 76 77 void RtpSender::ResendPackets( 78 const MissingFramesAndPacketsMap& missing_frames_and_packets, 79 bool cancel_rtx_if_not_in_list, 80 base::TimeDelta dedupe_window) { 81 DCHECK(storage_); 82 // Iterate over all frames in the list. 83 for (MissingFramesAndPacketsMap::const_iterator it = 84 missing_frames_and_packets.begin(); 85 it != missing_frames_and_packets.end(); 86 ++it) { 87 SendPacketVector packets_to_resend; 88 uint8 frame_id = it->first; 89 // Set of packets that the receiver wants us to re-send. 90 // If empty, we need to re-send all packets for this frame. 91 const PacketIdSet& missing_packet_set = it->second; 92 93 bool resend_all = missing_packet_set.find(kRtcpCastAllPacketsLost) != 94 missing_packet_set.end(); 95 bool resend_last = missing_packet_set.find(kRtcpCastLastPacket) != 96 missing_packet_set.end(); 97 98 const SendPacketVector* stored_packets = storage_->GetFrame8(frame_id); 99 if (!stored_packets) 100 continue; 101 102 for (SendPacketVector::const_iterator it = stored_packets->begin(); 103 it != stored_packets->end(); ++it) { 104 const PacketKey& packet_key = it->first; 105 const uint16 packet_id = packet_key.second.second; 106 107 // Should we resend the packet? 108 bool resend = resend_all; 109 110 // Should we resend it because it's in the missing_packet_set? 111 if (!resend && 112 missing_packet_set.find(packet_id) != missing_packet_set.end()) { 113 resend = true; 114 } 115 116 // If we were asked to resend the last packet, check if it's the 117 // last packet. 118 if (!resend && resend_last && (it + 1) == stored_packets->end()) { 119 resend = true; 120 } 121 122 if (resend) { 123 // Resend packet to the network. 124 VLOG(3) << "Resend " << static_cast<int>(frame_id) << ":" 125 << packet_id; 126 // Set a unique incremental sequence number for every packet. 127 PacketRef packet_copy = FastCopyPacket(it->second); 128 UpdateSequenceNumber(&packet_copy->data); 129 packets_to_resend.push_back(std::make_pair(packet_key, packet_copy)); 130 } else if (cancel_rtx_if_not_in_list) { 131 transport_->CancelSendingPacket(it->first); 132 } 133 } 134 transport_->ResendPackets(packets_to_resend, dedupe_window); 135 } 136 } 137 138 void RtpSender::UpdateSequenceNumber(Packet* packet) { 139 // TODO(miu): This is an abstraction violation. This needs to be a part of 140 // the overall packet (de)serialization consolidation. 141 static const int kByteOffsetToSequenceNumber = 2; 142 base::BigEndianWriter big_endian_writer( 143 reinterpret_cast<char*>((&packet->front()) + kByteOffsetToSequenceNumber), 144 sizeof(uint16)); 145 big_endian_writer.WriteU16(packetizer_->NextSequenceNumber()); 146 } 147 148 } // namespace transport 149 } // namespace cast 150 } // namespace media 151