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.
5 #include "media/cast/transport/rtp_sender/rtp_sender.h"
7 #include "base/logging.h"
8 #include "base/rand_util.h"
9 #include "media/cast/transport/cast_transport_defines.h"
10 #include "media/cast/transport/pacing/paced_sender.h"
16 // Schedule the RTP statistics callback every 33mS. As this interval affects the
17 // time offset of the render and playout times, we want it in the same ball park
19 static const int kStatsCallbackIntervalMs = 33;
22 base::TickClock* clock,
23 const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner,
24 PacedSender* const transport)
26 transport_(transport),
28 transport_task_runner_(transport_task_runner),
30 // Randomly set sequence number start value.
31 config_.sequence_number = base::RandInt(0, 65535);
34 RtpSender::~RtpSender() {}
36 bool RtpSender::InitializeAudio(const CastTransportAudioConfig& config) {
37 storage_.reset(new PacketStorage(config.rtp.max_outstanding_frames));
38 if (!storage_->IsValid()) {
42 config_.ssrc = config.rtp.config.ssrc;
43 config_.payload_type = config.rtp.config.payload_type;
44 config_.frequency = config.frequency;
45 config_.audio_codec = config.codec;
46 packetizer_.reset(new RtpPacketizer(transport_, storage_.get(), config_));
50 bool RtpSender::InitializeVideo(const CastTransportVideoConfig& config) {
51 storage_.reset(new PacketStorage(config.rtp.max_outstanding_frames));
52 if (!storage_->IsValid()) {
55 config_.audio = false;
56 config_.ssrc = config.rtp.config.ssrc;
57 config_.payload_type = config.rtp.config.payload_type;
58 config_.frequency = kVideoFrequency;
59 config_.video_codec = config.codec;
60 packetizer_.reset(new RtpPacketizer(transport_, storage_.get(), config_));
64 void RtpSender::IncomingEncodedVideoFrame(const EncodedVideoFrame* video_frame,
65 const base::TimeTicks& capture_time) {
67 packetizer_->IncomingEncodedVideoFrame(video_frame, capture_time);
70 void RtpSender::IncomingEncodedAudioFrame(
71 const EncodedAudioFrame* audio_frame,
72 const base::TimeTicks& recorded_time) {
74 packetizer_->IncomingEncodedAudioFrame(audio_frame, recorded_time);
77 void RtpSender::ResendPackets(
78 const MissingFramesAndPacketsMap& missing_frames_and_packets) {
80 // Iterate over all frames in the list.
81 for (MissingFramesAndPacketsMap::const_iterator it =
82 missing_frames_and_packets.begin();
83 it != missing_frames_and_packets.end();
85 SendPacketVector packets_to_resend;
86 uint8 frame_id = it->first;
87 const PacketIdSet& packets_set = it->second;
90 if (packets_set.empty()) {
91 VLOG(3) << "Missing all packets in frame " << static_cast<int>(frame_id);
95 // Get packet from storage.
96 success = storage_->GetPacket(frame_id, packet_id, &packets_to_resend);
98 // Check that we got at least one packet.
99 DCHECK(packet_id != 0 || success)
100 << "Failed to resend frame " << static_cast<int>(frame_id);
102 // Resend packet to the network.
104 VLOG(3) << "Resend " << static_cast<int>(frame_id) << ":"
106 // Set a unique incremental sequence number for every packet.
107 PacketRef packet = packets_to_resend.back().second;
108 UpdateSequenceNumber(&packet->data);
109 // Set the size as correspond to each frame.
114 // Iterate over all of the packets in the frame.
115 for (PacketIdSet::const_iterator set_it = packets_set.begin();
116 set_it != packets_set.end();
118 uint16 packet_id = *set_it;
119 success = storage_->GetPacket(frame_id, packet_id, &packets_to_resend);
121 // Check that we got at least one packet.
122 DCHECK(set_it != packets_set.begin() || success)
123 << "Failed to resend frame " << frame_id;
125 // Resend packet to the network.
127 VLOG(3) << "Resend " << static_cast<int>(frame_id) << ":"
129 PacketRef packet = packets_to_resend.back().second;
130 UpdateSequenceNumber(&packet->data);
134 transport_->ResendPackets(packets_to_resend);
138 void RtpSender::UpdateSequenceNumber(Packet* packet) {
139 uint16 new_sequence_number = packetizer_->NextSequenceNumber();
141 (*packet)[index] = (static_cast<uint8>(new_sequence_number));
142 (*packet)[index + 1] = (static_cast<uint8>(new_sequence_number >> 8));
145 void RtpSender::SubscribeRtpStatsCallback(
146 const CastTransportRtpStatistics& callback) {
147 stats_callback_ = callback;
148 ScheduleNextStatsReport();
151 void RtpSender::ScheduleNextStatsReport() {
152 transport_task_runner_->PostDelayedTask(
154 base::Bind(&RtpSender::RtpStatistics, weak_factory_.GetWeakPtr()),
155 base::TimeDelta::FromMilliseconds(kStatsCallbackIntervalMs));
158 void RtpSender::RtpStatistics() {
159 RtcpSenderInfo sender_info;
160 base::TimeTicks time_sent;
161 uint32 rtp_timestamp = 0;
162 packetizer_->LastSentTimestamp(&time_sent, &rtp_timestamp);
163 sender_info.send_packet_count = packetizer_->send_packets_count();
164 sender_info.send_octet_count = packetizer_->send_octet_count();
165 stats_callback_.Run(sender_info, time_sent, rtp_timestamp);
166 ScheduleNextStatsReport();
169 } // namespace transport