blob: 76073ab101ae727eee80aae55e0beb823c7e01e4 [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,
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000025 RtpRtcpClock* clock,
26 Transport* transport,
27 RtpAudioFeedback* audio_feedback)
28 : Bitrate(clock),
29 _id(id),
30 _audioConfigured(audio),
31 _audio(NULL),
32 _video(NULL),
33 _sendCritsect(CriticalSectionWrapper::CreateCriticalSection()),
34 _transport(transport),
35 _sendingMedia(true), // Default to sending media
niklase@google.com470e71d2011-07-07 08:21:25 +000036
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000037 _maxPayloadLength(IP_PACKET_SIZE-28), // default is IP-v4/UDP
38 _targetSendBitrate(0),
39 _packetOverHead(28),
niklase@google.com470e71d2011-07-07 08:21:25 +000040
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000041 _payloadType(-1),
42 _payloadTypeMap(),
niklase@google.com470e71d2011-07-07 08:21:25 +000043
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000044 _rtpHeaderExtensionMap(),
45 _transmissionTimeOffset(0),
niklase@google.com470e71d2011-07-07 08:21:25 +000046
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000047 _nackByteCountTimes(),
48 _nackByteCount(),
49 _nackBitrate(clock),
niklase@google.com470e71d2011-07-07 08:21:25 +000050
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000051 _packetHistory(new RTPPacketHistory(clock)),
52 _sendBucket(clock),
53 _timeLastSendToNetworkUpdate(clock->GetTimeInMS()),
54 _transmissionSmoothing(false),
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +000055
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000056 _packetsSent(0),
57 _payloadBytesSent(0),
niklase@google.com470e71d2011-07-07 08:21:25 +000058
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000059 _startTimeStampForced(false),
60 _startTimeStamp(0),
61 _ssrcDB(*SSRCDatabase::GetSSRCDatabase()),
62 _remoteSSRC(0),
63 _sequenceNumberForced(false),
64 _sequenceNumber(0),
65 _sequenceNumberRTX(0),
66 _ssrcForced(false),
67 _ssrc(0),
68 _timeStamp(0),
69 _CSRCs(0),
70 _CSRC(),
71 _includeCSRCs(true),
72 _RTX(false),
73 _ssrcRTX(0) {
74 memset(_nackByteCountTimes, 0, sizeof(_nackByteCountTimes));
75 memset(_nackByteCount, 0, sizeof(_nackByteCount));
76 memset(_CSRC, 0, sizeof(_CSRC));
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +000077
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000078 // We need to seed the random generator.
79 srand( (WebRtc_UWord32)_clock.GetTimeInMS() );
80 _ssrc = _ssrcDB.CreateSSRC(); // Can't be 0.
niklase@google.com470e71d2011-07-07 08:21:25 +000081
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000082 if (audio) {
83 _audio = new RTPSenderAudio(id, &_clock, this);
84 _audio->RegisterAudioCallback(audio_feedback);
85 } else {
86 _video = new RTPSenderVideo(id, &_clock, this);
87 }
88 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +000089}
90
pwestin@webrtc.org00741872012-01-19 15:56:10 +000091RTPSender::~RTPSender() {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +000092 if (_remoteSSRC != 0) {
pwestin@webrtc.org00741872012-01-19 15:56:10 +000093 _ssrcDB.ReturnSSRC(_remoteSSRC);
94 }
95 _ssrcDB.ReturnSSRC(_ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +000096
pwestin@webrtc.org00741872012-01-19 15:56:10 +000097 SSRCDatabase::ReturnSSRCDatabase();
98 delete _sendCritsect;
pwestin@webrtc.org00741872012-01-19 15:56:10 +000099 while (!_payloadTypeMap.empty()) {
100 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
101 _payloadTypeMap.begin();
102 delete it->second;
103 _payloadTypeMap.erase(it);
104 }
105 delete _packetHistory;
106 delete _audio;
107 delete _video;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000108
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000109 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, _id, "%s deleted", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +0000110}
niklase@google.com470e71d2011-07-07 08:21:25 +0000111
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000112void RTPSender::SetTargetSendBitrate(const WebRtc_UWord32 bits) {
113 _targetSendBitrate = static_cast<uint16_t>(bits / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +0000114}
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000115
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000116WebRtc_UWord16 RTPSender::ActualSendBitrateKbit() const {
117 return (WebRtc_UWord16) (Bitrate::BitrateNow() / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +0000118}
119
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000120WebRtc_UWord32 RTPSender::VideoBitrateSent() const {
121 if (_video) {
stefan@webrtc.orgfbea4e52011-10-27 16:08:29 +0000122 return _video->VideoBitrateSent();
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000123 }
124 return 0;
stefan@webrtc.orgfbea4e52011-10-27 16:08:29 +0000125}
126
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000127WebRtc_UWord32 RTPSender::FecOverheadRate() const {
128 if (_video) {
stefan@webrtc.orgfbea4e52011-10-27 16:08:29 +0000129 return _video->FecOverheadRate();
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000130 }
131 return 0;
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000132}
133
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000134WebRtc_UWord32 RTPSender::NackOverheadRate() const {
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +0000135 return _nackBitrate.BitrateLast();
136}
137
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000138WebRtc_Word32 RTPSender::SetTransmissionTimeOffset(
139 const WebRtc_Word32 transmissionTimeOffset) {
140 if (transmissionTimeOffset > (0x800000 - 1) ||
141 transmissionTimeOffset < -(0x800000 - 1)) { // Word24
142 return -1;
143 }
144 CriticalSectionScoped cs(_sendCritsect);
145 _transmissionTimeOffset = transmissionTimeOffset;
146 return 0;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000147}
148
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000149WebRtc_Word32 RTPSender::RegisterRtpHeaderExtension(const RTPExtensionType type,
150 const WebRtc_UWord8 id) {
151 CriticalSectionScoped cs(_sendCritsect);
152 return _rtpHeaderExtensionMap.Register(type, id);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000153}
154
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000155WebRtc_Word32 RTPSender::DeregisterRtpHeaderExtension(
156 const RTPExtensionType type) {
157 CriticalSectionScoped cs(_sendCritsect);
158 return _rtpHeaderExtensionMap.Deregister(type);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000159}
160
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000161WebRtc_UWord16 RTPSender::RtpHeaderExtensionTotalLength() const {
162 CriticalSectionScoped cs(_sendCritsect);
163 return _rtpHeaderExtensionMap.GetTotalLengthInBytes();
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000164}
165
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000166WebRtc_Word32 RTPSender::RegisterPayload(
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000167 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000168 const WebRtc_Word8 payloadNumber,
169 const WebRtc_UWord32 frequency,
170 const WebRtc_UWord8 channels,
171 const WebRtc_UWord32 rate) {
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000172 assert(payloadName);
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000173 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000174
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000175 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
176 _payloadTypeMap.find(payloadNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +0000177
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000178 if (_payloadTypeMap.end() != it) {
179 // we already use this payload type
180 ModuleRTPUtility::Payload* payload = it->second;
181 assert(payload);
niklase@google.com470e71d2011-07-07 08:21:25 +0000182
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000183 // check if it's the same as we already have
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000184 if (ModuleRTPUtility::StringCompare(payload->name, payloadName,
185 RTP_PAYLOAD_NAME_SIZE - 1)) {
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000186 if (_audioConfigured && payload->audio &&
187 payload->typeSpecific.Audio.frequency == frequency &&
188 (payload->typeSpecific.Audio.rate == rate ||
189 payload->typeSpecific.Audio.rate == 0 || rate == 0)) {
190 payload->typeSpecific.Audio.rate = rate;
191 // Ensure that we update the rate if new or old is zero
niklase@google.com470e71d2011-07-07 08:21:25 +0000192 return 0;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000193 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000194 if (!_audioConfigured && !payload->audio) {
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000195 return 0;
196 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000197 }
198 return -1;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000199 }
200 WebRtc_Word32 retVal = -1;
201 ModuleRTPUtility::Payload* payload = NULL;
202 if (_audioConfigured) {
203 retVal = _audio->RegisterAudioPayload(payloadName, payloadNumber, frequency,
204 channels, rate, payload);
205 } else {
206 retVal = _video->RegisterVideoPayload(payloadName, payloadNumber, rate,
207 payload);
208 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000209 if (payload) {
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000210 _payloadTypeMap[payloadNumber] = payload;
211 }
212 return retVal;
niklase@google.com470e71d2011-07-07 08:21:25 +0000213}
214
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000215WebRtc_Word32 RTPSender::DeRegisterSendPayload(const WebRtc_Word8 payloadType) {
216 CriticalSectionScoped lock(_sendCritsect);
217
218 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
219 _payloadTypeMap.find(payloadType);
220
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000221 if (_payloadTypeMap.end() == it) {
222 return -1;
223 }
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000224 ModuleRTPUtility::Payload* payload = it->second;
225 delete payload;
226 _payloadTypeMap.erase(it);
227 return 0;
228}
niklase@google.com470e71d2011-07-07 08:21:25 +0000229
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000230WebRtc_Word8 RTPSender::SendPayloadType() const {
231 return _payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000232}
233
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000234int RTPSender::SendPayloadFrequency() const {
235 return _audio->AudioFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000236}
237
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000238WebRtc_Word32 RTPSender::SetMaxPayloadLength(
239 const WebRtc_UWord16 maxPayloadLength,
240 const WebRtc_UWord16 packetOverHead) {
241 // sanity check
242 if (maxPayloadLength < 100 || maxPayloadLength > IP_PACKET_SIZE) {
243 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
244 "%s invalid argument", __FUNCTION__);
245 return -1;
246 }
247 CriticalSectionScoped cs(_sendCritsect);
248 _maxPayloadLength = maxPayloadLength;
249 _packetOverHead = packetOverHead;
niklase@google.com470e71d2011-07-07 08:21:25 +0000250
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000251 WEBRTC_TRACE(kTraceInfo, kTraceRtpRtcp, _id,
252 "SetMaxPayloadLength to %d.", maxPayloadLength);
253 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000254}
255
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000256WebRtc_UWord16 RTPSender::MaxDataPayloadLength() const {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000257 if (_audioConfigured) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000258 return _maxPayloadLength - RTPHeaderLength();
259 } else {
260 return _maxPayloadLength - RTPHeaderLength() -
261 _video->FECPacketOverhead() - ((_RTX) ? 2 : 0);
262 // Include the FEC/ULP/RED overhead.
263 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000264}
265
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000266WebRtc_UWord16 RTPSender::MaxPayloadLength() const {
267 return _maxPayloadLength;
niklase@google.com470e71d2011-07-07 08:21:25 +0000268}
269
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000270WebRtc_UWord16 RTPSender::PacketOverHead() const {
271 return _packetOverHead;
niklase@google.com470e71d2011-07-07 08:21:25 +0000272}
273
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000274void RTPSender::SetTransmissionSmoothingStatus(const bool enable) {
275 CriticalSectionScoped cs(_sendCritsect);
276 _transmissionSmoothing = enable;
277}
278
279bool RTPSender::TransmissionSmoothingStatus() const {
280 CriticalSectionScoped cs(_sendCritsect);
281 return _transmissionSmoothing;
282}
283
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000284void RTPSender::SetRTXStatus(const bool enable,
285 const bool setSSRC,
286 const WebRtc_UWord32 SSRC) {
287 CriticalSectionScoped cs(_sendCritsect);
288 _RTX = enable;
289 if (enable) {
290 if (setSSRC) {
291 _ssrcRTX = SSRC;
292 } else {
293 _ssrcRTX = _ssrcDB.CreateSSRC(); // can't be 0
294 }
295 }
296}
297
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000298void RTPSender::RTXStatus(bool* enable, WebRtc_UWord32* SSRC) const {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000299 CriticalSectionScoped cs(_sendCritsect);
300 *enable = _RTX;
301 *SSRC = _ssrcRTX;
302}
303
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000304WebRtc_Word32 RTPSender::CheckPayloadType(const WebRtc_Word8 payloadType,
305 RtpVideoCodecTypes& videoType) {
306 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000307
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000308 if (payloadType < 0) {
309 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
310 "\tinvalid payloadType (%d)", payloadType);
311 return -1;
312 }
313 if (_audioConfigured) {
314 WebRtc_Word8 redPlType = -1;
315 if (_audio->RED(redPlType) == 0) {
316 // We have configured RED.
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000317 if (redPlType == payloadType) {
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000318 // And it's a match...
319 return 0;
320 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000321 }
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000322 }
323 if (_payloadType == payloadType) {
324 if (!_audioConfigured) {
325 videoType = _video->VideoCodecType();
niklase@google.com470e71d2011-07-07 08:21:25 +0000326 }
327 return 0;
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000328 }
329 std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
330 _payloadTypeMap.find(payloadType);
331 if (it == _payloadTypeMap.end()) {
332 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
333 "\tpayloadType:%d not registered", payloadType);
334 return -1;
335 }
336 _payloadType = payloadType;
337 ModuleRTPUtility::Payload* payload = it->second;
338 assert(payload);
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000339 if (!payload->audio && !_audioConfigured) {
340 _video->SetVideoCodecType(payload->typeSpecific.Video.videoCodecType);
341 videoType = payload->typeSpecific.Video.videoCodecType;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000342 _video->SetMaxConfiguredBitrateVideo(payload->typeSpecific.Video.maxRate);
pwestin@webrtc.org00741872012-01-19 15:56:10 +0000343 }
344 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000345}
346
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000347WebRtc_Word32 RTPSender::SendOutgoingData(
348 const FrameType frame_type,
349 const WebRtc_Word8 payload_type,
350 const WebRtc_UWord32 capture_timestamp,
351 int64_t capture_time_ms,
352 const WebRtc_UWord8* payload_data,
353 const WebRtc_UWord32 payload_size,
354 const RTPFragmentationHeader* fragmentation,
355 VideoCodecInformation* codec_info,
356 const RTPVideoTypeHeader* rtp_type_hdr) {
357 {
358 // Drop this packet if we're not sending media packets.
359 CriticalSectionScoped cs(_sendCritsect);
360 if (!_sendingMedia) {
361 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000362 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000363 }
364 RtpVideoCodecTypes video_type = kRtpNoVideo;
365 if (CheckPayloadType(payload_type, video_type) != 0) {
366 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
367 "%s invalid argument failed to find payloadType:%d",
368 __FUNCTION__, payload_type);
369 return -1;
370 }
371
372 if (_audioConfigured) {
373 assert(frame_type == kAudioFrameSpeech ||
374 frame_type == kAudioFrameCN ||
375 frame_type == kFrameEmpty);
376
377 return _audio->SendAudio(frame_type, payload_type, capture_timestamp,
378 payload_data, payload_size,fragmentation);
379 } else {
380 assert(frame_type != kAudioFrameSpeech &&
381 frame_type != kAudioFrameCN);
382
383 if (frame_type == kFrameEmpty) {
384 return SendPaddingAccordingToBitrate(payload_type, capture_timestamp,
385 capture_time_ms);
niklase@google.com470e71d2011-07-07 08:21:25 +0000386 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000387 return _video->SendVideo(video_type,
388 frame_type,
389 payload_type,
390 capture_timestamp,
391 capture_time_ms,
392 payload_data,
393 payload_size,
394 fragmentation,
395 codec_info,
396 rtp_type_hdr);
397 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000398}
399
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000400WebRtc_Word32 RTPSender::SendPaddingAccordingToBitrate(
401 WebRtc_Word8 payload_type,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000402 WebRtc_UWord32 capture_timestamp,
403 int64_t capture_time_ms) {
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000404 // Current bitrate since last estimate(1 second) averaged with the
405 // estimate since then, to get the most up to date bitrate.
406 uint32_t current_bitrate = BitrateNow();
407 int bitrate_diff = _targetSendBitrate * 1000 - current_bitrate;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000408 if (bitrate_diff <= 0) {
409 return 0;
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000410 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000411 int bytes = 0;
412 if (current_bitrate == 0) {
413 // Start up phase. Send one 33.3 ms batch to start with.
414 bytes = (bitrate_diff / 8) / 30;
415 } else {
416 bytes = (bitrate_diff / 8);
417 // Cap at 200 ms of target send data.
418 int bytes_cap = _targetSendBitrate * 25; // 1000 / 8 / 5
419 if (bytes > bytes_cap) {
420 bytes = bytes_cap;
421 }
422 }
423 return SendPadData(payload_type, capture_timestamp, capture_time_ms, bytes);
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000424}
425
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000426WebRtc_Word32 RTPSender::SendPadData(WebRtc_Word8 payload_type,
427 WebRtc_UWord32 capture_timestamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000428 int64_t capture_time_ms,
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000429 WebRtc_Word32 bytes) {
430 // Drop this packet if we're not sending media packets
431 if (!_sendingMedia) {
432 return 0;
433 }
434 // Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP.
435 int max_length = 224;
436 WebRtc_UWord8 data_buffer[IP_PACKET_SIZE];
437
438 for (; bytes > 0; bytes -= max_length) {
asapersson@webrtc.org63a34f42012-04-20 13:20:27 +0000439 int padding_bytes_in_packet = max_length;
440 if (bytes < max_length) {
441 padding_bytes_in_packet = (bytes + 16) & 0xffe0; // Keep our modulus 32.
442 }
443 if (padding_bytes_in_packet < 32) {
444 // Sanity don't send empty packets.
445 break;
446 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000447 // Correct seq num, timestamp and payload type.
448 int header_length = BuildRTPheader(data_buffer,
449 payload_type,
450 false, // No markerbit.
451 capture_timestamp,
452 true, // Timestamp provided.
453 true); // Increment sequence number.
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000454 data_buffer[0] |= 0x20; // Set padding bit.
455 WebRtc_Word32* data =
456 reinterpret_cast<WebRtc_Word32*>(&(data_buffer[header_length]));
457
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000458 // Fill data buffer with random data.
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000459 for (int j = 0; j < (padding_bytes_in_packet >> 2); j++) {
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000460 data[j] = rand();
461 }
462 // Set number of padding bytes in the last byte of the packet.
463 data_buffer[header_length + padding_bytes_in_packet - 1] =
464 padding_bytes_in_packet;
465 // Send the packet
466 if (0 > SendToNetwork(data_buffer,
467 padding_bytes_in_packet,
468 header_length,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000469 capture_time_ms,
pwestin@webrtc.org12d97f62012-01-05 10:54:44 +0000470 kDontRetransmit)) {
471 // Error sending the packet.
472 break;
473 }
474 }
475 if (bytes > 31) { // 31 due to our modulus 32.
476 // We did not manage to send all bytes.
477 return -1;
478 }
479 return 0;
480}
481
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000482void RTPSender::SetStorePacketsStatus(
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000483 const bool enable,
484 const WebRtc_UWord16 numberToStore) {
485 _packetHistory->SetStorePacketsStatus(enable, numberToStore);
niklase@google.com470e71d2011-07-07 08:21:25 +0000486}
487
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000488bool RTPSender::StorePackets() const {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000489 return _packetHistory->StorePackets();
niklase@google.com470e71d2011-07-07 08:21:25 +0000490}
491
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000492WebRtc_Word32 RTPSender::ReSendPacket(WebRtc_UWord16 packet_id,
493 WebRtc_UWord32 min_resend_time) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000494
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000495 WebRtc_UWord16 length = IP_PACKET_SIZE;
496 WebRtc_UWord8 data_buffer[IP_PACKET_SIZE];
497 WebRtc_UWord8* buffer_to_send_ptr = data_buffer;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000498
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000499 int64_t stored_time_in_ms;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000500 StorageType type;
501 bool found = _packetHistory->GetRTPPacket(packet_id,
502 min_resend_time, data_buffer, &length, &stored_time_in_ms, &type);
503 if (!found) {
504 // Packet not found.
asapersson@webrtc.org83ed0a42012-04-23 12:43:05 +0000505 return 0;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000506 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000507 if (length == 0 || type == kDontRetransmit) {
508 // No bytes copied (packet recently resent, skip resending) or
509 // packet should not be retransmitted.
510 return 0;
511 }
pwestin@webrtc.orgb30f0ed2012-01-23 16:23:31 +0000512 WebRtc_UWord8 data_buffer_rtx[IP_PACKET_SIZE];
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000513 if (_RTX) {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000514 buffer_to_send_ptr = data_buffer_rtx;
515
516 CriticalSectionScoped cs(_sendCritsect);
517 // Add RTX header.
518 ModuleRTPUtility::RTPHeaderParser rtpParser(
519 reinterpret_cast<const WebRtc_UWord8*>(data_buffer),
520 length);
521
522 WebRtcRTPHeader rtp_header;
523 rtpParser.Parse(rtp_header);
524
525 // Add original RTP header.
526 memcpy(data_buffer_rtx, data_buffer, rtp_header.header.headerLength);
527
528 // Replace sequence number.
529 WebRtc_UWord8* ptr = data_buffer_rtx + 2;
530 ModuleRTPUtility::AssignUWord16ToBuffer(ptr, _sequenceNumberRTX++);
531
532 // Replace SSRC.
533 ptr += 6;
534 ModuleRTPUtility::AssignUWord32ToBuffer(ptr, _ssrcRTX);
535
536 // Add OSN (original sequence number).
537 ptr = data_buffer_rtx + rtp_header.header.headerLength;
538 ModuleRTPUtility::AssignUWord16ToBuffer(
539 ptr, rtp_header.header.sequenceNumber);
540 ptr += 2;
541
542 // Add original payload data.
543 memcpy(ptr,
544 data_buffer + rtp_header.header.headerLength,
545 length - rtp_header.header.headerLength);
546 length += 2;
547 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000548 WebRtc_Word32 bytes_sent = ReSendToNetwork(buffer_to_send_ptr, length);
549 if (bytes_sent <= 0) {
550 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
551 "Transport failed to resend packet_id %u", packet_id);
552 return -1;
553 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000554 // Store the time when the packet was last resent.
555 _packetHistory->UpdateResendTime(packet_id);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000556 return bytes_sent;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000557}
558
559WebRtc_Word32 RTPSender::ReSendToNetwork(const WebRtc_UWord8* packet,
560 const WebRtc_UWord32 size) {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000561 WebRtc_Word32 bytes_sent = -1;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000562 if (_transport) {
563 bytes_sent = _transport->SendPacket(_id, packet, size);
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000564 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000565 if (bytes_sent <= 0) {
566 return -1;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000567 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000568 // Update send statistics
569 CriticalSectionScoped cs(_sendCritsect);
570 Bitrate::Update(bytes_sent);
571 _packetsSent++;
572 // We on purpose don't add to _payloadBytesSent since this is a
573 // re-transmit and not new payload data.
574 return bytes_sent;
niklase@google.com470e71d2011-07-07 08:21:25 +0000575}
576
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000577int RTPSender::SelectiveRetransmissions() const {
578 if (!_video) return -1;
579 return _video->SelectiveRetransmissions();
580}
581
582int RTPSender::SetSelectiveRetransmissions(uint8_t settings) {
583 if (!_video) return -1;
584 return _video->SetSelectiveRetransmissions(settings);
585}
586
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000587void RTPSender::OnReceivedNACK(const WebRtc_UWord16 nackSequenceNumbersLength,
588 const WebRtc_UWord16* nackSequenceNumbers,
589 const WebRtc_UWord16 avgRTT) {
590 const WebRtc_Word64 now = _clock.GetTimeInMS();
591 WebRtc_UWord32 bytesReSent = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000592
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000593 // Enough bandwidth to send NACK?
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000594 if (!ProcessNACKBitRate(now)) {
595 WEBRTC_TRACE(kTraceStream,
596 kTraceRtpRtcp,
597 _id,
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000598 "NACK bitrate reached. Skip sending NACK response. Target %d",
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000599 _targetSendBitrate);
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000600 return;
601 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000602
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000603 for (WebRtc_UWord16 i = 0; i < nackSequenceNumbersLength; ++i) {
604 const WebRtc_Word32 bytesSent = ReSendPacket(nackSequenceNumbers[i],
605 5+avgRTT);
606 if (bytesSent > 0) {
607 bytesReSent += bytesSent;
608 } else if (bytesSent == 0) {
609 // The packet has previously been resent.
610 // Try resending next packet in the list.
611 continue;
612 } else if (bytesSent < 0) {
613 // Failed to send one Sequence number. Give up the rest in this nack.
614 WEBRTC_TRACE(kTraceWarning,
615 kTraceRtpRtcp,
616 _id,
617 "Failed resending RTP packet %d, Discard rest of packets",
618 nackSequenceNumbers[i]);
619 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000620 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000621 // delay bandwidth estimate (RTT * BW)
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000622 if (_targetSendBitrate != 0 && avgRTT) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000623 // kbits/s * ms = bits => bits/8 = bytes
624 WebRtc_UWord32 targetBytes =
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000625 (static_cast<WebRtc_UWord32>(_targetSendBitrate) * avgRTT) >> 3;
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000626 if (bytesReSent > targetBytes) {
627 break; // ignore the rest of the packets in the list
628 }
629 }
630 }
631 if (bytesReSent > 0) {
632 // TODO(pwestin) consolidate these two methods.
633 UpdateNACKBitRate(bytesReSent, now);
634 _nackBitrate.Update(bytesReSent);
635 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000636}
637
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000638bool RTPSender::ProcessNACKBitRate(const WebRtc_UWord32 now) {
639 WebRtc_UWord32 num = 0;
640 WebRtc_Word32 byteCount = 0;
641 const WebRtc_UWord32 avgInterval=1000;
niklase@google.com470e71d2011-07-07 08:21:25 +0000642
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000643 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000644
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000645 if (_targetSendBitrate == 0) {
646 return true;
647 }
648 for (num = 0; num < NACK_BYTECOUNT_SIZE; num++) {
649 if ((now - _nackByteCountTimes[num]) > avgInterval) {
650 // don't use data older than 1sec
651 break;
652 } else {
653 byteCount += _nackByteCount[num];
niklase@google.com470e71d2011-07-07 08:21:25 +0000654 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000655 }
656 WebRtc_Word32 timeInterval = avgInterval;
657 if (num == NACK_BYTECOUNT_SIZE) {
658 // More than NACK_BYTECOUNT_SIZE nack messages has been received
659 // during the last msgInterval
660 timeInterval = now - _nackByteCountTimes[num-1];
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000661 if (timeInterval < 0) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000662 timeInterval = avgInterval;
niklase@google.com470e71d2011-07-07 08:21:25 +0000663 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000664 }
665 return (byteCount*8) < (_targetSendBitrate * timeInterval);
niklase@google.com470e71d2011-07-07 08:21:25 +0000666}
667
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000668void RTPSender::UpdateNACKBitRate(const WebRtc_UWord32 bytes,
669 const WebRtc_UWord32 now) {
670 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000671
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000672 // save bitrate statistics
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000673 if (bytes > 0) {
674 if (now == 0) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000675 // add padding length
676 _nackByteCount[0] += bytes;
677 } else {
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000678 if (_nackByteCountTimes[0] == 0) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000679 // first no shift
680 } else {
681 // shift
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000682 for (int i = (NACK_BYTECOUNT_SIZE-2); i >= 0 ; i--) {
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000683 _nackByteCount[i+1] = _nackByteCount[i];
684 _nackByteCountTimes[i+1] = _nackByteCountTimes[i];
niklase@google.com470e71d2011-07-07 08:21:25 +0000685 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000686 }
687 _nackByteCount[0] = bytes;
688 _nackByteCountTimes[0] = now;
niklase@google.com470e71d2011-07-07 08:21:25 +0000689 }
pwestin@webrtc.org8281e7d2012-01-10 14:09:18 +0000690 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000691}
692
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000693void RTPSender::ProcessSendToNetwork() {
pwestin@webrtc.org18530052012-07-03 10:41:54 +0000694 WebRtc_Word64 delta_time_ms;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000695 {
696 CriticalSectionScoped cs(_sendCritsect);
697
698 if (!_transmissionSmoothing) {
699 return;
700 }
pwestin@webrtc.org18530052012-07-03 10:41:54 +0000701 WebRtc_Word64 now = _clock.GetTimeInMS();
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000702 delta_time_ms = now - _timeLastSendToNetworkUpdate;
703 _timeLastSendToNetworkUpdate = now;
704 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000705 _sendBucket.UpdateBytesPerInterval(delta_time_ms, _targetSendBitrate);
706
707 while (!_sendBucket.Empty()) {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000708 WebRtc_Word32 seq_num = _sendBucket.GetNextPacket();
709 if (seq_num < 0) {
710 break;
711 }
712
713 WebRtc_UWord8 data_buffer[IP_PACKET_SIZE];
714 WebRtc_UWord16 length = IP_PACKET_SIZE;
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000715 int64_t stored_time_ms;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000716 StorageType type;
asapersson@webrtc.org869ce2d2012-01-16 11:58:36 +0000717 bool found = _packetHistory->GetRTPPacket(seq_num, 0, data_buffer, &length,
718 &stored_time_ms, &type);
719 if (!found) {
720 assert(false);
721 return;
722 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000723 assert(length > 0);
724
pwestin@webrtc.org18530052012-07-03 10:41:54 +0000725 WebRtc_Word64 diff_ms = _clock.GetTimeInMS() - stored_time_ms;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000726
727 ModuleRTPUtility::RTPHeaderParser rtpParser(data_buffer, length);
728 WebRtcRTPHeader rtp_header;
asapersson@webrtc.org869ce2d2012-01-16 11:58:36 +0000729 rtpParser.Parse(rtp_header);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000730
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000731 if (UpdateTransmissionTimeOffset(data_buffer, length, rtp_header,
732 diff_ms)) {
733 // Update stored packet in case of receiving a re-transmission request.
734 _packetHistory->ReplaceRTPHeader(data_buffer,
735 rtp_header.header.sequenceNumber,
736 rtp_header.header.headerLength);
737 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000738
739 // Send packet
740 WebRtc_Word32 bytes_sent = -1;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000741 if (_transport) {
742 bytes_sent = _transport->SendPacket(_id, data_buffer, length);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000743 }
744
745 // Update send statistics
746 if (bytes_sent > 0) {
747 CriticalSectionScoped cs(_sendCritsect);
748 Bitrate::Update(bytes_sent);
749 _packetsSent++;
750 if (bytes_sent > rtp_header.header.headerLength) {
751 _payloadBytesSent += bytes_sent - rtp_header.header.headerLength;
752 }
753 }
phoglund@webrtc.orgbaaf2432012-05-31 10:47:35 +0000754 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000755}
756
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000757WebRtc_Word32 RTPSender::SendToNetwork(WebRtc_UWord8* buffer,
758 WebRtc_UWord16 payload_length,
759 WebRtc_UWord16 rtp_header_length,
760 int64_t capture_time_ms,
761 StorageType storage) {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000762 // Used for NACK or to spead out the transmission of packets.
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000763 if (_packetHistory->PutRTPPacket(buffer, rtp_header_length + payload_length,
764 _maxPayloadLength, capture_time_ms, storage) != 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000765 return -1;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000766 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000767 if (_transmissionSmoothing) {
768 const WebRtc_UWord16 sequenceNumber = (buffer[2] << 8) + buffer[3];
asapersson@webrtc.org23fd5592012-09-24 12:07:13 +0000769 const WebRtc_UWord32 timestamp = (buffer[4] << 24) + (buffer[5] << 16) +
770 (buffer[6] << 8) + buffer[7];
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000771 _sendBucket.Fill(sequenceNumber, timestamp,
772 rtp_header_length + payload_length);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000773 // Packet will be sent at a later time.
774 return 0;
775 }
stefan@webrtc.org715faaf2012-08-28 15:20:39 +0000776 // |capture_time_ms| <= 0 is considered invalid.
777 // TODO(holmer): This should be changed all over Video Engine so that negative
778 // time is consider invalid, while 0 is considered a valid time.
779 if (capture_time_ms > 0) {
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000780 ModuleRTPUtility::RTPHeaderParser rtpParser(buffer,
781 rtp_header_length + payload_length);
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000782 WebRtcRTPHeader rtp_header;
mflodman@webrtc.org90071dd2012-08-13 17:13:27 +0000783 rtpParser.Parse(rtp_header);
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000784 int64_t time_now = _clock.GetTimeInMS();
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000785 if (UpdateTransmissionTimeOffset(buffer, rtp_header_length + payload_length,
786 rtp_header, time_now - capture_time_ms)) {
787 // Update stored packet in case of receiving a re-transmission request.
788 _packetHistory->ReplaceRTPHeader(buffer, rtp_header.header.sequenceNumber,
789 rtp_header.header.headerLength);
790 }
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000791 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000792 // Send packet
793 WebRtc_Word32 bytes_sent = -1;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000794 if (_transport) {
795 bytes_sent = _transport->SendPacket(_id, buffer,
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000796 payload_length + rtp_header_length);
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000797 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000798 if (bytes_sent <= 0) {
799 return -1;
800 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000801 // Update send statistics
802 CriticalSectionScoped cs(_sendCritsect);
803 Bitrate::Update(bytes_sent);
804 _packetsSent++;
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000805 if (bytes_sent > rtp_header_length) {
806 _payloadBytesSent += bytes_sent - rtp_header_length;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000807 }
808 return 0;
stefan@webrtc.org6a4bef42011-12-22 12:52:41 +0000809}
810
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000811void RTPSender::ProcessBitrate() {
812 CriticalSectionScoped cs(_sendCritsect);
813 Bitrate::Process();
814 _nackBitrate.Process();
815 if (_audioConfigured) {
816 return;
817 }
818 _video->ProcessBitrate();
niklase@google.com470e71d2011-07-07 08:21:25 +0000819}
820
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000821WebRtc_UWord16 RTPSender::RTPHeaderLength() const {
822 WebRtc_UWord16 rtpHeaderLength = 12;
823 if (_includeCSRCs) {
824 rtpHeaderLength += sizeof(WebRtc_UWord32)*_CSRCs;
825 }
826 rtpHeaderLength += RtpHeaderExtensionTotalLength();
827 return rtpHeaderLength;
niklase@google.com470e71d2011-07-07 08:21:25 +0000828}
829
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000830WebRtc_UWord16 RTPSender::IncrementSequenceNumber() {
831 CriticalSectionScoped cs(_sendCritsect);
832 return _sequenceNumber++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000833}
834
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000835void RTPSender::ResetDataCounters() {
836 _packetsSent = 0;
837 _payloadBytesSent = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000838}
839
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000840WebRtc_UWord32 RTPSender::Packets() const {
841 // Don't use critsect to avoid potental deadlock
842 return _packetsSent;
niklase@google.com470e71d2011-07-07 08:21:25 +0000843}
844
845// number of sent RTP bytes
846// dont use critsect to avoid potental deadlock
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000847WebRtc_UWord32 RTPSender::Bytes() const {
848 return _payloadBytesSent;
niklase@google.com470e71d2011-07-07 08:21:25 +0000849}
850
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000851WebRtc_Word32 RTPSender::BuildRTPheader(WebRtc_UWord8* dataBuffer,
852 const WebRtc_Word8 payloadType,
853 const bool markerBit,
854 const WebRtc_UWord32 captureTimeStamp,
855 const bool timeStampProvided,
856 const bool incSequenceNumber) {
857 assert(payloadType>=0);
858 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000859
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000860 dataBuffer[0] = static_cast<WebRtc_UWord8>(0x80); // version 2
861 dataBuffer[1] = static_cast<WebRtc_UWord8>(payloadType);
862 if (markerBit) {
863 dataBuffer[1] |= kRtpMarkerBitMask; // MarkerBit is set
864 }
865 if (timeStampProvided) {
866 _timeStamp = _startTimeStamp + captureTimeStamp;
867 } else {
868 // make a unique time stamp
869 // we can't inc by the actual time, since then we increase the risk of back
870 // timing.
871 _timeStamp++;
872 }
873 ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer+2, _sequenceNumber);
874 ModuleRTPUtility::AssignUWord32ToBuffer(dataBuffer+4, _timeStamp);
875 ModuleRTPUtility::AssignUWord32ToBuffer(dataBuffer+8, _ssrc);
876 WebRtc_Word32 rtpHeaderLength = 12;
niklase@google.com470e71d2011-07-07 08:21:25 +0000877
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000878 // Add the CSRCs if any
879 if (_includeCSRCs && _CSRCs > 0) {
880 if (_CSRCs > kRtpCsrcSize) {
881 // error
882 assert(false);
883 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000884 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000885 WebRtc_UWord8* ptr = &dataBuffer[rtpHeaderLength];
886 for (WebRtc_UWord32 i = 0; i < _CSRCs; ++i) {
887 ModuleRTPUtility::AssignUWord32ToBuffer(ptr, _CSRC[i]);
888 ptr +=4;
niklase@google.com470e71d2011-07-07 08:21:25 +0000889 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000890 dataBuffer[0] = (dataBuffer[0]&0xf0) | _CSRCs;
niklase@google.com470e71d2011-07-07 08:21:25 +0000891
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000892 // Update length of header
893 rtpHeaderLength += sizeof(WebRtc_UWord32)*_CSRCs;
894 }
895 _sequenceNumber++; // prepare for next packet
niklase@google.com470e71d2011-07-07 08:21:25 +0000896
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000897 WebRtc_UWord16 len = BuildRTPHeaderExtension(dataBuffer + rtpHeaderLength);
898 if (len) {
899 dataBuffer[0] |= 0x10; // set eXtension bit
900 rtpHeaderLength += len;
901 }
902 return rtpHeaderLength;
niklase@google.com470e71d2011-07-07 08:21:25 +0000903}
904
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000905WebRtc_UWord16 RTPSender::BuildRTPHeaderExtension(
906 WebRtc_UWord8* dataBuffer) const {
907 if (_rtpHeaderExtensionMap.Size() <= 0) {
908 return 0;
909 }
910 /* RTP header extension, RFC 3550.
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000911 0 1 2 3
912 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
913 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
914 | defined by profile | length |
915 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
916 | header extension |
917 | .... |
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000918 */
919 const WebRtc_UWord32 kPosLength = 2;
920 const WebRtc_UWord32 kHeaderLength = RTP_ONE_BYTE_HEADER_LENGTH_IN_BYTES;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000921
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000922 // Add extension ID (0xBEDE).
923 ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer,
924 RTP_ONE_BYTE_HEADER_EXTENSION);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000925
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000926 // Add extensions.
927 WebRtc_UWord16 total_block_length = 0;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000928
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000929 RTPExtensionType type = _rtpHeaderExtensionMap.First();
930 while (type != kRtpExtensionNone) {
931 WebRtc_UWord8 block_length = 0;
932 if (type == kRtpExtensionTransmissionTimeOffset) {
933 block_length = BuildTransmissionTimeOffsetExtension(
934 dataBuffer + kHeaderLength + total_block_length);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000935 }
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000936 total_block_length += block_length;
937 type = _rtpHeaderExtensionMap.Next(type);
938 }
939 if (total_block_length == 0) {
940 // No extension added.
941 return 0;
942 }
943 // Set header length (in number of Word32, header excluded).
944 assert(total_block_length % 4 == 0);
945 ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer + kPosLength,
946 total_block_length / 4);
947 // Total added length.
948 return kHeaderLength + total_block_length;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000949}
950
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000951WebRtc_UWord8 RTPSender::BuildTransmissionTimeOffsetExtension(
952 WebRtc_UWord8* dataBuffer) const {
953 // From RFC 5450: Transmission Time Offsets in RTP Streams.
954 //
955 // The transmission time is signaled to the receiver in-band using the
956 // general mechanism for RTP header extensions [RFC5285]. The payload
957 // of this extension (the transmitted value) is a 24-bit signed integer.
958 // When added to the RTP timestamp of the packet, it represents the
959 // "effective" RTP transmission time of the packet, on the RTP
960 // timescale.
961 //
962 // The form of the transmission offset extension block:
963 //
964 // 0 1 2 3
965 // 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
966 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
967 // | ID | len=2 | transmission offset |
968 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000969
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000970 // Get id defined by user.
971 WebRtc_UWord8 id;
972 if (_rtpHeaderExtensionMap.GetId(kRtpExtensionTransmissionTimeOffset, &id)
973 != 0) {
974 // Not registered.
975 return 0;
976 }
977 int pos = 0;
978 const WebRtc_UWord8 len = 2;
979 dataBuffer[pos++] = (id << 4) + len;
980 ModuleRTPUtility::AssignUWord24ToBuffer(dataBuffer + pos,
981 _transmissionTimeOffset);
982 pos += 3;
983 assert(pos == TRANSMISSION_TIME_OFFSET_LENGTH_IN_BYTES);
984 return TRANSMISSION_TIME_OFFSET_LENGTH_IN_BYTES;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000985}
986
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +0000987bool RTPSender::UpdateTransmissionTimeOffset(
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000988 WebRtc_UWord8* rtp_packet,
989 const WebRtc_UWord16 rtp_packet_length,
990 const WebRtcRTPHeader& rtp_header,
mflodman@webrtc.orgba853c92012-08-10 14:30:53 +0000991 const WebRtc_Word64 time_diff_ms) const {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000992 CriticalSectionScoped cs(_sendCritsect);
993
994 // Get length until start of transmission block.
995 int transmission_block_pos =
996 _rtpHeaderExtensionMap.GetLengthUntilBlockStartInBytes(
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +0000997 kRtpExtensionTransmissionTimeOffset);
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +0000998 if (transmission_block_pos < 0) {
999 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001000 "Failed to update transmission time offset, not registered.");
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +00001001 return false;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001002 }
1003
1004 int block_pos = 12 + rtp_header.header.numCSRCs + transmission_block_pos;
mflodman@webrtc.orgba853c92012-08-10 14:30:53 +00001005 if (rtp_packet_length < block_pos + 4 ||
1006 rtp_header.header.headerLength < block_pos + 4) {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001007 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001008 "Failed to update transmission time offset, invalid length.");
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +00001009 return false;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001010 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001011 // Verify that header contains extension.
1012 if (!((rtp_packet[12 + rtp_header.header.numCSRCs] == 0xBE) &&
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001013 (rtp_packet[12 + rtp_header.header.numCSRCs + 1] == 0xDE))) {
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001014 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
1015 "Failed to update transmission time offset, hdr extension not found.");
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +00001016 return false;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001017 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001018 // Get id.
1019 WebRtc_UWord8 id = 0;
1020 if (_rtpHeaderExtensionMap.GetId(kRtpExtensionTransmissionTimeOffset,
1021 &id) != 0) {
1022 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001023 "Failed to update transmission time offset, no id.");
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +00001024 return false;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001025 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001026 // Verify first byte in block.
1027 const WebRtc_UWord8 first_block_byte = (id << 4) + 2;
1028 if (rtp_packet[block_pos] != first_block_byte) {
1029 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001030 "Failed to update transmission time offset.");
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +00001031 return false;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001032 }
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001033 // Update transmission offset field.
1034 ModuleRTPUtility::AssignUWord24ToBuffer(rtp_packet + block_pos + 1,
mflodman@webrtc.orgba853c92012-08-10 14:30:53 +00001035 time_diff_ms * 90); // RTP timestamp.
asapersson@webrtc.orge5b49a02012-11-06 13:09:39 +00001036 return true;
asapersson@webrtc.org0b3c35a2012-01-16 11:06:31 +00001037}
1038
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001039void RTPSender::SetSendingStatus(const bool enabled) {
1040 if (enabled) {
1041 WebRtc_UWord32 freq;
1042 if (_audioConfigured) {
1043 WebRtc_UWord32 frequency = _audio->AudioFrequency();
1044
1045 // sanity
1046 switch(frequency) {
1047 case 8000:
1048 case 12000:
1049 case 16000:
1050 case 24000:
1051 case 32000:
1052 break;
1053 default:
1054 assert(false);
1055 return;
1056 }
1057 freq = frequency;
1058 } else {
1059 freq = 90000; // 90 KHz for all video
1060 }
1061 WebRtc_UWord32 RTPtime = ModuleRTPUtility::GetCurrentRTP(&_clock, freq);
1062
1063 // will be ignored if it's already configured via API
1064 SetStartTimestamp(RTPtime, false);
1065 } else {
1066 if (!_ssrcForced) {
1067 // generate a new SSRC
1068 _ssrcDB.ReturnSSRC(_ssrc);
1069 _ssrc = _ssrcDB.CreateSSRC(); // can't be 0
1070
1071 }
1072 // Don't initialize seq number if SSRC passed externally.
1073 if (!_sequenceNumberForced && !_ssrcForced) {
1074 // generate a new sequence number
1075 _sequenceNumber = rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);
1076 }
1077 }
1078}
1079
1080void RTPSender::SetSendingMediaStatus(const bool enabled) {
1081 CriticalSectionScoped cs(_sendCritsect);
1082 _sendingMedia = enabled;
1083}
1084
1085bool RTPSender::SendingMedia() const {
1086 CriticalSectionScoped cs(_sendCritsect);
1087 return _sendingMedia;
1088}
1089
1090WebRtc_UWord32 RTPSender::Timestamp() const {
1091 CriticalSectionScoped cs(_sendCritsect);
1092 return _timeStamp;
1093}
1094
1095void RTPSender::SetStartTimestamp(WebRtc_UWord32 timestamp, bool force) {
1096 CriticalSectionScoped cs(_sendCritsect);
1097 if (force) {
1098 _startTimeStampForced = force;
1099 _startTimeStamp = timestamp;
1100 } else {
1101 if (!_startTimeStampForced) {
1102 _startTimeStamp = timestamp;
1103 }
1104 }
1105}
1106
1107WebRtc_UWord32 RTPSender::StartTimestamp() const {
1108 CriticalSectionScoped cs(_sendCritsect);
1109 return _startTimeStamp;
1110}
1111
1112WebRtc_UWord32 RTPSender::GenerateNewSSRC() {
1113 // if configured via API, return 0
1114 CriticalSectionScoped cs(_sendCritsect);
1115
1116 if (_ssrcForced) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001117 return 0;
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001118 }
1119 _ssrc = _ssrcDB.CreateSSRC(); // can't be 0
1120 return _ssrc;
niklase@google.com470e71d2011-07-07 08:21:25 +00001121}
1122
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001123void RTPSender::SetSSRC(WebRtc_UWord32 ssrc) {
1124 // this is configured via the API
1125 CriticalSectionScoped cs(_sendCritsect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001126
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001127 if (_ssrc == ssrc && _ssrcForced) {
1128 return; // since it's same ssrc, don't reset anything
1129 }
1130 _ssrcForced = true;
1131 _ssrcDB.ReturnSSRC(_ssrc);
1132 _ssrcDB.RegisterSSRC(ssrc);
1133 _ssrc = ssrc;
1134 if (!_sequenceNumberForced) {
1135 _sequenceNumber = rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);
1136 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001137}
1138
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001139WebRtc_UWord32 RTPSender::SSRC() const {
1140 CriticalSectionScoped cs(_sendCritsect);
1141 return _ssrc;
niklase@google.com470e71d2011-07-07 08:21:25 +00001142}
1143
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001144void RTPSender::SetCSRCStatus(const bool include) {
1145 _includeCSRCs = include;
niklase@google.com470e71d2011-07-07 08:21:25 +00001146}
1147
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001148void RTPSender::SetCSRCs(const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize],
1149 const WebRtc_UWord8 arrLength) {
1150 assert(arrLength <= kRtpCsrcSize);
1151 CriticalSectionScoped cs(_sendCritsect);
1152
1153 for (int i = 0; i < arrLength;i++) {
1154 _CSRC[i] = arrOfCSRC[i];
1155 }
1156 _CSRCs = arrLength;
niklase@google.com470e71d2011-07-07 08:21:25 +00001157}
1158
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001159WebRtc_Word32 RTPSender::CSRCs(WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]) const {
1160 assert(arrOfCSRC);
1161 CriticalSectionScoped cs(_sendCritsect);
1162 for (int i = 0; i < _CSRCs && i < kRtpCsrcSize;i++) {
1163 arrOfCSRC[i] = _CSRC[i];
1164 }
1165 return _CSRCs;
niklase@google.com470e71d2011-07-07 08:21:25 +00001166}
1167
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001168void RTPSender::SetSequenceNumber(WebRtc_UWord16 seq) {
1169 CriticalSectionScoped cs(_sendCritsect);
1170 _sequenceNumberForced = true;
1171 _sequenceNumber = seq;
niklase@google.com470e71d2011-07-07 08:21:25 +00001172}
1173
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001174WebRtc_UWord16 RTPSender::SequenceNumber() const {
1175 CriticalSectionScoped cs(_sendCritsect);
1176 return _sequenceNumber;
niklase@google.com470e71d2011-07-07 08:21:25 +00001177}
1178
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001179/*
1180 * Audio
1181 */
1182WebRtc_Word32 RTPSender::SendTelephoneEvent(const WebRtc_UWord8 key,
1183 const WebRtc_UWord16 time_ms,
1184 const WebRtc_UWord8 level) {
1185 if (!_audioConfigured) {
1186 return -1;
1187 }
1188 return _audio->SendTelephoneEvent(key, time_ms, level);
niklase@google.com470e71d2011-07-07 08:21:25 +00001189}
1190
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001191bool RTPSender::SendTelephoneEventActive(WebRtc_Word8& telephoneEvent) const {
1192 if (!_audioConfigured) {
1193 return false;
1194 }
1195 return _audio->SendTelephoneEventActive(telephoneEvent);
niklase@google.com470e71d2011-07-07 08:21:25 +00001196}
1197
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001198WebRtc_Word32 RTPSender::SetAudioPacketSize(
1199 const WebRtc_UWord16 packetSizeSamples) {
1200 if (!_audioConfigured) {
1201 return -1;
1202 }
1203 return _audio->SetAudioPacketSize(packetSizeSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00001204}
1205
1206WebRtc_Word32
1207RTPSender::SetAudioLevelIndicationStatus(const bool enable,
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001208 const WebRtc_UWord8 ID) {
1209 if (!_audioConfigured) {
1210 return -1;
1211 }
1212 return _audio->SetAudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00001213}
1214
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001215WebRtc_Word32 RTPSender::AudioLevelIndicationStatus(bool& enable,
1216 WebRtc_UWord8& ID) const {
1217 return _audio->AudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00001218}
1219
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001220WebRtc_Word32 RTPSender::SetAudioLevel(const WebRtc_UWord8 level_dBov) {
1221 return _audio->SetAudioLevel(level_dBov);
niklase@google.com470e71d2011-07-07 08:21:25 +00001222}
1223
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001224WebRtc_Word32 RTPSender::SetRED(const WebRtc_Word8 payloadType) {
1225 if (!_audioConfigured) {
1226 return -1;
1227 }
1228 return _audio->SetRED(payloadType);
niklase@google.com470e71d2011-07-07 08:21:25 +00001229}
1230
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001231WebRtc_Word32 RTPSender::RED(WebRtc_Word8& payloadType) const {
1232 if (!_audioConfigured) {
1233 return -1;
1234 }
1235 return _audio->RED(payloadType);
niklase@google.com470e71d2011-07-07 08:21:25 +00001236}
1237
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001238/*
1239 * Video
1240 */
1241VideoCodecInformation* RTPSender::CodecInformationVideo() {
1242 if (_audioConfigured) {
1243 return NULL;
1244 }
1245 return _video->CodecInformationVideo();
niklase@google.com470e71d2011-07-07 08:21:25 +00001246}
1247
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001248RtpVideoCodecTypes RTPSender::VideoCodecType() const {
1249 if (_audioConfigured) {
1250 return kRtpNoVideo;
1251 }
1252 return _video->VideoCodecType();
niklase@google.com470e71d2011-07-07 08:21:25 +00001253}
1254
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001255WebRtc_UWord32 RTPSender::MaxConfiguredBitrateVideo() const {
1256 if (_audioConfigured) {
1257 return 0;
1258 }
1259 return _video->MaxConfiguredBitrateVideo();
niklase@google.com470e71d2011-07-07 08:21:25 +00001260}
1261
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001262WebRtc_Word32 RTPSender::SendRTPIntraRequest() {
1263 if (_audioConfigured) {
1264 return -1;
1265 }
1266 return _video->SendRTPIntraRequest();
niklase@google.com470e71d2011-07-07 08:21:25 +00001267}
1268
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001269WebRtc_Word32 RTPSender::SetGenericFECStatus(
1270 const bool enable,
1271 const WebRtc_UWord8 payloadTypeRED,
1272 const WebRtc_UWord8 payloadTypeFEC) {
1273 if (_audioConfigured) {
1274 return -1;
1275 }
1276 return _video->SetGenericFECStatus(enable, payloadTypeRED, payloadTypeFEC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001277}
1278
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001279WebRtc_Word32 RTPSender::GenericFECStatus(bool& enable,
1280 WebRtc_UWord8& payloadTypeRED,
1281 WebRtc_UWord8& payloadTypeFEC) const {
1282 if (_audioConfigured) {
1283 return -1;
1284 }
1285 return _video->GenericFECStatus(enable, payloadTypeRED, payloadTypeFEC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001286}
1287
stefan@webrtc.orge0d6fa42012-03-20 22:10:56 +00001288WebRtc_Word32 RTPSender::SetFecParameters(
1289 const FecProtectionParams* delta_params,
1290 const FecProtectionParams* key_params) {
1291 if (_audioConfigured) {
1292 return -1;
1293 }
1294 return _video->SetFecParameters(delta_params, key_params);
marpan@google.com80c5d7a2011-07-15 21:32:40 +00001295}
pwestin@webrtc.orgc66e8b32012-11-07 17:01:04 +00001296} // namespace webrtc