blob: 2270c070b1c9956bfa394b090506bc9d6a1ac8c7 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
leozwang@webrtc.org39e96592012-03-01 18:22:48 +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
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000011#include "webrtc/video_engine/vie_receiver.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
mflodman@webrtc.org4fd55272013-02-06 17:46:39 +000013#include <vector>
14
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000015#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +000016#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000017#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
18#include "webrtc/modules/utility/interface/rtp_dump.h"
19#include "webrtc/modules/video_coding/main/interface/video_coding.h"
20#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
21#include "webrtc/system_wrappers/interface/tick_util.h"
22#include "webrtc/system_wrappers/interface/trace.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000023
24namespace webrtc {
25
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000026ViEReceiver::ViEReceiver(const int32_t channel_id,
stefan@webrtc.org976a7e62012-09-21 13:20:21 +000027 VideoCodingModule* module_vcm,
28 RemoteBitrateEstimator* remote_bitrate_estimator)
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +000029 : receive_cs_(CriticalSectionWrapper::CreateCriticalSection()),
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000030 channel_id_(channel_id),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +000031 rtp_header_parser_(RtpHeaderParser::Create()),
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000032 rtp_rtcp_(NULL),
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000033 vcm_(module_vcm),
stefan@webrtc.org976a7e62012-09-21 13:20:21 +000034 remote_bitrate_estimator_(remote_bitrate_estimator),
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000035 external_decryption_(NULL),
36 decryption_buffer_(NULL),
37 rtp_dump_(NULL),
38 receiving_(false) {
stefan@webrtc.org976a7e62012-09-21 13:20:21 +000039 assert(remote_bitrate_estimator);
niklase@google.com470e71d2011-07-07 08:21:25 +000040}
41
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000042ViEReceiver::~ViEReceiver() {
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000043 if (decryption_buffer_) {
44 delete[] decryption_buffer_;
45 decryption_buffer_ = NULL;
46 }
47 if (rtp_dump_) {
48 rtp_dump_->Stop();
49 RtpDump::DestroyRtpDump(rtp_dump_);
50 rtp_dump_ = NULL;
51 }
niklase@google.com470e71d2011-07-07 08:21:25 +000052}
53
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000054int ViEReceiver::RegisterExternalDecryption(Encryption* decryption) {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +000055 CriticalSectionScoped cs(receive_cs_.get());
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000056 if (external_decryption_) {
57 return -1;
58 }
pbos@webrtc.orgb238d122013-04-09 13:41:51 +000059 decryption_buffer_ = new uint8_t[kViEMaxMtu];
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000060 if (decryption_buffer_ == NULL) {
61 return -1;
62 }
63 external_decryption_ = decryption;
64 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000065}
66
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000067int ViEReceiver::DeregisterExternalDecryption() {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +000068 CriticalSectionScoped cs(receive_cs_.get());
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000069 if (external_decryption_ == NULL) {
70 return -1;
71 }
72 external_decryption_ = NULL;
73 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000074}
75
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000076void ViEReceiver::SetRtpRtcpModule(RtpRtcp* module) {
77 rtp_rtcp_ = module;
78}
79
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +000080void ViEReceiver::RegisterSimulcastRtpRtcpModules(
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000081 const std::list<RtpRtcp*>& rtp_modules) {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +000082 CriticalSectionScoped cs(receive_cs_.get());
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000083 rtp_rtcp_simulcast_.clear();
84
85 if (!rtp_modules.empty()) {
86 rtp_rtcp_simulcast_.insert(rtp_rtcp_simulcast_.begin(),
87 rtp_modules.begin(),
88 rtp_modules.end());
89 }
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +000090}
91
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +000092int ViEReceiver::SetReceiveTimestampOffsetStatus(bool enable, int id) {
93 if (enable) {
94 return rtp_header_parser_->RegisterRtpHeaderExtension(
95 kRtpExtensionTransmissionTimeOffset, id);
96 } else {
97 return rtp_header_parser_->DeregisterRtpHeaderExtension(
98 kRtpExtensionTransmissionTimeOffset);
99 }
100}
101
102int ViEReceiver::SetReceiveAbsoluteSendTimeStatus(bool enable, int id) {
103 if (enable) {
104 return rtp_header_parser_->RegisterRtpHeaderExtension(
105 kRtpExtensionAbsoluteSendTime, id);
106 } else {
107 return rtp_header_parser_->DeregisterRtpHeaderExtension(
108 kRtpExtensionAbsoluteSendTime);
109 }
110}
111
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000112int ViEReceiver::ReceivedRTPPacket(const void* rtp_packet,
113 int rtp_packet_length) {
114 if (!receiving_) {
115 return -1;
116 }
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000117 return InsertRTPPacket(static_cast<const int8_t*>(rtp_packet),
118 rtp_packet_length);
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000119}
120
121int ViEReceiver::ReceivedRTCPPacket(const void* rtcp_packet,
122 int rtcp_packet_length) {
123 if (!receiving_) {
124 return -1;
125 }
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000126 return InsertRTCPPacket(static_cast<const int8_t*>(rtcp_packet),
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000127 rtcp_packet_length);
128}
129
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000130int32_t ViEReceiver::OnReceivedPayloadData(
131 const uint8_t* payload_data, const uint16_t payload_size,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000132 const WebRtcRTPHeader* rtp_header) {
133 if (rtp_header == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000134 return 0;
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000135 }
136
stefan@webrtc.org976a7e62012-09-21 13:20:21 +0000137 // TODO(holmer): Make sure packets reconstructed using FEC are not passed to
138 // the bandwidth estimator.
stefan@webrtc.org1a2a6dd2012-10-31 12:21:13 +0000139 const int packet_size = payload_size + rtp_header->header.paddingLength;
solenberg@webrtc.org561990f2013-05-22 19:04:19 +0000140 remote_bitrate_estimator_->IncomingPacket(TickTime::MillisecondTimestamp(),
141 packet_size, *rtp_header);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000142 if (vcm_->IncomingPacket(payload_data, payload_size, *rtp_header) != 0) {
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000143 // Check this...
144 return -1;
145 }
146 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000147}
148
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000149void ViEReceiver::OnSendReportReceived(const int32_t id,
150 const uint32_t senderSSRC,
stefan@webrtc.org976a7e62012-09-21 13:20:21 +0000151 uint32_t ntp_secs,
152 uint32_t ntp_frac,
153 uint32_t timestamp) {
154 remote_bitrate_estimator_->IncomingRtcp(senderSSRC, ntp_secs, ntp_frac,
155 timestamp);
156}
157
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000158int ViEReceiver::InsertRTPPacket(const int8_t* rtp_packet,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000159 int rtp_packet_length) {
160 // TODO(mflodman) Change decrypt to get rid of this cast.
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000161 int8_t* tmp_ptr = const_cast<int8_t*>(rtp_packet);
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000162 unsigned char* received_packet = reinterpret_cast<unsigned char*>(tmp_ptr);
163 int received_packet_length = rtp_packet_length;
niklase@google.com470e71d2011-07-07 08:21:25 +0000164
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000165 {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000166 CriticalSectionScoped cs(receive_cs_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000167
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000168 if (external_decryption_) {
mflodman@webrtc.org34e83b82012-10-17 11:05:54 +0000169 int decrypted_length = kViEMaxMtu;
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000170 external_decryption_->decrypt(channel_id_, received_packet,
171 decryption_buffer_, received_packet_length,
172 &decrypted_length);
173 if (decrypted_length <= 0) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000174 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
175 "RTP decryption failed");
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 return -1;
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000177 } else if (decrypted_length > kViEMaxMtu) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000178 WEBRTC_TRACE(webrtc::kTraceCritical, webrtc::kTraceVideo, channel_id_,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000179 "InsertRTPPacket: %d bytes is allocated as RTP decrytption"
180 " output, external decryption used %d bytes. => memory is "
181 " now corrupted", kViEMaxMtu, decrypted_length);
182 return -1;
183 }
184 received_packet = decryption_buffer_;
185 received_packet_length = decrypted_length;
niklase@google.com470e71d2011-07-07 08:21:25 +0000186 }
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000187
188 if (rtp_dump_) {
189 rtp_dump_->DumpPacket(received_packet,
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000190 static_cast<uint16_t>(received_packet_length));
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000191 }
192 }
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000193 RTPHeader header;
194 if (!rtp_header_parser_->Parse(received_packet, received_packet_length,
195 &header)) {
196 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideo, channel_id_,
197 "IncomingPacket invalid RTP header");
198 return -1;
199 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000200 assert(rtp_rtcp_); // Should be set by owner at construction time.
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000201 return rtp_rtcp_->IncomingRtpPacket(received_packet, received_packet_length,
202 header);
niklase@google.com470e71d2011-07-07 08:21:25 +0000203}
204
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000205int ViEReceiver::InsertRTCPPacket(const int8_t* rtcp_packet,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000206 int rtcp_packet_length) {
207 // TODO(mflodman) Change decrypt to get rid of this cast.
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000208 int8_t* tmp_ptr = const_cast<int8_t*>(rtcp_packet);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000209 unsigned char* received_packet = reinterpret_cast<unsigned char*>(tmp_ptr);
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000210 int received_packet_length = rtcp_packet_length;
211 {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000212 CriticalSectionScoped cs(receive_cs_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000213
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000214 if (external_decryption_) {
mflodman@webrtc.org34e83b82012-10-17 11:05:54 +0000215 int decrypted_length = kViEMaxMtu;
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000216 external_decryption_->decrypt_rtcp(channel_id_, received_packet,
217 decryption_buffer_,
218 received_packet_length,
219 &decrypted_length);
220 if (decrypted_length <= 0) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000221 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
222 "RTP decryption failed");
niklase@google.com470e71d2011-07-07 08:21:25 +0000223 return -1;
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000224 } else if (decrypted_length > kViEMaxMtu) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000225 WEBRTC_TRACE(webrtc::kTraceCritical, webrtc::kTraceVideo, channel_id_,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000226 "InsertRTCPPacket: %d bytes is allocated as RTP "
227 " decrytption output, external decryption used %d bytes. "
228 " => memory is now corrupted",
229 kViEMaxMtu, decrypted_length);
230 return -1;
231 }
232 received_packet = decryption_buffer_;
233 received_packet_length = decrypted_length;
niklase@google.com470e71d2011-07-07 08:21:25 +0000234 }
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000235
236 if (rtp_dump_) {
237 rtp_dump_->DumpPacket(
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000238 received_packet, static_cast<uint16_t>(received_packet_length));
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000239 }
240 }
241 {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000242 CriticalSectionScoped cs(receive_cs_.get());
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000243 std::list<RtpRtcp*>::iterator it = rtp_rtcp_simulcast_.begin();
244 while (it != rtp_rtcp_simulcast_.end()) {
245 RtpRtcp* rtp_rtcp = *it++;
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000246 rtp_rtcp->IncomingRtcpPacket(received_packet, received_packet_length);
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000247 }
248 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000249 assert(rtp_rtcp_); // Should be set by owner at construction time.
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000250 return rtp_rtcp_->IncomingRtcpPacket(received_packet, received_packet_length);
niklase@google.com470e71d2011-07-07 08:21:25 +0000251}
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000252
253void ViEReceiver::StartReceive() {
254 receiving_ = true;
255}
256
257void ViEReceiver::StopReceive() {
258 receiving_ = false;
259}
260
261int ViEReceiver::StartRTPDump(const char file_nameUTF8[1024]) {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000262 CriticalSectionScoped cs(receive_cs_.get());
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000263 if (rtp_dump_) {
264 // Restart it if it already exists and is started
265 rtp_dump_->Stop();
266 } else {
267 rtp_dump_ = RtpDump::CreateRtpDump();
268 if (rtp_dump_ == NULL) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000269 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000270 "StartRTPDump: Failed to create RTP dump");
271 return -1;
272 }
273 }
274 if (rtp_dump_->Start(file_nameUTF8) != 0) {
275 RtpDump::DestroyRtpDump(rtp_dump_);
276 rtp_dump_ = NULL;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000277 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000278 "StartRTPDump: Failed to start RTP dump");
279 return -1;
280 }
281 return 0;
282}
283
284int ViEReceiver::StopRTPDump() {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000285 CriticalSectionScoped cs(receive_cs_.get());
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000286 if (rtp_dump_) {
287 if (rtp_dump_->IsActive()) {
288 rtp_dump_->Stop();
289 } else {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000290 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000291 "StopRTPDump: Dump not active");
292 }
293 RtpDump::DestroyRtpDump(rtp_dump_);
294 rtp_dump_ = NULL;
295 } else {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000296 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000297 "StopRTPDump: RTP dump not started");
298 return -1;
299 }
300 return 0;
301}
302
stefan@webrtc.orgb5865072013-02-01 14:33:42 +0000303// TODO(holmer): To be moved to ViEChannelGroup.
mflodman@webrtc.org4fd55272013-02-06 17:46:39 +0000304void ViEReceiver::EstimatedReceiveBandwidth(
stefan@webrtc.orgb5865072013-02-01 14:33:42 +0000305 unsigned int* available_bandwidth) const {
306 std::vector<unsigned int> ssrcs;
mflodman@webrtc.org4fd55272013-02-06 17:46:39 +0000307
308 // LatestEstimate returns an error if there is no valid bitrate estimate, but
309 // ViEReceiver instead returns a zero estimate.
310 remote_bitrate_estimator_->LatestEstimate(&ssrcs, available_bandwidth);
mflodman@webrtc.orga066cbf2013-05-28 15:00:15 +0000311 if (std::find(ssrcs.begin(), ssrcs.end(), rtp_rtcp_->RemoteSSRC()) !=
312 ssrcs.end()) {
stefan@webrtc.orgb5865072013-02-01 14:33:42 +0000313 *available_bandwidth /= ssrcs.size();
mflodman@webrtc.org4fd55272013-02-06 17:46:39 +0000314 } else {
315 *available_bandwidth = 0;
stefan@webrtc.orgb5865072013-02-01 14:33:42 +0000316 }
stefan@webrtc.orgb5865072013-02-01 14:33:42 +0000317}
318
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000319} // namespace webrtc