blob: eb88be7ca2e349dba60b336625da116ef0f72a98 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +000011#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
12
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000013#include <stdlib.h> // srand
niklase@google.com470e71d2011-07-07 08:21:25 +000014
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +000015#include "webrtc/modules/rtp_rtcp/source/rtp_sender_audio.h"
16#include "webrtc/modules/rtp_rtcp/source/rtp_sender_video.h"
17#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +000018#include "webrtc/system_wrappers/interface/logging.h"
stefan@webrtc.org88e0dda2014-07-04 09:20:42 +000019#include "webrtc/system_wrappers/interface/tick_util.h"
hclam@chromium.org806dc3b2013-04-09 19:54:10 +000020#include "webrtc/system_wrappers/interface/trace_event.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000021
22namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000023
stefan@webrtc.orga8179622013-06-04 13:47:36 +000024// Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP.
25const int kMaxPaddingLength = 224;
stefan@webrtc.org0a3c1472013-12-05 14:05:07 +000026const int kSendSideDelayWindowMs = 1000;
stefan@webrtc.orga8179622013-06-04 13:47:36 +000027
hclam@chromium.org806dc3b2013-04-09 19:54:10 +000028namespace {
29
30const char* FrameTypeToString(const FrameType frame_type) {
31 switch (frame_type) {
32 case kFrameEmpty: return "empty";
33 case kAudioFrameSpeech: return "audio_speech";
34 case kAudioFrameCN: return "audio_cn";
35 case kVideoFrameKey: return "video_key";
36 case kVideoFrameDelta: return "video_delta";
hclam@chromium.org806dc3b2013-04-09 19:54:10 +000037 }
38 return "";
39}
40
41} // namespace
42
sprang@webrtc.org6811b6e2013-12-13 09:46:59 +000043RTPSender::RTPSender(const int32_t id,
44 const bool audio,
45 Clock* clock,
46 Transport* transport,
47 RtpAudioFeedback* audio_feedback,
andresp@webrtc.orgd11bec42014-07-08 14:32:58 +000048 PacedSender* paced_sender,
andresp@webrtc.org8f151212014-07-10 09:39:23 +000049 BitrateStatisticsObserver* bitrate_callback,
stefan@webrtc.org168f23f2014-07-11 13:44:02 +000050 FrameCountObserver* frame_count_observer,
51 SendSideDelayObserver* send_side_delay_observer)
sprang@webrtc.org6811b6e2013-12-13 09:46:59 +000052 : clock_(clock),
53 bitrate_sent_(clock, this),
54 id_(id),
55 audio_configured_(audio),
56 audio_(NULL),
57 video_(NULL),
58 paced_sender_(paced_sender),
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +000059 send_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
sprang@webrtc.org6811b6e2013-12-13 09:46:59 +000060 transport_(transport),
61 sending_media_(true), // Default to sending media.
62 max_payload_length_(IP_PACKET_SIZE - 28), // Default is IP-v4/UDP.
sprang@webrtc.org6811b6e2013-12-13 09:46:59 +000063 packet_over_head_(28),
64 payload_type_(-1),
65 payload_type_map_(),
66 rtp_header_extension_map_(),
67 transmission_time_offset_(0),
68 absolute_send_time_(0),
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +000069 // NACK.
sprang@webrtc.org6811b6e2013-12-13 09:46:59 +000070 nack_byte_count_times_(),
71 nack_byte_count_(),
72 nack_bitrate_(clock, NULL),
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +000073 packet_history_(clock),
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +000074 // Statistics
pbos@webrtc.orge07049f2013-09-10 11:29:17 +000075 statistics_crit_(CriticalSectionWrapper::CreateCriticalSection()),
sprang@webrtc.org6811b6e2013-12-13 09:46:59 +000076 rtp_stats_callback_(NULL),
andresp@webrtc.orgd11bec42014-07-08 14:32:58 +000077 bitrate_callback_(bitrate_callback),
andresp@webrtc.org8f151212014-07-10 09:39:23 +000078 frame_count_observer_(frame_count_observer),
stefan@webrtc.org168f23f2014-07-11 13:44:02 +000079 send_side_delay_observer_(send_side_delay_observer),
sprang@webrtc.orgebad7652013-12-05 14:29:02 +000080 // RTP variables
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +000081 start_timestamp_forced_(false),
82 start_timestamp_(0),
sprang@webrtc.org6811b6e2013-12-13 09:46:59 +000083 ssrc_db_(*SSRCDatabase::GetSSRCDatabase()),
84 remote_ssrc_(0),
85 sequence_number_forced_(false),
86 ssrc_forced_(false),
87 timestamp_(0),
88 capture_time_ms_(0),
89 last_timestamp_time_ms_(0),
stefan@webrtc.org8b94e3d2014-07-17 16:10:14 +000090 media_has_been_sent_(false),
sprang@webrtc.org6811b6e2013-12-13 09:46:59 +000091 last_packet_marker_bit_(false),
92 num_csrcs_(0),
93 csrcs_(),
94 include_csrcs_(true),
95 rtx_(kRtxOff),
andresp@webrtc.orgd09d0742014-03-26 14:27:34 +000096 payload_type_rtx_(-1),
97 target_bitrate_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
stefan@webrtc.orga15fbfd2014-06-17 17:32:05 +000098 target_bitrate_(0) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +000099 memset(nack_byte_count_times_, 0, sizeof(nack_byte_count_times_));
100 memset(nack_byte_count_, 0, sizeof(nack_byte_count_));
stefan@webrtc.orga8179622013-06-04 13:47:36 +0000101 memset(csrcs_, 0, sizeof(csrcs_));
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000102 // We need to seed the random generator.
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000103 srand(static_cast<uint32_t>(clock_->TimeInMilliseconds()));
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000104 ssrc_ = ssrc_db_.CreateSSRC(); // Can't be 0.
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000105 ssrc_rtx_ = ssrc_db_.CreateSSRC(); // Can't be 0.
106 // Random start, 16 bits. Can't be 0.
107 sequence_number_rtx_ = static_cast<uint16_t>(rand() + 1) & 0x7FFF;
108 sequence_number_ = static_cast<uint16_t>(rand() + 1) & 0x7FFF;
niklase@google.com470e71d2011-07-07 08:21:25 +0000109
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000110 if (audio) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000111 audio_ = new RTPSenderAudio(id, clock_, this);
112 audio_->RegisterAudioCallback(audio_feedback);
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000113 } else {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000114 video_ = new RTPSenderVideo(clock_, this);
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000115 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000116}
117
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000118RTPSender::~RTPSender() {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000119 if (remote_ssrc_ != 0) {
120 ssrc_db_.ReturnSSRC(remote_ssrc_);
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000121 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000122 ssrc_db_.ReturnSSRC(ssrc_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000123
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000124 SSRCDatabase::ReturnSSRCDatabase();
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000125 delete send_critsect_;
126 while (!payload_type_map_.empty()) {
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000127 std::map<int8_t, RtpUtility::Payload*>::iterator it =
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000128 payload_type_map_.begin();
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000129 delete it->second;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000130 payload_type_map_.erase(it);
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000131 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000132 delete audio_;
133 delete video_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000134}
niklase@google.com470e71d2011-07-07 08:21:25 +0000135
stefan@webrtc.orga15fbfd2014-06-17 17:32:05 +0000136void RTPSender::SetTargetBitrate(uint32_t bitrate) {
137 CriticalSectionScoped cs(target_bitrate_critsect_.get());
138 target_bitrate_ = bitrate;
139}
140
141uint32_t RTPSender::GetTargetBitrate() {
142 CriticalSectionScoped cs(target_bitrate_critsect_.get());
143 return target_bitrate_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000144}
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000145
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000146uint16_t RTPSender::ActualSendBitrateKbit() const {
sprang@webrtc.org6811b6e2013-12-13 09:46:59 +0000147 return (uint16_t)(bitrate_sent_.BitrateNow() / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +0000148}
149
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000150uint32_t RTPSender::VideoBitrateSent() const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000151 if (video_) {
152 return video_->VideoBitrateSent();
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000153 }
154 return 0;
stefan@webrtc.orgfbea4e52011-10-27 16:08:29 +0000155}
156
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000157uint32_t RTPSender::FecOverheadRate() const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000158 if (video_) {
159 return video_->FecOverheadRate();
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000160 }
161 return 0;
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000162}
163
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000164uint32_t RTPSender::NackOverheadRate() const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000165 return nack_bitrate_.BitrateLast();
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000166}
167
stefan@webrtc.org0a3c1472013-12-05 14:05:07 +0000168bool RTPSender::GetSendSideDelay(int* avg_send_delay_ms,
169 int* max_send_delay_ms) const {
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000170 CriticalSectionScoped lock(statistics_crit_.get());
stefan@webrtc.org0a3c1472013-12-05 14:05:07 +0000171 SendDelayMap::const_iterator it = send_delays_.upper_bound(
172 clock_->TimeInMilliseconds() - kSendSideDelayWindowMs);
sprang@webrtc.org5a320fb2014-03-13 15:12:37 +0000173 if (it == send_delays_.end())
stefan@webrtc.org0a3c1472013-12-05 14:05:07 +0000174 return false;
175 int num_delays = 0;
176 for (; it != send_delays_.end(); ++it) {
177 *max_send_delay_ms = std::max(*max_send_delay_ms, it->second);
178 *avg_send_delay_ms += it->second;
179 ++num_delays;
180 }
181 *avg_send_delay_ms = (*avg_send_delay_ms + num_delays / 2) / num_delays;
182 return true;
183}
184
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000185int32_t RTPSender::SetTransmissionTimeOffset(
186 const int32_t transmission_time_offset) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000187 if (transmission_time_offset > (0x800000 - 1) ||
188 transmission_time_offset < -(0x800000 - 1)) { // Word24.
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000189 return -1;
190 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000191 CriticalSectionScoped cs(send_critsect_);
192 transmission_time_offset_ = transmission_time_offset;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000193 return 0;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000194}
195
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +0000196int32_t RTPSender::SetAbsoluteSendTime(
197 const uint32_t absolute_send_time) {
198 if (absolute_send_time > 0xffffff) { // UWord24.
199 return -1;
200 }
201 CriticalSectionScoped cs(send_critsect_);
202 absolute_send_time_ = absolute_send_time;
203 return 0;
204}
205
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000206int32_t RTPSender::RegisterRtpHeaderExtension(const RTPExtensionType type,
207 const uint8_t id) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000208 CriticalSectionScoped cs(send_critsect_);
209 return rtp_header_extension_map_.Register(type, id);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000210}
211
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000212int32_t RTPSender::DeregisterRtpHeaderExtension(
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000213 const RTPExtensionType type) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000214 CriticalSectionScoped cs(send_critsect_);
215 return rtp_header_extension_map_.Deregister(type);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000216}
217
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000218uint16_t RTPSender::RtpHeaderExtensionTotalLength() const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000219 CriticalSectionScoped cs(send_critsect_);
220 return rtp_header_extension_map_.GetTotalLengthInBytes();
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000221}
222
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000223int32_t RTPSender::RegisterPayload(
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000224 const char payload_name[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000225 const int8_t payload_number, const uint32_t frequency,
226 const uint8_t channels, const uint32_t rate) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000227 assert(payload_name);
228 CriticalSectionScoped cs(send_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000229
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000230 std::map<int8_t, RtpUtility::Payload*>::iterator it =
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000231 payload_type_map_.find(payload_number);
niklase@google.com470e71d2011-07-07 08:21:25 +0000232
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000233 if (payload_type_map_.end() != it) {
234 // We already use this payload type.
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000235 RtpUtility::Payload* payload = it->second;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000236 assert(payload);
niklase@google.com470e71d2011-07-07 08:21:25 +0000237
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000238 // Check if it's the same as we already have.
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000239 if (RtpUtility::StringCompare(
240 payload->name, payload_name, RTP_PAYLOAD_NAME_SIZE - 1)) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000241 if (audio_configured_ && payload->audio &&
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000242 payload->typeSpecific.Audio.frequency == frequency &&
243 (payload->typeSpecific.Audio.rate == rate ||
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000244 payload->typeSpecific.Audio.rate == 0 || rate == 0)) {
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000245 payload->typeSpecific.Audio.rate = rate;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000246 // Ensure that we update the rate if new or old is zero.
niklase@google.com470e71d2011-07-07 08:21:25 +0000247 return 0;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000248 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000249 if (!audio_configured_ && !payload->audio) {
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000250 return 0;
251 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000252 }
253 return -1;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000254 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000255 int32_t ret_val = -1;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000256 RtpUtility::Payload* payload = NULL;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000257 if (audio_configured_) {
258 ret_val = audio_->RegisterAudioPayload(payload_name, payload_number,
259 frequency, channels, rate, payload);
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000260 } else {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000261 ret_val = video_->RegisterVideoPayload(payload_name, payload_number, rate,
262 payload);
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000263 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000264 if (payload) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000265 payload_type_map_[payload_number] = payload;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000266 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000267 return ret_val;
niklase@google.com470e71d2011-07-07 08:21:25 +0000268}
269
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000270int32_t RTPSender::DeRegisterSendPayload(
271 const int8_t payload_type) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000272 CriticalSectionScoped lock(send_critsect_);
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000273
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000274 std::map<int8_t, RtpUtility::Payload*>::iterator it =
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000275 payload_type_map_.find(payload_type);
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000276
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000277 if (payload_type_map_.end() == it) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000278 return -1;
279 }
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000280 RtpUtility::Payload* payload = it->second;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000281 delete payload;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000282 payload_type_map_.erase(it);
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000283 return 0;
284}
niklase@google.com470e71d2011-07-07 08:21:25 +0000285
sprang@webrtc.orgefcad392014-03-25 16:51:35 +0000286int8_t RTPSender::SendPayloadType() const {
287 CriticalSectionScoped cs(send_critsect_);
288 return payload_type_;
289}
niklase@google.com470e71d2011-07-07 08:21:25 +0000290
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000291int RTPSender::SendPayloadFrequency() const {
292 return audio_ != NULL ? audio_->AudioFrequency() : kVideoPayloadTypeFrequency;
293}
niklase@google.com470e71d2011-07-07 08:21:25 +0000294
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000295int32_t RTPSender::SetMaxPayloadLength(
296 const uint16_t max_payload_length,
297 const uint16_t packet_over_head) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000298 // Sanity check.
299 if (max_payload_length < 100 || max_payload_length > IP_PACKET_SIZE) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000300 LOG(LS_ERROR) << "Invalid max payload length: " << max_payload_length;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000301 return -1;
302 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000303 CriticalSectionScoped cs(send_critsect_);
304 max_payload_length_ = max_payload_length;
305 packet_over_head_ = packet_over_head;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000306 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000307}
308
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000309uint16_t RTPSender::MaxDataPayloadLength() const {
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000310 int rtx;
311 {
312 CriticalSectionScoped rtx_lock(send_critsect_);
313 rtx = rtx_;
314 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000315 if (audio_configured_) {
316 return max_payload_length_ - RTPHeaderLength();
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000317 } else {
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000318 return max_payload_length_ - RTPHeaderLength() // RTP overhead.
319 - video_->FECPacketOverhead() // FEC/ULP/RED overhead.
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000320 - ((rtx) ? 2 : 0); // RTX overhead.
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000321 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000322}
323
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000324uint16_t RTPSender::MaxPayloadLength() const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000325 return max_payload_length_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000326}
327
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000328uint16_t RTPSender::PacketOverHead() const { return packet_over_head_; }
niklase@google.com470e71d2011-07-07 08:21:25 +0000329
stefan@webrtc.orgef927552014-06-05 08:25:29 +0000330void RTPSender::SetRTXStatus(int mode) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000331 CriticalSectionScoped cs(send_critsect_);
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000332 rtx_ = mode;
stefan@webrtc.orgef927552014-06-05 08:25:29 +0000333}
334
335void RTPSender::SetRtxSsrc(uint32_t ssrc) {
336 CriticalSectionScoped cs(send_critsect_);
337 ssrc_rtx_ = ssrc;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000338}
339
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000340uint32_t RTPSender::RtxSsrc() const {
341 CriticalSectionScoped cs(send_critsect_);
342 return ssrc_rtx_;
343}
344
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000345void RTPSender::RTXStatus(int* mode, uint32_t* ssrc,
mflodman@webrtc.org9f5ebb52013-04-12 14:55:46 +0000346 int* payload_type) const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000347 CriticalSectionScoped cs(send_critsect_);
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000348 *mode = rtx_;
mflodman@webrtc.org9f5ebb52013-04-12 14:55:46 +0000349 *ssrc = ssrc_rtx_;
350 *payload_type = payload_type_rtx_;
351}
352
mflodman@webrtc.org9f5ebb52013-04-12 14:55:46 +0000353void RTPSender::SetRtxPayloadType(int payload_type) {
354 CriticalSectionScoped cs(send_critsect_);
355 payload_type_rtx_ = payload_type;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000356}
357
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000358int32_t RTPSender::CheckPayloadType(const int8_t payload_type,
359 RtpVideoCodecTypes *video_type) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000360 CriticalSectionScoped cs(send_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000361
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000362 if (payload_type < 0) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000363 LOG(LS_ERROR) << "Invalid payload_type " << payload_type;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000364 return -1;
365 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000366 if (audio_configured_) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000367 int8_t red_pl_type = -1;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000368 if (audio_->RED(red_pl_type) == 0) {
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000369 // We have configured RED.
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000370 if (red_pl_type == payload_type) {
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000371 // And it's a match...
372 return 0;
373 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000374 }
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000375 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000376 if (payload_type_ == payload_type) {
377 if (!audio_configured_) {
378 *video_type = video_->VideoCodecType();
niklase@google.com470e71d2011-07-07 08:21:25 +0000379 }
380 return 0;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000381 }
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000382 std::map<int8_t, RtpUtility::Payload*>::iterator it =
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000383 payload_type_map_.find(payload_type);
384 if (it == payload_type_map_.end()) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000385 LOG(LS_WARNING) << "Payload type " << payload_type << " not registered.";
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000386 return -1;
387 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000388 payload_type_ = payload_type;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000389 RtpUtility::Payload* payload = it->second;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000390 assert(payload);
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000391 if (!payload->audio && !audio_configured_) {
392 video_->SetVideoCodecType(payload->typeSpecific.Video.videoCodecType);
393 *video_type = payload->typeSpecific.Video.videoCodecType;
394 video_->SetMaxConfiguredBitrateVideo(payload->typeSpecific.Video.maxRate);
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000395 }
396 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000397}
398
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000399int32_t RTPSender::SendOutgoingData(
400 const FrameType frame_type, const int8_t payload_type,
401 const uint32_t capture_timestamp, int64_t capture_time_ms,
402 const uint8_t *payload_data, const uint32_t payload_size,
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000403 const RTPFragmentationHeader *fragmentation,
404 VideoCodecInformation *codec_info, const RTPVideoTypeHeader *rtp_type_hdr) {
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000405 uint32_t ssrc;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000406 {
407 // Drop this packet if we're not sending media packets.
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000408 CriticalSectionScoped cs(send_critsect_);
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000409 ssrc = ssrc_;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000410 if (!sending_media_) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000411 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000412 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000413 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000414 RtpVideoCodecTypes video_type = kRtpVideoGeneric;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000415 if (CheckPayloadType(payload_type, &video_type) != 0) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000416 LOG(LS_ERROR) << "Don't send data with unknown payload type.";
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000417 return -1;
418 }
419
sprang@webrtc.org71f055f2013-12-04 15:09:27 +0000420 uint32_t ret_val;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000421 if (audio_configured_) {
hclam@chromium.org1a7b9b92013-07-08 21:31:18 +0000422 TRACE_EVENT_ASYNC_STEP1("webrtc", "Audio", capture_timestamp,
423 "Send", "type", FrameTypeToString(frame_type));
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000424 assert(frame_type == kAudioFrameSpeech || frame_type == kAudioFrameCN ||
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000425 frame_type == kFrameEmpty);
426
sprang@webrtc.org71f055f2013-12-04 15:09:27 +0000427 ret_val = audio_->SendAudio(frame_type, payload_type, capture_timestamp,
428 payload_data, payload_size, fragmentation);
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000429 } else {
hclam@chromium.org1a7b9b92013-07-08 21:31:18 +0000430 TRACE_EVENT_ASYNC_STEP1("webrtc", "Video", capture_time_ms,
431 "Send", "type", FrameTypeToString(frame_type));
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000432 assert(frame_type != kAudioFrameSpeech && frame_type != kAudioFrameCN);
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000433
pbos@webrtc.org63c60ed2014-07-16 09:37:29 +0000434 if (frame_type == kFrameEmpty)
435 return 0;
436
sprang@webrtc.org71f055f2013-12-04 15:09:27 +0000437 ret_val = video_->SendVideo(video_type, frame_type, payload_type,
438 capture_timestamp, capture_time_ms,
439 payload_data, payload_size,
440 fragmentation, codec_info,
441 rtp_type_hdr);
442
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000443 }
sprang@webrtc.org71f055f2013-12-04 15:09:27 +0000444
445 CriticalSectionScoped cs(statistics_crit_.get());
446 uint32_t frame_count = ++frame_counts_[frame_type];
447 if (frame_count_observer_) {
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000448 frame_count_observer_->FrameCountUpdated(frame_type, frame_count, ssrc);
sprang@webrtc.org71f055f2013-12-04 15:09:27 +0000449 }
450
451 return ret_val;
niklase@google.com470e71d2011-07-07 08:21:25 +0000452}
453
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000454int RTPSender::SendRedundantPayloads(int payload_type, int bytes_to_send) {
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000455 uint8_t buffer[IP_PACKET_SIZE];
456 int bytes_left = bytes_to_send;
457 while (bytes_left > 0) {
458 uint16_t length = bytes_left;
459 int64_t capture_time_ms;
460 if (!packet_history_.GetBestFittingPacket(buffer, &length,
461 &capture_time_ms)) {
462 break;
463 }
stefan@webrtc.org7c6ff2d2014-03-19 18:14:52 +0000464 if (!PrepareAndSendPacket(buffer, length, capture_time_ms, true, false))
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000465 return -1;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000466 RtpUtility::RtpHeaderParser rtp_parser(buffer, length);
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000467 RTPHeader rtp_header;
468 rtp_parser.Parse(rtp_header);
469 bytes_left -= length - rtp_header.headerLength;
470 }
471 return bytes_to_send - bytes_left;
472}
473
stefan@webrtc.orga8179622013-06-04 13:47:36 +0000474int RTPSender::BuildPaddingPacket(uint8_t* packet, int header_length,
475 int32_t bytes) {
476 int padding_bytes_in_packet = kMaxPaddingLength;
477 if (bytes < kMaxPaddingLength) {
stefan@webrtc.org8ccb9f92013-06-19 14:13:42 +0000478 padding_bytes_in_packet = bytes;
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000479 }
stefan@webrtc.orga8179622013-06-04 13:47:36 +0000480 packet[0] |= 0x20; // Set padding bit.
481 int32_t *data =
482 reinterpret_cast<int32_t *>(&(packet[header_length]));
483
484 // Fill data buffer with random data.
485 for (int j = 0; j < (padding_bytes_in_packet >> 2); ++j) {
486 data[j] = rand(); // NOLINT
487 }
488 // Set number of padding bytes in the last byte of the packet.
489 packet[header_length + padding_bytes_in_packet - 1] = padding_bytes_in_packet;
490 return padding_bytes_in_packet;
491}
492
pbos@webrtc.org72491b92014-07-10 16:24:54 +0000493int RTPSender::SendPadData(int payload_type,
494 uint32_t timestamp,
495 int64_t capture_time_ms,
pbos@webrtc.org63c60ed2014-07-16 09:37:29 +0000496 int32_t bytes) {
stefan@webrtc.orga8179622013-06-04 13:47:36 +0000497 // Drop this packet if we're not sending media packets.
sprang@webrtc.org5a320fb2014-03-13 15:12:37 +0000498 if (!SendingMedia()) {
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000499 return bytes;
stefan@webrtc.orga8179622013-06-04 13:47:36 +0000500 }
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000501 int padding_bytes_in_packet = 0;
502 int bytes_sent = 0;
503 for (; bytes > 0; bytes -= padding_bytes_in_packet) {
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000504 // Always send full padding packets.
pbos@webrtc.org63c60ed2014-07-16 09:37:29 +0000505 if (bytes < kMaxPaddingLength)
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000506 bytes = kMaxPaddingLength;
pbos@webrtc.org63c60ed2014-07-16 09:37:29 +0000507
stefan@webrtc.org8ccb9f92013-06-19 14:13:42 +0000508 uint32_t ssrc;
509 uint16_t sequence_number;
pbos@webrtc.org63c60ed2014-07-16 09:37:29 +0000510 bool over_rtx;
stefan@webrtc.org8ccb9f92013-06-19 14:13:42 +0000511 {
512 CriticalSectionScoped cs(send_critsect_);
513 // Only send padding packets following the last packet of a frame,
514 // indicated by the marker bit.
stefan@webrtc.org8ccb9f92013-06-19 14:13:42 +0000515 if (rtx_ == kRtxOff) {
pbos@webrtc.org63c60ed2014-07-16 09:37:29 +0000516 // Without RTX we can't send padding in the middle of frames.
517 if (!last_packet_marker_bit_)
518 return bytes_sent;
stefan@webrtc.org8ccb9f92013-06-19 14:13:42 +0000519 ssrc = ssrc_;
520 sequence_number = sequence_number_;
521 ++sequence_number_;
pbos@webrtc.org63c60ed2014-07-16 09:37:29 +0000522 over_rtx = false;
stefan@webrtc.org8ccb9f92013-06-19 14:13:42 +0000523 } else {
stefan@webrtc.org8b94e3d2014-07-17 16:10:14 +0000524 // Without abs-send-time a media packet must be sent before padding so
525 // that the timestamps used for estimation are correct.
526 if (!media_has_been_sent_ && !rtp_header_extension_map_.IsRegistered(
527 kRtpExtensionAbsoluteSendTime))
528 return bytes_sent;
stefan@webrtc.org8ccb9f92013-06-19 14:13:42 +0000529 ssrc = ssrc_rtx_;
530 sequence_number = sequence_number_rtx_;
531 ++sequence_number_rtx_;
pbos@webrtc.org63c60ed2014-07-16 09:37:29 +0000532 over_rtx = true;
stefan@webrtc.org8ccb9f92013-06-19 14:13:42 +0000533 }
534 }
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000535
stefan@webrtc.org8ccb9f92013-06-19 14:13:42 +0000536 uint8_t padding_packet[IP_PACKET_SIZE];
pbos@webrtc.org72491b92014-07-10 16:24:54 +0000537 int header_length = CreateRTPHeader(padding_packet,
538 payload_type,
539 ssrc,
540 false,
541 timestamp,
542 sequence_number,
543 NULL,
stefan@webrtc.org8ccb9f92013-06-19 14:13:42 +0000544 0);
pbos@webrtc.org72491b92014-07-10 16:24:54 +0000545 padding_bytes_in_packet =
546 BuildPaddingPacket(padding_packet, header_length, bytes);
547 int length = padding_bytes_in_packet + header_length;
548 int64_t now_ms = clock_->TimeInMilliseconds();
549
550 RtpUtility::RtpHeaderParser rtp_parser(padding_packet, length);
551 RTPHeader rtp_header;
552 rtp_parser.Parse(rtp_header);
553
554 if (capture_time_ms > 0) {
555 UpdateTransmissionTimeOffset(
556 padding_packet, length, rtp_header, now_ms - capture_time_ms);
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000557 }
pbos@webrtc.org72491b92014-07-10 16:24:54 +0000558
559 UpdateAbsoluteSendTime(padding_packet, length, rtp_header, now_ms);
560 if (!SendPacketToNetwork(padding_packet, length))
561 break;
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000562 bytes_sent += padding_bytes_in_packet;
pbos@webrtc.org72491b92014-07-10 16:24:54 +0000563 UpdateRtpStats(padding_packet, length, rtp_header, over_rtx, false);
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000564 }
pbos@webrtc.org72491b92014-07-10 16:24:54 +0000565
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000566 return bytes_sent;
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000567}
568
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000569void RTPSender::SetStorePacketsStatus(const bool enable,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000570 const uint16_t number_to_store) {
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000571 packet_history_.SetStorePacketsStatus(enable, number_to_store);
niklase@google.com470e71d2011-07-07 08:21:25 +0000572}
573
pwestin@webrtc.orgb0061f92013-04-27 00:41:08 +0000574bool RTPSender::StorePackets() const {
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000575 return packet_history_.StorePackets();
pwestin@webrtc.orgb0061f92013-04-27 00:41:08 +0000576}
niklase@google.com470e71d2011-07-07 08:21:25 +0000577
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000578int32_t RTPSender::ReSendPacket(uint16_t packet_id, uint32_t min_resend_time) {
579 uint16_t length = IP_PACKET_SIZE;
580 uint8_t data_buffer[IP_PACKET_SIZE];
pwestin@webrtc.orgb0061f92013-04-27 00:41:08 +0000581 int64_t capture_time_ms;
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000582 if (!packet_history_.GetPacketAndSetSendTime(packet_id, min_resend_time, true,
583 data_buffer, &length,
584 &capture_time_ms)) {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000585 // Packet not found.
asapersson@webrtc.org83ed0a42012-04-23 12:43:05 +0000586 return 0;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000587 }
pwestin@webrtc.orgb0061f92013-04-27 00:41:08 +0000588
pwestin@webrtc.orgb0061f92013-04-27 00:41:08 +0000589 if (paced_sender_) {
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000590 RtpUtility::RtpHeaderParser rtp_parser(data_buffer, length);
stefan@webrtc.org7c6ff2d2014-03-19 18:14:52 +0000591 RTPHeader header;
592 if (!rtp_parser.Parse(header)) {
593 assert(false);
stefan@webrtc.org7c6ff2d2014-03-19 18:14:52 +0000594 return -1;
595 }
stefan@webrtc.org88e0dda2014-07-04 09:20:42 +0000596 // Convert from TickTime to Clock since capture_time_ms is based on
597 // TickTime.
598 // TODO(holmer): Remove this conversion when we remove the use of TickTime.
599 int64_t clock_delta_ms = clock_->TimeInMilliseconds() -
600 TickTime::MillisecondTimestamp();
pwestin@webrtc.orgb0061f92013-04-27 00:41:08 +0000601 if (!paced_sender_->SendPacket(PacedSender::kHighPriority,
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000602 header.ssrc,
603 header.sequenceNumber,
stefan@webrtc.org88e0dda2014-07-04 09:20:42 +0000604 capture_time_ms + clock_delta_ms,
stefan@webrtc.org9b82f5a2013-11-13 15:29:21 +0000605 length - header.headerLength,
606 true)) {
pwestin@webrtc.orgb0061f92013-04-27 00:41:08 +0000607 // We can't send the packet right now.
608 // We will be called when it is time.
stefan@webrtc.org5c58f632013-05-23 13:36:55 +0000609 return length;
pwestin@webrtc.orgb0061f92013-04-27 00:41:08 +0000610 }
611 }
stefan@webrtc.org8b94e3d2014-07-17 16:10:14 +0000612 int rtx = kRtxOff;
613 {
614 CriticalSectionScoped lock(send_critsect_);
615 rtx = rtx_;
616 }
stefan@webrtc.org7c6ff2d2014-03-19 18:14:52 +0000617 return PrepareAndSendPacket(data_buffer, length, capture_time_ms,
stefan@webrtc.org8b94e3d2014-07-17 16:10:14 +0000618 (rtx & kRtxRetransmitted) > 0, true) ?
stefan@webrtc.org16395222014-03-19 19:34:07 +0000619 length : -1;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000620}
621
pwestin@webrtc.orgb0061f92013-04-27 00:41:08 +0000622bool RTPSender::SendPacketToNetwork(const uint8_t *packet, uint32_t size) {
623 int bytes_sent = -1;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000624 if (transport_) {
625 bytes_sent = transport_->SendPacket(id_, packet, size);
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000626 }
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000627 TRACE_EVENT_INSTANT2("webrtc_rtp", "RTPSender::SendPacketToNetwork",
628 "size", size, "sent", bytes_sent);
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000629 // TODO(pwestin): Add a separate bitrate for sent bitrate after pacer.
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000630 if (bytes_sent <= 0) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000631 LOG(LS_WARNING) << "Transport failed to send packet";
pwestin@webrtc.orgb0061f92013-04-27 00:41:08 +0000632 return false;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000633 }
pwestin@webrtc.orgb0061f92013-04-27 00:41:08 +0000634 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000635}
636
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000637int RTPSender::SelectiveRetransmissions() const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000638 if (!video_)
639 return -1;
640 return video_->SelectiveRetransmissions();
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000641}
642
643int RTPSender::SetSelectiveRetransmissions(uint8_t settings) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000644 if (!video_)
645 return -1;
646 return video_->SetSelectiveRetransmissions(settings);
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000647}
648
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000649void RTPSender::OnReceivedNACK(
stefan@webrtc.orgbecf9c82013-02-01 15:09:57 +0000650 const std::list<uint16_t>& nack_sequence_numbers,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000651 const uint16_t avg_rtt) {
hclam@chromium.org806dc3b2013-04-09 19:54:10 +0000652 TRACE_EVENT2("webrtc_rtp", "RTPSender::OnReceivedNACK",
653 "num_seqnum", nack_sequence_numbers.size(), "avg_rtt", avg_rtt);
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000654 const int64_t now = clock_->TimeInMilliseconds();
655 uint32_t bytes_re_sent = 0;
stefan@webrtc.orga15fbfd2014-06-17 17:32:05 +0000656 uint32_t target_bitrate = GetTargetBitrate();
niklase@google.com470e71d2011-07-07 08:21:25 +0000657
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000658 // Enough bandwidth to send NACK?
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000659 if (!ProcessNACKBitRate(now)) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000660 LOG(LS_INFO) << "NACK bitrate reached. Skip sending NACK response. Target "
stefan@webrtc.orga15fbfd2014-06-17 17:32:05 +0000661 << target_bitrate;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000662 return;
663 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000664
stefan@webrtc.orgbecf9c82013-02-01 15:09:57 +0000665 for (std::list<uint16_t>::const_iterator it = nack_sequence_numbers.begin();
666 it != nack_sequence_numbers.end(); ++it) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000667 const int32_t bytes_sent = ReSendPacket(*it, 5 + avg_rtt);
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000668 if (bytes_sent > 0) {
669 bytes_re_sent += bytes_sent;
670 } else if (bytes_sent == 0) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000671 // The packet has previously been resent.
672 // Try resending next packet in the list.
673 continue;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000674 } else if (bytes_sent < 0) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000675 // Failed to send one Sequence number. Give up the rest in this nack.
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000676 LOG(LS_WARNING) << "Failed resending RTP packet " << *it
677 << ", Discard rest of packets";
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000678 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000679 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000680 // Delay bandwidth estimate (RTT * BW).
stefan@webrtc.orga15fbfd2014-06-17 17:32:05 +0000681 if (target_bitrate != 0 && avg_rtt) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000682 // kbits/s * ms = bits => bits/8 = bytes
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000683 uint32_t target_bytes =
stefan@webrtc.orga15fbfd2014-06-17 17:32:05 +0000684 (static_cast<uint32_t>(target_bitrate / 1000) * avg_rtt) >> 3;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000685 if (bytes_re_sent > target_bytes) {
686 break; // Ignore the rest of the packets in the list.
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000687 }
688 }
689 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000690 if (bytes_re_sent > 0) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000691 // TODO(pwestin) consolidate these two methods.
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000692 UpdateNACKBitRate(bytes_re_sent, now);
693 nack_bitrate_.Update(bytes_re_sent);
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000694 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000695}
696
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000697bool RTPSender::ProcessNACKBitRate(const uint32_t now) {
698 uint32_t num = 0;
stefan@webrtc.orga15fbfd2014-06-17 17:32:05 +0000699 int byte_count = 0;
henrike@webrtc.orgfe526ff2014-06-25 20:59:51 +0000700 const uint32_t kAvgIntervalMs = 1000;
stefan@webrtc.orga15fbfd2014-06-17 17:32:05 +0000701 uint32_t target_bitrate = GetTargetBitrate();
niklase@google.com470e71d2011-07-07 08:21:25 +0000702
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000703 CriticalSectionScoped cs(send_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000704
stefan@webrtc.orga15fbfd2014-06-17 17:32:05 +0000705 if (target_bitrate == 0) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000706 return true;
707 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000708 for (num = 0; num < NACK_BYTECOUNT_SIZE; ++num) {
stefan@webrtc.orga15fbfd2014-06-17 17:32:05 +0000709 if ((now - nack_byte_count_times_[num]) > kAvgIntervalMs) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000710 // Don't use data older than 1sec.
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000711 break;
712 } else {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000713 byte_count += nack_byte_count_[num];
niklase@google.com470e71d2011-07-07 08:21:25 +0000714 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000715 }
henrike@webrtc.orgfe526ff2014-06-25 20:59:51 +0000716 uint32_t time_interval = kAvgIntervalMs;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000717 if (num == NACK_BYTECOUNT_SIZE) {
718 // More than NACK_BYTECOUNT_SIZE nack messages has been received
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000719 // during the last msg_interval.
henrike@webrtc.orgfe526ff2014-06-25 20:59:51 +0000720 if (nack_byte_count_times_[num - 1] <= now) {
721 time_interval = now - nack_byte_count_times_[num - 1];
niklase@google.com470e71d2011-07-07 08:21:25 +0000722 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000723 }
stefan@webrtc.orga15fbfd2014-06-17 17:32:05 +0000724 return (byte_count * 8) <
725 static_cast<int>(target_bitrate / 1000 * time_interval);
niklase@google.com470e71d2011-07-07 08:21:25 +0000726}
727
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000728void RTPSender::UpdateNACKBitRate(const uint32_t bytes,
729 const uint32_t now) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000730 CriticalSectionScoped cs(send_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000731
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000732 // Save bitrate statistics.
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000733 if (bytes > 0) {
734 if (now == 0) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000735 // Add padding length.
736 nack_byte_count_[0] += bytes;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000737 } else {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000738 if (nack_byte_count_times_[0] == 0) {
739 // First no shift.
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000740 } else {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000741 // Shift.
742 for (int i = (NACK_BYTECOUNT_SIZE - 2); i >= 0; i--) {
743 nack_byte_count_[i + 1] = nack_byte_count_[i];
744 nack_byte_count_times_[i + 1] = nack_byte_count_times_[i];
niklase@google.com470e71d2011-07-07 08:21:25 +0000745 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000746 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000747 nack_byte_count_[0] = bytes;
748 nack_byte_count_times_[0] = now;
niklase@google.com470e71d2011-07-07 08:21:25 +0000749 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000750 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000751}
752
pwestin@webrtc.orgb0061f92013-04-27 00:41:08 +0000753// Called from pacer when we can send the packet.
hclam@chromium.org2e402ce2013-06-20 20:18:31 +0000754bool RTPSender::TimeToSendPacket(uint16_t sequence_number,
stefan@webrtc.org9b82f5a2013-11-13 15:29:21 +0000755 int64_t capture_time_ms,
756 bool retransmission) {
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000757 uint16_t length = IP_PACKET_SIZE;
758 uint8_t data_buffer[IP_PACKET_SIZE];
pwestin@webrtc.orgb0061f92013-04-27 00:41:08 +0000759 int64_t stored_time_ms;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000760
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000761 if (!packet_history_.GetPacketAndSetSendTime(sequence_number,
762 0,
763 retransmission,
764 data_buffer,
765 &length,
766 &stored_time_ms)) {
hclam@chromium.org2e402ce2013-06-20 20:18:31 +0000767 // Packet cannot be found. Allow sending to continue.
768 return true;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000769 }
stefan@webrtc.org0a3c1472013-12-05 14:05:07 +0000770 if (!retransmission && capture_time_ms > 0) {
771 UpdateDelayStatistics(capture_time_ms, clock_->TimeInMilliseconds());
772 }
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000773 int rtx;
774 {
775 CriticalSectionScoped lock(send_critsect_);
776 rtx = rtx_;
777 }
778 return PrepareAndSendPacket(data_buffer,
779 length,
780 capture_time_ms,
781 retransmission && (rtx & kRtxRetransmitted) > 0,
stefan@webrtc.org7c6ff2d2014-03-19 18:14:52 +0000782 retransmission);
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000783}
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000784
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000785bool RTPSender::PrepareAndSendPacket(uint8_t* buffer,
786 uint16_t length,
787 int64_t capture_time_ms,
stefan@webrtc.org7c6ff2d2014-03-19 18:14:52 +0000788 bool send_over_rtx,
789 bool is_retransmit) {
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000790 uint8_t *buffer_to_send_ptr = buffer;
791
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000792 RtpUtility::RtpHeaderParser rtp_parser(buffer, length);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000793 RTPHeader rtp_header;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000794 rtp_parser.Parse(rtp_header);
stefan@webrtc.org7c6ff2d2014-03-19 18:14:52 +0000795 TRACE_EVENT_INSTANT2("webrtc_rtp", "PrepareAndSendPacket",
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000796 "timestamp", rtp_header.timestamp,
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000797 "seqnum", rtp_header.sequenceNumber);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000798
stefan@webrtc.org9b82f5a2013-11-13 15:29:21 +0000799 uint8_t data_buffer_rtx[IP_PACKET_SIZE];
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000800 if (send_over_rtx) {
801 BuildRtxPacket(buffer, &length, data_buffer_rtx);
stefan@webrtc.org9b82f5a2013-11-13 15:29:21 +0000802 buffer_to_send_ptr = data_buffer_rtx;
803 }
804
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +0000805 int64_t now_ms = clock_->TimeInMilliseconds();
806 int64_t diff_ms = now_ms - capture_time_ms;
stefan@webrtc.org420b2562014-05-30 12:17:15 +0000807 UpdateTransmissionTimeOffset(buffer_to_send_ptr, length, rtp_header,
808 diff_ms);
809 UpdateAbsoluteSendTime(buffer_to_send_ptr, length, rtp_header, now_ms);
sprang@webrtc.orgebad7652013-12-05 14:29:02 +0000810 bool ret = SendPacketToNetwork(buffer_to_send_ptr, length);
stefan@webrtc.org8b94e3d2014-07-17 16:10:14 +0000811 if (ret) {
812 CriticalSectionScoped lock(send_critsect_);
813 media_has_been_sent_ = true;
814 }
stefan@webrtc.org7c6ff2d2014-03-19 18:14:52 +0000815 UpdateRtpStats(buffer_to_send_ptr, length, rtp_header, send_over_rtx,
816 is_retransmit);
sprang@webrtc.orgebad7652013-12-05 14:29:02 +0000817 return ret;
818}
819
820void RTPSender::UpdateRtpStats(const uint8_t* buffer,
821 uint32_t size,
822 const RTPHeader& header,
823 bool is_rtx,
824 bool is_retransmit) {
sprang@webrtc.orgebad7652013-12-05 14:29:02 +0000825 StreamDataCounters* counters;
sprang@webrtc.org5314e852014-01-27 13:20:36 +0000826 // Get ssrc before taking statistics_crit_ to avoid possible deadlock.
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000827 uint32_t ssrc = is_rtx ? RtxSsrc() : SSRC();
sprang@webrtc.org5314e852014-01-27 13:20:36 +0000828
829 CriticalSectionScoped lock(statistics_crit_.get());
sprang@webrtc.orgebad7652013-12-05 14:29:02 +0000830 if (is_rtx) {
831 counters = &rtx_rtp_stats_;
sprang@webrtc.orgebad7652013-12-05 14:29:02 +0000832 } else {
833 counters = &rtp_stats_;
sprang@webrtc.orgebad7652013-12-05 14:29:02 +0000834 }
835
sprang@webrtc.org6811b6e2013-12-13 09:46:59 +0000836 bitrate_sent_.Update(size);
sprang@webrtc.orgebad7652013-12-05 14:29:02 +0000837 ++counters->packets;
838 if (IsFecPacket(buffer, header)) {
839 ++counters->fec_packets;
840 }
841
842 if (is_retransmit) {
843 ++counters->retransmitted_packets;
844 } else {
845 counters->bytes += size - (header.headerLength + header.paddingLength);
846 counters->header_bytes += header.headerLength;
847 counters->padding_bytes += header.paddingLength;
848 }
849
850 if (rtp_stats_callback_) {
851 rtp_stats_callback_->DataCountersUpdated(*counters, ssrc);
852 }
853}
854
855bool RTPSender::IsFecPacket(const uint8_t* buffer,
856 const RTPHeader& header) const {
857 if (!video_) {
858 return false;
859 }
860 bool fec_enabled;
861 uint8_t pt_red;
862 uint8_t pt_fec;
863 video_->GenericFECStatus(fec_enabled, pt_red, pt_fec);
864 return fec_enabled &&
865 header.payloadType == pt_red &&
866 buffer[header.headerLength] == pt_fec;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000867}
868
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000869int RTPSender::TimeToSendPadding(int bytes) {
pbos@webrtc.org63c60ed2014-07-16 09:37:29 +0000870 assert(bytes > 0);
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000871 int payload_type;
stefan@webrtc.org8ccb9f92013-06-19 14:13:42 +0000872 int64_t capture_time_ms;
873 uint32_t timestamp;
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000874 int rtx;
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000875 {
876 CriticalSectionScoped cs(send_critsect_);
sprang@webrtc.org5a320fb2014-03-13 15:12:37 +0000877 if (!sending_media_) {
878 return 0;
879 }
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000880 payload_type = ((rtx_ & kRtxRedundantPayloads) > 0) ? payload_type_rtx_ :
881 payload_type_;
stefan@webrtc.org8ccb9f92013-06-19 14:13:42 +0000882 timestamp = timestamp_;
883 capture_time_ms = capture_time_ms_;
henrik.lundin@webrtc.org6e95d7a2013-11-15 08:59:19 +0000884 if (last_timestamp_time_ms_ > 0) {
885 timestamp +=
886 (clock_->TimeInMilliseconds() - last_timestamp_time_ms_) * 90;
887 capture_time_ms +=
888 (clock_->TimeInMilliseconds() - last_timestamp_time_ms_);
889 }
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000890 rtx = rtx_;
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000891 }
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000892 int bytes_sent = 0;
893 if ((rtx & kRtxRedundantPayloads) != 0)
894 bytes_sent = SendRedundantPayloads(payload_type, bytes);
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000895 bytes -= bytes_sent;
896 if (bytes > 0) {
pbos@webrtc.org63c60ed2014-07-16 09:37:29 +0000897 int padding_sent =
898 SendPadData(payload_type, timestamp, capture_time_ms, bytes);
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000899 bytes_sent += padding_sent;
900 }
901 return bytes_sent;
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000902}
903
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000904// TODO(pwestin): send in the RtpHeaderParser to avoid parsing it again.
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000905int32_t RTPSender::SendToNetwork(
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000906 uint8_t *buffer, int payload_length, int rtp_header_length,
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000907 int64_t capture_time_ms, StorageType storage,
908 PacedSender::Priority priority) {
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000909 RtpUtility::RtpHeaderParser rtp_parser(buffer,
910 payload_length + rtp_header_length);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000911 RTPHeader rtp_header;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000912 rtp_parser.Parse(rtp_header);
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000913
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +0000914 int64_t now_ms = clock_->TimeInMilliseconds();
915
stefan@webrtc.org715faaf2012-08-28 15:20:39 +0000916 // |capture_time_ms| <= 0 is considered invalid.
917 // TODO(holmer): This should be changed all over Video Engine so that negative
918 // time is consider invalid, while 0 is considered a valid time.
919 if (capture_time_ms > 0) {
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000920 UpdateTransmissionTimeOffset(buffer, payload_length + rtp_header_length,
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +0000921 rtp_header, now_ms - capture_time_ms);
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000922 }
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +0000923
924 UpdateAbsoluteSendTime(buffer, payload_length + rtp_header_length,
925 rtp_header, now_ms);
926
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000927 // Used for NACK and to spread out the transmission of packets.
stefan@webrtc.org7e9315b2013-12-04 10:24:26 +0000928 if (packet_history_.PutRTPPacket(buffer, rtp_header_length + payload_length,
929 max_payload_length_, capture_time_ms,
930 storage) != 0) {
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000931 return -1;
932 }
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000933
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000934 if (paced_sender_ && storage != kDontStore) {
stefan@webrtc.org88e0dda2014-07-04 09:20:42 +0000935 int64_t clock_delta_ms = clock_->TimeInMilliseconds() -
936 TickTime::MillisecondTimestamp();
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000937 if (!paced_sender_->SendPacket(priority, rtp_header.ssrc,
stefan@webrtc.org88e0dda2014-07-04 09:20:42 +0000938 rtp_header.sequenceNumber,
939 capture_time_ms + clock_delta_ms,
stefan@webrtc.org9b82f5a2013-11-13 15:29:21 +0000940 payload_length, false)) {
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000941 // We can't send the packet right now.
942 // We will be called when it is time.
pwestin@webrtc.orgb0061f92013-04-27 00:41:08 +0000943 return 0;
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000944 }
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000945 }
stefan@webrtc.org0a3c1472013-12-05 14:05:07 +0000946 if (capture_time_ms > 0) {
947 UpdateDelayStatistics(capture_time_ms, now_ms);
948 }
sprang@webrtc.orgebad7652013-12-05 14:29:02 +0000949 uint32_t length = payload_length + rtp_header_length;
950 if (!SendPacketToNetwork(buffer, length))
951 return -1;
stefan@webrtc.org8b94e3d2014-07-17 16:10:14 +0000952 assert(payload_length - rtp_header.paddingLength > 0);
953 {
954 CriticalSectionScoped lock(send_critsect_);
955 media_has_been_sent_ = true;
956 }
sprang@webrtc.orgebad7652013-12-05 14:29:02 +0000957 UpdateRtpStats(buffer, length, rtp_header, false, false);
958 return 0;
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000959}
960
stefan@webrtc.org0a3c1472013-12-05 14:05:07 +0000961void RTPSender::UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms) {
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000962 uint32_t ssrc;
963 int avg_delay_ms = 0;
964 int max_delay_ms = 0;
965 {
966 CriticalSectionScoped lock(send_critsect_);
967 ssrc = ssrc_;
968 }
969 {
970 CriticalSectionScoped cs(statistics_crit_.get());
971 // TODO(holmer): Compute this iteratively instead.
972 send_delays_[now_ms] = now_ms - capture_time_ms;
973 send_delays_.erase(send_delays_.begin(),
974 send_delays_.lower_bound(now_ms -
975 kSendSideDelayWindowMs));
976 }
977 if (send_side_delay_observer_ &&
978 GetSendSideDelay(&avg_delay_ms, &max_delay_ms)) {
979 send_side_delay_observer_->SendSideDelayUpdated(avg_delay_ms,
980 max_delay_ms, ssrc);
981 }
stefan@webrtc.org0a3c1472013-12-05 14:05:07 +0000982}
983
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000984void RTPSender::ProcessBitrate() {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000985 CriticalSectionScoped cs(send_critsect_);
sprang@webrtc.org6811b6e2013-12-13 09:46:59 +0000986 bitrate_sent_.Process();
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000987 nack_bitrate_.Process();
988 if (audio_configured_) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000989 return;
990 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000991 video_->ProcessBitrate();
niklase@google.com470e71d2011-07-07 08:21:25 +0000992}
993
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000994uint16_t RTPSender::RTPHeaderLength() const {
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000995 CriticalSectionScoped lock(send_critsect_);
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000996 uint16_t rtp_header_length = 12;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +0000997 if (include_csrcs_) {
stefan@webrtc.orga8179622013-06-04 13:47:36 +0000998 rtp_header_length += sizeof(uint32_t) * num_csrcs_;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000999 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001000 rtp_header_length += RtpHeaderExtensionTotalLength();
1001 return rtp_header_length;
niklase@google.com470e71d2011-07-07 08:21:25 +00001002}
1003
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001004uint16_t RTPSender::IncrementSequenceNumber() {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001005 CriticalSectionScoped cs(send_critsect_);
1006 return sequence_number_++;
niklase@google.com470e71d2011-07-07 08:21:25 +00001007}
1008
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001009void RTPSender::ResetDataCounters() {
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +00001010 uint32_t ssrc;
1011 uint32_t ssrc_rtx;
1012 {
1013 CriticalSectionScoped ssrc_lock(send_critsect_);
1014 ssrc = ssrc_;
1015 ssrc_rtx = ssrc_rtx_;
1016 }
pbos@webrtc.orge07049f2013-09-10 11:29:17 +00001017 CriticalSectionScoped lock(statistics_crit_.get());
sprang@webrtc.orgebad7652013-12-05 14:29:02 +00001018 rtp_stats_ = StreamDataCounters();
1019 rtx_rtp_stats_ = StreamDataCounters();
1020 if (rtp_stats_callback_) {
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +00001021 rtp_stats_callback_->DataCountersUpdated(rtp_stats_, ssrc);
1022 rtp_stats_callback_->DataCountersUpdated(rtx_rtp_stats_, ssrc_rtx);
sprang@webrtc.orgebad7652013-12-05 14:29:02 +00001023 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001024}
1025
pbos@webrtc.org2f4b14e2014-07-15 15:25:39 +00001026void RTPSender::GetDataCounters(StreamDataCounters* rtp_stats,
1027 StreamDataCounters* rtx_stats) const {
pbos@webrtc.orge07049f2013-09-10 11:29:17 +00001028 CriticalSectionScoped lock(statistics_crit_.get());
pbos@webrtc.org2f4b14e2014-07-15 15:25:39 +00001029 *rtp_stats = rtp_stats_;
1030 *rtx_stats = rtx_rtp_stats_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001031}
1032
stefan@webrtc.orga8179622013-06-04 13:47:36 +00001033int RTPSender::CreateRTPHeader(
1034 uint8_t* header, int8_t payload_type, uint32_t ssrc, bool marker_bit,
1035 uint32_t timestamp, uint16_t sequence_number, const uint32_t* csrcs,
1036 uint8_t num_csrcs) const {
1037 header[0] = 0x80; // version 2.
1038 header[1] = static_cast<uint8_t>(payload_type);
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001039 if (marker_bit) {
stefan@webrtc.orga8179622013-06-04 13:47:36 +00001040 header[1] |= kRtpMarkerBitMask; // Marker bit is set.
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001041 }
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001042 RtpUtility::AssignUWord16ToBuffer(header + 2, sequence_number);
1043 RtpUtility::AssignUWord32ToBuffer(header + 4, timestamp);
1044 RtpUtility::AssignUWord32ToBuffer(header + 8, ssrc);
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001045 int32_t rtp_header_length = 12;
niklase@google.com470e71d2011-07-07 08:21:25 +00001046
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001047 // Add the CSRCs if any.
stefan@webrtc.orga8179622013-06-04 13:47:36 +00001048 if (num_csrcs > 0) {
1049 if (num_csrcs > kRtpCsrcSize) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001050 // error
1051 assert(false);
1052 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001053 }
stefan@webrtc.orga8179622013-06-04 13:47:36 +00001054 uint8_t *ptr = &header[rtp_header_length];
1055 for (int i = 0; i < num_csrcs; ++i) {
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001056 RtpUtility::AssignUWord32ToBuffer(ptr, csrcs[i]);
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001057 ptr += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +00001058 }
stefan@webrtc.orga8179622013-06-04 13:47:36 +00001059 header[0] = (header[0] & 0xf0) | num_csrcs;
niklase@google.com470e71d2011-07-07 08:21:25 +00001060
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001061 // Update length of header.
stefan@webrtc.orga8179622013-06-04 13:47:36 +00001062 rtp_header_length += sizeof(uint32_t) * num_csrcs;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001063 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001064
stefan@webrtc.orga8179622013-06-04 13:47:36 +00001065 uint16_t len = BuildRTPHeaderExtension(header + rtp_header_length);
1066 if (len > 0) {
1067 header[0] |= 0x10; // Set extension bit.
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001068 rtp_header_length += len;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001069 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001070 return rtp_header_length;
niklase@google.com470e71d2011-07-07 08:21:25 +00001071}
1072
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +00001073int32_t RTPSender::BuildRTPheader(uint8_t* data_buffer,
1074 const int8_t payload_type,
1075 const bool marker_bit,
1076 const uint32_t capture_timestamp,
1077 int64_t capture_time_ms,
1078 const bool timestamp_provided,
1079 const bool inc_sequence_number) {
stefan@webrtc.orga8179622013-06-04 13:47:36 +00001080 assert(payload_type >= 0);
1081 CriticalSectionScoped cs(send_critsect_);
1082
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +00001083 if (timestamp_provided) {
1084 timestamp_ = start_timestamp_ + capture_timestamp;
stefan@webrtc.orga8179622013-06-04 13:47:36 +00001085 } else {
1086 // Make a unique time stamp.
1087 // We can't inc by the actual time, since then we increase the risk of back
1088 // timing.
1089 timestamp_++;
1090 }
henrik.lundin@webrtc.org6e95d7a2013-11-15 08:59:19 +00001091 last_timestamp_time_ms_ = clock_->TimeInMilliseconds();
stefan@webrtc.orga8179622013-06-04 13:47:36 +00001092 uint32_t sequence_number = sequence_number_++;
stefan@webrtc.org8ccb9f92013-06-19 14:13:42 +00001093 capture_time_ms_ = capture_time_ms;
1094 last_packet_marker_bit_ = marker_bit;
stefan@webrtc.orga8179622013-06-04 13:47:36 +00001095 int csrcs_length = 0;
1096 if (include_csrcs_)
1097 csrcs_length = num_csrcs_;
1098 return CreateRTPHeader(data_buffer, payload_type, ssrc_, marker_bit,
1099 timestamp_, sequence_number, csrcs_, csrcs_length);
1100}
1101
1102uint16_t RTPSender::BuildRTPHeaderExtension(uint8_t* data_buffer) const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001103 if (rtp_header_extension_map_.Size() <= 0) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001104 return 0;
1105 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001106 // RTP header extension, RFC 3550.
1107 // 0 1 2 3
1108 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1109 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1110 // | defined by profile | length |
1111 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1112 // | header extension |
1113 // | .... |
1114 //
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001115 const uint32_t kPosLength = 2;
pbos@webrtc.org3004c792013-05-07 12:36:21 +00001116 const uint32_t kHeaderLength = kRtpOneByteHeaderLength;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001117
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001118 // Add extension ID (0xBEDE).
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001119 RtpUtility::AssignUWord16ToBuffer(data_buffer, kRtpOneByteHeaderExtensionId);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001120
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001121 // Add extensions.
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001122 uint16_t total_block_length = 0;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001123
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001124 RTPExtensionType type = rtp_header_extension_map_.First();
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001125 while (type != kRtpExtensionNone) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001126 uint8_t block_length = 0;
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001127 switch (type) {
1128 case kRtpExtensionTransmissionTimeOffset:
1129 block_length = BuildTransmissionTimeOffsetExtension(
1130 data_buffer + kHeaderLength + total_block_length);
1131 break;
solenberg@webrtc.orgc0352d52013-05-20 20:55:07 +00001132 case kRtpExtensionAudioLevel:
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00001133 block_length = BuildAudioLevelExtension(
1134 data_buffer + kHeaderLength + total_block_length);
solenberg@webrtc.orgc0352d52013-05-20 20:55:07 +00001135 break;
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001136 case kRtpExtensionAbsoluteSendTime:
1137 block_length = BuildAbsoluteSendTimeExtension(
1138 data_buffer + kHeaderLength + total_block_length);
1139 break;
1140 default:
1141 assert(false);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001142 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001143 total_block_length += block_length;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001144 type = rtp_header_extension_map_.Next(type);
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001145 }
1146 if (total_block_length == 0) {
1147 // No extension added.
1148 return 0;
1149 }
1150 // Set header length (in number of Word32, header excluded).
1151 assert(total_block_length % 4 == 0);
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001152 RtpUtility::AssignUWord16ToBuffer(data_buffer + kPosLength,
1153 total_block_length / 4);
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001154 // Total added length.
1155 return kHeaderLength + total_block_length;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001156}
1157
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001158uint8_t RTPSender::BuildTransmissionTimeOffsetExtension(
1159 uint8_t* data_buffer) const {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001160 // From RFC 5450: Transmission Time Offsets in RTP Streams.
1161 //
1162 // The transmission time is signaled to the receiver in-band using the
1163 // general mechanism for RTP header extensions [RFC5285]. The payload
1164 // of this extension (the transmitted value) is a 24-bit signed integer.
1165 // When added to the RTP timestamp of the packet, it represents the
1166 // "effective" RTP transmission time of the packet, on the RTP
1167 // timescale.
1168 //
1169 // The form of the transmission offset extension block:
1170 //
1171 // 0 1 2 3
1172 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1173 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1174 // | ID | len=2 | transmission offset |
1175 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001176
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001177 // Get id defined by user.
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001178 uint8_t id;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001179 if (rtp_header_extension_map_.GetId(kRtpExtensionTransmissionTimeOffset,
1180 &id) != 0) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001181 // Not registered.
1182 return 0;
1183 }
pbos@webrtc.org3004c792013-05-07 12:36:21 +00001184 size_t pos = 0;
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001185 const uint8_t len = 2;
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001186 data_buffer[pos++] = (id << 4) + len;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001187 RtpUtility::AssignUWord24ToBuffer(data_buffer + pos,
1188 transmission_time_offset_);
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001189 pos += 3;
pbos@webrtc.org3004c792013-05-07 12:36:21 +00001190 assert(pos == kTransmissionTimeOffsetLength);
1191 return kTransmissionTimeOffsetLength;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001192}
1193
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00001194uint8_t RTPSender::BuildAudioLevelExtension(uint8_t* data_buffer) const {
1195 // An RTP Header Extension for Client-to-Mixer Audio Level Indication
1196 //
1197 // https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
1198 //
1199 // The form of the audio level extension block:
1200 //
1201 // 0 1 2 3
1202 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1203 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1204 // | ID | len=0 |V| level | 0x00 | 0x00 |
1205 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1206 //
1207 // Note that we always include 2 pad bytes, which will result in legal and
1208 // correctly parsed RTP, but may be a bit wasteful if more short extensions
1209 // are implemented. Right now the pad bytes would anyway be required at end
1210 // of the extension block, so it makes no difference.
1211
1212 // Get id defined by user.
1213 uint8_t id;
1214 if (rtp_header_extension_map_.GetId(kRtpExtensionAudioLevel, &id) != 0) {
1215 // Not registered.
1216 return 0;
1217 }
1218 size_t pos = 0;
1219 const uint8_t len = 0;
1220 data_buffer[pos++] = (id << 4) + len;
1221 data_buffer[pos++] = (1 << 7) + 0; // Voice, 0 dBov.
1222 data_buffer[pos++] = 0; // Padding.
1223 data_buffer[pos++] = 0; // Padding.
1224 // kAudioLevelLength is including pad bytes.
1225 assert(pos == kAudioLevelLength);
1226 return kAudioLevelLength;
1227}
1228
1229uint8_t RTPSender::BuildAbsoluteSendTimeExtension(uint8_t* data_buffer) const {
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001230 // Absolute send time in RTP streams.
1231 //
1232 // The absolute send time is signaled to the receiver in-band using the
1233 // general mechanism for RTP header extensions [RFC5285]. The payload
1234 // of this extension (the transmitted value) is a 24-bit unsigned integer
1235 // containing the sender's current time in seconds as a fixed point number
1236 // with 18 bits fractional part.
1237 //
1238 // The form of the absolute send time extension block:
1239 //
1240 // 0 1 2 3
1241 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1242 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1243 // | ID | len=2 | absolute send time |
1244 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1245
1246 // Get id defined by user.
1247 uint8_t id;
1248 if (rtp_header_extension_map_.GetId(kRtpExtensionAbsoluteSendTime,
1249 &id) != 0) {
1250 // Not registered.
1251 return 0;
1252 }
1253 size_t pos = 0;
1254 const uint8_t len = 2;
1255 data_buffer[pos++] = (id << 4) + len;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001256 RtpUtility::AssignUWord24ToBuffer(data_buffer + pos, absolute_send_time_);
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001257 pos += 3;
1258 assert(pos == kAbsoluteSendTimeLength);
1259 return kAbsoluteSendTimeLength;
1260}
1261
stefan@webrtc.org420b2562014-05-30 12:17:15 +00001262void RTPSender::UpdateTransmissionTimeOffset(
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001263 uint8_t *rtp_packet, const uint16_t rtp_packet_length,
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001264 const RTPHeader &rtp_header, const int64_t time_diff_ms) const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001265 CriticalSectionScoped cs(send_critsect_);
stefan@webrtc.org2f8d5f32014-04-15 12:28:46 +00001266 // Get id.
1267 uint8_t id = 0;
1268 if (rtp_header_extension_map_.GetId(kRtpExtensionTransmissionTimeOffset,
1269 &id) != 0) {
1270 // Not registered.
stefan@webrtc.org420b2562014-05-30 12:17:15 +00001271 return;
stefan@webrtc.org2f8d5f32014-04-15 12:28:46 +00001272 }
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001273 // Get length until start of header extension block.
1274 int extension_block_pos =
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001275 rtp_header_extension_map_.GetLengthUntilBlockStartInBytes(
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001276 kRtpExtensionTransmissionTimeOffset);
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001277 if (extension_block_pos < 0) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001278 LOG(LS_WARNING)
1279 << "Failed to update transmission time offset, not registered.";
stefan@webrtc.org420b2562014-05-30 12:17:15 +00001280 return;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001281 }
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001282 int block_pos = 12 + rtp_header.numCSRCs + extension_block_pos;
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001283 if (rtp_packet_length < block_pos + kTransmissionTimeOffsetLength ||
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001284 rtp_header.headerLength <
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001285 block_pos + kTransmissionTimeOffsetLength) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001286 LOG(LS_WARNING)
1287 << "Failed to update transmission time offset, invalid length.";
stefan@webrtc.org420b2562014-05-30 12:17:15 +00001288 return;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001289 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001290 // Verify that header contains extension.
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001291 if (!((rtp_packet[12 + rtp_header.numCSRCs] == 0xBE) &&
1292 (rtp_packet[12 + rtp_header.numCSRCs + 1] == 0xDE))) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001293 LOG(LS_WARNING) << "Failed to update transmission time offset, hdr "
1294 "extension not found.";
stefan@webrtc.org420b2562014-05-30 12:17:15 +00001295 return;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001296 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001297 // Verify first byte in block.
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001298 const uint8_t first_block_byte = (id << 4) + 2;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001299 if (rtp_packet[block_pos] != first_block_byte) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001300 LOG(LS_WARNING) << "Failed to update transmission time offset.";
stefan@webrtc.org420b2562014-05-30 12:17:15 +00001301 return;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001302 }
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001303 // Update transmission offset field (converting to a 90 kHz timestamp).
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001304 RtpUtility::AssignUWord24ToBuffer(rtp_packet + block_pos + 1,
1305 time_diff_ms * 90); // RTP timestamp.
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001306}
1307
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00001308bool RTPSender::UpdateAudioLevel(uint8_t *rtp_packet,
1309 const uint16_t rtp_packet_length,
1310 const RTPHeader &rtp_header,
1311 const bool is_voiced,
1312 const uint8_t dBov) const {
1313 CriticalSectionScoped cs(send_critsect_);
1314
stefan@webrtc.org2f8d5f32014-04-15 12:28:46 +00001315 // Get id.
1316 uint8_t id = 0;
1317 if (rtp_header_extension_map_.GetId(kRtpExtensionAudioLevel, &id) != 0) {
1318 // Not registered.
1319 return false;
1320 }
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00001321 // Get length until start of header extension block.
1322 int extension_block_pos =
1323 rtp_header_extension_map_.GetLengthUntilBlockStartInBytes(
1324 kRtpExtensionAudioLevel);
1325 if (extension_block_pos < 0) {
andrew@webrtc.org2c3f1ab2014-04-15 21:26:34 +00001326 // The feature is not enabled.
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00001327 return false;
1328 }
1329 int block_pos = 12 + rtp_header.numCSRCs + extension_block_pos;
1330 if (rtp_packet_length < block_pos + kAudioLevelLength ||
1331 rtp_header.headerLength < block_pos + kAudioLevelLength) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001332 LOG(LS_WARNING) << "Failed to update audio level, invalid length.";
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00001333 return false;
1334 }
1335 // Verify that header contains extension.
1336 if (!((rtp_packet[12 + rtp_header.numCSRCs] == 0xBE) &&
1337 (rtp_packet[12 + rtp_header.numCSRCs + 1] == 0xDE))) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001338 LOG(LS_WARNING) << "Failed to update audio level, hdr extension not found.";
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00001339 return false;
1340 }
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00001341 // Verify first byte in block.
1342 const uint8_t first_block_byte = (id << 4) + 0;
1343 if (rtp_packet[block_pos] != first_block_byte) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001344 LOG(LS_WARNING) << "Failed to update audio level.";
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00001345 return false;
1346 }
1347 rtp_packet[block_pos + 1] = (is_voiced ? 0x80 : 0x00) + (dBov & 0x7f);
1348 return true;
1349}
1350
stefan@webrtc.org420b2562014-05-30 12:17:15 +00001351void RTPSender::UpdateAbsoluteSendTime(
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001352 uint8_t *rtp_packet, const uint16_t rtp_packet_length,
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001353 const RTPHeader &rtp_header, const int64_t now_ms) const {
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001354 CriticalSectionScoped cs(send_critsect_);
1355
stefan@webrtc.org2f8d5f32014-04-15 12:28:46 +00001356 // Get id.
1357 uint8_t id = 0;
1358 if (rtp_header_extension_map_.GetId(kRtpExtensionAbsoluteSendTime,
1359 &id) != 0) {
1360 // Not registered.
stefan@webrtc.org420b2562014-05-30 12:17:15 +00001361 return;
stefan@webrtc.org2f8d5f32014-04-15 12:28:46 +00001362 }
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001363 // Get length until start of header extension block.
1364 int extension_block_pos =
1365 rtp_header_extension_map_.GetLengthUntilBlockStartInBytes(
1366 kRtpExtensionAbsoluteSendTime);
1367 if (extension_block_pos < 0) {
andrew@webrtc.org2c3f1ab2014-04-15 21:26:34 +00001368 // The feature is not enabled.
stefan@webrtc.org420b2562014-05-30 12:17:15 +00001369 return;
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001370 }
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001371 int block_pos = 12 + rtp_header.numCSRCs + extension_block_pos;
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001372 if (rtp_packet_length < block_pos + kAbsoluteSendTimeLength ||
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001373 rtp_header.headerLength < block_pos + kAbsoluteSendTimeLength) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001374 LOG(LS_WARNING) << "Failed to update absolute send time, invalid length.";
stefan@webrtc.org420b2562014-05-30 12:17:15 +00001375 return;
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001376 }
1377 // Verify that header contains extension.
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001378 if (!((rtp_packet[12 + rtp_header.numCSRCs] == 0xBE) &&
1379 (rtp_packet[12 + rtp_header.numCSRCs + 1] == 0xDE))) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001380 LOG(LS_WARNING)
1381 << "Failed to update absolute send time, hdr extension not found.";
stefan@webrtc.org420b2562014-05-30 12:17:15 +00001382 return;
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001383 }
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001384 // Verify first byte in block.
1385 const uint8_t first_block_byte = (id << 4) + 2;
1386 if (rtp_packet[block_pos] != first_block_byte) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001387 LOG(LS_WARNING) << "Failed to update absolute send time.";
stefan@webrtc.org420b2562014-05-30 12:17:15 +00001388 return;
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001389 }
1390 // Update absolute send time field (convert ms to 24-bit unsigned with 18 bit
1391 // fractional part).
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001392 RtpUtility::AssignUWord24ToBuffer(rtp_packet + block_pos + 1,
1393 ((now_ms << 18) / 1000) & 0x00ffffff);
solenberg@webrtc.org7ebbea12013-05-16 11:10:31 +00001394}
1395
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001396void RTPSender::SetSendingStatus(bool enabled) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001397 if (enabled) {
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001398 uint32_t frequency_hz = SendPayloadFrequency();
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001399 uint32_t RTPtime = RtpUtility::GetCurrentRTP(clock_, frequency_hz);
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001400
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001401 // Will be ignored if it's already configured via API.
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001402 SetStartTimestamp(RTPtime, false);
1403 } else {
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +00001404 CriticalSectionScoped lock(send_critsect_);
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001405 if (!ssrc_forced_) {
1406 // Generate a new SSRC.
1407 ssrc_db_.ReturnSSRC(ssrc_);
1408 ssrc_ = ssrc_db_.CreateSSRC(); // Can't be 0.
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001409 }
1410 // Don't initialize seq number if SSRC passed externally.
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001411 if (!sequence_number_forced_ && !ssrc_forced_) {
1412 // Generate a new sequence number.
1413 sequence_number_ =
1414 rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER); // NOLINT
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001415 }
1416 }
1417}
1418
1419void RTPSender::SetSendingMediaStatus(const bool enabled) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001420 CriticalSectionScoped cs(send_critsect_);
1421 sending_media_ = enabled;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001422}
1423
1424bool RTPSender::SendingMedia() const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001425 CriticalSectionScoped cs(send_critsect_);
1426 return sending_media_;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001427}
1428
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001429uint32_t RTPSender::Timestamp() const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001430 CriticalSectionScoped cs(send_critsect_);
stefan@webrtc.orga8179622013-06-04 13:47:36 +00001431 return timestamp_;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001432}
1433
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001434void RTPSender::SetStartTimestamp(uint32_t timestamp, bool force) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001435 CriticalSectionScoped cs(send_critsect_);
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001436 if (force) {
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +00001437 start_timestamp_forced_ = true;
1438 start_timestamp_ = timestamp;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001439 } else {
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +00001440 if (!start_timestamp_forced_) {
1441 start_timestamp_ = timestamp;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001442 }
1443 }
1444}
1445
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001446uint32_t RTPSender::StartTimestamp() const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001447 CriticalSectionScoped cs(send_critsect_);
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +00001448 return start_timestamp_;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001449}
1450
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001451uint32_t RTPSender::GenerateNewSSRC() {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001452 // If configured via API, return 0.
1453 CriticalSectionScoped cs(send_critsect_);
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001454
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001455 if (ssrc_forced_) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001456 return 0;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001457 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001458 ssrc_ = ssrc_db_.CreateSSRC(); // Can't be 0.
1459 return ssrc_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001460}
1461
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001462void RTPSender::SetSSRC(uint32_t ssrc) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001463 // This is configured via the API.
1464 CriticalSectionScoped cs(send_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00001465
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001466 if (ssrc_ == ssrc && ssrc_forced_) {
1467 return; // Since it's same ssrc, don't reset anything.
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001468 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001469 ssrc_forced_ = true;
1470 ssrc_db_.ReturnSSRC(ssrc_);
1471 ssrc_db_.RegisterSSRC(ssrc);
1472 ssrc_ = ssrc;
1473 if (!sequence_number_forced_) {
1474 sequence_number_ =
1475 rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER); // NOLINT
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001476 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001477}
1478
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001479uint32_t RTPSender::SSRC() const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001480 CriticalSectionScoped cs(send_critsect_);
1481 return ssrc_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001482}
1483
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001484void RTPSender::SetCSRCStatus(const bool include) {
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +00001485 CriticalSectionScoped lock(send_critsect_);
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001486 include_csrcs_ = include;
niklase@google.com470e71d2011-07-07 08:21:25 +00001487}
1488
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001489void RTPSender::SetCSRCs(const uint32_t arr_of_csrc[kRtpCsrcSize],
1490 const uint8_t arr_length) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001491 assert(arr_length <= kRtpCsrcSize);
1492 CriticalSectionScoped cs(send_critsect_);
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001493
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001494 for (int i = 0; i < arr_length; i++) {
stefan@webrtc.orga8179622013-06-04 13:47:36 +00001495 csrcs_[i] = arr_of_csrc[i];
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001496 }
stefan@webrtc.orga8179622013-06-04 13:47:36 +00001497 num_csrcs_ = arr_length;
niklase@google.com470e71d2011-07-07 08:21:25 +00001498}
1499
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001500int32_t RTPSender::CSRCs(uint32_t arr_of_csrc[kRtpCsrcSize]) const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001501 assert(arr_of_csrc);
1502 CriticalSectionScoped cs(send_critsect_);
stefan@webrtc.orga8179622013-06-04 13:47:36 +00001503 for (int i = 0; i < num_csrcs_ && i < kRtpCsrcSize; i++) {
1504 arr_of_csrc[i] = csrcs_[i];
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001505 }
stefan@webrtc.orga8179622013-06-04 13:47:36 +00001506 return num_csrcs_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001507}
1508
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001509void RTPSender::SetSequenceNumber(uint16_t seq) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001510 CriticalSectionScoped cs(send_critsect_);
1511 sequence_number_forced_ = true;
1512 sequence_number_ = seq;
niklase@google.com470e71d2011-07-07 08:21:25 +00001513}
1514
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001515uint16_t RTPSender::SequenceNumber() const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001516 CriticalSectionScoped cs(send_critsect_);
1517 return sequence_number_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001518}
1519
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001520// Audio.
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001521int32_t RTPSender::SendTelephoneEvent(const uint8_t key,
1522 const uint16_t time_ms,
1523 const uint8_t level) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001524 if (!audio_configured_) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001525 return -1;
1526 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001527 return audio_->SendTelephoneEvent(key, time_ms, level);
niklase@google.com470e71d2011-07-07 08:21:25 +00001528}
1529
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001530bool RTPSender::SendTelephoneEventActive(int8_t *telephone_event) const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001531 if (!audio_configured_) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001532 return false;
1533 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001534 return audio_->SendTelephoneEventActive(*telephone_event);
niklase@google.com470e71d2011-07-07 08:21:25 +00001535}
1536
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001537int32_t RTPSender::SetAudioPacketSize(
1538 const uint16_t packet_size_samples) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001539 if (!audio_configured_) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001540 return -1;
1541 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001542 return audio_->SetAudioPacketSize(packet_size_samples);
niklase@google.com470e71d2011-07-07 08:21:25 +00001543}
1544
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001545int32_t RTPSender::SetAudioLevel(const uint8_t level_d_bov) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001546 return audio_->SetAudioLevel(level_d_bov);
niklase@google.com470e71d2011-07-07 08:21:25 +00001547}
1548
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001549int32_t RTPSender::SetRED(const int8_t payload_type) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001550 if (!audio_configured_) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001551 return -1;
1552 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001553 return audio_->SetRED(payload_type);
niklase@google.com470e71d2011-07-07 08:21:25 +00001554}
1555
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001556int32_t RTPSender::RED(int8_t *payload_type) const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001557 if (!audio_configured_) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001558 return -1;
1559 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001560 return audio_->RED(*payload_type);
niklase@google.com470e71d2011-07-07 08:21:25 +00001561}
1562
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001563// Video
1564VideoCodecInformation *RTPSender::CodecInformationVideo() {
1565 if (audio_configured_) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001566 return NULL;
1567 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001568 return video_->CodecInformationVideo();
niklase@google.com470e71d2011-07-07 08:21:25 +00001569}
1570
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001571RtpVideoCodecTypes RTPSender::VideoCodecType() const {
pbos@webrtc.org8911ce42013-03-18 16:39:03 +00001572 assert(!audio_configured_ && "Sender is an audio stream!");
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001573 return video_->VideoCodecType();
niklase@google.com470e71d2011-07-07 08:21:25 +00001574}
1575
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001576uint32_t RTPSender::MaxConfiguredBitrateVideo() const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001577 if (audio_configured_) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001578 return 0;
1579 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001580 return video_->MaxConfiguredBitrateVideo();
niklase@google.com470e71d2011-07-07 08:21:25 +00001581}
1582
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001583int32_t RTPSender::SendRTPIntraRequest() {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001584 if (audio_configured_) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001585 return -1;
1586 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001587 return video_->SendRTPIntraRequest();
niklase@google.com470e71d2011-07-07 08:21:25 +00001588}
1589
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001590int32_t RTPSender::SetGenericFECStatus(
1591 const bool enable, const uint8_t payload_type_red,
1592 const uint8_t payload_type_fec) {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001593 if (audio_configured_) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001594 return -1;
1595 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001596 return video_->SetGenericFECStatus(enable, payload_type_red,
1597 payload_type_fec);
niklase@google.com470e71d2011-07-07 08:21:25 +00001598}
1599
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001600int32_t RTPSender::GenericFECStatus(
1601 bool *enable, uint8_t *payload_type_red,
1602 uint8_t *payload_type_fec) const {
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001603 if (audio_configured_) {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001604 return -1;
1605 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001606 return video_->GenericFECStatus(
1607 *enable, *payload_type_red, *payload_type_fec);
niklase@google.com470e71d2011-07-07 08:21:25 +00001608}
1609
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001610int32_t RTPSender::SetFecParameters(
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001611 const FecProtectionParams *delta_params,
1612 const FecProtectionParams *key_params) {
1613 if (audio_configured_) {
stefan@webrtc.orge0d6fa42012-03-20 22:10:56 +00001614 return -1;
1615 }
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001616 return video_->SetFecParameters(delta_params, key_params);
marpan@google.com80c5d7a2011-07-15 21:32:40 +00001617}
phoglund@webrtc.org43da54a2013-01-25 10:53:38 +00001618
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001619void RTPSender::BuildRtxPacket(uint8_t* buffer, uint16_t* length,
1620 uint8_t* buffer_rtx) {
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +00001621 CriticalSectionScoped cs(send_critsect_);
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001622 uint8_t* data_buffer_rtx = buffer_rtx;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +00001623 // Add RTX header.
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001624 RtpUtility::RtpHeaderParser rtp_parser(
1625 reinterpret_cast<const uint8_t*>(buffer), *length);
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +00001626
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001627 RTPHeader rtp_header;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +00001628 rtp_parser.Parse(rtp_header);
1629
1630 // Add original RTP header.
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001631 memcpy(data_buffer_rtx, buffer, rtp_header.headerLength);
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +00001632
mflodman@webrtc.org9f5ebb52013-04-12 14:55:46 +00001633 // Replace payload type, if a specific type is set for RTX.
1634 if (payload_type_rtx_ != -1) {
1635 data_buffer_rtx[1] = static_cast<uint8_t>(payload_type_rtx_);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001636 if (rtp_header.markerBit)
mflodman@webrtc.org9f5ebb52013-04-12 14:55:46 +00001637 data_buffer_rtx[1] |= kRtpMarkerBitMask;
1638 }
1639
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +00001640 // Replace sequence number.
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001641 uint8_t *ptr = data_buffer_rtx + 2;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001642 RtpUtility::AssignUWord16ToBuffer(ptr, sequence_number_rtx_++);
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +00001643
1644 // Replace SSRC.
1645 ptr += 6;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001646 RtpUtility::AssignUWord32ToBuffer(ptr, ssrc_rtx_);
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +00001647
1648 // Add OSN (original sequence number).
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001649 ptr = data_buffer_rtx + rtp_header.headerLength;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001650 RtpUtility::AssignUWord16ToBuffer(ptr, rtp_header.sequenceNumber);
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +00001651 ptr += 2;
1652
1653 // Add original payload data.
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001654 memcpy(ptr, buffer + rtp_header.headerLength,
1655 *length - rtp_header.headerLength);
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +00001656 *length += 2;
1657}
1658
sprang@webrtc.orgebad7652013-12-05 14:29:02 +00001659void RTPSender::RegisterRtpStatisticsCallback(
1660 StreamDataCountersCallback* callback) {
1661 CriticalSectionScoped cs(statistics_crit_.get());
sprang@webrtc.orgebad7652013-12-05 14:29:02 +00001662 rtp_stats_callback_ = callback;
1663}
1664
1665StreamDataCountersCallback* RTPSender::GetRtpStatisticsCallback() const {
1666 CriticalSectionScoped cs(statistics_crit_.get());
1667 return rtp_stats_callback_;
1668}
1669
sprang@webrtc.org6811b6e2013-12-13 09:46:59 +00001670uint32_t RTPSender::BitrateSent() const { return bitrate_sent_.BitrateLast(); }
1671
1672void RTPSender::BitrateUpdated(const BitrateStatistics& stats) {
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +00001673 uint32_t ssrc;
1674 {
1675 CriticalSectionScoped ssrc_lock(send_critsect_);
1676 ssrc = ssrc_;
1677 }
sprang@webrtc.org6811b6e2013-12-13 09:46:59 +00001678 if (bitrate_callback_) {
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +00001679 bitrate_callback_->Notify(stats, ssrc);
sprang@webrtc.org6811b6e2013-12-13 09:46:59 +00001680 }
1681}
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +00001682
1683void RTPSender::SetRtpState(const RtpState& rtp_state) {
1684 SetStartTimestamp(rtp_state.start_timestamp, true);
1685 CriticalSectionScoped lock(send_critsect_);
1686 sequence_number_ = rtp_state.sequence_number;
1687 sequence_number_forced_ = true;
1688 timestamp_ = rtp_state.timestamp;
1689 capture_time_ms_ = rtp_state.capture_time_ms;
1690 last_timestamp_time_ms_ = rtp_state.last_timestamp_time_ms;
stefan@webrtc.org8b94e3d2014-07-17 16:10:14 +00001691 media_has_been_sent_ = rtp_state.media_has_been_sent;
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +00001692}
1693
1694RtpState RTPSender::GetRtpState() const {
1695 CriticalSectionScoped lock(send_critsect_);
1696
1697 RtpState state;
1698 state.sequence_number = sequence_number_;
1699 state.start_timestamp = start_timestamp_;
1700 state.timestamp = timestamp_;
1701 state.capture_time_ms = capture_time_ms_;
1702 state.last_timestamp_time_ms = last_timestamp_time_ms_;
stefan@webrtc.org8b94e3d2014-07-17 16:10:14 +00001703 state.media_has_been_sent = media_has_been_sent_;
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +00001704
1705 return state;
1706}
1707
1708void RTPSender::SetRtxRtpState(const RtpState& rtp_state) {
1709 CriticalSectionScoped lock(send_critsect_);
1710 sequence_number_rtx_ = rtp_state.sequence_number;
1711}
1712
1713RtpState RTPSender::GetRtxRtpState() const {
1714 CriticalSectionScoped lock(send_critsect_);
1715
1716 RtpState state;
1717 state.sequence_number = sequence_number_rtx_;
1718 state.start_timestamp = start_timestamp_;
1719
1720 return state;
1721}
1722
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001723} // namespace webrtc