blob: 259f0bebe04408984d6e090c311a275d2550ab88 [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
11#include <cstdlib> // srand
12
13#include "rtp_sender.h"
14
15#include "critical_section_wrapper.h"
16#include "trace.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000017
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +000018#include "rtp_packet_history.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000019#include "rtp_sender_audio.h"
20#include "rtp_sender_video.h"
21
22namespace webrtc {
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000023RTPSender::RTPSender(const WebRtc_Word32 id,
24 const bool audio,
25 RtpRtcpClock* clock) :
26 Bitrate(clock),
niklase@google.com470e71d2011-07-07 08:21:25 +000027 _id(id),
28 _audioConfigured(audio),
29 _audio(NULL),
30 _video(NULL),
henrike@webrtc.org65573f22011-12-13 19:17:27 +000031 _sendCritsect(CriticalSectionWrapper::CreateCriticalSection()),
32 _transportCritsect(CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +000033
34 _transport(NULL),
35
36 _sendingMedia(true), // Default to sending media
37
38 _maxPayloadLength(IP_PACKET_SIZE-28), // default is IP/UDP
39 _targetSendBitrate(0),
40 _packetOverHead(28),
41
42 _payloadType(-1),
43 _payloadTypeMap(),
44
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +000045 _rtpHeaderExtensionMap(),
46 _transmissionTimeOffset(0),
47
niklase@google.com470e71d2011-07-07 08:21:25 +000048 // NACK
49 _nackByteCountTimes(),
50 _nackByteCount(),
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000051 _nackBitrate(clock),
niklase@google.com470e71d2011-07-07 08:21:25 +000052
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +000053 _packetHistory(new RTPPacketHistory(clock)),
asapersson@webrtc.org23fd5592012-09-24 12:07:13 +000054 _sendBucket(clock),
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +000055 _timeLastSendToNetworkUpdate(clock->GetTimeInMS()),
56 _transmissionSmoothing(false),
57
niklase@google.com470e71d2011-07-07 08:21:25 +000058 // statistics
59 _packetsSent(0),
60 _payloadBytesSent(0),
61
62 // RTP variables
63 _startTimeStampForced(false),
64 _startTimeStamp(0),
65 _ssrcDB(*SSRCDatabase::GetSSRCDatabase()),
66 _remoteSSRC(0),
67 _sequenceNumberForced(false),
68 _sequenceNumber(0),
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +000069 _sequenceNumberRTX(0),
niklase@google.com470e71d2011-07-07 08:21:25 +000070 _ssrcForced(false),
71 _ssrc(0),
72 _timeStamp(0),
73 _CSRCs(0),
74 _CSRC(),
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +000075 _includeCSRCs(true),
76 _RTX(false),
77 _ssrcRTX(0)
niklase@google.com470e71d2011-07-07 08:21:25 +000078{
79 memset(_nackByteCountTimes, 0, sizeof(_nackByteCountTimes));
80 memset(_nackByteCount, 0, sizeof(_nackByteCount));
81
82 memset(_CSRC, 0, sizeof(_CSRC));
83
84 // we need to seed the random generator, otherwise we get 26500 each time, hardly a random value :)
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000085 srand( (WebRtc_UWord32)_clock.GetTimeInMS() );
niklase@google.com470e71d2011-07-07 08:21:25 +000086
87 _ssrc = _ssrcDB.CreateSSRC(); // can't be 0
88
89 if(audio)
90 {
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000091 _audio = new RTPSenderAudio(id, &_clock, this);
niklase@google.com470e71d2011-07-07 08:21:25 +000092 } else
93 {
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000094 _video = new RTPSenderVideo(id, &_clock, this);
niklase@google.com470e71d2011-07-07 08:21:25 +000095 }
96 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
97}
98
pwestin@webrtc.org00741872012-01-19 15:56:10 +000099RTPSender::~RTPSender() {
100 if(_remoteSSRC != 0) {
101 _ssrcDB.ReturnSSRC(_remoteSSRC);
102 }
103 _ssrcDB.ReturnSSRC(_ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000104
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000105 SSRCDatabase::ReturnSSRCDatabase();
106 delete _sendCritsect;
107 delete _transportCritsect;
108 while (!_payloadTypeMap.empty()) {
109 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
110 _payloadTypeMap.begin();
111 delete it->second;
112 _payloadTypeMap.erase(it);
113 }
114 delete _packetHistory;
115 delete _audio;
116 delete _video;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000117
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000118 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, _id, "%s deleted", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +0000119}
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000120/*
niklase@google.com470e71d2011-07-07 08:21:25 +0000121WebRtc_Word32
122RTPSender::Init(const WebRtc_UWord32 remoteSSRC)
123{
124 CriticalSectionScoped cs(_sendCritsect);
125
126 // reset to default generation
127 _ssrcForced = false;
128 _startTimeStampForced = false;
129
130 // register a remote SSRC if we have it to avoid collisions
131 if(remoteSSRC != 0)
132 {
133 if(_ssrc == remoteSSRC)
134 {
135 // collision detected
136 _ssrc = _ssrcDB.CreateSSRC(); // can't be 0
137 }
138 _remoteSSRC = remoteSSRC;
139 _ssrcDB.RegisterSSRC(remoteSSRC);
140 }
141 _sequenceNumber = rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000142 _sequenceNumberRTX = rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);
niklase@google.com470e71d2011-07-07 08:21:25 +0000143 _packetsSent = 0;
144 _payloadBytesSent = 0;
145 _packetOverHead = 28;
146
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000147 _rtpHeaderExtensionMap.Erase();
148
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000149 while (!_payloadTypeMap.empty()) {
150 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
151 _payloadTypeMap.begin();
152 delete it->second;
153 _payloadTypeMap.erase(it);
154 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000155
156 memset(_CSRC, 0, sizeof(_CSRC));
157
158 memset(_nackByteCount, 0, sizeof(_nackByteCount));
159 memset(_nackByteCountTimes, 0, sizeof(_nackByteCountTimes));
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000160 _nackBitrate.Init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000161
162 SetStorePacketsStatus(false, 0);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000163 _sendBucket.Reset();
niklase@google.com470e71d2011-07-07 08:21:25 +0000164
165 Bitrate::Init();
166
167 if(_audioConfigured)
168 {
169 _audio->Init();
170 } else
171 {
172 _video->Init();
173 }
174 return(0);
175}
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000176*/
niklase@google.com470e71d2011-07-07 08:21:25 +0000177
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000178void RTPSender::SetTargetSendBitrate(const WebRtc_UWord32 bits) {
179 _targetSendBitrate = static_cast<uint16_t>(bits / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +0000180}
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000181
niklase@google.com470e71d2011-07-07 08:21:25 +0000182WebRtc_UWord16
183RTPSender::ActualSendBitrateKbit() const
184{
185 return (WebRtc_UWord16) (Bitrate::BitrateNow()/1000);
186}
187
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000188WebRtc_UWord32
stefan@webrtc.orgfbea4e52011-10-27 16:08:29 +0000189RTPSender::VideoBitrateSent() const {
190 if (_video)
191 return _video->VideoBitrateSent();
192 else
193 return 0;
194}
195
196WebRtc_UWord32
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000197RTPSender::FecOverheadRate() const {
stefan@webrtc.orgfbea4e52011-10-27 16:08:29 +0000198 if (_video)
199 return _video->FecOverheadRate();
200 else
201 return 0;
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000202}
203
204WebRtc_UWord32
205RTPSender::NackOverheadRate() const {
206 return _nackBitrate.BitrateLast();
207}
208
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000209WebRtc_Word32
210RTPSender::SetTransmissionTimeOffset(
211 const WebRtc_Word32 transmissionTimeOffset)
212{
213 if (transmissionTimeOffset > (0x800000 - 1) ||
214 transmissionTimeOffset < -(0x800000 - 1)) // Word24
215 {
216 return -1;
217 }
218 CriticalSectionScoped cs(_sendCritsect);
219 _transmissionTimeOffset = transmissionTimeOffset;
220 return 0;
221}
222
223WebRtc_Word32
224RTPSender::RegisterRtpHeaderExtension(const RTPExtensionType type,
225 const WebRtc_UWord8 id)
226{
227 CriticalSectionScoped cs(_sendCritsect);
228 return _rtpHeaderExtensionMap.Register(type, id);
229}
230
231WebRtc_Word32
232RTPSender::DeregisterRtpHeaderExtension(const RTPExtensionType type)
233{
234 CriticalSectionScoped cs(_sendCritsect);
235 return _rtpHeaderExtensionMap.Deregister(type);
236}
237
238WebRtc_UWord16
239RTPSender::RtpHeaderExtensionTotalLength() const
240{
241 CriticalSectionScoped cs(_sendCritsect);
242 return _rtpHeaderExtensionMap.GetTotalLengthInBytes();
243}
244
niklase@google.com470e71d2011-07-07 08:21:25 +0000245//can be called multiple times
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000246WebRtc_Word32 RTPSender::RegisterPayload(
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000247 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000248 const WebRtc_Word8 payloadNumber,
249 const WebRtc_UWord32 frequency,
250 const WebRtc_UWord8 channels,
251 const WebRtc_UWord32 rate) {
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000252 assert(payloadName);
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000253 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000254
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000255 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
256 _payloadTypeMap.find(payloadNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +0000257
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000258 if (_payloadTypeMap.end() != it) {
259 // we already use this payload type
260 ModuleRTPUtility::Payload* payload = it->second;
261 assert(payload);
niklase@google.com470e71d2011-07-07 08:21:25 +0000262
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000263 // check if it's the same as we already have
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000264 if (ModuleRTPUtility::StringCompare(payload->name, payloadName,
265 RTP_PAYLOAD_NAME_SIZE - 1)) {
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000266 if (_audioConfigured && payload->audio &&
267 payload->typeSpecific.Audio.frequency == frequency &&
268 (payload->typeSpecific.Audio.rate == rate ||
269 payload->typeSpecific.Audio.rate == 0 || rate == 0)) {
270 payload->typeSpecific.Audio.rate = rate;
271 // Ensure that we update the rate if new or old is zero
niklase@google.com470e71d2011-07-07 08:21:25 +0000272 return 0;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000273 }
274 if(!_audioConfigured && !payload->audio) {
275 return 0;
276 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000277 }
278 return -1;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000279 }
280 WebRtc_Word32 retVal = -1;
281 ModuleRTPUtility::Payload* payload = NULL;
282 if (_audioConfigured) {
283 retVal = _audio->RegisterAudioPayload(payloadName, payloadNumber, frequency,
284 channels, rate, payload);
285 } else {
286 retVal = _video->RegisterVideoPayload(payloadName, payloadNumber, rate,
287 payload);
288 }
289 if(payload) {
290 _payloadTypeMap[payloadNumber] = payload;
291 }
292 return retVal;
niklase@google.com470e71d2011-07-07 08:21:25 +0000293}
294
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000295WebRtc_Word32 RTPSender::DeRegisterSendPayload(const WebRtc_Word8 payloadType) {
296 CriticalSectionScoped lock(_sendCritsect);
297
298 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
299 _payloadTypeMap.find(payloadType);
300
301 if (_payloadTypeMap.end() == it) return -1;
302
303 ModuleRTPUtility::Payload* payload = it->second;
304 delete payload;
305 _payloadTypeMap.erase(it);
306 return 0;
307}
niklase@google.com470e71d2011-07-07 08:21:25 +0000308
309WebRtc_Word8 RTPSender::SendPayloadType() const
310{
311 return _payloadType;
312}
313
314
315int RTPSender::SendPayloadFrequency() const
316{
317 return _audio->AudioFrequency();
318}
319
320
niklase@google.com470e71d2011-07-07 08:21:25 +0000321WebRtc_Word32
322RTPSender::SetMaxPayloadLength(const WebRtc_UWord16 maxPayloadLength, const WebRtc_UWord16 packetOverHead)
323{
324 // sanity check
325 if(maxPayloadLength < 100 || maxPayloadLength > IP_PACKET_SIZE)
326 {
327 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
328 return -1;
329 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000330
331 CriticalSectionScoped cs(_sendCritsect);
332 _maxPayloadLength = maxPayloadLength;
333 _packetOverHead = packetOverHead;
334
335 WEBRTC_TRACE(kTraceInfo, kTraceRtpRtcp, _id, "SetMaxPayloadLength to %d.", maxPayloadLength);
336 return 0;
337}
338
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000339WebRtc_UWord16 RTPSender::MaxDataPayloadLength() const {
340 if(_audioConfigured) {
341 return _maxPayloadLength - RTPHeaderLength();
342 } else {
343 return _maxPayloadLength - RTPHeaderLength() -
344 _video->FECPacketOverhead() - ((_RTX) ? 2 : 0);
345 // Include the FEC/ULP/RED overhead.
346 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000347}
348
349WebRtc_UWord16
350RTPSender::MaxPayloadLength() const
351{
352 return _maxPayloadLength;
353}
354
355WebRtc_UWord16
356RTPSender::PacketOverHead() const
357{
358 return _packetOverHead;
359}
360
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000361void RTPSender::SetTransmissionSmoothingStatus(const bool enable) {
362 CriticalSectionScoped cs(_sendCritsect);
363 _transmissionSmoothing = enable;
364}
365
366bool RTPSender::TransmissionSmoothingStatus() const {
367 CriticalSectionScoped cs(_sendCritsect);
368 return _transmissionSmoothing;
369}
370
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000371void RTPSender::SetRTXStatus(const bool enable,
372 const bool setSSRC,
373 const WebRtc_UWord32 SSRC) {
374 CriticalSectionScoped cs(_sendCritsect);
375 _RTX = enable;
376 if (enable) {
377 if (setSSRC) {
378 _ssrcRTX = SSRC;
379 } else {
380 _ssrcRTX = _ssrcDB.CreateSSRC(); // can't be 0
381 }
382 }
383}
384
385void RTPSender::RTXStatus(bool* enable,
386 WebRtc_UWord32* SSRC) const {
387 CriticalSectionScoped cs(_sendCritsect);
388 *enable = _RTX;
389 *SSRC = _ssrcRTX;
390}
391
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000392WebRtc_Word32 RTPSender::CheckPayloadType(const WebRtc_Word8 payloadType,
393 RtpVideoCodecTypes& videoType) {
394 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000395
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000396 if (payloadType < 0) {
397 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
398 "\tinvalid payloadType (%d)", payloadType);
399 return -1;
400 }
401 if (_audioConfigured) {
402 WebRtc_Word8 redPlType = -1;
403 if (_audio->RED(redPlType) == 0) {
404 // We have configured RED.
405 if(redPlType == payloadType) {
406 // And it's a match...
407 return 0;
408 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000409 }
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000410 }
411 if (_payloadType == payloadType) {
412 if (!_audioConfigured) {
413 videoType = _video->VideoCodecType();
niklase@google.com470e71d2011-07-07 08:21:25 +0000414 }
415 return 0;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000416 }
417 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
418 _payloadTypeMap.find(payloadType);
419 if (it == _payloadTypeMap.end()) {
420 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
421 "\tpayloadType:%d not registered", payloadType);
422 return -1;
423 }
424 _payloadType = payloadType;
425 ModuleRTPUtility::Payload* payload = it->second;
426 assert(payload);
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000427 if (!payload->audio && !_audioConfigured) {
428 _video->SetVideoCodecType(payload->typeSpecific.Video.videoCodecType);
429 videoType = payload->typeSpecific.Video.videoCodecType;
430 _video->SetMaxConfiguredBitrateVideo(
431 payload->typeSpecific.Video.maxRate);
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000432 }
433 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000434}
435
436WebRtc_Word32
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000437RTPSender::SendOutgoingData(const FrameType frame_type,
438 const WebRtc_Word8 payload_type,
439 const WebRtc_UWord32 capture_timestamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000440 int64_t capture_time_ms,
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000441 const WebRtc_UWord8* payload_data,
442 const WebRtc_UWord32 payload_size,
niklase@google.com470e71d2011-07-07 08:21:25 +0000443 const RTPFragmentationHeader* fragmentation,
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000444 VideoCodecInformation* codec_info,
445 const RTPVideoTypeHeader* rtp_type_hdr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000446{
447 {
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000448 // Drop this packet if we're not sending media packets.
niklase@google.com470e71d2011-07-07 08:21:25 +0000449 CriticalSectionScoped cs(_sendCritsect);
450 if (!_sendingMedia)
451 {
452 return 0;
453 }
454 }
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000455 RtpVideoCodecTypes video_type = kRtpNoVideo;
456 if (CheckPayloadType(payload_type, video_type) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000457 {
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000458 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
459 "%s invalid argument failed to find payloadType:%d",
460 __FUNCTION__, payload_type);
niklase@google.com470e71d2011-07-07 08:21:25 +0000461 return -1;
462 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000463
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000464 if (_audioConfigured)
niklase@google.com470e71d2011-07-07 08:21:25 +0000465 {
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000466 assert(frame_type == kAudioFrameSpeech ||
467 frame_type == kAudioFrameCN ||
468 frame_type == kFrameEmpty);
niklase@google.com470e71d2011-07-07 08:21:25 +0000469
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000470 return _audio->SendAudio(frame_type, payload_type, capture_timestamp,
471 payload_data, payload_size,fragmentation);
472 } else {
473 assert(frame_type != kAudioFrameSpeech &&
474 frame_type != kAudioFrameCN);
niklase@google.com470e71d2011-07-07 08:21:25 +0000475
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000476 if (frame_type == kFrameEmpty) {
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000477 return SendPaddingAccordingToBitrate(payload_type, capture_timestamp,
478 capture_time_ms);
pwestin@webrtc.orgddab60b2012-04-23 14:52:15 +0000479 }
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000480 return _video->SendVideo(video_type,
481 frame_type,
482 payload_type,
483 capture_timestamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000484 capture_time_ms,
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000485 payload_data,
486 payload_size,
niklase@google.com470e71d2011-07-07 08:21:25 +0000487 fragmentation,
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000488 codec_info,
489 rtp_type_hdr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000490 }
491}
492
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000493WebRtc_Word32 RTPSender::SendPaddingAccordingToBitrate(
494 WebRtc_Word8 payload_type,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000495 WebRtc_UWord32 capture_timestamp,
496 int64_t capture_time_ms) {
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000497 // Current bitrate since last estimate(1 second) averaged with the
498 // estimate since then, to get the most up to date bitrate.
499 uint32_t current_bitrate = BitrateNow();
500 int bitrate_diff = _targetSendBitrate * 1000 - current_bitrate;
501 if (bitrate_diff > 0) {
502 int bytes = 0;
503 if (current_bitrate == 0) {
504 // Start up phase. Send one 33.3 ms batch to start with.
505 bytes = (bitrate_diff / 8) / 30;
506 } else {
507 bytes = (bitrate_diff / 8);
508 // Cap at 200 ms of target send data.
509 int bytes_cap = _targetSendBitrate * 25; // 1000 / 8 / 5
510 if (bytes > bytes_cap) {
511 bytes = bytes_cap;
512 }
513 }
514 // Send padding data.
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000515 return SendPadData(payload_type, capture_timestamp, capture_time_ms, bytes);
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000516 }
517 return 0;
518}
519
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000520WebRtc_Word32 RTPSender::SendPadData(WebRtc_Word8 payload_type,
521 WebRtc_UWord32 capture_timestamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000522 int64_t capture_time_ms,
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000523 WebRtc_Word32 bytes) {
524 // Drop this packet if we're not sending media packets
525 if (!_sendingMedia) {
526 return 0;
527 }
528 // Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP.
529 int max_length = 224;
530 WebRtc_UWord8 data_buffer[IP_PACKET_SIZE];
531
532 for (; bytes > 0; bytes -= max_length) {
asapersson@webrtc.org63a34f42012-04-20 13:20:27 +0000533 int padding_bytes_in_packet = max_length;
534 if (bytes < max_length) {
535 padding_bytes_in_packet = (bytes + 16) & 0xffe0; // Keep our modulus 32.
536 }
537 if (padding_bytes_in_packet < 32) {
538 // Sanity don't send empty packets.
539 break;
540 }
541
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000542 WebRtc_Word32 header_length;
543 {
544 // Correct seq num, timestamp and payload type.
545 header_length = BuildRTPheader(data_buffer,
546 payload_type,
547 false, // No markerbit.
548 capture_timestamp,
549 true, // Timestamp provided.
550 true); // Increment sequence number.
551 }
552 data_buffer[0] |= 0x20; // Set padding bit.
553 WebRtc_Word32* data =
554 reinterpret_cast<WebRtc_Word32*>(&(data_buffer[header_length]));
555
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000556 // Fill data buffer with random data.
557 for(int j = 0; j < (padding_bytes_in_packet >> 2); j++) {
558 data[j] = rand();
559 }
560 // Set number of padding bytes in the last byte of the packet.
561 data_buffer[header_length + padding_bytes_in_packet - 1] =
562 padding_bytes_in_packet;
563 // Send the packet
564 if (0 > SendToNetwork(data_buffer,
565 padding_bytes_in_packet,
566 header_length,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000567 capture_time_ms,
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000568 kDontRetransmit)) {
569 // Error sending the packet.
570 break;
571 }
572 }
573 if (bytes > 31) { // 31 due to our modulus 32.
574 // We did not manage to send all bytes.
575 return -1;
576 }
577 return 0;
578}
579
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000580WebRtc_Word32 RTPSender::SetStorePacketsStatus(
581 const bool enable,
582 const WebRtc_UWord16 numberToStore) {
583 _packetHistory->SetStorePacketsStatus(enable, numberToStore);
584 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000585}
586
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000587bool RTPSender::StorePackets() const {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000588 return _packetHistory->StorePackets();
niklase@google.com470e71d2011-07-07 08:21:25 +0000589}
590
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000591WebRtc_Word32 RTPSender::ReSendPacket(WebRtc_UWord16 packet_id,
592 WebRtc_UWord32 min_resend_time) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000593
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000594 WebRtc_UWord16 length = IP_PACKET_SIZE;
595 WebRtc_UWord8 data_buffer[IP_PACKET_SIZE];
596 WebRtc_UWord8* buffer_to_send_ptr = data_buffer;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000597
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000598 int64_t stored_time_in_ms;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000599 StorageType type;
600 bool found = _packetHistory->GetRTPPacket(packet_id,
601 min_resend_time, data_buffer, &length, &stored_time_in_ms, &type);
602 if (!found) {
603 // Packet not found.
asapersson@webrtc.org83ed0a42012-04-23 12:43:05 +0000604 return 0;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000605 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000606
607 if (length == 0 || type == kDontRetransmit) {
608 // No bytes copied (packet recently resent, skip resending) or
609 // packet should not be retransmitted.
610 return 0;
611 }
612
pwestin@webrtc.orgb30f0ed2012-01-23 16:23:31 +0000613 WebRtc_UWord8 data_buffer_rtx[IP_PACKET_SIZE];
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000614 if (_RTX) {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000615 buffer_to_send_ptr = data_buffer_rtx;
616
617 CriticalSectionScoped cs(_sendCritsect);
618 // Add RTX header.
619 ModuleRTPUtility::RTPHeaderParser rtpParser(
620 reinterpret_cast<const WebRtc_UWord8*>(data_buffer),
621 length);
622
623 WebRtcRTPHeader rtp_header;
624 rtpParser.Parse(rtp_header);
625
626 // Add original RTP header.
627 memcpy(data_buffer_rtx, data_buffer, rtp_header.header.headerLength);
628
629 // Replace sequence number.
630 WebRtc_UWord8* ptr = data_buffer_rtx + 2;
631 ModuleRTPUtility::AssignUWord16ToBuffer(ptr, _sequenceNumberRTX++);
632
633 // Replace SSRC.
634 ptr += 6;
635 ModuleRTPUtility::AssignUWord32ToBuffer(ptr, _ssrcRTX);
636
637 // Add OSN (original sequence number).
638 ptr = data_buffer_rtx + rtp_header.header.headerLength;
639 ModuleRTPUtility::AssignUWord16ToBuffer(
640 ptr, rtp_header.header.sequenceNumber);
641 ptr += 2;
642
643 // Add original payload data.
644 memcpy(ptr,
645 data_buffer + rtp_header.header.headerLength,
646 length - rtp_header.header.headerLength);
647 length += 2;
648 }
649
650 WebRtc_Word32 bytes_sent = ReSendToNetwork(buffer_to_send_ptr, length);
651 if (bytes_sent <= 0) {
652 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
653 "Transport failed to resend packet_id %u", packet_id);
654 return -1;
655 }
656
657 // Store the time when the packet was last resent.
658 _packetHistory->UpdateResendTime(packet_id);
659
660 return bytes_sent;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000661}
662
663WebRtc_Word32 RTPSender::ReSendToNetwork(const WebRtc_UWord8* packet,
664 const WebRtc_UWord32 size) {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000665 WebRtc_Word32 bytes_sent = -1;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000666 {
667 CriticalSectionScoped lock(_transportCritsect);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000668 if (_transport) {
669 bytes_sent = _transport->SendPacket(_id, packet, size);
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000670 }
671 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000672
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000673 if (bytes_sent <= 0) {
674 return -1;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000675 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000676
677 // Update send statistics
678 CriticalSectionScoped cs(_sendCritsect);
679 Bitrate::Update(bytes_sent);
680 _packetsSent++;
681 // We on purpose don't add to _payloadBytesSent since this is a
682 // re-transmit and not new payload data.
683 return bytes_sent;
niklase@google.com470e71d2011-07-07 08:21:25 +0000684}
685
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000686int RTPSender::SelectiveRetransmissions() const {
687 if (!_video) return -1;
688 return _video->SelectiveRetransmissions();
689}
690
691int RTPSender::SetSelectiveRetransmissions(uint8_t settings) {
692 if (!_video) return -1;
693 return _video->SetSelectiveRetransmissions(settings);
694}
695
niklase@google.com470e71d2011-07-07 08:21:25 +0000696void
697RTPSender::OnReceivedNACK(const WebRtc_UWord16 nackSequenceNumbersLength,
698 const WebRtc_UWord16* nackSequenceNumbers,
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000699 const WebRtc_UWord16 avgRTT) {
pwestin@webrtc.org18530052012-07-03 10:41:54 +0000700 const WebRtc_Word64 now = _clock.GetTimeInMS();
niklase@google.com470e71d2011-07-07 08:21:25 +0000701 WebRtc_UWord32 bytesReSent = 0;
702
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000703 // Enough bandwidth to send NACK?
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000704 if (!ProcessNACKBitRate(now)) {
705 WEBRTC_TRACE(kTraceStream,
706 kTraceRtpRtcp,
707 _id,
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000708 "NACK bitrate reached. Skip sending NACK response. Target %d",
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000709 _targetSendBitrate);
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000710 return;
711 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000712
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000713 for (WebRtc_UWord16 i = 0; i < nackSequenceNumbersLength; ++i) {
714 const WebRtc_Word32 bytesSent = ReSendPacket(nackSequenceNumbers[i],
715 5+avgRTT);
716 if (bytesSent > 0) {
717 bytesReSent += bytesSent;
718 } else if (bytesSent == 0) {
719 // The packet has previously been resent.
720 // Try resending next packet in the list.
721 continue;
722 } else if (bytesSent < 0) {
723 // Failed to send one Sequence number. Give up the rest in this nack.
724 WEBRTC_TRACE(kTraceWarning,
725 kTraceRtpRtcp,
726 _id,
727 "Failed resending RTP packet %d, Discard rest of packets",
728 nackSequenceNumbers[i]);
729 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000730 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000731 // delay bandwidth estimate (RTT * BW)
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000732 if (_targetSendBitrate != 0 && avgRTT) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000733 // kbits/s * ms = bits => bits/8 = bytes
734 WebRtc_UWord32 targetBytes =
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000735 (static_cast<WebRtc_UWord32>(_targetSendBitrate) * avgRTT) >> 3;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000736 if (bytesReSent > targetBytes) {
737 break; // ignore the rest of the packets in the list
738 }
739 }
740 }
741 if (bytesReSent > 0) {
742 // TODO(pwestin) consolidate these two methods.
743 UpdateNACKBitRate(bytesReSent, now);
744 _nackBitrate.Update(bytesReSent);
745 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000746}
747
748/**
749* @return true if the nack bitrate is lower than the requested max bitrate
750*/
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000751bool RTPSender::ProcessNACKBitRate(const WebRtc_UWord32 now) {
752 WebRtc_UWord32 num = 0;
753 WebRtc_Word32 byteCount = 0;
754 const WebRtc_UWord32 avgInterval=1000;
niklase@google.com470e71d2011-07-07 08:21:25 +0000755
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000756 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000757
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000758 if (_targetSendBitrate == 0) {
759 return true;
760 }
761 for (num = 0; num < NACK_BYTECOUNT_SIZE; num++) {
762 if ((now - _nackByteCountTimes[num]) > avgInterval) {
763 // don't use data older than 1sec
764 break;
765 } else {
766 byteCount += _nackByteCount[num];
niklase@google.com470e71d2011-07-07 08:21:25 +0000767 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000768 }
769 WebRtc_Word32 timeInterval = avgInterval;
770 if (num == NACK_BYTECOUNT_SIZE) {
771 // More than NACK_BYTECOUNT_SIZE nack messages has been received
772 // during the last msgInterval
773 timeInterval = now - _nackByteCountTimes[num-1];
774 if(timeInterval < 0) {
775 timeInterval = avgInterval;
niklase@google.com470e71d2011-07-07 08:21:25 +0000776 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000777 }
778 return (byteCount*8) < (_targetSendBitrate * timeInterval);
niklase@google.com470e71d2011-07-07 08:21:25 +0000779}
780
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000781void RTPSender::UpdateNACKBitRate(const WebRtc_UWord32 bytes,
782 const WebRtc_UWord32 now) {
783 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000784
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000785 // save bitrate statistics
786 if(bytes > 0) {
787 if(now == 0) {
788 // add padding length
789 _nackByteCount[0] += bytes;
790 } else {
791 if(_nackByteCountTimes[0] == 0) {
792 // first no shift
793 } else {
794 // shift
795 for(int i = (NACK_BYTECOUNT_SIZE-2); i >= 0 ; i--) {
796 _nackByteCount[i+1] = _nackByteCount[i];
797 _nackByteCountTimes[i+1] = _nackByteCountTimes[i];
niklase@google.com470e71d2011-07-07 08:21:25 +0000798 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000799 }
800 _nackByteCount[0] = bytes;
801 _nackByteCountTimes[0] = now;
niklase@google.com470e71d2011-07-07 08:21:25 +0000802 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000803 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000804}
805
pwestin@webrtc.orgddab60b2012-04-23 14:52:15 +0000806// Function triggered by timer.
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000807void RTPSender::ProcessSendToNetwork() {
pwestin@webrtc.org18530052012-07-03 10:41:54 +0000808 WebRtc_Word64 delta_time_ms;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000809 {
810 CriticalSectionScoped cs(_sendCritsect);
811
812 if (!_transmissionSmoothing) {
813 return;
814 }
pwestin@webrtc.org18530052012-07-03 10:41:54 +0000815 WebRtc_Word64 now = _clock.GetTimeInMS();
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000816 delta_time_ms = now - _timeLastSendToNetworkUpdate;
817 _timeLastSendToNetworkUpdate = now;
818 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000819 _sendBucket.UpdateBytesPerInterval(delta_time_ms, _targetSendBitrate);
820
821 while (!_sendBucket.Empty()) {
822
823 WebRtc_Word32 seq_num = _sendBucket.GetNextPacket();
824 if (seq_num < 0) {
825 break;
826 }
827
828 WebRtc_UWord8 data_buffer[IP_PACKET_SIZE];
829 WebRtc_UWord16 length = IP_PACKET_SIZE;
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000830 int64_t stored_time_ms;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000831 StorageType type;
asapersson@webrtc.org869ce2d2012-01-16 11:58:36 +0000832 bool found = _packetHistory->GetRTPPacket(seq_num, 0, data_buffer, &length,
833 &stored_time_ms, &type);
834 if (!found) {
835 assert(false);
836 return;
837 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000838 assert(length > 0);
839
pwestin@webrtc.org18530052012-07-03 10:41:54 +0000840 WebRtc_Word64 diff_ms = _clock.GetTimeInMS() - stored_time_ms;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000841
842 ModuleRTPUtility::RTPHeaderParser rtpParser(data_buffer, length);
843 WebRtcRTPHeader rtp_header;
asapersson@webrtc.org869ce2d2012-01-16 11:58:36 +0000844 rtpParser.Parse(rtp_header);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000845
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000846 if (UpdateTransmissionTimeOffset(data_buffer, length, rtp_header,
847 diff_ms)) {
848 // Update stored packet in case of receiving a re-transmission request.
849 _packetHistory->ReplaceRTPHeader(data_buffer,
850 rtp_header.header.sequenceNumber,
851 rtp_header.header.headerLength);
852 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000853
854 // Send packet
855 WebRtc_Word32 bytes_sent = -1;
856 {
857 CriticalSectionScoped cs(_transportCritsect);
858 if (_transport) {
859 bytes_sent = _transport->SendPacket(_id, data_buffer, length);
860 }
861 }
862
863 // Update send statistics
864 if (bytes_sent > 0) {
865 CriticalSectionScoped cs(_sendCritsect);
866 Bitrate::Update(bytes_sent);
867 _packetsSent++;
868 if (bytes_sent > rtp_header.header.headerLength) {
869 _payloadBytesSent += bytes_sent - rtp_header.header.headerLength;
870 }
871 }
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000872 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000873}
874
niklase@google.com470e71d2011-07-07 08:21:25 +0000875WebRtc_Word32
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000876RTPSender::SendToNetwork(WebRtc_UWord8* buffer,
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000877 const WebRtc_UWord16 payload_length,
878 const WebRtc_UWord16 rtp_header_length,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000879 int64_t capture_time_ms,
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000880 const StorageType storage)
niklase@google.com470e71d2011-07-07 08:21:25 +0000881{
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000882 // Used for NACK or to spead out the transmission of packets.
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000883 if (_packetHistory->PutRTPPacket(buffer, rtp_header_length + payload_length,
884 _maxPayloadLength, capture_time_ms, storage) != 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000885 return -1;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000886 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000887
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000888 if (_transmissionSmoothing) {
889 const WebRtc_UWord16 sequenceNumber = (buffer[2] << 8) + buffer[3];
asapersson@webrtc.org23fd5592012-09-24 12:07:13 +0000890 const WebRtc_UWord32 timestamp = (buffer[4] << 24) + (buffer[5] << 16) +
891 (buffer[6] << 8) + buffer[7];
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000892 _sendBucket.Fill(sequenceNumber, timestamp,
893 rtp_header_length + payload_length);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000894 // Packet will be sent at a later time.
895 return 0;
896 }
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000897
stefan@webrtc.org715faaf2012-08-28 15:20:39 +0000898 // |capture_time_ms| <= 0 is considered invalid.
899 // TODO(holmer): This should be changed all over Video Engine so that negative
900 // time is consider invalid, while 0 is considered a valid time.
901 if (capture_time_ms > 0) {
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000902 ModuleRTPUtility::RTPHeaderParser rtpParser(buffer,
903 rtp_header_length + payload_length);
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000904 WebRtcRTPHeader rtp_header;
mflodman@webrtc.org90071dd2012-08-13 17:13:27 +0000905 rtpParser.Parse(rtp_header);
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000906 int64_t time_now = _clock.GetTimeInMS();
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000907 if (UpdateTransmissionTimeOffset(buffer, rtp_header_length + payload_length,
908 rtp_header, time_now - capture_time_ms)) {
909 // Update stored packet in case of receiving a re-transmission request.
910 _packetHistory->ReplaceRTPHeader(buffer, rtp_header.header.sequenceNumber,
911 rtp_header.header.headerLength);
912 }
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000913 }
914
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000915 // Send packet
916 WebRtc_Word32 bytes_sent = -1;
917 {
918 CriticalSectionScoped cs(_transportCritsect);
919 if (_transport) {
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000920 bytes_sent = _transport->SendPacket(_id, buffer,
921 payload_length + rtp_header_length);
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000922 }
923 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000924
925 if (bytes_sent <= 0) {
926 return -1;
927 }
928
929 // Update send statistics
930 CriticalSectionScoped cs(_sendCritsect);
931 Bitrate::Update(bytes_sent);
932 _packetsSent++;
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000933 if (bytes_sent > rtp_header_length) {
934 _payloadBytesSent += bytes_sent - rtp_header_length;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000935 }
936 return 0;
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000937}
938
niklase@google.com470e71d2011-07-07 08:21:25 +0000939void
940RTPSender::ProcessBitrate()
941{
942 CriticalSectionScoped cs(_sendCritsect);
943
944 Bitrate::Process();
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000945 _nackBitrate.Process();
wu@webrtc.org76aea652011-10-17 21:40:32 +0000946
947 if (_audioConfigured)
948 return;
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000949 _video->ProcessBitrate();
niklase@google.com470e71d2011-07-07 08:21:25 +0000950}
951
952WebRtc_UWord16
953RTPSender::RTPHeaderLength() const
954{
955 WebRtc_UWord16 rtpHeaderLength = 12;
956
957 if(_includeCSRCs)
958 {
959 rtpHeaderLength += sizeof(WebRtc_UWord32)*_CSRCs;
960 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000961 rtpHeaderLength += RtpHeaderExtensionTotalLength();
962
niklase@google.com470e71d2011-07-07 08:21:25 +0000963 return rtpHeaderLength;
964}
965
966WebRtc_UWord16
967RTPSender::IncrementSequenceNumber()
968{
969 CriticalSectionScoped cs(_sendCritsect);
970 return _sequenceNumber++;
971}
972
973WebRtc_Word32
974RTPSender::ResetDataCounters()
975{
976 _packetsSent = 0;
977 _payloadBytesSent = 0;
978
979 return 0;
980}
981
982// number of sent RTP packets
983// dont use critsect to avoid potental deadlock
984WebRtc_UWord32
985RTPSender::Packets() const
986{
987 return _packetsSent;
988}
989
990// number of sent RTP bytes
991// dont use critsect to avoid potental deadlock
992WebRtc_UWord32
993RTPSender::Bytes() const
994{
995 return _payloadBytesSent;
996}
997
998WebRtc_Word32
999RTPSender::BuildRTPheader(WebRtc_UWord8* dataBuffer,
1000 const WebRtc_Word8 payloadType,
1001 const bool markerBit,
1002 const WebRtc_UWord32 captureTimeStamp,
1003 const bool timeStampProvided,
1004 const bool incSequenceNumber)
1005{
1006 assert(payloadType>=0);
1007
1008 CriticalSectionScoped cs(_sendCritsect);
1009
1010 dataBuffer[0] = static_cast<WebRtc_UWord8>(0x80); // version 2
1011 dataBuffer[1] = static_cast<WebRtc_UWord8>(payloadType);
1012 if (markerBit)
1013 {
1014 dataBuffer[1] |= kRtpMarkerBitMask; // MarkerBit is set
1015 }
1016
1017 if(timeStampProvided)
1018 {
1019 _timeStamp = _startTimeStamp + captureTimeStamp;
1020 } else
1021 {
1022 // make a unique time stamp
1023 // used for inband signaling
1024 // we can't inc by the actual time, since then we increase the risk of back timing
1025 _timeStamp++;
1026 }
1027
1028 ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer+2, _sequenceNumber);
1029 ModuleRTPUtility::AssignUWord32ToBuffer(dataBuffer+4, _timeStamp);
1030 ModuleRTPUtility::AssignUWord32ToBuffer(dataBuffer+8, _ssrc);
1031
1032 WebRtc_Word32 rtpHeaderLength = 12;
1033
1034 // Add the CSRCs if any
1035 if (_includeCSRCs && _CSRCs > 0)
1036 {
1037 if(_CSRCs > kRtpCsrcSize)
1038 {
1039 // error
1040 assert(false);
1041 return -1;
1042 }
1043 WebRtc_UWord8* ptr = &dataBuffer[rtpHeaderLength];
1044 for (WebRtc_UWord32 i = 0; i < _CSRCs; ++i)
1045 {
1046 ModuleRTPUtility::AssignUWord32ToBuffer(ptr, _CSRC[i]);
1047 ptr +=4;
1048 }
1049 dataBuffer[0] = (dataBuffer[0]&0xf0) | _CSRCs;
1050
1051 // Update length of header
1052 rtpHeaderLength += sizeof(WebRtc_UWord32)*_CSRCs;
1053 }
1054 {
1055 _sequenceNumber++; // prepare for next packet
1056 }
1057
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001058 WebRtc_UWord16 len = BuildRTPHeaderExtension(dataBuffer + rtpHeaderLength);
1059 if (len)
1060 {
1061 dataBuffer[0] |= 0x10; // set eXtension bit
1062 rtpHeaderLength += len;
1063 }
1064
niklase@google.com470e71d2011-07-07 08:21:25 +00001065 return rtpHeaderLength;
1066}
1067
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001068WebRtc_UWord16
1069RTPSender::BuildRTPHeaderExtension(WebRtc_UWord8* dataBuffer) const
1070{
1071 if (_rtpHeaderExtensionMap.Size() <= 0) {
1072 return 0;
1073 }
1074
1075 /* RTP header extension, RFC 3550.
1076 0 1 2 3
1077 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
1078 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1079 | defined by profile | length |
1080 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1081 | header extension |
1082 | .... |
1083 */
1084
1085 const WebRtc_UWord32 kPosLength = 2;
1086 const WebRtc_UWord32 kHeaderLength = RTP_ONE_BYTE_HEADER_LENGTH_IN_BYTES;
1087
1088 // Add extension ID (0xBEDE).
1089 ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer,
1090 RTP_ONE_BYTE_HEADER_EXTENSION);
1091
1092 // Add extensions.
1093 WebRtc_UWord16 total_block_length = 0;
1094
1095 RTPExtensionType type = _rtpHeaderExtensionMap.First();
pwestin@webrtc.org6c1d4152012-01-04 17:04:51 +00001096 while (type != kRtpExtensionNone)
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001097 {
1098 WebRtc_UWord8 block_length = 0;
pwestin@webrtc.org6c1d4152012-01-04 17:04:51 +00001099 if (type == kRtpExtensionTransmissionTimeOffset)
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001100 {
1101 block_length = BuildTransmissionTimeOffsetExtension(
1102 dataBuffer + kHeaderLength + total_block_length);
1103 }
1104 total_block_length += block_length;
1105 type = _rtpHeaderExtensionMap.Next(type);
1106 }
1107
1108 if (total_block_length == 0)
1109 {
1110 // No extension added.
1111 return 0;
1112 }
1113
1114 // Set header length (in number of Word32, header excluded).
1115 assert(total_block_length % 4 == 0);
1116 ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer + kPosLength,
1117 total_block_length / 4);
1118
1119 // Total added length.
1120 return kHeaderLength + total_block_length;
1121}
1122
1123WebRtc_UWord8
1124RTPSender::BuildTransmissionTimeOffsetExtension(WebRtc_UWord8* dataBuffer) const
1125{
1126 // From RFC 5450: Transmission Time Offsets in RTP Streams.
1127 //
1128 // The transmission time is signaled to the receiver in-band using the
1129 // general mechanism for RTP header extensions [RFC5285]. The payload
1130 // of this extension (the transmitted value) is a 24-bit signed integer.
1131 // When added to the RTP timestamp of the packet, it represents the
1132 // "effective" RTP transmission time of the packet, on the RTP
1133 // timescale.
1134 //
1135 // The form of the transmission offset extension block:
1136 //
1137 // 0 1 2 3
1138 // 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
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001139 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001140 // | ID | len=2 | transmission offset |
1141 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1142
1143 // Get id defined by user.
1144 WebRtc_UWord8 id;
pwestin@webrtc.org6c1d4152012-01-04 17:04:51 +00001145 if (_rtpHeaderExtensionMap.GetId(kRtpExtensionTransmissionTimeOffset, &id)
1146 != 0) {
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001147 // Not registered.
1148 return 0;
1149 }
1150
1151 int pos = 0;
1152 const WebRtc_UWord8 len = 2;
1153 dataBuffer[pos++] = (id << 4) + len;
1154 ModuleRTPUtility::AssignUWord24ToBuffer(dataBuffer + pos,
1155 _transmissionTimeOffset);
1156 pos += 3;
1157 assert(pos == TRANSMISSION_TIME_OFFSET_LENGTH_IN_BYTES);
1158 return TRANSMISSION_TIME_OFFSET_LENGTH_IN_BYTES;
1159}
1160
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +00001161bool RTPSender::UpdateTransmissionTimeOffset(
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001162 WebRtc_UWord8* rtp_packet,
1163 const WebRtc_UWord16 rtp_packet_length,
1164 const WebRtcRTPHeader& rtp_header,
mflodman@webrtc.orgba853c92012-08-10 14:30:53 +00001165 const WebRtc_Word64 time_diff_ms) const {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001166 CriticalSectionScoped cs(_sendCritsect);
1167
1168 // Get length until start of transmission block.
1169 int transmission_block_pos =
1170 _rtpHeaderExtensionMap.GetLengthUntilBlockStartInBytes(
1171 kRtpExtensionTransmissionTimeOffset);
1172 if (transmission_block_pos < 0) {
1173 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
1174 "Failed to update transmission time offset, not registered.");
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +00001175 return false;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001176 }
1177
1178 int block_pos = 12 + rtp_header.header.numCSRCs + transmission_block_pos;
mflodman@webrtc.orgba853c92012-08-10 14:30:53 +00001179 if (rtp_packet_length < block_pos + 4 ||
1180 rtp_header.header.headerLength < block_pos + 4) {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001181 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
1182 "Failed to update transmission time offset, invalid length.");
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +00001183 return false;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001184 }
1185
1186 // Verify that header contains extension.
1187 if (!((rtp_packet[12 + rtp_header.header.numCSRCs] == 0xBE) &&
1188 (rtp_packet[12 + rtp_header.header.numCSRCs + 1] == 0xDE))) {
1189 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
1190 "Failed to update transmission time offset, hdr extension not found.");
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +00001191 return false;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001192 }
1193
1194 // Get id.
1195 WebRtc_UWord8 id = 0;
1196 if (_rtpHeaderExtensionMap.GetId(kRtpExtensionTransmissionTimeOffset,
1197 &id) != 0) {
1198 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
1199 "Failed to update transmission time offset, no id.");
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +00001200 return false;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001201 }
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +00001202
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001203 // Verify first byte in block.
1204 const WebRtc_UWord8 first_block_byte = (id << 4) + 2;
1205 if (rtp_packet[block_pos] != first_block_byte) {
1206 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
1207 "Failed to update transmission time offset.");
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +00001208 return false;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001209 }
1210
1211 // Update transmission offset field.
1212 ModuleRTPUtility::AssignUWord24ToBuffer(rtp_packet + block_pos + 1,
mflodman@webrtc.orgba853c92012-08-10 14:30:53 +00001213 time_diff_ms * 90); // RTP timestamp.
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +00001214 return true;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001215}
1216
niklase@google.com470e71d2011-07-07 08:21:25 +00001217WebRtc_Word32
1218RTPSender::RegisterSendTransport(Transport* transport)
1219{
1220 CriticalSectionScoped cs(_transportCritsect);
1221 _transport = transport;
1222 return 0;
1223}
1224
1225void
1226RTPSender::SetSendingStatus(const bool enabled)
1227{
1228 if(enabled)
1229 {
1230 WebRtc_UWord32 freq;
1231 if(_audioConfigured)
1232 {
1233 WebRtc_UWord32 frequency = _audio->AudioFrequency();
1234
1235 // sanity
1236 switch(frequency)
1237 {
1238 case 8000:
1239 case 12000:
1240 case 16000:
1241 case 24000:
1242 case 32000:
1243 break;
1244 default:
1245 assert(false);
1246 return;
1247 }
1248 freq = frequency;
1249 } else
1250 {
1251 freq = 90000; // 90 KHz for all video
1252 }
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +00001253 WebRtc_UWord32 RTPtime = ModuleRTPUtility::GetCurrentRTP(&_clock, freq);
niklase@google.com470e71d2011-07-07 08:21:25 +00001254
1255 SetStartTimestamp(RTPtime); // will be ignored if it's already configured via API
1256
1257 } else
1258 {
1259 if(!_ssrcForced)
1260 {
1261 // generate a new SSRC
1262 _ssrcDB.ReturnSSRC(_ssrc);
1263 _ssrc = _ssrcDB.CreateSSRC(); // can't be 0
1264
1265 }
1266 if(!_sequenceNumberForced && !_ssrcForced) // don't initialize seq number if SSRC passed externally
1267 {
1268 // generate a new sequence number
1269 _sequenceNumber = rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);
1270 }
1271 }
1272}
1273
1274void
1275RTPSender::SetSendingMediaStatus(const bool enabled)
1276{
1277 CriticalSectionScoped cs(_sendCritsect);
1278 _sendingMedia = enabled;
1279}
1280
1281bool
1282RTPSender::SendingMedia() const
1283{
1284 CriticalSectionScoped cs(_sendCritsect);
1285 return _sendingMedia;
1286}
1287
1288WebRtc_UWord32
1289RTPSender::Timestamp() const
1290{
1291 CriticalSectionScoped cs(_sendCritsect);
1292 return _timeStamp;
1293}
1294
1295
1296WebRtc_Word32
1297RTPSender::SetStartTimestamp( const WebRtc_UWord32 timestamp, const bool force)
1298{
1299 CriticalSectionScoped cs(_sendCritsect);
1300 if(force)
1301 {
1302 _startTimeStampForced = force;
1303 _startTimeStamp = timestamp;
1304 } else
1305 {
1306 if(!_startTimeStampForced)
1307 {
1308 _startTimeStamp = timestamp;
1309 }
1310 }
1311 return 0;
1312}
1313
1314WebRtc_UWord32
1315RTPSender::StartTimestamp() const
1316{
1317 CriticalSectionScoped cs(_sendCritsect);
1318 return _startTimeStamp;
1319}
1320
1321WebRtc_UWord32
1322RTPSender::GenerateNewSSRC()
1323{
1324 // if configured via API, return 0
1325 CriticalSectionScoped cs(_sendCritsect);
1326
1327 if(_ssrcForced)
1328 {
1329 return 0;
1330 }
1331 _ssrc = _ssrcDB.CreateSSRC(); // can't be 0
1332 return _ssrc;
1333}
1334
1335WebRtc_Word32
1336RTPSender::SetSSRC(WebRtc_UWord32 ssrc)
1337{
1338 // this is configured via the API
1339 CriticalSectionScoped cs(_sendCritsect);
1340
1341 if (_ssrc == ssrc && _ssrcForced)
1342 {
1343 return 0; // since it's same ssrc, don't reset anything
1344 }
1345
1346 _ssrcForced = true;
1347
1348 _ssrcDB.ReturnSSRC(_ssrc);
1349 _ssrcDB.RegisterSSRC(ssrc);
1350 _ssrc = ssrc;
1351
1352 if(!_sequenceNumberForced)
1353 {
1354 _sequenceNumber = rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);
1355 }
1356 return 0;
1357}
1358
1359WebRtc_UWord32
1360RTPSender::SSRC() const
1361{
1362 CriticalSectionScoped cs(_sendCritsect);
1363 return _ssrc;
1364}
1365
1366WebRtc_Word32
1367RTPSender::SetCSRCStatus(const bool include)
1368{
1369 _includeCSRCs = include;
1370 return 0;
1371}
1372
1373WebRtc_Word32
1374RTPSender::SetCSRCs(const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize],
1375 const WebRtc_UWord8 arrLength)
1376{
1377 if(arrLength > kRtpCsrcSize)
1378 {
1379 assert(false);
1380 return -1;
1381 }
1382
1383 CriticalSectionScoped cs(_sendCritsect);
1384
1385 for(int i = 0; i < arrLength;i++)
1386 {
1387 _CSRC[i] = arrOfCSRC[i];
1388 }
1389 _CSRCs = arrLength;
1390 return 0;
1391}
1392
1393WebRtc_Word32
1394RTPSender::CSRCs(WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]) const
1395{
1396 CriticalSectionScoped cs(_sendCritsect);
1397
1398 if(arrOfCSRC == NULL)
1399 {
1400 assert(false);
1401 return -1;
1402 }
1403 for(int i = 0; i < _CSRCs && i < kRtpCsrcSize;i++)
1404 {
1405 arrOfCSRC[i] = _CSRC[i];
1406 }
1407 return _CSRCs;
1408}
1409
1410WebRtc_Word32
1411RTPSender::SetSequenceNumber(WebRtc_UWord16 seq)
1412{
1413 CriticalSectionScoped cs(_sendCritsect);
1414 _sequenceNumberForced = true;
1415 _sequenceNumber = seq;
1416 return 0;
1417}
1418
1419WebRtc_UWord16
1420RTPSender::SequenceNumber() const
1421{
1422 CriticalSectionScoped cs(_sendCritsect);
1423 return _sequenceNumber;
1424}
1425
1426
1427 /*
1428 * Audio
1429 */
1430WebRtc_Word32
1431RTPSender::RegisterAudioCallback(RtpAudioFeedback* messagesCallback)
1432{
1433 if(!_audioConfigured)
1434 {
1435 return -1;
1436 }
1437 return _audio->RegisterAudioCallback(messagesCallback);
1438}
1439
1440 // Send a DTMF tone, RFC 2833 (4733)
1441WebRtc_Word32
1442RTPSender::SendTelephoneEvent(const WebRtc_UWord8 key,
1443 const WebRtc_UWord16 time_ms,
1444 const WebRtc_UWord8 level)
1445{
1446 if(!_audioConfigured)
1447 {
1448 return -1;
1449 }
1450 return _audio->SendTelephoneEvent(key, time_ms, level);
1451}
1452
1453bool
1454RTPSender::SendTelephoneEventActive(WebRtc_Word8& telephoneEvent) const
1455{
1456 if(!_audioConfigured)
1457 {
1458 return false;
1459 }
1460 return _audio->SendTelephoneEventActive(telephoneEvent);
1461}
1462
1463 // set audio packet size, used to determine when it's time to send a DTMF packet in silence (CNG)
1464WebRtc_Word32
1465RTPSender::SetAudioPacketSize(const WebRtc_UWord16 packetSizeSamples)
1466{
1467 if(!_audioConfigured)
1468 {
1469 return -1;
1470 }
1471 return _audio->SetAudioPacketSize(packetSizeSamples);
1472}
1473
1474WebRtc_Word32
1475RTPSender::SetAudioLevelIndicationStatus(const bool enable,
1476 const WebRtc_UWord8 ID)
1477{
1478 if(!_audioConfigured)
1479 {
1480 return -1;
1481 }
1482 return _audio->SetAudioLevelIndicationStatus(enable, ID);
1483}
1484
1485WebRtc_Word32
1486RTPSender::AudioLevelIndicationStatus(bool& enable,
1487 WebRtc_UWord8& ID) const
1488{
1489 return _audio->AudioLevelIndicationStatus(enable, ID);
1490}
1491
1492WebRtc_Word32
1493RTPSender::SetAudioLevel(const WebRtc_UWord8 level_dBov)
1494{
1495 return _audio->SetAudioLevel(level_dBov);
1496}
1497
1498 // Set payload type for Redundant Audio Data RFC 2198
1499WebRtc_Word32
1500RTPSender::SetRED(const WebRtc_Word8 payloadType)
1501{
1502 if(!_audioConfigured)
1503 {
1504 return -1;
1505 }
1506 return _audio->SetRED(payloadType);
1507}
1508
1509 // Get payload type for Redundant Audio Data RFC 2198
1510WebRtc_Word32
1511RTPSender::RED(WebRtc_Word8& payloadType) const
1512{
1513 if(!_audioConfigured)
1514 {
andrew@webrtc.org4f390002011-08-24 20:35:35 +00001515 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001516 }
1517 return _audio->RED(payloadType);
1518}
1519
1520 /*
1521 * Video
1522 */
1523VideoCodecInformation*
1524RTPSender::CodecInformationVideo()
1525{
1526 if(_audioConfigured)
1527 {
1528 return NULL;
1529 }
1530 return _video->CodecInformationVideo();
1531}
1532
1533RtpVideoCodecTypes
1534RTPSender::VideoCodecType() const
1535{
1536 if(_audioConfigured)
1537 {
1538 return kRtpNoVideo;
1539 }
1540 return _video->VideoCodecType();
1541}
1542
1543WebRtc_UWord32
1544RTPSender::MaxConfiguredBitrateVideo() const
1545{
1546 if(_audioConfigured)
1547 {
1548 return 0;
1549 }
1550 return _video->MaxConfiguredBitrateVideo();
1551}
1552
1553WebRtc_Word32
1554RTPSender::SendRTPIntraRequest()
1555{
1556 if(_audioConfigured)
1557 {
1558 return -1;
1559 }
1560 return _video->SendRTPIntraRequest();
1561}
1562
1563// FEC
1564WebRtc_Word32
1565RTPSender::SetGenericFECStatus(const bool enable,
1566 const WebRtc_UWord8 payloadTypeRED,
1567 const WebRtc_UWord8 payloadTypeFEC)
1568{
1569 if(_audioConfigured)
1570 {
1571 return -1;
1572 }
1573 return _video->SetGenericFECStatus(enable, payloadTypeRED, payloadTypeFEC);
1574}
1575
1576WebRtc_Word32
1577RTPSender::GenericFECStatus(bool& enable,
1578 WebRtc_UWord8& payloadTypeRED,
1579 WebRtc_UWord8& payloadTypeFEC) const
1580{
1581 if(_audioConfigured)
1582 {
1583 return -1;
1584 }
1585 return _video->GenericFECStatus(enable, payloadTypeRED, payloadTypeFEC);
1586}
1587
stefan@webrtc.orge0d6fa42012-03-20 22:10:56 +00001588WebRtc_Word32 RTPSender::SetFecParameters(
1589 const FecProtectionParams* delta_params,
1590 const FecProtectionParams* key_params) {
1591 if (_audioConfigured) {
1592 return -1;
1593 }
1594 return _video->SetFecParameters(delta_params, key_params);
marpan@google.com80c5d7a2011-07-15 21:32:40 +00001595}
niklase@google.com470e71d2011-07-07 08:21:25 +00001596} // namespace webrtc