blob: 374ce5320e5a5eb3cd9a741235fbdbca1367b3de [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 _keepAliveIsActive(false),
49 _keepAlivePayloadType(-1),
50 _keepAliveLastSent(0),
51 _keepAliveDeltaTimeSend(0),
52
niklase@google.com470e71d2011-07-07 08:21:25 +000053 // NACK
54 _nackByteCountTimes(),
55 _nackByteCount(),
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000056 _nackBitrate(clock),
niklase@google.com470e71d2011-07-07 08:21:25 +000057
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +000058 _packetHistory(new RTPPacketHistory(clock)),
59 _sendBucket(),
60 _timeLastSendToNetworkUpdate(clock->GetTimeInMS()),
61 _transmissionSmoothing(false),
62
niklase@google.com470e71d2011-07-07 08:21:25 +000063 // statistics
64 _packetsSent(0),
65 _payloadBytesSent(0),
66
67 // RTP variables
68 _startTimeStampForced(false),
69 _startTimeStamp(0),
70 _ssrcDB(*SSRCDatabase::GetSSRCDatabase()),
71 _remoteSSRC(0),
72 _sequenceNumberForced(false),
73 _sequenceNumber(0),
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +000074 _sequenceNumberRTX(0),
niklase@google.com470e71d2011-07-07 08:21:25 +000075 _ssrcForced(false),
76 _ssrc(0),
77 _timeStamp(0),
78 _CSRCs(0),
79 _CSRC(),
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +000080 _includeCSRCs(true),
81 _RTX(false),
82 _ssrcRTX(0)
niklase@google.com470e71d2011-07-07 08:21:25 +000083{
84 memset(_nackByteCountTimes, 0, sizeof(_nackByteCountTimes));
85 memset(_nackByteCount, 0, sizeof(_nackByteCount));
86
87 memset(_CSRC, 0, sizeof(_CSRC));
88
89 // 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 +000090 srand( (WebRtc_UWord32)_clock.GetTimeInMS() );
niklase@google.com470e71d2011-07-07 08:21:25 +000091
92 _ssrc = _ssrcDB.CreateSSRC(); // can't be 0
93
94 if(audio)
95 {
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000096 _audio = new RTPSenderAudio(id, &_clock, this);
niklase@google.com470e71d2011-07-07 08:21:25 +000097 } else
98 {
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000099 _video = new RTPSenderVideo(id, &_clock, this);
niklase@google.com470e71d2011-07-07 08:21:25 +0000100 }
101 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
102}
103
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000104RTPSender::~RTPSender() {
105 if(_remoteSSRC != 0) {
106 _ssrcDB.ReturnSSRC(_remoteSSRC);
107 }
108 _ssrcDB.ReturnSSRC(_ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000109
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000110 SSRCDatabase::ReturnSSRCDatabase();
111 delete _sendCritsect;
112 delete _transportCritsect;
113 while (!_payloadTypeMap.empty()) {
114 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
115 _payloadTypeMap.begin();
116 delete it->second;
117 _payloadTypeMap.erase(it);
118 }
119 delete _packetHistory;
120 delete _audio;
121 delete _video;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000122
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000123 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, _id, "%s deleted", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +0000124}
125
126WebRtc_Word32
127RTPSender::Init(const WebRtc_UWord32 remoteSSRC)
128{
129 CriticalSectionScoped cs(_sendCritsect);
130
131 // reset to default generation
132 _ssrcForced = false;
133 _startTimeStampForced = false;
134
135 // register a remote SSRC if we have it to avoid collisions
136 if(remoteSSRC != 0)
137 {
138 if(_ssrc == remoteSSRC)
139 {
140 // collision detected
141 _ssrc = _ssrcDB.CreateSSRC(); // can't be 0
142 }
143 _remoteSSRC = remoteSSRC;
144 _ssrcDB.RegisterSSRC(remoteSSRC);
145 }
146 _sequenceNumber = rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000147 _sequenceNumberRTX = rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);
niklase@google.com470e71d2011-07-07 08:21:25 +0000148 _packetsSent = 0;
149 _payloadBytesSent = 0;
150 _packetOverHead = 28;
151
152 _keepAlivePayloadType = -1;
153
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000154 _rtpHeaderExtensionMap.Erase();
155
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000156 while (!_payloadTypeMap.empty()) {
157 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
158 _payloadTypeMap.begin();
159 delete it->second;
160 _payloadTypeMap.erase(it);
161 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000162
163 memset(_CSRC, 0, sizeof(_CSRC));
164
165 memset(_nackByteCount, 0, sizeof(_nackByteCount));
166 memset(_nackByteCountTimes, 0, sizeof(_nackByteCountTimes));
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000167 _nackBitrate.Init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000168
169 SetStorePacketsStatus(false, 0);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000170 _sendBucket.Reset();
niklase@google.com470e71d2011-07-07 08:21:25 +0000171
172 Bitrate::Init();
173
174 if(_audioConfigured)
175 {
176 _audio->Init();
177 } else
178 {
179 _video->Init();
180 }
181 return(0);
182}
183
184void
185RTPSender::ChangeUniqueId(const WebRtc_Word32 id)
186{
187 _id = id;
188 if(_audioConfigured)
189 {
190 _audio->ChangeUniqueId(id);
191 } else
192 {
193 _video->ChangeUniqueId(id);
194 }
195}
196
197WebRtc_Word32
198RTPSender::SetTargetSendBitrate(const WebRtc_UWord32 bits)
199{
200 _targetSendBitrate = (WebRtc_UWord16)(bits/1000);
201 return 0;
202}
203
204WebRtc_UWord16
205RTPSender::TargetSendBitrateKbit() const
206{
207 return _targetSendBitrate;
208}
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000209
niklase@google.com470e71d2011-07-07 08:21:25 +0000210WebRtc_UWord16
211RTPSender::ActualSendBitrateKbit() const
212{
213 return (WebRtc_UWord16) (Bitrate::BitrateNow()/1000);
214}
215
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000216WebRtc_UWord32
stefan@webrtc.orgfbea4e52011-10-27 16:08:29 +0000217RTPSender::VideoBitrateSent() const {
218 if (_video)
219 return _video->VideoBitrateSent();
220 else
221 return 0;
222}
223
224WebRtc_UWord32
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000225RTPSender::FecOverheadRate() const {
stefan@webrtc.orgfbea4e52011-10-27 16:08:29 +0000226 if (_video)
227 return _video->FecOverheadRate();
228 else
229 return 0;
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000230}
231
232WebRtc_UWord32
233RTPSender::NackOverheadRate() const {
234 return _nackBitrate.BitrateLast();
235}
236
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000237WebRtc_Word32
238RTPSender::SetTransmissionTimeOffset(
239 const WebRtc_Word32 transmissionTimeOffset)
240{
241 if (transmissionTimeOffset > (0x800000 - 1) ||
242 transmissionTimeOffset < -(0x800000 - 1)) // Word24
243 {
244 return -1;
245 }
246 CriticalSectionScoped cs(_sendCritsect);
247 _transmissionTimeOffset = transmissionTimeOffset;
248 return 0;
249}
250
251WebRtc_Word32
252RTPSender::RegisterRtpHeaderExtension(const RTPExtensionType type,
253 const WebRtc_UWord8 id)
254{
255 CriticalSectionScoped cs(_sendCritsect);
256 return _rtpHeaderExtensionMap.Register(type, id);
257}
258
259WebRtc_Word32
260RTPSender::DeregisterRtpHeaderExtension(const RTPExtensionType type)
261{
262 CriticalSectionScoped cs(_sendCritsect);
263 return _rtpHeaderExtensionMap.Deregister(type);
264}
265
266WebRtc_UWord16
267RTPSender::RtpHeaderExtensionTotalLength() const
268{
269 CriticalSectionScoped cs(_sendCritsect);
270 return _rtpHeaderExtensionMap.GetTotalLengthInBytes();
271}
272
niklase@google.com470e71d2011-07-07 08:21:25 +0000273//can be called multiple times
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000274WebRtc_Word32 RTPSender::RegisterPayload(
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000275 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000276 const WebRtc_Word8 payloadNumber,
277 const WebRtc_UWord32 frequency,
278 const WebRtc_UWord8 channels,
279 const WebRtc_UWord32 rate) {
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000280 assert(payloadName);
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000281 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000282
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000283 if (payloadNumber == _keepAlivePayloadType) {
284 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "invalid state",
285 __FUNCTION__);
286 return -1;
287 }
288 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
289 _payloadTypeMap.find(payloadNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +0000290
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000291 if (_payloadTypeMap.end() != it) {
292 // we already use this payload type
293 ModuleRTPUtility::Payload* payload = it->second;
294 assert(payload);
niklase@google.com470e71d2011-07-07 08:21:25 +0000295
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000296 // check if it's the same as we already have
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000297 if (ModuleRTPUtility::StringCompare(payload->name, payloadName,
298 RTP_PAYLOAD_NAME_SIZE - 1)) {
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000299 if (_audioConfigured && payload->audio &&
300 payload->typeSpecific.Audio.frequency == frequency &&
301 (payload->typeSpecific.Audio.rate == rate ||
302 payload->typeSpecific.Audio.rate == 0 || rate == 0)) {
303 payload->typeSpecific.Audio.rate = rate;
304 // Ensure that we update the rate if new or old is zero
niklase@google.com470e71d2011-07-07 08:21:25 +0000305 return 0;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000306 }
307 if(!_audioConfigured && !payload->audio) {
308 return 0;
309 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000310 }
311 return -1;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000312 }
313 WebRtc_Word32 retVal = -1;
314 ModuleRTPUtility::Payload* payload = NULL;
315 if (_audioConfigured) {
316 retVal = _audio->RegisterAudioPayload(payloadName, payloadNumber, frequency,
317 channels, rate, payload);
318 } else {
319 retVal = _video->RegisterVideoPayload(payloadName, payloadNumber, rate,
320 payload);
321 }
322 if(payload) {
323 _payloadTypeMap[payloadNumber] = payload;
324 }
325 return retVal;
niklase@google.com470e71d2011-07-07 08:21:25 +0000326}
327
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000328WebRtc_Word32 RTPSender::DeRegisterSendPayload(const WebRtc_Word8 payloadType) {
329 CriticalSectionScoped lock(_sendCritsect);
330
331 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
332 _payloadTypeMap.find(payloadType);
333
334 if (_payloadTypeMap.end() == it) return -1;
335
336 ModuleRTPUtility::Payload* payload = it->second;
337 delete payload;
338 _payloadTypeMap.erase(it);
339 return 0;
340}
niklase@google.com470e71d2011-07-07 08:21:25 +0000341
342WebRtc_Word8 RTPSender::SendPayloadType() const
343{
344 return _payloadType;
345}
346
347
348int RTPSender::SendPayloadFrequency() const
349{
350 return _audio->AudioFrequency();
351}
352
353
354// See http://www.ietf.org/internet-drafts/draft-ietf-avt-app-rtp-keepalive-04.txt
355// for details about this method. Only Section 4.6 is implemented so far.
356bool
357RTPSender::RTPKeepalive() const
358{
359 return _keepAliveIsActive;
360}
361
362WebRtc_Word32
363RTPSender::RTPKeepaliveStatus(bool* enable,
364 WebRtc_Word8* unknownPayloadType,
365 WebRtc_UWord16* deltaTransmitTimeMS) const
366{
367 CriticalSectionScoped cs(_sendCritsect);
368
369 if(enable)
370 {
371 *enable = _keepAliveIsActive;
372 }
373 if(unknownPayloadType)
374 {
375 *unknownPayloadType = _keepAlivePayloadType;
376 }
377 if(deltaTransmitTimeMS)
378 {
379 *deltaTransmitTimeMS =_keepAliveDeltaTimeSend;
380 }
381 return 0;
382}
383
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000384WebRtc_Word32 RTPSender::EnableRTPKeepalive(
385 const WebRtc_Word8 unknownPayloadType,
386 const WebRtc_UWord16 deltaTransmitTimeMS) {
387 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000388
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000389 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
390 _payloadTypeMap.find(unknownPayloadType);
niklase@google.com470e71d2011-07-07 08:21:25 +0000391
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000392 if (it != _payloadTypeMap.end()) {
393 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument",
394 __FUNCTION__);
395 return -1;
396 }
397 _keepAliveIsActive = true;
398 _keepAlivePayloadType = unknownPayloadType;
399 _keepAliveLastSent = _clock.GetTimeInMS();
400 _keepAliveDeltaTimeSend = deltaTransmitTimeMS;
401 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000402}
403
404WebRtc_Word32
405RTPSender::DisableRTPKeepalive()
406{
407 _keepAliveIsActive = false;
408 return 0;
409}
410
411bool
412RTPSender::TimeToSendRTPKeepalive() const
413{
414 CriticalSectionScoped cs(_sendCritsect);
415
416 bool timeToSend(false);
417
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000418 WebRtc_UWord32 dT = _clock.GetTimeInMS() - _keepAliveLastSent;
niklase@google.com470e71d2011-07-07 08:21:25 +0000419 if (dT > _keepAliveDeltaTimeSend)
420 {
421 timeToSend = true;
422 }
423 return timeToSend;
424}
425
426// ----------------------------------------------------------------------------
427// From the RFC draft:
428//
429// 4.6. RTP Packet with Unknown Payload Type
430//
431// The application sends an RTP packet of 0 length with a dynamic
432// payload type that has not been negotiated by the peers (e.g. not
433// negotiated within the SDP offer/answer, and thus not mapped to any
434// media format).
435//
436// The sequence number is incremented by one for each packet, as it is
437// sent within the same RTP session as the actual media. The timestamp
438// contains the same value a media packet would have at this time. The
439// marker bit is not significant for the keepalive packets and is thus
440// set to zero.
441//
442// Normally the peer will ignore this packet, as RTP [RFC3550] states
443// that "a receiver MUST ignore packets with payload types that it does
444// not understand".
445//
446// Cons:
447// o [RFC4566] and [RFC3264] mandate not to send media with inactive
448// and recvonly attributes, however this is mitigated as no real
449// media is sent with this mechanism.
450//
451// Recommendation:
452// o This method should be used for RTP keepalive.
453//
454// 7. Timing and Transport Considerations
455//
456// An application supporting this specification must transmit keepalive
457// packets every Tr seconds during the whole duration of the media
458// session. Tr SHOULD be configurable, and otherwise MUST default to 15
459// seconds.
460//
461// Keepalives packets within a particular RTP session MUST use the tuple
462// (source IP address, source TCP/UDP ports, target IP address, target
463// TCP/UDP Port) of the regular RTP packets.
464//
465// The agent SHOULD only send RTP keepalive when it does not send
466// regular RTP packets.
467//
468// http://www.ietf.org/internet-drafts/draft-ietf-avt-app-rtp-keepalive-04.txt
469// ----------------------------------------------------------------------------
470
471WebRtc_Word32
472RTPSender::SendRTPKeepalivePacket()
473{
474 // RFC summary:
475 //
476 // - Send an RTP packet of 0 length;
477 // - dynamic payload type has not been negotiated (not mapped to any media);
478 // - sequence number is incremented by one for each packet;
479 // - timestamp contains the same value a media packet would have at this time;
480 // - marker bit is set to zero.
481
482 WebRtc_UWord8 dataBuffer[IP_PACKET_SIZE];
483 WebRtc_UWord16 rtpHeaderLength = 12;
484 {
485 CriticalSectionScoped cs(_sendCritsect);
486
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000487 WebRtc_UWord32 now = _clock.GetTimeInMS();
niklase@google.com470e71d2011-07-07 08:21:25 +0000488 WebRtc_UWord32 dT = now -_keepAliveLastSent; // delta time in MS
489
490 WebRtc_UWord32 freqKHz = 90; // video
491 if(_audioConfigured)
492 {
493 freqKHz = _audio->AudioFrequency()/1000;
494 }
495 WebRtc_UWord32 dSamples = dT*freqKHz;
496
497 // set timestamp
498 _timeStamp += dSamples;
499 _keepAliveLastSent = now;
500
501 rtpHeaderLength = RTPHeaderLength();
502
503 // correct seq num, time stamp and payloadtype
504 BuildRTPheader(dataBuffer, _keepAlivePayloadType, false, 0, false);
505 }
506
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000507 return SendToNetwork(dataBuffer, 0, rtpHeaderLength, kAllowRetransmission);
niklase@google.com470e71d2011-07-07 08:21:25 +0000508}
509
510WebRtc_Word32
511RTPSender::SetMaxPayloadLength(const WebRtc_UWord16 maxPayloadLength, const WebRtc_UWord16 packetOverHead)
512{
513 // sanity check
514 if(maxPayloadLength < 100 || maxPayloadLength > IP_PACKET_SIZE)
515 {
516 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
517 return -1;
518 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000519
520 CriticalSectionScoped cs(_sendCritsect);
521 _maxPayloadLength = maxPayloadLength;
522 _packetOverHead = packetOverHead;
523
524 WEBRTC_TRACE(kTraceInfo, kTraceRtpRtcp, _id, "SetMaxPayloadLength to %d.", maxPayloadLength);
525 return 0;
526}
527
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000528WebRtc_UWord16 RTPSender::MaxDataPayloadLength() const {
529 if(_audioConfigured) {
530 return _maxPayloadLength - RTPHeaderLength();
531 } else {
532 return _maxPayloadLength - RTPHeaderLength() -
533 _video->FECPacketOverhead() - ((_RTX) ? 2 : 0);
534 // Include the FEC/ULP/RED overhead.
535 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000536}
537
538WebRtc_UWord16
539RTPSender::MaxPayloadLength() const
540{
541 return _maxPayloadLength;
542}
543
544WebRtc_UWord16
545RTPSender::PacketOverHead() const
546{
547 return _packetOverHead;
548}
549
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000550void RTPSender::SetTransmissionSmoothingStatus(const bool enable) {
551 CriticalSectionScoped cs(_sendCritsect);
552 _transmissionSmoothing = enable;
553}
554
555bool RTPSender::TransmissionSmoothingStatus() const {
556 CriticalSectionScoped cs(_sendCritsect);
557 return _transmissionSmoothing;
558}
559
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000560void RTPSender::SetRTXStatus(const bool enable,
561 const bool setSSRC,
562 const WebRtc_UWord32 SSRC) {
563 CriticalSectionScoped cs(_sendCritsect);
564 _RTX = enable;
565 if (enable) {
566 if (setSSRC) {
567 _ssrcRTX = SSRC;
568 } else {
569 _ssrcRTX = _ssrcDB.CreateSSRC(); // can't be 0
570 }
571 }
572}
573
574void RTPSender::RTXStatus(bool* enable,
575 WebRtc_UWord32* SSRC) const {
576 CriticalSectionScoped cs(_sendCritsect);
577 *enable = _RTX;
578 *SSRC = _ssrcRTX;
579}
580
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000581WebRtc_Word32 RTPSender::CheckPayloadType(const WebRtc_Word8 payloadType,
582 RtpVideoCodecTypes& videoType) {
583 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000584
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000585 if (payloadType < 0) {
586 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
587 "\tinvalid payloadType (%d)", payloadType);
588 return -1;
589 }
590 if (_audioConfigured) {
591 WebRtc_Word8 redPlType = -1;
592 if (_audio->RED(redPlType) == 0) {
593 // We have configured RED.
594 if(redPlType == payloadType) {
595 // And it's a match...
596 return 0;
597 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000598 }
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000599 }
600 if (_payloadType == payloadType) {
601 if (!_audioConfigured) {
602 videoType = _video->VideoCodecType();
niklase@google.com470e71d2011-07-07 08:21:25 +0000603 }
604 return 0;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000605 }
606 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
607 _payloadTypeMap.find(payloadType);
608 if (it == _payloadTypeMap.end()) {
609 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
610 "\tpayloadType:%d not registered", payloadType);
611 return -1;
612 }
613 _payloadType = payloadType;
614 ModuleRTPUtility::Payload* payload = it->second;
615 assert(payload);
616 if (payload->audio) {
617 if (_audioConfigured) {
618 // Extract payload frequency
619 int payloadFreqHz;
620 if (ModuleRTPUtility::StringCompare(payload->name,"g722",4)&&
621 (payload->name[4] == 0)) {
622 //Check that strings end there, g722.1...
623 // Special case for G.722, bug in spec
624 payloadFreqHz=8000;
625 } else {
626 payloadFreqHz=payload->typeSpecific.Audio.frequency;
627 }
628
629 //we don't do anything if it's CN
630 if ((_audio->AudioFrequency() != payloadFreqHz)&&
631 (!ModuleRTPUtility::StringCompare(payload->name,"cn",2))) {
632 _audio->SetAudioFrequency(payloadFreqHz);
633 // We need to correct the timestamp again,
634 // since this might happen after we've set it
635 WebRtc_UWord32 RTPtime =
636 ModuleRTPUtility::GetCurrentRTP(&_clock, payloadFreqHz);
637 SetStartTimestamp(RTPtime);
638 // will be ignored if it's already configured via API
639 }
640 }
641 } else {
642 if(!_audioConfigured) {
643 _video->SetVideoCodecType(payload->typeSpecific.Video.videoCodecType);
644 videoType = payload->typeSpecific.Video.videoCodecType;
645 _video->SetMaxConfiguredBitrateVideo(
646 payload->typeSpecific.Video.maxRate);
647 }
648 }
649 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000650}
651
652WebRtc_Word32
653RTPSender::SendOutgoingData(const FrameType frameType,
654 const WebRtc_Word8 payloadType,
655 const WebRtc_UWord32 captureTimeStamp,
656 const WebRtc_UWord8* payloadData,
657 const WebRtc_UWord32 payloadSize,
658 const RTPFragmentationHeader* fragmentation,
659 VideoCodecInformation* codecInfo,
660 const RTPVideoTypeHeader* rtpTypeHdr)
661{
662 {
663 // Drop this packet if we're not sending media packets
664 CriticalSectionScoped cs(_sendCritsect);
665 if (!_sendingMedia)
666 {
667 return 0;
668 }
669 }
niklas.enbom@webrtc.org553657b2012-01-12 08:49:34 +0000670 RtpVideoCodecTypes videoType = kRtpNoVideo;
niklase@google.com470e71d2011-07-07 08:21:25 +0000671 if(CheckPayloadType(payloadType, videoType) != 0)
672 {
673 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument failed to find payloadType:%d", __FUNCTION__, payloadType);
674 return -1;
675 }
676 // update keepalive so that we don't trigger keepalive messages while sending data
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000677 _keepAliveLastSent = _clock.GetTimeInMS();
niklase@google.com470e71d2011-07-07 08:21:25 +0000678
679 if(_audioConfigured)
680 {
681 // assert video frameTypes
682 assert(frameType == kAudioFrameSpeech ||
683 frameType == kAudioFrameCN ||
684 frameType == kFrameEmpty);
685
686 return _audio->SendAudio(frameType, payloadType, captureTimeStamp, payloadData, payloadSize,fragmentation);
687 } else
688 {
689 // assert audio frameTypes
690 assert(frameType == kVideoFrameKey ||
691 frameType == kVideoFrameDelta ||
692 frameType == kVideoFrameGolden ||
693 frameType == kVideoFrameAltRef);
694
695 return _video->SendVideo(videoType,
696 frameType,
697 payloadType,
698 captureTimeStamp,
699 payloadData,
700 payloadSize,
701 fragmentation,
702 codecInfo,
703 rtpTypeHdr);
704 }
705}
706
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000707WebRtc_Word32 RTPSender::SendPadData(WebRtc_Word8 payload_type,
708 WebRtc_UWord32 capture_timestamp,
709 WebRtc_Word32 bytes) {
710 // Drop this packet if we're not sending media packets
711 if (!_sendingMedia) {
712 return 0;
713 }
714 // Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP.
715 int max_length = 224;
716 WebRtc_UWord8 data_buffer[IP_PACKET_SIZE];
717
718 for (; bytes > 0; bytes -= max_length) {
719 WebRtc_Word32 header_length;
720 {
721 // Correct seq num, timestamp and payload type.
722 header_length = BuildRTPheader(data_buffer,
723 payload_type,
724 false, // No markerbit.
725 capture_timestamp,
726 true, // Timestamp provided.
727 true); // Increment sequence number.
728 }
729 data_buffer[0] |= 0x20; // Set padding bit.
730 WebRtc_Word32* data =
731 reinterpret_cast<WebRtc_Word32*>(&(data_buffer[header_length]));
732
733 int padding_bytes_in_packet = max_length;
734 if (bytes < max_length) {
735 padding_bytes_in_packet = (bytes + 16) & 0xffe0; // Keep our modulus 32.
736 }
737 if (padding_bytes_in_packet < 32) {
738 // Sanity don't send empty packets.
739 break;
740 }
741 // Fill data buffer with random data.
742 for(int j = 0; j < (padding_bytes_in_packet >> 2); j++) {
743 data[j] = rand();
744 }
745 // Set number of padding bytes in the last byte of the packet.
746 data_buffer[header_length + padding_bytes_in_packet - 1] =
747 padding_bytes_in_packet;
748 // Send the packet
749 if (0 > SendToNetwork(data_buffer,
750 padding_bytes_in_packet,
751 header_length,
752 kDontRetransmit)) {
753 // Error sending the packet.
754 break;
755 }
756 }
757 if (bytes > 31) { // 31 due to our modulus 32.
758 // We did not manage to send all bytes.
759 return -1;
760 }
761 return 0;
762}
763
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000764WebRtc_Word32 RTPSender::SetStorePacketsStatus(
765 const bool enable,
766 const WebRtc_UWord16 numberToStore) {
767 _packetHistory->SetStorePacketsStatus(enable, numberToStore);
768 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000769}
770
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000771bool RTPSender::StorePackets() const {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000772 return _packetHistory->StorePackets();
niklase@google.com470e71d2011-07-07 08:21:25 +0000773}
774
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000775WebRtc_Word32 RTPSender::ReSendPacket(WebRtc_UWord16 packet_id,
776 WebRtc_UWord32 min_resend_time) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000777
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000778 WebRtc_UWord16 length = IP_PACKET_SIZE;
779 WebRtc_UWord8 data_buffer[IP_PACKET_SIZE];
780 WebRtc_UWord8* buffer_to_send_ptr = data_buffer;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000781
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000782 WebRtc_UWord32 stored_time_in_ms;
783 StorageType type;
784 bool found = _packetHistory->GetRTPPacket(packet_id,
785 min_resend_time, data_buffer, &length, &stored_time_in_ms, &type);
786 if (!found) {
787 // Packet not found.
788 return -1;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000789 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000790
791 if (length == 0 || type == kDontRetransmit) {
792 // No bytes copied (packet recently resent, skip resending) or
793 // packet should not be retransmitted.
794 return 0;
795 }
796
pwestin@webrtc.orgb30f0ed2012-01-23 16:23:31 +0000797 WebRtc_UWord8 data_buffer_rtx[IP_PACKET_SIZE];
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000798 if (_RTX) {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000799 buffer_to_send_ptr = data_buffer_rtx;
800
801 CriticalSectionScoped cs(_sendCritsect);
802 // Add RTX header.
803 ModuleRTPUtility::RTPHeaderParser rtpParser(
804 reinterpret_cast<const WebRtc_UWord8*>(data_buffer),
805 length);
806
807 WebRtcRTPHeader rtp_header;
808 rtpParser.Parse(rtp_header);
809
810 // Add original RTP header.
811 memcpy(data_buffer_rtx, data_buffer, rtp_header.header.headerLength);
812
813 // Replace sequence number.
814 WebRtc_UWord8* ptr = data_buffer_rtx + 2;
815 ModuleRTPUtility::AssignUWord16ToBuffer(ptr, _sequenceNumberRTX++);
816
817 // Replace SSRC.
818 ptr += 6;
819 ModuleRTPUtility::AssignUWord32ToBuffer(ptr, _ssrcRTX);
820
821 // Add OSN (original sequence number).
822 ptr = data_buffer_rtx + rtp_header.header.headerLength;
823 ModuleRTPUtility::AssignUWord16ToBuffer(
824 ptr, rtp_header.header.sequenceNumber);
825 ptr += 2;
826
827 // Add original payload data.
828 memcpy(ptr,
829 data_buffer + rtp_header.header.headerLength,
830 length - rtp_header.header.headerLength);
831 length += 2;
832 }
833
834 WebRtc_Word32 bytes_sent = ReSendToNetwork(buffer_to_send_ptr, length);
835 if (bytes_sent <= 0) {
836 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
837 "Transport failed to resend packet_id %u", packet_id);
838 return -1;
839 }
840
841 // Store the time when the packet was last resent.
842 _packetHistory->UpdateResendTime(packet_id);
843
844 return bytes_sent;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000845}
846
847WebRtc_Word32 RTPSender::ReSendToNetwork(const WebRtc_UWord8* packet,
848 const WebRtc_UWord32 size) {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000849 WebRtc_Word32 bytes_sent = -1;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000850 {
851 CriticalSectionScoped lock(_transportCritsect);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000852 if (_transport) {
853 bytes_sent = _transport->SendPacket(_id, packet, size);
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000854 }
855 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000856
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000857 if (bytes_sent <= 0) {
858 return -1;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000859 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000860
861 // Update send statistics
862 CriticalSectionScoped cs(_sendCritsect);
863 Bitrate::Update(bytes_sent);
864 _packetsSent++;
865 // We on purpose don't add to _payloadBytesSent since this is a
866 // re-transmit and not new payload data.
867 return bytes_sent;
niklase@google.com470e71d2011-07-07 08:21:25 +0000868}
869
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000870int RTPSender::SelectiveRetransmissions() const {
871 if (!_video) return -1;
872 return _video->SelectiveRetransmissions();
873}
874
875int RTPSender::SetSelectiveRetransmissions(uint8_t settings) {
876 if (!_video) return -1;
877 return _video->SetSelectiveRetransmissions(settings);
878}
879
niklase@google.com470e71d2011-07-07 08:21:25 +0000880void
881RTPSender::OnReceivedNACK(const WebRtc_UWord16 nackSequenceNumbersLength,
882 const WebRtc_UWord16* nackSequenceNumbers,
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000883 const WebRtc_UWord16 avgRTT) {
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000884 const WebRtc_UWord32 now = _clock.GetTimeInMS();
niklase@google.com470e71d2011-07-07 08:21:25 +0000885 WebRtc_UWord32 bytesReSent = 0;
886
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000887 // Enough bandwidth to send NACK?
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000888 if (!ProcessNACKBitRate(now)) {
889 WEBRTC_TRACE(kTraceStream,
890 kTraceRtpRtcp,
891 _id,
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000892 "NACK bitrate reached. Skip sending NACK response. Target %d",
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000893 TargetSendBitrateKbit());
894 return;
895 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000896
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000897 for (WebRtc_UWord16 i = 0; i < nackSequenceNumbersLength; ++i) {
898 const WebRtc_Word32 bytesSent = ReSendPacket(nackSequenceNumbers[i],
899 5+avgRTT);
900 if (bytesSent > 0) {
901 bytesReSent += bytesSent;
902 } else if (bytesSent == 0) {
903 // The packet has previously been resent.
904 // Try resending next packet in the list.
905 continue;
906 } else if (bytesSent < 0) {
907 // Failed to send one Sequence number. Give up the rest in this nack.
908 WEBRTC_TRACE(kTraceWarning,
909 kTraceRtpRtcp,
910 _id,
911 "Failed resending RTP packet %d, Discard rest of packets",
912 nackSequenceNumbers[i]);
913 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000914 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000915 // delay bandwidth estimate (RTT * BW)
916 if (TargetSendBitrateKbit() != 0 && avgRTT) {
917 // kbits/s * ms = bits => bits/8 = bytes
918 WebRtc_UWord32 targetBytes =
919 (static_cast<WebRtc_UWord32>(TargetSendBitrateKbit()) * avgRTT) >> 3;
920 if (bytesReSent > targetBytes) {
921 break; // ignore the rest of the packets in the list
922 }
923 }
924 }
925 if (bytesReSent > 0) {
926 // TODO(pwestin) consolidate these two methods.
927 UpdateNACKBitRate(bytesReSent, now);
928 _nackBitrate.Update(bytesReSent);
929 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000930}
931
932/**
933* @return true if the nack bitrate is lower than the requested max bitrate
934*/
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000935bool RTPSender::ProcessNACKBitRate(const WebRtc_UWord32 now) {
936 WebRtc_UWord32 num = 0;
937 WebRtc_Word32 byteCount = 0;
938 const WebRtc_UWord32 avgInterval=1000;
niklase@google.com470e71d2011-07-07 08:21:25 +0000939
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000940 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000941
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000942 if (_targetSendBitrate == 0) {
943 return true;
944 }
945 for (num = 0; num < NACK_BYTECOUNT_SIZE; num++) {
946 if ((now - _nackByteCountTimes[num]) > avgInterval) {
947 // don't use data older than 1sec
948 break;
949 } else {
950 byteCount += _nackByteCount[num];
niklase@google.com470e71d2011-07-07 08:21:25 +0000951 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000952 }
953 WebRtc_Word32 timeInterval = avgInterval;
954 if (num == NACK_BYTECOUNT_SIZE) {
955 // More than NACK_BYTECOUNT_SIZE nack messages has been received
956 // during the last msgInterval
957 timeInterval = now - _nackByteCountTimes[num-1];
958 if(timeInterval < 0) {
959 timeInterval = avgInterval;
niklase@google.com470e71d2011-07-07 08:21:25 +0000960 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000961 }
962 return (byteCount*8) < (_targetSendBitrate * timeInterval);
niklase@google.com470e71d2011-07-07 08:21:25 +0000963}
964
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000965void RTPSender::UpdateNACKBitRate(const WebRtc_UWord32 bytes,
966 const WebRtc_UWord32 now) {
967 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000968
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000969 // save bitrate statistics
970 if(bytes > 0) {
971 if(now == 0) {
972 // add padding length
973 _nackByteCount[0] += bytes;
974 } else {
975 if(_nackByteCountTimes[0] == 0) {
976 // first no shift
977 } else {
978 // shift
979 for(int i = (NACK_BYTECOUNT_SIZE-2); i >= 0 ; i--) {
980 _nackByteCount[i+1] = _nackByteCount[i];
981 _nackByteCountTimes[i+1] = _nackByteCountTimes[i];
niklase@google.com470e71d2011-07-07 08:21:25 +0000982 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000983 }
984 _nackByteCount[0] = bytes;
985 _nackByteCountTimes[0] = now;
niklase@google.com470e71d2011-07-07 08:21:25 +0000986 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000987 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000988}
989
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000990void RTPSender::ProcessSendToNetwork() {
991
992 // triggered by timer
993 WebRtc_UWord32 delta_time_ms;
994 {
995 CriticalSectionScoped cs(_sendCritsect);
996
997 if (!_transmissionSmoothing) {
998 return;
999 }
1000
1001 WebRtc_UWord32 now = _clock.GetTimeInMS();
1002 delta_time_ms = now - _timeLastSendToNetworkUpdate;
1003 _timeLastSendToNetworkUpdate = now;
1004 }
1005
1006 _sendBucket.UpdateBytesPerInterval(delta_time_ms, _targetSendBitrate);
1007
1008 while (!_sendBucket.Empty()) {
1009
1010 WebRtc_Word32 seq_num = _sendBucket.GetNextPacket();
1011 if (seq_num < 0) {
1012 break;
1013 }
1014
1015 WebRtc_UWord8 data_buffer[IP_PACKET_SIZE];
1016 WebRtc_UWord16 length = IP_PACKET_SIZE;
1017 WebRtc_UWord32 stored_time_ms;
1018 StorageType type;
asapersson@webrtc.org869ce2d2012-01-16 11:58:36 +00001019 bool found = _packetHistory->GetRTPPacket(seq_num, 0, data_buffer, &length,
1020 &stored_time_ms, &type);
1021 if (!found) {
1022 assert(false);
1023 return;
1024 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001025 assert(length > 0);
1026
1027 WebRtc_UWord32 diff_ms = _clock.GetTimeInMS() - stored_time_ms;
1028
1029 ModuleRTPUtility::RTPHeaderParser rtpParser(data_buffer, length);
1030 WebRtcRTPHeader rtp_header;
asapersson@webrtc.org869ce2d2012-01-16 11:58:36 +00001031 rtpParser.Parse(rtp_header);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001032
1033 UpdateTransmissionTimeOffset(data_buffer, length, rtp_header, diff_ms);
1034
1035 // Send packet
1036 WebRtc_Word32 bytes_sent = -1;
1037 {
1038 CriticalSectionScoped cs(_transportCritsect);
1039 if (_transport) {
1040 bytes_sent = _transport->SendPacket(_id, data_buffer, length);
1041 }
1042 }
1043
1044 // Update send statistics
1045 if (bytes_sent > 0) {
1046 CriticalSectionScoped cs(_sendCritsect);
1047 Bitrate::Update(bytes_sent);
1048 _packetsSent++;
1049 if (bytes_sent > rtp_header.header.headerLength) {
1050 _payloadBytesSent += bytes_sent - rtp_header.header.headerLength;
1051 }
1052 }
1053 }
1054}
1055
niklase@google.com470e71d2011-07-07 08:21:25 +00001056WebRtc_Word32
1057RTPSender::SendToNetwork(const WebRtc_UWord8* buffer,
1058 const WebRtc_UWord16 length,
1059 const WebRtc_UWord16 rtpLength,
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +00001060 const StorageType storage)
niklase@google.com470e71d2011-07-07 08:21:25 +00001061{
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001062 // Used for NACK or to spead out the transmission of packets.
1063 if (_packetHistory->PutRTPPacket(
1064 buffer, rtpLength + length, _maxPayloadLength, storage) != 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001065 return -1;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001066 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001067
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001068 if (_transmissionSmoothing) {
1069 const WebRtc_UWord16 sequenceNumber = (buffer[2] << 8) + buffer[3];
1070 _sendBucket.Fill(sequenceNumber, rtpLength + length);
1071 // Packet will be sent at a later time.
1072 return 0;
1073 }
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +00001074
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001075 // Send packet
1076 WebRtc_Word32 bytes_sent = -1;
1077 {
1078 CriticalSectionScoped cs(_transportCritsect);
1079 if (_transport) {
1080 bytes_sent = _transport->SendPacket(_id, buffer, length + rtpLength);
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +00001081 }
1082 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001083
1084 if (bytes_sent <= 0) {
1085 return -1;
1086 }
1087
1088 // Update send statistics
1089 CriticalSectionScoped cs(_sendCritsect);
1090 Bitrate::Update(bytes_sent);
1091 _packetsSent++;
1092 if (bytes_sent > rtpLength) {
1093 _payloadBytesSent += bytes_sent - rtpLength;
1094 }
1095 return 0;
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +00001096}
1097
niklase@google.com470e71d2011-07-07 08:21:25 +00001098void
1099RTPSender::ProcessBitrate()
1100{
1101 CriticalSectionScoped cs(_sendCritsect);
1102
1103 Bitrate::Process();
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +00001104 _nackBitrate.Process();
wu@webrtc.org76aea652011-10-17 21:40:32 +00001105
1106 if (_audioConfigured)
1107 return;
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +00001108 _video->ProcessBitrate();
niklase@google.com470e71d2011-07-07 08:21:25 +00001109}
1110
1111WebRtc_UWord16
1112RTPSender::RTPHeaderLength() const
1113{
1114 WebRtc_UWord16 rtpHeaderLength = 12;
1115
1116 if(_includeCSRCs)
1117 {
1118 rtpHeaderLength += sizeof(WebRtc_UWord32)*_CSRCs;
1119 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001120 rtpHeaderLength += RtpHeaderExtensionTotalLength();
1121
niklase@google.com470e71d2011-07-07 08:21:25 +00001122 return rtpHeaderLength;
1123}
1124
1125WebRtc_UWord16
1126RTPSender::IncrementSequenceNumber()
1127{
1128 CriticalSectionScoped cs(_sendCritsect);
1129 return _sequenceNumber++;
1130}
1131
1132WebRtc_Word32
1133RTPSender::ResetDataCounters()
1134{
1135 _packetsSent = 0;
1136 _payloadBytesSent = 0;
1137
1138 return 0;
1139}
1140
1141// number of sent RTP packets
1142// dont use critsect to avoid potental deadlock
1143WebRtc_UWord32
1144RTPSender::Packets() const
1145{
1146 return _packetsSent;
1147}
1148
1149// number of sent RTP bytes
1150// dont use critsect to avoid potental deadlock
1151WebRtc_UWord32
1152RTPSender::Bytes() const
1153{
1154 return _payloadBytesSent;
1155}
1156
1157WebRtc_Word32
1158RTPSender::BuildRTPheader(WebRtc_UWord8* dataBuffer,
1159 const WebRtc_Word8 payloadType,
1160 const bool markerBit,
1161 const WebRtc_UWord32 captureTimeStamp,
1162 const bool timeStampProvided,
1163 const bool incSequenceNumber)
1164{
1165 assert(payloadType>=0);
1166
1167 CriticalSectionScoped cs(_sendCritsect);
1168
1169 dataBuffer[0] = static_cast<WebRtc_UWord8>(0x80); // version 2
1170 dataBuffer[1] = static_cast<WebRtc_UWord8>(payloadType);
1171 if (markerBit)
1172 {
1173 dataBuffer[1] |= kRtpMarkerBitMask; // MarkerBit is set
1174 }
1175
1176 if(timeStampProvided)
1177 {
1178 _timeStamp = _startTimeStamp + captureTimeStamp;
1179 } else
1180 {
1181 // make a unique time stamp
1182 // used for inband signaling
1183 // we can't inc by the actual time, since then we increase the risk of back timing
1184 _timeStamp++;
1185 }
1186
1187 ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer+2, _sequenceNumber);
1188 ModuleRTPUtility::AssignUWord32ToBuffer(dataBuffer+4, _timeStamp);
1189 ModuleRTPUtility::AssignUWord32ToBuffer(dataBuffer+8, _ssrc);
1190
1191 WebRtc_Word32 rtpHeaderLength = 12;
1192
1193 // Add the CSRCs if any
1194 if (_includeCSRCs && _CSRCs > 0)
1195 {
1196 if(_CSRCs > kRtpCsrcSize)
1197 {
1198 // error
1199 assert(false);
1200 return -1;
1201 }
1202 WebRtc_UWord8* ptr = &dataBuffer[rtpHeaderLength];
1203 for (WebRtc_UWord32 i = 0; i < _CSRCs; ++i)
1204 {
1205 ModuleRTPUtility::AssignUWord32ToBuffer(ptr, _CSRC[i]);
1206 ptr +=4;
1207 }
1208 dataBuffer[0] = (dataBuffer[0]&0xf0) | _CSRCs;
1209
1210 // Update length of header
1211 rtpHeaderLength += sizeof(WebRtc_UWord32)*_CSRCs;
1212 }
1213 {
1214 _sequenceNumber++; // prepare for next packet
1215 }
1216
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001217 WebRtc_UWord16 len = BuildRTPHeaderExtension(dataBuffer + rtpHeaderLength);
1218 if (len)
1219 {
1220 dataBuffer[0] |= 0x10; // set eXtension bit
1221 rtpHeaderLength += len;
1222 }
1223
niklase@google.com470e71d2011-07-07 08:21:25 +00001224 return rtpHeaderLength;
1225}
1226
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001227WebRtc_UWord16
1228RTPSender::BuildRTPHeaderExtension(WebRtc_UWord8* dataBuffer) const
1229{
1230 if (_rtpHeaderExtensionMap.Size() <= 0) {
1231 return 0;
1232 }
1233
1234 /* RTP header extension, RFC 3550.
1235 0 1 2 3
1236 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
1237 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1238 | defined by profile | length |
1239 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1240 | header extension |
1241 | .... |
1242 */
1243
1244 const WebRtc_UWord32 kPosLength = 2;
1245 const WebRtc_UWord32 kHeaderLength = RTP_ONE_BYTE_HEADER_LENGTH_IN_BYTES;
1246
1247 // Add extension ID (0xBEDE).
1248 ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer,
1249 RTP_ONE_BYTE_HEADER_EXTENSION);
1250
1251 // Add extensions.
1252 WebRtc_UWord16 total_block_length = 0;
1253
1254 RTPExtensionType type = _rtpHeaderExtensionMap.First();
pwestin@webrtc.org6c1d4152012-01-04 17:04:51 +00001255 while (type != kRtpExtensionNone)
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001256 {
1257 WebRtc_UWord8 block_length = 0;
pwestin@webrtc.org6c1d4152012-01-04 17:04:51 +00001258 if (type == kRtpExtensionTransmissionTimeOffset)
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001259 {
1260 block_length = BuildTransmissionTimeOffsetExtension(
1261 dataBuffer + kHeaderLength + total_block_length);
1262 }
1263 total_block_length += block_length;
1264 type = _rtpHeaderExtensionMap.Next(type);
1265 }
1266
1267 if (total_block_length == 0)
1268 {
1269 // No extension added.
1270 return 0;
1271 }
1272
1273 // Set header length (in number of Word32, header excluded).
1274 assert(total_block_length % 4 == 0);
1275 ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer + kPosLength,
1276 total_block_length / 4);
1277
1278 // Total added length.
1279 return kHeaderLength + total_block_length;
1280}
1281
1282WebRtc_UWord8
1283RTPSender::BuildTransmissionTimeOffsetExtension(WebRtc_UWord8* dataBuffer) const
1284{
1285 // From RFC 5450: Transmission Time Offsets in RTP Streams.
1286 //
1287 // The transmission time is signaled to the receiver in-band using the
1288 // general mechanism for RTP header extensions [RFC5285]. The payload
1289 // of this extension (the transmitted value) is a 24-bit signed integer.
1290 // When added to the RTP timestamp of the packet, it represents the
1291 // "effective" RTP transmission time of the packet, on the RTP
1292 // timescale.
1293 //
1294 // The form of the transmission offset extension block:
1295 //
1296 // 0 1 2 3
1297 // 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 +00001298 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001299 // | ID | len=2 | transmission offset |
1300 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1301
1302 // Get id defined by user.
1303 WebRtc_UWord8 id;
pwestin@webrtc.org6c1d4152012-01-04 17:04:51 +00001304 if (_rtpHeaderExtensionMap.GetId(kRtpExtensionTransmissionTimeOffset, &id)
1305 != 0) {
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001306 // Not registered.
1307 return 0;
1308 }
1309
1310 int pos = 0;
1311 const WebRtc_UWord8 len = 2;
1312 dataBuffer[pos++] = (id << 4) + len;
1313 ModuleRTPUtility::AssignUWord24ToBuffer(dataBuffer + pos,
1314 _transmissionTimeOffset);
1315 pos += 3;
1316 assert(pos == TRANSMISSION_TIME_OFFSET_LENGTH_IN_BYTES);
1317 return TRANSMISSION_TIME_OFFSET_LENGTH_IN_BYTES;
1318}
1319
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001320void RTPSender::UpdateTransmissionTimeOffset(
1321 WebRtc_UWord8* rtp_packet,
1322 const WebRtc_UWord16 rtp_packet_length,
1323 const WebRtcRTPHeader& rtp_header,
1324 const WebRtc_UWord32 time_ms) const {
1325 CriticalSectionScoped cs(_sendCritsect);
1326
1327 // Get length until start of transmission block.
1328 int transmission_block_pos =
1329 _rtpHeaderExtensionMap.GetLengthUntilBlockStartInBytes(
1330 kRtpExtensionTransmissionTimeOffset);
1331 if (transmission_block_pos < 0) {
1332 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
1333 "Failed to update transmission time offset, not registered.");
1334 return;
1335 }
1336
1337 int block_pos = 12 + rtp_header.header.numCSRCs + transmission_block_pos;
1338 if ((rtp_packet_length < block_pos + 4)) {
1339 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
1340 "Failed to update transmission time offset, invalid length.");
1341 return;
1342 }
1343
1344 // Verify that header contains extension.
1345 if (!((rtp_packet[12 + rtp_header.header.numCSRCs] == 0xBE) &&
1346 (rtp_packet[12 + rtp_header.header.numCSRCs + 1] == 0xDE))) {
1347 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
1348 "Failed to update transmission time offset, hdr extension not found.");
1349 return;
1350 }
1351
1352 // Get id.
1353 WebRtc_UWord8 id = 0;
1354 if (_rtpHeaderExtensionMap.GetId(kRtpExtensionTransmissionTimeOffset,
1355 &id) != 0) {
1356 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
1357 "Failed to update transmission time offset, no id.");
1358 return;
1359 }
1360
1361 // Verify first byte in block.
1362 const WebRtc_UWord8 first_block_byte = (id << 4) + 2;
1363 if (rtp_packet[block_pos] != first_block_byte) {
1364 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
1365 "Failed to update transmission time offset.");
1366 return;
1367 }
1368
1369 // Update transmission offset field.
1370 ModuleRTPUtility::AssignUWord24ToBuffer(rtp_packet + block_pos + 1,
1371 time_ms * 90); // RTP timestamp
1372}
1373
niklase@google.com470e71d2011-07-07 08:21:25 +00001374WebRtc_Word32
1375RTPSender::RegisterSendTransport(Transport* transport)
1376{
1377 CriticalSectionScoped cs(_transportCritsect);
1378 _transport = transport;
1379 return 0;
1380}
1381
1382void
1383RTPSender::SetSendingStatus(const bool enabled)
1384{
1385 if(enabled)
1386 {
1387 WebRtc_UWord32 freq;
1388 if(_audioConfigured)
1389 {
1390 WebRtc_UWord32 frequency = _audio->AudioFrequency();
1391
1392 // sanity
1393 switch(frequency)
1394 {
1395 case 8000:
1396 case 12000:
1397 case 16000:
1398 case 24000:
1399 case 32000:
1400 break;
1401 default:
1402 assert(false);
1403 return;
1404 }
1405 freq = frequency;
1406 } else
1407 {
1408 freq = 90000; // 90 KHz for all video
1409 }
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +00001410 WebRtc_UWord32 RTPtime = ModuleRTPUtility::GetCurrentRTP(&_clock, freq);
niklase@google.com470e71d2011-07-07 08:21:25 +00001411
1412 SetStartTimestamp(RTPtime); // will be ignored if it's already configured via API
1413
1414 } else
1415 {
1416 if(!_ssrcForced)
1417 {
1418 // generate a new SSRC
1419 _ssrcDB.ReturnSSRC(_ssrc);
1420 _ssrc = _ssrcDB.CreateSSRC(); // can't be 0
1421
1422 }
1423 if(!_sequenceNumberForced && !_ssrcForced) // don't initialize seq number if SSRC passed externally
1424 {
1425 // generate a new sequence number
1426 _sequenceNumber = rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);
1427 }
1428 }
1429}
1430
1431void
1432RTPSender::SetSendingMediaStatus(const bool enabled)
1433{
1434 CriticalSectionScoped cs(_sendCritsect);
1435 _sendingMedia = enabled;
1436}
1437
1438bool
1439RTPSender::SendingMedia() const
1440{
1441 CriticalSectionScoped cs(_sendCritsect);
1442 return _sendingMedia;
1443}
1444
1445WebRtc_UWord32
1446RTPSender::Timestamp() const
1447{
1448 CriticalSectionScoped cs(_sendCritsect);
1449 return _timeStamp;
1450}
1451
1452
1453WebRtc_Word32
1454RTPSender::SetStartTimestamp( const WebRtc_UWord32 timestamp, const bool force)
1455{
1456 CriticalSectionScoped cs(_sendCritsect);
1457 if(force)
1458 {
1459 _startTimeStampForced = force;
1460 _startTimeStamp = timestamp;
1461 } else
1462 {
1463 if(!_startTimeStampForced)
1464 {
1465 _startTimeStamp = timestamp;
1466 }
1467 }
1468 return 0;
1469}
1470
1471WebRtc_UWord32
1472RTPSender::StartTimestamp() const
1473{
1474 CriticalSectionScoped cs(_sendCritsect);
1475 return _startTimeStamp;
1476}
1477
1478WebRtc_UWord32
1479RTPSender::GenerateNewSSRC()
1480{
1481 // if configured via API, return 0
1482 CriticalSectionScoped cs(_sendCritsect);
1483
1484 if(_ssrcForced)
1485 {
1486 return 0;
1487 }
1488 _ssrc = _ssrcDB.CreateSSRC(); // can't be 0
1489 return _ssrc;
1490}
1491
1492WebRtc_Word32
1493RTPSender::SetSSRC(WebRtc_UWord32 ssrc)
1494{
1495 // this is configured via the API
1496 CriticalSectionScoped cs(_sendCritsect);
1497
1498 if (_ssrc == ssrc && _ssrcForced)
1499 {
1500 return 0; // since it's same ssrc, don't reset anything
1501 }
1502
1503 _ssrcForced = true;
1504
1505 _ssrcDB.ReturnSSRC(_ssrc);
1506 _ssrcDB.RegisterSSRC(ssrc);
1507 _ssrc = ssrc;
1508
1509 if(!_sequenceNumberForced)
1510 {
1511 _sequenceNumber = rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);
1512 }
1513 return 0;
1514}
1515
1516WebRtc_UWord32
1517RTPSender::SSRC() const
1518{
1519 CriticalSectionScoped cs(_sendCritsect);
1520 return _ssrc;
1521}
1522
1523WebRtc_Word32
1524RTPSender::SetCSRCStatus(const bool include)
1525{
1526 _includeCSRCs = include;
1527 return 0;
1528}
1529
1530WebRtc_Word32
1531RTPSender::SetCSRCs(const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize],
1532 const WebRtc_UWord8 arrLength)
1533{
1534 if(arrLength > kRtpCsrcSize)
1535 {
1536 assert(false);
1537 return -1;
1538 }
1539
1540 CriticalSectionScoped cs(_sendCritsect);
1541
1542 for(int i = 0; i < arrLength;i++)
1543 {
1544 _CSRC[i] = arrOfCSRC[i];
1545 }
1546 _CSRCs = arrLength;
1547 return 0;
1548}
1549
1550WebRtc_Word32
1551RTPSender::CSRCs(WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]) const
1552{
1553 CriticalSectionScoped cs(_sendCritsect);
1554
1555 if(arrOfCSRC == NULL)
1556 {
1557 assert(false);
1558 return -1;
1559 }
1560 for(int i = 0; i < _CSRCs && i < kRtpCsrcSize;i++)
1561 {
1562 arrOfCSRC[i] = _CSRC[i];
1563 }
1564 return _CSRCs;
1565}
1566
1567WebRtc_Word32
1568RTPSender::SetSequenceNumber(WebRtc_UWord16 seq)
1569{
1570 CriticalSectionScoped cs(_sendCritsect);
1571 _sequenceNumberForced = true;
1572 _sequenceNumber = seq;
1573 return 0;
1574}
1575
1576WebRtc_UWord16
1577RTPSender::SequenceNumber() const
1578{
1579 CriticalSectionScoped cs(_sendCritsect);
1580 return _sequenceNumber;
1581}
1582
1583
1584 /*
1585 * Audio
1586 */
1587WebRtc_Word32
1588RTPSender::RegisterAudioCallback(RtpAudioFeedback* messagesCallback)
1589{
1590 if(!_audioConfigured)
1591 {
1592 return -1;
1593 }
1594 return _audio->RegisterAudioCallback(messagesCallback);
1595}
1596
1597 // Send a DTMF tone, RFC 2833 (4733)
1598WebRtc_Word32
1599RTPSender::SendTelephoneEvent(const WebRtc_UWord8 key,
1600 const WebRtc_UWord16 time_ms,
1601 const WebRtc_UWord8 level)
1602{
1603 if(!_audioConfigured)
1604 {
1605 return -1;
1606 }
1607 return _audio->SendTelephoneEvent(key, time_ms, level);
1608}
1609
1610bool
1611RTPSender::SendTelephoneEventActive(WebRtc_Word8& telephoneEvent) const
1612{
1613 if(!_audioConfigured)
1614 {
1615 return false;
1616 }
1617 return _audio->SendTelephoneEventActive(telephoneEvent);
1618}
1619
1620 // set audio packet size, used to determine when it's time to send a DTMF packet in silence (CNG)
1621WebRtc_Word32
1622RTPSender::SetAudioPacketSize(const WebRtc_UWord16 packetSizeSamples)
1623{
1624 if(!_audioConfigured)
1625 {
1626 return -1;
1627 }
1628 return _audio->SetAudioPacketSize(packetSizeSamples);
1629}
1630
1631WebRtc_Word32
1632RTPSender::SetAudioLevelIndicationStatus(const bool enable,
1633 const WebRtc_UWord8 ID)
1634{
1635 if(!_audioConfigured)
1636 {
1637 return -1;
1638 }
1639 return _audio->SetAudioLevelIndicationStatus(enable, ID);
1640}
1641
1642WebRtc_Word32
1643RTPSender::AudioLevelIndicationStatus(bool& enable,
1644 WebRtc_UWord8& ID) const
1645{
1646 return _audio->AudioLevelIndicationStatus(enable, ID);
1647}
1648
1649WebRtc_Word32
1650RTPSender::SetAudioLevel(const WebRtc_UWord8 level_dBov)
1651{
1652 return _audio->SetAudioLevel(level_dBov);
1653}
1654
1655 // Set payload type for Redundant Audio Data RFC 2198
1656WebRtc_Word32
1657RTPSender::SetRED(const WebRtc_Word8 payloadType)
1658{
1659 if(!_audioConfigured)
1660 {
1661 return -1;
1662 }
1663 return _audio->SetRED(payloadType);
1664}
1665
1666 // Get payload type for Redundant Audio Data RFC 2198
1667WebRtc_Word32
1668RTPSender::RED(WebRtc_Word8& payloadType) const
1669{
1670 if(!_audioConfigured)
1671 {
andrew@webrtc.org4f390002011-08-24 20:35:35 +00001672 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001673 }
1674 return _audio->RED(payloadType);
1675}
1676
1677 /*
1678 * Video
1679 */
1680VideoCodecInformation*
1681RTPSender::CodecInformationVideo()
1682{
1683 if(_audioConfigured)
1684 {
1685 return NULL;
1686 }
1687 return _video->CodecInformationVideo();
1688}
1689
1690RtpVideoCodecTypes
1691RTPSender::VideoCodecType() const
1692{
1693 if(_audioConfigured)
1694 {
1695 return kRtpNoVideo;
1696 }
1697 return _video->VideoCodecType();
1698}
1699
1700WebRtc_UWord32
1701RTPSender::MaxConfiguredBitrateVideo() const
1702{
1703 if(_audioConfigured)
1704 {
1705 return 0;
1706 }
1707 return _video->MaxConfiguredBitrateVideo();
1708}
1709
1710WebRtc_Word32
1711RTPSender::SendRTPIntraRequest()
1712{
1713 if(_audioConfigured)
1714 {
1715 return -1;
1716 }
1717 return _video->SendRTPIntraRequest();
1718}
1719
1720// FEC
1721WebRtc_Word32
1722RTPSender::SetGenericFECStatus(const bool enable,
1723 const WebRtc_UWord8 payloadTypeRED,
1724 const WebRtc_UWord8 payloadTypeFEC)
1725{
1726 if(_audioConfigured)
1727 {
1728 return -1;
1729 }
1730 return _video->SetGenericFECStatus(enable, payloadTypeRED, payloadTypeFEC);
1731}
1732
1733WebRtc_Word32
1734RTPSender::GenericFECStatus(bool& enable,
1735 WebRtc_UWord8& payloadTypeRED,
1736 WebRtc_UWord8& payloadTypeFEC) const
1737{
1738 if(_audioConfigured)
1739 {
1740 return -1;
1741 }
1742 return _video->GenericFECStatus(enable, payloadTypeRED, payloadTypeFEC);
1743}
1744
1745WebRtc_Word32
1746RTPSender::SetFECCodeRate(const WebRtc_UWord8 keyFrameCodeRate,
1747 const WebRtc_UWord8 deltaFrameCodeRate)
1748{
1749 if(_audioConfigured)
1750 {
1751 return -1;
1752 }
1753 return _video->SetFECCodeRate(keyFrameCodeRate, deltaFrameCodeRate);
1754}
marpan@google.com80c5d7a2011-07-15 21:32:40 +00001755
1756WebRtc_Word32
1757RTPSender::SetFECUepProtection(const bool keyUseUepProtection,
1758 const bool deltaUseUepProtection)
1759
1760{
1761 if(_audioConfigured)
1762 {
1763 return -1;
1764 }
1765 return _video->SetFECUepProtection(keyUseUepProtection,
1766 deltaUseUepProtection);
1767}
niklase@google.com470e71d2011-07-07 08:21:25 +00001768} // namespace webrtc