blob: abbe395cbdafac29fae6f7fdb92730b7c86d26d9 [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
niklase@google.com470e71d2011-07-07 08:21:25 +000013#include <cstdlib> // srand
14
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +000015#include "webrtc/modules/pacing/include/paced_sender.h"
16#include "webrtc/modules/rtp_rtcp/source/rtp_packet_history.h"
17#include "webrtc/modules/rtp_rtcp/source/rtp_sender_audio.h"
18#include "webrtc/modules/rtp_rtcp/source/rtp_sender_video.h"
19#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
20#include "webrtc/system_wrappers/interface/trace.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000021
22namespace webrtc {
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000023RTPSender::RTPSender(const WebRtc_Word32 id,
24 const bool audio,
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000025 RtpRtcpClock* clock,
26 Transport* transport,
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +000027 RtpAudioFeedback* audio_feedback,
28 PacedSender* paced_sender)
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000029 : Bitrate(clock),
30 _id(id),
31 _audioConfigured(audio),
32 _audio(NULL),
33 _video(NULL),
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +000034 paced_sender_(paced_sender),
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000035 _sendCritsect(CriticalSectionWrapper::CreateCriticalSection()),
36 _transport(transport),
37 _sendingMedia(true), // Default to sending media
niklase@google.com470e71d2011-07-07 08:21:25 +000038
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000039 _maxPayloadLength(IP_PACKET_SIZE-28), // default is IP-v4/UDP
40 _targetSendBitrate(0),
41 _packetOverHead(28),
niklase@google.com470e71d2011-07-07 08:21:25 +000042
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000043 _payloadType(-1),
44 _payloadTypeMap(),
niklase@google.com470e71d2011-07-07 08:21:25 +000045
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000046 _rtpHeaderExtensionMap(),
47 _transmissionTimeOffset(0),
niklase@google.com470e71d2011-07-07 08:21:25 +000048
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +000049 // NACK
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000050 _nackByteCountTimes(),
51 _nackByteCount(),
52 _nackBitrate(clock),
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000053 _packetHistory(new RTPPacketHistory(clock)),
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +000054
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +000055 // statistics
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000056 _packetsSent(0),
57 _payloadBytesSent(0),
niklase@google.com470e71d2011-07-07 08:21:25 +000058
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000059 _startTimeStampForced(false),
60 _startTimeStamp(0),
61 _ssrcDB(*SSRCDatabase::GetSSRCDatabase()),
62 _remoteSSRC(0),
63 _sequenceNumberForced(false),
64 _sequenceNumber(0),
65 _sequenceNumberRTX(0),
66 _ssrcForced(false),
67 _ssrc(0),
68 _timeStamp(0),
69 _CSRCs(0),
70 _CSRC(),
71 _includeCSRCs(true),
72 _RTX(false),
73 _ssrcRTX(0) {
74 memset(_nackByteCountTimes, 0, sizeof(_nackByteCountTimes));
75 memset(_nackByteCount, 0, sizeof(_nackByteCount));
76 memset(_CSRC, 0, sizeof(_CSRC));
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000077 // We need to seed the random generator.
78 srand( (WebRtc_UWord32)_clock.GetTimeInMS() );
79 _ssrc = _ssrcDB.CreateSSRC(); // Can't be 0.
niklase@google.com470e71d2011-07-07 08:21:25 +000080
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000081 if (audio) {
82 _audio = new RTPSenderAudio(id, &_clock, this);
83 _audio->RegisterAudioCallback(audio_feedback);
84 } else {
85 _video = new RTPSenderVideo(id, &_clock, this);
86 }
87 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +000088}
89
pwestin@webrtc.org00741872012-01-19 15:56:10 +000090RTPSender::~RTPSender() {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000091 if (_remoteSSRC != 0) {
pwestin@webrtc.org00741872012-01-19 15:56:10 +000092 _ssrcDB.ReturnSSRC(_remoteSSRC);
93 }
94 _ssrcDB.ReturnSSRC(_ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +000095
pwestin@webrtc.org00741872012-01-19 15:56:10 +000096 SSRCDatabase::ReturnSSRCDatabase();
97 delete _sendCritsect;
pwestin@webrtc.org00741872012-01-19 15:56:10 +000098 while (!_payloadTypeMap.empty()) {
99 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
100 _payloadTypeMap.begin();
101 delete it->second;
102 _payloadTypeMap.erase(it);
103 }
104 delete _packetHistory;
105 delete _audio;
106 delete _video;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000107
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000108 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, _id, "%s deleted", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +0000109}
niklase@google.com470e71d2011-07-07 08:21:25 +0000110
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000111void RTPSender::SetTargetSendBitrate(const WebRtc_UWord32 bits) {
112 _targetSendBitrate = static_cast<uint16_t>(bits / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +0000113}
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000114
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000115WebRtc_UWord16 RTPSender::ActualSendBitrateKbit() const {
116 return (WebRtc_UWord16) (Bitrate::BitrateNow() / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +0000117}
118
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000119WebRtc_UWord32 RTPSender::VideoBitrateSent() const {
120 if (_video) {
stefan@webrtc.orgfbea4e52011-10-27 16:08:29 +0000121 return _video->VideoBitrateSent();
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000122 }
123 return 0;
stefan@webrtc.orgfbea4e52011-10-27 16:08:29 +0000124}
125
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000126WebRtc_UWord32 RTPSender::FecOverheadRate() const {
127 if (_video) {
stefan@webrtc.orgfbea4e52011-10-27 16:08:29 +0000128 return _video->FecOverheadRate();
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000129 }
130 return 0;
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000131}
132
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000133WebRtc_UWord32 RTPSender::NackOverheadRate() const {
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000134 return _nackBitrate.BitrateLast();
135}
136
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000137WebRtc_Word32 RTPSender::SetTransmissionTimeOffset(
138 const WebRtc_Word32 transmissionTimeOffset) {
139 if (transmissionTimeOffset > (0x800000 - 1) ||
140 transmissionTimeOffset < -(0x800000 - 1)) { // Word24
141 return -1;
142 }
143 CriticalSectionScoped cs(_sendCritsect);
144 _transmissionTimeOffset = transmissionTimeOffset;
145 return 0;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000146}
147
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000148WebRtc_Word32 RTPSender::RegisterRtpHeaderExtension(const RTPExtensionType type,
149 const WebRtc_UWord8 id) {
150 CriticalSectionScoped cs(_sendCritsect);
151 return _rtpHeaderExtensionMap.Register(type, id);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000152}
153
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000154WebRtc_Word32 RTPSender::DeregisterRtpHeaderExtension(
155 const RTPExtensionType type) {
156 CriticalSectionScoped cs(_sendCritsect);
157 return _rtpHeaderExtensionMap.Deregister(type);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000158}
159
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000160WebRtc_UWord16 RTPSender::RtpHeaderExtensionTotalLength() const {
161 CriticalSectionScoped cs(_sendCritsect);
162 return _rtpHeaderExtensionMap.GetTotalLengthInBytes();
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000163}
164
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000165WebRtc_Word32 RTPSender::RegisterPayload(
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000166 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000167 const WebRtc_Word8 payloadNumber,
168 const WebRtc_UWord32 frequency,
169 const WebRtc_UWord8 channels,
170 const WebRtc_UWord32 rate) {
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000171 assert(payloadName);
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000172 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000173
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000174 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
175 _payloadTypeMap.find(payloadNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +0000176
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000177 if (_payloadTypeMap.end() != it) {
178 // we already use this payload type
179 ModuleRTPUtility::Payload* payload = it->second;
180 assert(payload);
niklase@google.com470e71d2011-07-07 08:21:25 +0000181
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000182 // check if it's the same as we already have
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000183 if (ModuleRTPUtility::StringCompare(payload->name, payloadName,
184 RTP_PAYLOAD_NAME_SIZE - 1)) {
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000185 if (_audioConfigured && payload->audio &&
186 payload->typeSpecific.Audio.frequency == frequency &&
187 (payload->typeSpecific.Audio.rate == rate ||
188 payload->typeSpecific.Audio.rate == 0 || rate == 0)) {
189 payload->typeSpecific.Audio.rate = rate;
190 // Ensure that we update the rate if new or old is zero
niklase@google.com470e71d2011-07-07 08:21:25 +0000191 return 0;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000192 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000193 if (!_audioConfigured && !payload->audio) {
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000194 return 0;
195 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000196 }
197 return -1;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000198 }
199 WebRtc_Word32 retVal = -1;
200 ModuleRTPUtility::Payload* payload = NULL;
201 if (_audioConfigured) {
202 retVal = _audio->RegisterAudioPayload(payloadName, payloadNumber, frequency,
203 channels, rate, payload);
204 } else {
205 retVal = _video->RegisterVideoPayload(payloadName, payloadNumber, rate,
206 payload);
207 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000208 if (payload) {
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000209 _payloadTypeMap[payloadNumber] = payload;
210 }
211 return retVal;
niklase@google.com470e71d2011-07-07 08:21:25 +0000212}
213
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000214WebRtc_Word32 RTPSender::DeRegisterSendPayload(const WebRtc_Word8 payloadType) {
215 CriticalSectionScoped lock(_sendCritsect);
216
217 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
218 _payloadTypeMap.find(payloadType);
219
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000220 if (_payloadTypeMap.end() == it) {
221 return -1;
222 }
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000223 ModuleRTPUtility::Payload* payload = it->second;
224 delete payload;
225 _payloadTypeMap.erase(it);
226 return 0;
227}
niklase@google.com470e71d2011-07-07 08:21:25 +0000228
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000229WebRtc_Word8 RTPSender::SendPayloadType() const {
230 return _payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000231}
232
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000233int RTPSender::SendPayloadFrequency() const {
234 return _audio->AudioFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000235}
236
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000237WebRtc_Word32 RTPSender::SetMaxPayloadLength(
238 const WebRtc_UWord16 maxPayloadLength,
239 const WebRtc_UWord16 packetOverHead) {
240 // sanity check
241 if (maxPayloadLength < 100 || maxPayloadLength > IP_PACKET_SIZE) {
242 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
243 "%s invalid argument", __FUNCTION__);
244 return -1;
245 }
246 CriticalSectionScoped cs(_sendCritsect);
247 _maxPayloadLength = maxPayloadLength;
248 _packetOverHead = packetOverHead;
niklase@google.com470e71d2011-07-07 08:21:25 +0000249
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000250 WEBRTC_TRACE(kTraceInfo, kTraceRtpRtcp, _id,
251 "SetMaxPayloadLength to %d.", maxPayloadLength);
252 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253}
254
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000255WebRtc_UWord16 RTPSender::MaxDataPayloadLength() const {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000256 if (_audioConfigured) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000257 return _maxPayloadLength - RTPHeaderLength();
258 } else {
259 return _maxPayloadLength - RTPHeaderLength() -
260 _video->FECPacketOverhead() - ((_RTX) ? 2 : 0);
261 // Include the FEC/ULP/RED overhead.
262 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000263}
264
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000265WebRtc_UWord16 RTPSender::MaxPayloadLength() const {
266 return _maxPayloadLength;
niklase@google.com470e71d2011-07-07 08:21:25 +0000267}
268
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000269WebRtc_UWord16 RTPSender::PacketOverHead() const {
270 return _packetOverHead;
niklase@google.com470e71d2011-07-07 08:21:25 +0000271}
272
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000273void RTPSender::SetRTXStatus(const bool enable,
274 const bool setSSRC,
275 const WebRtc_UWord32 SSRC) {
276 CriticalSectionScoped cs(_sendCritsect);
277 _RTX = enable;
278 if (enable) {
279 if (setSSRC) {
280 _ssrcRTX = SSRC;
281 } else {
282 _ssrcRTX = _ssrcDB.CreateSSRC(); // can't be 0
283 }
284 }
285}
286
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000287void RTPSender::RTXStatus(bool* enable, WebRtc_UWord32* SSRC) const {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000288 CriticalSectionScoped cs(_sendCritsect);
289 *enable = _RTX;
290 *SSRC = _ssrcRTX;
291}
292
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000293WebRtc_Word32 RTPSender::CheckPayloadType(const WebRtc_Word8 payloadType,
294 RtpVideoCodecTypes& videoType) {
295 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000296
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000297 if (payloadType < 0) {
298 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
299 "\tinvalid payloadType (%d)", payloadType);
300 return -1;
301 }
302 if (_audioConfigured) {
303 WebRtc_Word8 redPlType = -1;
304 if (_audio->RED(redPlType) == 0) {
305 // We have configured RED.
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000306 if (redPlType == payloadType) {
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000307 // And it's a match...
308 return 0;
309 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000310 }
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000311 }
312 if (_payloadType == payloadType) {
313 if (!_audioConfigured) {
314 videoType = _video->VideoCodecType();
niklase@google.com470e71d2011-07-07 08:21:25 +0000315 }
316 return 0;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000317 }
318 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
319 _payloadTypeMap.find(payloadType);
320 if (it == _payloadTypeMap.end()) {
321 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
322 "\tpayloadType:%d not registered", payloadType);
323 return -1;
324 }
325 _payloadType = payloadType;
326 ModuleRTPUtility::Payload* payload = it->second;
327 assert(payload);
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000328 if (!payload->audio && !_audioConfigured) {
329 _video->SetVideoCodecType(payload->typeSpecific.Video.videoCodecType);
330 videoType = payload->typeSpecific.Video.videoCodecType;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000331 _video->SetMaxConfiguredBitrateVideo(payload->typeSpecific.Video.maxRate);
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000332 }
333 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000334}
335
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000336WebRtc_Word32 RTPSender::SendOutgoingData(
337 const FrameType frame_type,
338 const WebRtc_Word8 payload_type,
339 const WebRtc_UWord32 capture_timestamp,
340 int64_t capture_time_ms,
341 const WebRtc_UWord8* payload_data,
342 const WebRtc_UWord32 payload_size,
343 const RTPFragmentationHeader* fragmentation,
344 VideoCodecInformation* codec_info,
345 const RTPVideoTypeHeader* rtp_type_hdr) {
346 {
347 // Drop this packet if we're not sending media packets.
348 CriticalSectionScoped cs(_sendCritsect);
349 if (!_sendingMedia) {
350 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000351 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000352 }
353 RtpVideoCodecTypes video_type = kRtpNoVideo;
354 if (CheckPayloadType(payload_type, video_type) != 0) {
355 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
356 "%s invalid argument failed to find payloadType:%d",
357 __FUNCTION__, payload_type);
358 return -1;
359 }
360
361 if (_audioConfigured) {
362 assert(frame_type == kAudioFrameSpeech ||
363 frame_type == kAudioFrameCN ||
364 frame_type == kFrameEmpty);
365
366 return _audio->SendAudio(frame_type, payload_type, capture_timestamp,
367 payload_data, payload_size,fragmentation);
368 } else {
369 assert(frame_type != kAudioFrameSpeech &&
370 frame_type != kAudioFrameCN);
371
372 if (frame_type == kFrameEmpty) {
373 return SendPaddingAccordingToBitrate(payload_type, capture_timestamp,
374 capture_time_ms);
niklase@google.com470e71d2011-07-07 08:21:25 +0000375 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000376 return _video->SendVideo(video_type,
377 frame_type,
378 payload_type,
379 capture_timestamp,
380 capture_time_ms,
381 payload_data,
382 payload_size,
383 fragmentation,
384 codec_info,
385 rtp_type_hdr);
386 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000387}
388
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000389WebRtc_Word32 RTPSender::SendPaddingAccordingToBitrate(
390 WebRtc_Word8 payload_type,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000391 WebRtc_UWord32 capture_timestamp,
392 int64_t capture_time_ms) {
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000393 // Current bitrate since last estimate(1 second) averaged with the
394 // estimate since then, to get the most up to date bitrate.
395 uint32_t current_bitrate = BitrateNow();
396 int bitrate_diff = _targetSendBitrate * 1000 - current_bitrate;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000397 if (bitrate_diff <= 0) {
398 return 0;
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000399 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000400 int bytes = 0;
401 if (current_bitrate == 0) {
402 // Start up phase. Send one 33.3 ms batch to start with.
403 bytes = (bitrate_diff / 8) / 30;
404 } else {
405 bytes = (bitrate_diff / 8);
406 // Cap at 200 ms of target send data.
407 int bytes_cap = _targetSendBitrate * 25; // 1000 / 8 / 5
408 if (bytes > bytes_cap) {
409 bytes = bytes_cap;
410 }
411 }
412 return SendPadData(payload_type, capture_timestamp, capture_time_ms, bytes);
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000413}
414
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000415WebRtc_Word32 RTPSender::SendPadData(WebRtc_Word8 payload_type,
416 WebRtc_UWord32 capture_timestamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000417 int64_t capture_time_ms,
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000418 WebRtc_Word32 bytes) {
419 // Drop this packet if we're not sending media packets
420 if (!_sendingMedia) {
421 return 0;
422 }
423 // Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP.
424 int max_length = 224;
425 WebRtc_UWord8 data_buffer[IP_PACKET_SIZE];
426
427 for (; bytes > 0; bytes -= max_length) {
asapersson@webrtc.org63a34f42012-04-20 13:20:27 +0000428 int padding_bytes_in_packet = max_length;
429 if (bytes < max_length) {
430 padding_bytes_in_packet = (bytes + 16) & 0xffe0; // Keep our modulus 32.
431 }
432 if (padding_bytes_in_packet < 32) {
433 // Sanity don't send empty packets.
434 break;
435 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000436 // Correct seq num, timestamp and payload type.
437 int header_length = BuildRTPheader(data_buffer,
438 payload_type,
439 false, // No markerbit.
440 capture_timestamp,
441 true, // Timestamp provided.
442 true); // Increment sequence number.
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000443 data_buffer[0] |= 0x20; // Set padding bit.
444 WebRtc_Word32* data =
445 reinterpret_cast<WebRtc_Word32*>(&(data_buffer[header_length]));
446
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000447 // Fill data buffer with random data.
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000448 for (int j = 0; j < (padding_bytes_in_packet >> 2); j++) {
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000449 data[j] = rand();
450 }
451 // Set number of padding bytes in the last byte of the packet.
452 data_buffer[header_length + padding_bytes_in_packet - 1] =
453 padding_bytes_in_packet;
454 // Send the packet
455 if (0 > SendToNetwork(data_buffer,
456 padding_bytes_in_packet,
457 header_length,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000458 capture_time_ms,
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000459 kDontRetransmit)) {
460 // Error sending the packet.
461 break;
462 }
463 }
464 if (bytes > 31) { // 31 due to our modulus 32.
465 // We did not manage to send all bytes.
466 return -1;
467 }
468 return 0;
469}
470
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000471void RTPSender::SetStorePacketsStatus(
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000472 const bool enable,
473 const WebRtc_UWord16 numberToStore) {
474 _packetHistory->SetStorePacketsStatus(enable, numberToStore);
niklase@google.com470e71d2011-07-07 08:21:25 +0000475}
476
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000477bool RTPSender::StorePackets() const {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000478 return _packetHistory->StorePackets();
niklase@google.com470e71d2011-07-07 08:21:25 +0000479}
480
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000481WebRtc_Word32 RTPSender::ReSendPacket(WebRtc_UWord16 packet_id,
482 WebRtc_UWord32 min_resend_time) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000483
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000484 WebRtc_UWord16 length = IP_PACKET_SIZE;
485 WebRtc_UWord8 data_buffer[IP_PACKET_SIZE];
486 WebRtc_UWord8* buffer_to_send_ptr = data_buffer;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000487
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000488 int64_t stored_time_in_ms;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000489 StorageType type;
490 bool found = _packetHistory->GetRTPPacket(packet_id,
491 min_resend_time, data_buffer, &length, &stored_time_in_ms, &type);
492 if (!found) {
493 // Packet not found.
asapersson@webrtc.org83ed0a42012-04-23 12:43:05 +0000494 return 0;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000495 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000496 if (length == 0 || type == kDontRetransmit) {
497 // No bytes copied (packet recently resent, skip resending) or
498 // packet should not be retransmitted.
499 return 0;
500 }
pwestin@webrtc.orgb30f0ed2012-01-23 16:23:31 +0000501 WebRtc_UWord8 data_buffer_rtx[IP_PACKET_SIZE];
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000502 if (_RTX) {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000503 buffer_to_send_ptr = data_buffer_rtx;
504
505 CriticalSectionScoped cs(_sendCritsect);
506 // Add RTX header.
507 ModuleRTPUtility::RTPHeaderParser rtpParser(
508 reinterpret_cast<const WebRtc_UWord8*>(data_buffer),
509 length);
510
511 WebRtcRTPHeader rtp_header;
512 rtpParser.Parse(rtp_header);
513
514 // Add original RTP header.
515 memcpy(data_buffer_rtx, data_buffer, rtp_header.header.headerLength);
516
517 // Replace sequence number.
518 WebRtc_UWord8* ptr = data_buffer_rtx + 2;
519 ModuleRTPUtility::AssignUWord16ToBuffer(ptr, _sequenceNumberRTX++);
520
521 // Replace SSRC.
522 ptr += 6;
523 ModuleRTPUtility::AssignUWord32ToBuffer(ptr, _ssrcRTX);
524
525 // Add OSN (original sequence number).
526 ptr = data_buffer_rtx + rtp_header.header.headerLength;
527 ModuleRTPUtility::AssignUWord16ToBuffer(
528 ptr, rtp_header.header.sequenceNumber);
529 ptr += 2;
530
531 // Add original payload data.
532 memcpy(ptr,
533 data_buffer + rtp_header.header.headerLength,
534 length - rtp_header.header.headerLength);
535 length += 2;
536 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000537 WebRtc_Word32 bytes_sent = ReSendToNetwork(buffer_to_send_ptr, length);
538 if (bytes_sent <= 0) {
539 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
540 "Transport failed to resend packet_id %u", packet_id);
541 return -1;
542 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000543 // Store the time when the packet was last resent.
544 _packetHistory->UpdateResendTime(packet_id);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000545 return bytes_sent;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000546}
547
548WebRtc_Word32 RTPSender::ReSendToNetwork(const WebRtc_UWord8* packet,
549 const WebRtc_UWord32 size) {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000550 WebRtc_Word32 bytes_sent = -1;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000551 if (_transport) {
552 bytes_sent = _transport->SendPacket(_id, packet, size);
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000553 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000554 if (bytes_sent <= 0) {
555 return -1;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000556 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000557 // Update send statistics
558 CriticalSectionScoped cs(_sendCritsect);
559 Bitrate::Update(bytes_sent);
560 _packetsSent++;
561 // We on purpose don't add to _payloadBytesSent since this is a
562 // re-transmit and not new payload data.
563 return bytes_sent;
niklase@google.com470e71d2011-07-07 08:21:25 +0000564}
565
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000566int RTPSender::SelectiveRetransmissions() const {
567 if (!_video) return -1;
568 return _video->SelectiveRetransmissions();
569}
570
571int RTPSender::SetSelectiveRetransmissions(uint8_t settings) {
572 if (!_video) return -1;
573 return _video->SetSelectiveRetransmissions(settings);
574}
575
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000576void RTPSender::OnReceivedNACK(const WebRtc_UWord16 nackSequenceNumbersLength,
577 const WebRtc_UWord16* nackSequenceNumbers,
578 const WebRtc_UWord16 avgRTT) {
579 const WebRtc_Word64 now = _clock.GetTimeInMS();
580 WebRtc_UWord32 bytesReSent = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000581
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000582 // Enough bandwidth to send NACK?
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000583 if (!ProcessNACKBitRate(now)) {
584 WEBRTC_TRACE(kTraceStream,
585 kTraceRtpRtcp,
586 _id,
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000587 "NACK bitrate reached. Skip sending NACK response. Target %d",
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000588 _targetSendBitrate);
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000589 return;
590 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000591
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000592 for (WebRtc_UWord16 i = 0; i < nackSequenceNumbersLength; ++i) {
593 const WebRtc_Word32 bytesSent = ReSendPacket(nackSequenceNumbers[i],
594 5+avgRTT);
595 if (bytesSent > 0) {
596 bytesReSent += bytesSent;
597 } else if (bytesSent == 0) {
598 // The packet has previously been resent.
599 // Try resending next packet in the list.
600 continue;
601 } else if (bytesSent < 0) {
602 // Failed to send one Sequence number. Give up the rest in this nack.
603 WEBRTC_TRACE(kTraceWarning,
604 kTraceRtpRtcp,
605 _id,
606 "Failed resending RTP packet %d, Discard rest of packets",
607 nackSequenceNumbers[i]);
608 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000609 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000610 // delay bandwidth estimate (RTT * BW)
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000611 if (_targetSendBitrate != 0 && avgRTT) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000612 // kbits/s * ms = bits => bits/8 = bytes
613 WebRtc_UWord32 targetBytes =
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000614 (static_cast<WebRtc_UWord32>(_targetSendBitrate) * avgRTT) >> 3;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000615 if (bytesReSent > targetBytes) {
616 break; // ignore the rest of the packets in the list
617 }
618 }
619 }
620 if (bytesReSent > 0) {
621 // TODO(pwestin) consolidate these two methods.
622 UpdateNACKBitRate(bytesReSent, now);
623 _nackBitrate.Update(bytesReSent);
624 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000625}
626
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000627bool RTPSender::ProcessNACKBitRate(const WebRtc_UWord32 now) {
628 WebRtc_UWord32 num = 0;
629 WebRtc_Word32 byteCount = 0;
630 const WebRtc_UWord32 avgInterval=1000;
niklase@google.com470e71d2011-07-07 08:21:25 +0000631
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000632 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000633
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000634 if (_targetSendBitrate == 0) {
635 return true;
636 }
637 for (num = 0; num < NACK_BYTECOUNT_SIZE; num++) {
638 if ((now - _nackByteCountTimes[num]) > avgInterval) {
639 // don't use data older than 1sec
640 break;
641 } else {
642 byteCount += _nackByteCount[num];
niklase@google.com470e71d2011-07-07 08:21:25 +0000643 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000644 }
645 WebRtc_Word32 timeInterval = avgInterval;
646 if (num == NACK_BYTECOUNT_SIZE) {
647 // More than NACK_BYTECOUNT_SIZE nack messages has been received
648 // during the last msgInterval
649 timeInterval = now - _nackByteCountTimes[num-1];
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000650 if (timeInterval < 0) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000651 timeInterval = avgInterval;
niklase@google.com470e71d2011-07-07 08:21:25 +0000652 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000653 }
654 return (byteCount*8) < (_targetSendBitrate * timeInterval);
niklase@google.com470e71d2011-07-07 08:21:25 +0000655}
656
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000657void RTPSender::UpdateNACKBitRate(const WebRtc_UWord32 bytes,
658 const WebRtc_UWord32 now) {
659 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000660
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000661 // save bitrate statistics
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000662 if (bytes > 0) {
663 if (now == 0) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000664 // add padding length
665 _nackByteCount[0] += bytes;
666 } else {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000667 if (_nackByteCountTimes[0] == 0) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000668 // first no shift
669 } else {
670 // shift
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000671 for (int i = (NACK_BYTECOUNT_SIZE-2); i >= 0 ; i--) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000672 _nackByteCount[i+1] = _nackByteCount[i];
673 _nackByteCountTimes[i+1] = _nackByteCountTimes[i];
niklase@google.com470e71d2011-07-07 08:21:25 +0000674 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000675 }
676 _nackByteCount[0] = bytes;
677 _nackByteCountTimes[0] = now;
niklase@google.com470e71d2011-07-07 08:21:25 +0000678 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000679 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000680}
681
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000682void RTPSender::TimeToSendPacket(uint16_t sequence_number,
683 int64_t capture_time_ms) {
684 StorageType type;
685 uint16_t length = IP_PACKET_SIZE;
686 uint8_t data_buffer[IP_PACKET_SIZE];
687 int64_t stored_time_ms; // TODO(pwestin) can we depricate this?
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000688
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000689 if (_packetHistory == NULL) {
690 return;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000691 }
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000692 if (!_packetHistory->GetRTPPacket(sequence_number, 0, data_buffer,
693 &length, &stored_time_ms, &type)) {
694 assert(false);
695 return;
696 }
697 assert(length > 0);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000698
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000699 ModuleRTPUtility::RTPHeaderParser rtpParser(data_buffer, length);
700 WebRtcRTPHeader rtp_header;
701 rtpParser.Parse(rtp_header);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000702
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000703 int64_t diff_ms = _clock.GetTimeInMS() - capture_time_ms;
704 if (UpdateTransmissionTimeOffset(data_buffer, length, rtp_header, diff_ms)) {
705 // Update stored packet in case of receiving a re-transmission request.
706 _packetHistory->ReplaceRTPHeader(data_buffer,
707 rtp_header.header.sequenceNumber,
708 rtp_header.header.headerLength);
709 }
710 int bytes_sent = -1;
711 if (_transport) {
712 bytes_sent = _transport->SendPacket(_id, data_buffer, length);
713 }
714 if (bytes_sent <= 0) {
715 return;
716 }
717 // Update send statistics
718 CriticalSectionScoped cs(_sendCritsect);
719 Bitrate::Update(bytes_sent);
720 _packetsSent++;
721 if (bytes_sent > rtp_header.header.headerLength) {
722 _payloadBytesSent += bytes_sent - rtp_header.header.headerLength;
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000723 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000724}
725
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000726// TODO(pwestin): send in the RTPHeaderParser to avoid parsing it again
727WebRtc_Word32 RTPSender::SendToNetwork(uint8_t* buffer,
728 int payload_length,
729 int rtp_header_length,
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000730 int64_t capture_time_ms,
731 StorageType storage) {
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000732 ModuleRTPUtility::RTPHeaderParser rtpParser(buffer,
733 payload_length + rtp_header_length);
734 WebRtcRTPHeader rtp_header;
735 rtpParser.Parse(rtp_header);
736
stefan@webrtc.org715faaf2012-08-28 15:20:39 +0000737 // |capture_time_ms| <= 0 is considered invalid.
738 // TODO(holmer): This should be changed all over Video Engine so that negative
739 // time is consider invalid, while 0 is considered a valid time.
740 if (capture_time_ms > 0) {
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000741 int64_t time_now = _clock.GetTimeInMS();
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000742 UpdateTransmissionTimeOffset(buffer, payload_length + rtp_header_length,
743 rtp_header, time_now - capture_time_ms);
744 }
745 // Used for NACK and to spread out the transmission of packets.
746 if (_packetHistory->PutRTPPacket(buffer, rtp_header_length + payload_length,
747 _maxPayloadLength, capture_time_ms, storage) != 0) {
748 return -1;
749 }
750 if (paced_sender_) {
751 if (!paced_sender_ ->SendPacket(PacedSender::kNormalPriority,
752 rtp_header.header.ssrc,
753 rtp_header.header.sequenceNumber,
754 capture_time_ms,
755 payload_length + rtp_header_length)) {
756 // We can't send the packet right now.
757 // We will be called when it is time.
758 return payload_length + rtp_header_length;
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000759 }
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000760 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000761 // Send packet
762 WebRtc_Word32 bytes_sent = -1;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000763 if (_transport) {
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000764 bytes_sent = _transport->SendPacket(_id,
765 buffer,
766 payload_length + rtp_header_length);
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000767 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000768 if (bytes_sent <= 0) {
769 return -1;
770 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000771 // Update send statistics
772 CriticalSectionScoped cs(_sendCritsect);
773 Bitrate::Update(bytes_sent);
774 _packetsSent++;
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000775 if (bytes_sent > rtp_header_length) {
776 _payloadBytesSent += bytes_sent - rtp_header_length;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000777 }
778 return 0;
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000779}
780
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000781void RTPSender::ProcessBitrate() {
782 CriticalSectionScoped cs(_sendCritsect);
783 Bitrate::Process();
784 _nackBitrate.Process();
785 if (_audioConfigured) {
786 return;
787 }
788 _video->ProcessBitrate();
niklase@google.com470e71d2011-07-07 08:21:25 +0000789}
790
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000791WebRtc_UWord16 RTPSender::RTPHeaderLength() const {
792 WebRtc_UWord16 rtpHeaderLength = 12;
793 if (_includeCSRCs) {
794 rtpHeaderLength += sizeof(WebRtc_UWord32)*_CSRCs;
795 }
796 rtpHeaderLength += RtpHeaderExtensionTotalLength();
797 return rtpHeaderLength;
niklase@google.com470e71d2011-07-07 08:21:25 +0000798}
799
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000800WebRtc_UWord16 RTPSender::IncrementSequenceNumber() {
801 CriticalSectionScoped cs(_sendCritsect);
802 return _sequenceNumber++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000803}
804
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000805void RTPSender::ResetDataCounters() {
806 _packetsSent = 0;
807 _payloadBytesSent = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000808}
809
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000810WebRtc_UWord32 RTPSender::Packets() const {
811 // Don't use critsect to avoid potental deadlock
812 return _packetsSent;
niklase@google.com470e71d2011-07-07 08:21:25 +0000813}
814
815// number of sent RTP bytes
816// dont use critsect to avoid potental deadlock
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000817WebRtc_UWord32 RTPSender::Bytes() const {
818 return _payloadBytesSent;
niklase@google.com470e71d2011-07-07 08:21:25 +0000819}
820
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000821WebRtc_Word32 RTPSender::BuildRTPheader(WebRtc_UWord8* dataBuffer,
822 const WebRtc_Word8 payloadType,
823 const bool markerBit,
824 const WebRtc_UWord32 captureTimeStamp,
825 const bool timeStampProvided,
826 const bool incSequenceNumber) {
827 assert(payloadType>=0);
828 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000829
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000830 dataBuffer[0] = static_cast<WebRtc_UWord8>(0x80); // version 2
831 dataBuffer[1] = static_cast<WebRtc_UWord8>(payloadType);
832 if (markerBit) {
833 dataBuffer[1] |= kRtpMarkerBitMask; // MarkerBit is set
834 }
835 if (timeStampProvided) {
836 _timeStamp = _startTimeStamp + captureTimeStamp;
837 } else {
838 // make a unique time stamp
839 // we can't inc by the actual time, since then we increase the risk of back
840 // timing.
841 _timeStamp++;
842 }
843 ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer+2, _sequenceNumber);
844 ModuleRTPUtility::AssignUWord32ToBuffer(dataBuffer+4, _timeStamp);
845 ModuleRTPUtility::AssignUWord32ToBuffer(dataBuffer+8, _ssrc);
846 WebRtc_Word32 rtpHeaderLength = 12;
niklase@google.com470e71d2011-07-07 08:21:25 +0000847
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000848 // Add the CSRCs if any
849 if (_includeCSRCs && _CSRCs > 0) {
850 if (_CSRCs > kRtpCsrcSize) {
851 // error
852 assert(false);
853 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000854 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000855 WebRtc_UWord8* ptr = &dataBuffer[rtpHeaderLength];
856 for (WebRtc_UWord32 i = 0; i < _CSRCs; ++i) {
857 ModuleRTPUtility::AssignUWord32ToBuffer(ptr, _CSRC[i]);
858 ptr +=4;
niklase@google.com470e71d2011-07-07 08:21:25 +0000859 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000860 dataBuffer[0] = (dataBuffer[0]&0xf0) | _CSRCs;
niklase@google.com470e71d2011-07-07 08:21:25 +0000861
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000862 // Update length of header
863 rtpHeaderLength += sizeof(WebRtc_UWord32)*_CSRCs;
864 }
865 _sequenceNumber++; // prepare for next packet
niklase@google.com470e71d2011-07-07 08:21:25 +0000866
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000867 WebRtc_UWord16 len = BuildRTPHeaderExtension(dataBuffer + rtpHeaderLength);
868 if (len) {
869 dataBuffer[0] |= 0x10; // set eXtension bit
870 rtpHeaderLength += len;
871 }
872 return rtpHeaderLength;
niklase@google.com470e71d2011-07-07 08:21:25 +0000873}
874
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000875WebRtc_UWord16 RTPSender::BuildRTPHeaderExtension(
876 WebRtc_UWord8* dataBuffer) const {
877 if (_rtpHeaderExtensionMap.Size() <= 0) {
878 return 0;
879 }
880 /* RTP header extension, RFC 3550.
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000881 0 1 2 3
882 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
883 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
884 | defined by profile | length |
885 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
886 | header extension |
887 | .... |
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000888 */
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000889 const WebRtc_UWord32 kPosLength = 2;
890 const WebRtc_UWord32 kHeaderLength = RTP_ONE_BYTE_HEADER_LENGTH_IN_BYTES;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000891
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000892 // Add extension ID (0xBEDE).
893 ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer,
894 RTP_ONE_BYTE_HEADER_EXTENSION);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000895
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000896 // Add extensions.
897 WebRtc_UWord16 total_block_length = 0;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000898
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000899 RTPExtensionType type = _rtpHeaderExtensionMap.First();
900 while (type != kRtpExtensionNone) {
901 WebRtc_UWord8 block_length = 0;
902 if (type == kRtpExtensionTransmissionTimeOffset) {
903 block_length = BuildTransmissionTimeOffsetExtension(
904 dataBuffer + kHeaderLength + total_block_length);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000905 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000906 total_block_length += block_length;
907 type = _rtpHeaderExtensionMap.Next(type);
908 }
909 if (total_block_length == 0) {
910 // No extension added.
911 return 0;
912 }
913 // Set header length (in number of Word32, header excluded).
914 assert(total_block_length % 4 == 0);
915 ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer + kPosLength,
916 total_block_length / 4);
917 // Total added length.
918 return kHeaderLength + total_block_length;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000919}
920
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000921WebRtc_UWord8 RTPSender::BuildTransmissionTimeOffsetExtension(
922 WebRtc_UWord8* dataBuffer) const {
923 // From RFC 5450: Transmission Time Offsets in RTP Streams.
924 //
925 // The transmission time is signaled to the receiver in-band using the
926 // general mechanism for RTP header extensions [RFC5285]. The payload
927 // of this extension (the transmitted value) is a 24-bit signed integer.
928 // When added to the RTP timestamp of the packet, it represents the
929 // "effective" RTP transmission time of the packet, on the RTP
930 // timescale.
931 //
932 // The form of the transmission offset extension block:
933 //
934 // 0 1 2 3
935 // 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
936 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
937 // | ID | len=2 | transmission offset |
938 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000939
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000940 // Get id defined by user.
941 WebRtc_UWord8 id;
942 if (_rtpHeaderExtensionMap.GetId(kRtpExtensionTransmissionTimeOffset, &id)
943 != 0) {
944 // Not registered.
945 return 0;
946 }
947 int pos = 0;
948 const WebRtc_UWord8 len = 2;
949 dataBuffer[pos++] = (id << 4) + len;
950 ModuleRTPUtility::AssignUWord24ToBuffer(dataBuffer + pos,
951 _transmissionTimeOffset);
952 pos += 3;
953 assert(pos == TRANSMISSION_TIME_OFFSET_LENGTH_IN_BYTES);
954 return TRANSMISSION_TIME_OFFSET_LENGTH_IN_BYTES;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000955}
956
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000957bool RTPSender::UpdateTransmissionTimeOffset(
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000958 WebRtc_UWord8* rtp_packet,
959 const WebRtc_UWord16 rtp_packet_length,
960 const WebRtcRTPHeader& rtp_header,
mflodman@webrtc.orgba853c92012-08-10 14:30:53 +0000961 const WebRtc_Word64 time_diff_ms) const {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000962 CriticalSectionScoped cs(_sendCritsect);
963
964 // Get length until start of transmission block.
965 int transmission_block_pos =
966 _rtpHeaderExtensionMap.GetLengthUntilBlockStartInBytes(
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000967 kRtpExtensionTransmissionTimeOffset);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000968 if (transmission_block_pos < 0) {
969 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000970 "Failed to update transmission time offset, not registered.");
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000971 return false;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000972 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000973 int block_pos = 12 + rtp_header.header.numCSRCs + transmission_block_pos;
mflodman@webrtc.orgba853c92012-08-10 14:30:53 +0000974 if (rtp_packet_length < block_pos + 4 ||
975 rtp_header.header.headerLength < block_pos + 4) {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000976 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000977 "Failed to update transmission time offset, invalid length.");
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000978 return false;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000979 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000980 // Verify that header contains extension.
981 if (!((rtp_packet[12 + rtp_header.header.numCSRCs] == 0xBE) &&
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000982 (rtp_packet[12 + rtp_header.header.numCSRCs + 1] == 0xDE))) {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000983 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
984 "Failed to update transmission time offset, hdr extension not found.");
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000985 return false;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000986 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000987 // Get id.
988 WebRtc_UWord8 id = 0;
989 if (_rtpHeaderExtensionMap.GetId(kRtpExtensionTransmissionTimeOffset,
990 &id) != 0) {
991 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000992 "Failed to update transmission time offset, no id.");
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000993 return false;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000994 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000995 // Verify first byte in block.
996 const WebRtc_UWord8 first_block_byte = (id << 4) + 2;
997 if (rtp_packet[block_pos] != first_block_byte) {
998 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000999 "Failed to update transmission time offset.");
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +00001000 return false;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001001 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001002 // Update transmission offset field.
1003 ModuleRTPUtility::AssignUWord24ToBuffer(rtp_packet + block_pos + 1,
mflodman@webrtc.orgba853c92012-08-10 14:30:53 +00001004 time_diff_ms * 90); // RTP timestamp.
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +00001005 return true;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001006}
1007
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001008void RTPSender::SetSendingStatus(const bool enabled) {
1009 if (enabled) {
1010 WebRtc_UWord32 freq;
1011 if (_audioConfigured) {
1012 WebRtc_UWord32 frequency = _audio->AudioFrequency();
1013
1014 // sanity
1015 switch(frequency) {
1016 case 8000:
1017 case 12000:
1018 case 16000:
1019 case 24000:
1020 case 32000:
1021 break;
1022 default:
1023 assert(false);
1024 return;
1025 }
1026 freq = frequency;
1027 } else {
1028 freq = 90000; // 90 KHz for all video
1029 }
1030 WebRtc_UWord32 RTPtime = ModuleRTPUtility::GetCurrentRTP(&_clock, freq);
1031
1032 // will be ignored if it's already configured via API
1033 SetStartTimestamp(RTPtime, false);
1034 } else {
1035 if (!_ssrcForced) {
1036 // generate a new SSRC
1037 _ssrcDB.ReturnSSRC(_ssrc);
1038 _ssrc = _ssrcDB.CreateSSRC(); // can't be 0
1039
1040 }
1041 // Don't initialize seq number if SSRC passed externally.
1042 if (!_sequenceNumberForced && !_ssrcForced) {
1043 // generate a new sequence number
1044 _sequenceNumber = rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);
1045 }
1046 }
1047}
1048
1049void RTPSender::SetSendingMediaStatus(const bool enabled) {
1050 CriticalSectionScoped cs(_sendCritsect);
1051 _sendingMedia = enabled;
1052}
1053
1054bool RTPSender::SendingMedia() const {
1055 CriticalSectionScoped cs(_sendCritsect);
1056 return _sendingMedia;
1057}
1058
1059WebRtc_UWord32 RTPSender::Timestamp() const {
1060 CriticalSectionScoped cs(_sendCritsect);
1061 return _timeStamp;
1062}
1063
1064void RTPSender::SetStartTimestamp(WebRtc_UWord32 timestamp, bool force) {
1065 CriticalSectionScoped cs(_sendCritsect);
1066 if (force) {
1067 _startTimeStampForced = force;
1068 _startTimeStamp = timestamp;
1069 } else {
1070 if (!_startTimeStampForced) {
1071 _startTimeStamp = timestamp;
1072 }
1073 }
1074}
1075
1076WebRtc_UWord32 RTPSender::StartTimestamp() const {
1077 CriticalSectionScoped cs(_sendCritsect);
1078 return _startTimeStamp;
1079}
1080
1081WebRtc_UWord32 RTPSender::GenerateNewSSRC() {
1082 // if configured via API, return 0
1083 CriticalSectionScoped cs(_sendCritsect);
1084
1085 if (_ssrcForced) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001086 return 0;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001087 }
1088 _ssrc = _ssrcDB.CreateSSRC(); // can't be 0
1089 return _ssrc;
niklase@google.com470e71d2011-07-07 08:21:25 +00001090}
1091
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001092void RTPSender::SetSSRC(WebRtc_UWord32 ssrc) {
1093 // this is configured via the API
1094 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001095
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001096 if (_ssrc == ssrc && _ssrcForced) {
1097 return; // since it's same ssrc, don't reset anything
1098 }
1099 _ssrcForced = true;
1100 _ssrcDB.ReturnSSRC(_ssrc);
1101 _ssrcDB.RegisterSSRC(ssrc);
1102 _ssrc = ssrc;
1103 if (!_sequenceNumberForced) {
1104 _sequenceNumber = rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);
1105 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001106}
1107
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001108WebRtc_UWord32 RTPSender::SSRC() const {
1109 CriticalSectionScoped cs(_sendCritsect);
1110 return _ssrc;
niklase@google.com470e71d2011-07-07 08:21:25 +00001111}
1112
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001113void RTPSender::SetCSRCStatus(const bool include) {
1114 _includeCSRCs = include;
niklase@google.com470e71d2011-07-07 08:21:25 +00001115}
1116
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001117void RTPSender::SetCSRCs(const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize],
1118 const WebRtc_UWord8 arrLength) {
1119 assert(arrLength <= kRtpCsrcSize);
1120 CriticalSectionScoped cs(_sendCritsect);
1121
1122 for (int i = 0; i < arrLength;i++) {
1123 _CSRC[i] = arrOfCSRC[i];
1124 }
1125 _CSRCs = arrLength;
niklase@google.com470e71d2011-07-07 08:21:25 +00001126}
1127
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001128WebRtc_Word32 RTPSender::CSRCs(WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]) const {
1129 assert(arrOfCSRC);
1130 CriticalSectionScoped cs(_sendCritsect);
1131 for (int i = 0; i < _CSRCs && i < kRtpCsrcSize;i++) {
1132 arrOfCSRC[i] = _CSRC[i];
1133 }
1134 return _CSRCs;
niklase@google.com470e71d2011-07-07 08:21:25 +00001135}
1136
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001137void RTPSender::SetSequenceNumber(WebRtc_UWord16 seq) {
1138 CriticalSectionScoped cs(_sendCritsect);
1139 _sequenceNumberForced = true;
1140 _sequenceNumber = seq;
niklase@google.com470e71d2011-07-07 08:21:25 +00001141}
1142
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001143WebRtc_UWord16 RTPSender::SequenceNumber() const {
1144 CriticalSectionScoped cs(_sendCritsect);
1145 return _sequenceNumber;
niklase@google.com470e71d2011-07-07 08:21:25 +00001146}
1147
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001148/*
1149 * Audio
1150 */
1151WebRtc_Word32 RTPSender::SendTelephoneEvent(const WebRtc_UWord8 key,
1152 const WebRtc_UWord16 time_ms,
1153 const WebRtc_UWord8 level) {
1154 if (!_audioConfigured) {
1155 return -1;
1156 }
1157 return _audio->SendTelephoneEvent(key, time_ms, level);
niklase@google.com470e71d2011-07-07 08:21:25 +00001158}
1159
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001160bool RTPSender::SendTelephoneEventActive(WebRtc_Word8& telephoneEvent) const {
1161 if (!_audioConfigured) {
1162 return false;
1163 }
1164 return _audio->SendTelephoneEventActive(telephoneEvent);
niklase@google.com470e71d2011-07-07 08:21:25 +00001165}
1166
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001167WebRtc_Word32 RTPSender::SetAudioPacketSize(
1168 const WebRtc_UWord16 packetSizeSamples) {
1169 if (!_audioConfigured) {
1170 return -1;
1171 }
1172 return _audio->SetAudioPacketSize(packetSizeSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00001173}
1174
1175WebRtc_Word32
1176RTPSender::SetAudioLevelIndicationStatus(const bool enable,
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001177 const WebRtc_UWord8 ID) {
1178 if (!_audioConfigured) {
1179 return -1;
1180 }
1181 return _audio->SetAudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00001182}
1183
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001184WebRtc_Word32 RTPSender::AudioLevelIndicationStatus(bool& enable,
1185 WebRtc_UWord8& ID) const {
1186 return _audio->AudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00001187}
1188
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001189WebRtc_Word32 RTPSender::SetAudioLevel(const WebRtc_UWord8 level_dBov) {
1190 return _audio->SetAudioLevel(level_dBov);
niklase@google.com470e71d2011-07-07 08:21:25 +00001191}
1192
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001193WebRtc_Word32 RTPSender::SetRED(const WebRtc_Word8 payloadType) {
1194 if (!_audioConfigured) {
1195 return -1;
1196 }
1197 return _audio->SetRED(payloadType);
niklase@google.com470e71d2011-07-07 08:21:25 +00001198}
1199
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001200WebRtc_Word32 RTPSender::RED(WebRtc_Word8& payloadType) const {
1201 if (!_audioConfigured) {
1202 return -1;
1203 }
1204 return _audio->RED(payloadType);
niklase@google.com470e71d2011-07-07 08:21:25 +00001205}
1206
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001207/*
1208 * Video
1209 */
1210VideoCodecInformation* RTPSender::CodecInformationVideo() {
1211 if (_audioConfigured) {
1212 return NULL;
1213 }
1214 return _video->CodecInformationVideo();
niklase@google.com470e71d2011-07-07 08:21:25 +00001215}
1216
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001217RtpVideoCodecTypes RTPSender::VideoCodecType() const {
1218 if (_audioConfigured) {
1219 return kRtpNoVideo;
1220 }
1221 return _video->VideoCodecType();
niklase@google.com470e71d2011-07-07 08:21:25 +00001222}
1223
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001224WebRtc_UWord32 RTPSender::MaxConfiguredBitrateVideo() const {
1225 if (_audioConfigured) {
1226 return 0;
1227 }
1228 return _video->MaxConfiguredBitrateVideo();
niklase@google.com470e71d2011-07-07 08:21:25 +00001229}
1230
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001231WebRtc_Word32 RTPSender::SendRTPIntraRequest() {
1232 if (_audioConfigured) {
1233 return -1;
1234 }
1235 return _video->SendRTPIntraRequest();
niklase@google.com470e71d2011-07-07 08:21:25 +00001236}
1237
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001238WebRtc_Word32 RTPSender::SetGenericFECStatus(
1239 const bool enable,
1240 const WebRtc_UWord8 payloadTypeRED,
1241 const WebRtc_UWord8 payloadTypeFEC) {
1242 if (_audioConfigured) {
1243 return -1;
1244 }
1245 return _video->SetGenericFECStatus(enable, payloadTypeRED, payloadTypeFEC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001246}
1247
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001248WebRtc_Word32 RTPSender::GenericFECStatus(bool& enable,
1249 WebRtc_UWord8& payloadTypeRED,
1250 WebRtc_UWord8& payloadTypeFEC) const {
1251 if (_audioConfigured) {
1252 return -1;
1253 }
1254 return _video->GenericFECStatus(enable, payloadTypeRED, payloadTypeFEC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001255}
1256
stefan@webrtc.orge0d6fa42012-03-20 22:10:56 +00001257WebRtc_Word32 RTPSender::SetFecParameters(
1258 const FecProtectionParams* delta_params,
1259 const FecProtectionParams* key_params) {
1260 if (_audioConfigured) {
1261 return -1;
1262 }
1263 return _video->SetFecParameters(delta_params, key_params);
marpan@google.com80c5d7a2011-07-15 21:32:40 +00001264}
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001265} // namespace webrtc