blob: 03449201116a034e21768ee5e399059d30bf97bb [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,
tnakamura@webrtc.orgaa4d96a2013-07-16 19:25:04 +000028 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.org08994cc2013-05-29 13:28:21 +000092bool ViEReceiver::SetReceiveTimestampOffsetStatus(bool enable, int id) {
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +000093 if (enable) {
94 return rtp_header_parser_->RegisterRtpHeaderExtension(
95 kRtpExtensionTransmissionTimeOffset, id);
96 } else {
97 return rtp_header_parser_->DeregisterRtpHeaderExtension(
98 kRtpExtensionTransmissionTimeOffset);
99 }
100}
101
stefan@webrtc.org08994cc2013-05-29 13:28:21 +0000102bool ViEReceiver::SetReceiveAbsoluteSendTimeStatus(bool enable, int id) {
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000103 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) {
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000114 return InsertRTPPacket(static_cast<const int8_t*>(rtp_packet),
115 rtp_packet_length);
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000116}
117
118int ViEReceiver::ReceivedRTCPPacket(const void* rtcp_packet,
119 int rtcp_packet_length) {
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000120 return InsertRTCPPacket(static_cast<const int8_t*>(rtcp_packet),
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000121 rtcp_packet_length);
122}
123
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000124int32_t ViEReceiver::OnReceivedPayloadData(
125 const uint8_t* payload_data, const uint16_t payload_size,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000126 const WebRtcRTPHeader* rtp_header) {
127 if (rtp_header == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000128 return 0;
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000129 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000130 if (vcm_->IncomingPacket(payload_data, payload_size, *rtp_header) != 0) {
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000131 // Check this...
132 return -1;
133 }
134 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000135}
136
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000137int ViEReceiver::InsertRTPPacket(const int8_t* rtp_packet,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000138 int rtp_packet_length) {
139 // TODO(mflodman) Change decrypt to get rid of this cast.
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000140 int8_t* tmp_ptr = const_cast<int8_t*>(rtp_packet);
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000141 unsigned char* received_packet = reinterpret_cast<unsigned char*>(tmp_ptr);
142 int received_packet_length = rtp_packet_length;
niklase@google.com470e71d2011-07-07 08:21:25 +0000143
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000144 {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000145 CriticalSectionScoped cs(receive_cs_.get());
braveyao@webrtc.orgb6433b72013-07-26 09:02:46 +0000146 if (!receiving_) {
147 return -1;
148 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000149
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000150 if (external_decryption_) {
mflodman@webrtc.org34e83b82012-10-17 11:05:54 +0000151 int decrypted_length = kViEMaxMtu;
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000152 external_decryption_->decrypt(channel_id_, received_packet,
153 decryption_buffer_, received_packet_length,
154 &decrypted_length);
155 if (decrypted_length <= 0) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000156 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
157 "RTP decryption failed");
niklase@google.com470e71d2011-07-07 08:21:25 +0000158 return -1;
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000159 } else if (decrypted_length > kViEMaxMtu) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000160 WEBRTC_TRACE(webrtc::kTraceCritical, webrtc::kTraceVideo, channel_id_,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000161 "InsertRTPPacket: %d bytes is allocated as RTP decrytption"
162 " output, external decryption used %d bytes. => memory is "
163 " now corrupted", kViEMaxMtu, decrypted_length);
164 return -1;
165 }
166 received_packet = decryption_buffer_;
167 received_packet_length = decrypted_length;
niklase@google.com470e71d2011-07-07 08:21:25 +0000168 }
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000169
170 if (rtp_dump_) {
171 rtp_dump_->DumpPacket(received_packet,
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000172 static_cast<uint16_t>(received_packet_length));
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000173 }
174 }
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000175 RTPHeader header;
176 if (!rtp_header_parser_->Parse(received_packet, received_packet_length,
177 &header)) {
178 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideo, channel_id_,
179 "IncomingPacket invalid RTP header");
180 return -1;
181 }
stefan@webrtc.orgde984782013-06-04 12:15:40 +0000182 const int payload_size = received_packet_length - header.headerLength;
183 remote_bitrate_estimator_->IncomingPacket(TickTime::MillisecondTimestamp(),
184 payload_size, header);
tnakamura@webrtc.orgaa4d96a2013-07-16 19:25:04 +0000185 assert(rtp_rtcp_); // Should be set by owner at construction time.
186 return rtp_rtcp_->IncomingRtpPacket(received_packet, received_packet_length,
187 header);
niklase@google.com470e71d2011-07-07 08:21:25 +0000188}
189
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000190int ViEReceiver::InsertRTCPPacket(const int8_t* rtcp_packet,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000191 int rtcp_packet_length) {
192 // TODO(mflodman) Change decrypt to get rid of this cast.
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000193 int8_t* tmp_ptr = const_cast<int8_t*>(rtcp_packet);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000194 unsigned char* received_packet = reinterpret_cast<unsigned char*>(tmp_ptr);
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000195 int received_packet_length = rtcp_packet_length;
196 {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000197 CriticalSectionScoped cs(receive_cs_.get());
braveyao@webrtc.orgb6433b72013-07-26 09:02:46 +0000198 if (!receiving_) {
199 return -1;
200 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000201
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000202 if (external_decryption_) {
mflodman@webrtc.org34e83b82012-10-17 11:05:54 +0000203 int decrypted_length = kViEMaxMtu;
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000204 external_decryption_->decrypt_rtcp(channel_id_, received_packet,
205 decryption_buffer_,
206 received_packet_length,
207 &decrypted_length);
208 if (decrypted_length <= 0) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000209 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
210 "RTP decryption failed");
niklase@google.com470e71d2011-07-07 08:21:25 +0000211 return -1;
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000212 } else if (decrypted_length > kViEMaxMtu) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000213 WEBRTC_TRACE(webrtc::kTraceCritical, webrtc::kTraceVideo, channel_id_,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000214 "InsertRTCPPacket: %d bytes is allocated as RTP "
215 " decrytption output, external decryption used %d bytes. "
216 " => memory is now corrupted",
217 kViEMaxMtu, decrypted_length);
218 return -1;
219 }
220 received_packet = decryption_buffer_;
221 received_packet_length = decrypted_length;
niklase@google.com470e71d2011-07-07 08:21:25 +0000222 }
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000223
224 if (rtp_dump_) {
225 rtp_dump_->DumpPacket(
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000226 received_packet, static_cast<uint16_t>(received_packet_length));
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000227 }
228 }
229 {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000230 CriticalSectionScoped cs(receive_cs_.get());
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000231 std::list<RtpRtcp*>::iterator it = rtp_rtcp_simulcast_.begin();
232 while (it != rtp_rtcp_simulcast_.end()) {
233 RtpRtcp* rtp_rtcp = *it++;
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000234 rtp_rtcp->IncomingRtcpPacket(received_packet, received_packet_length);
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000235 }
236 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000237 assert(rtp_rtcp_); // Should be set by owner at construction time.
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000238 return rtp_rtcp_->IncomingRtcpPacket(received_packet, received_packet_length);
niklase@google.com470e71d2011-07-07 08:21:25 +0000239}
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000240
241void ViEReceiver::StartReceive() {
braveyao@webrtc.orgb6433b72013-07-26 09:02:46 +0000242 CriticalSectionScoped cs(receive_cs_.get());
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000243 receiving_ = true;
244}
245
246void ViEReceiver::StopReceive() {
braveyao@webrtc.orgb6433b72013-07-26 09:02:46 +0000247 CriticalSectionScoped cs(receive_cs_.get());
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000248 receiving_ = false;
249}
250
251int ViEReceiver::StartRTPDump(const char file_nameUTF8[1024]) {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000252 CriticalSectionScoped cs(receive_cs_.get());
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000253 if (rtp_dump_) {
254 // Restart it if it already exists and is started
255 rtp_dump_->Stop();
256 } else {
257 rtp_dump_ = RtpDump::CreateRtpDump();
258 if (rtp_dump_ == NULL) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000259 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000260 "StartRTPDump: Failed to create RTP dump");
261 return -1;
262 }
263 }
264 if (rtp_dump_->Start(file_nameUTF8) != 0) {
265 RtpDump::DestroyRtpDump(rtp_dump_);
266 rtp_dump_ = NULL;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000267 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000268 "StartRTPDump: Failed to start RTP dump");
269 return -1;
270 }
271 return 0;
272}
273
274int ViEReceiver::StopRTPDump() {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000275 CriticalSectionScoped cs(receive_cs_.get());
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000276 if (rtp_dump_) {
277 if (rtp_dump_->IsActive()) {
278 rtp_dump_->Stop();
279 } else {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000280 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000281 "StopRTPDump: Dump not active");
282 }
283 RtpDump::DestroyRtpDump(rtp_dump_);
284 rtp_dump_ = NULL;
285 } else {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000286 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000287 "StopRTPDump: RTP dump not started");
288 return -1;
289 }
290 return 0;
291}
292
stefan@webrtc.orgb5865072013-02-01 14:33:42 +0000293// TODO(holmer): To be moved to ViEChannelGroup.
mflodman@webrtc.org4fd55272013-02-06 17:46:39 +0000294void ViEReceiver::EstimatedReceiveBandwidth(
stefan@webrtc.orgb5865072013-02-01 14:33:42 +0000295 unsigned int* available_bandwidth) const {
296 std::vector<unsigned int> ssrcs;
mflodman@webrtc.org4fd55272013-02-06 17:46:39 +0000297
298 // LatestEstimate returns an error if there is no valid bitrate estimate, but
299 // ViEReceiver instead returns a zero estimate.
300 remote_bitrate_estimator_->LatestEstimate(&ssrcs, available_bandwidth);
tnakamura@webrtc.orgaa4d96a2013-07-16 19:25:04 +0000301 if (std::find(ssrcs.begin(), ssrcs.end(), rtp_rtcp_->RemoteSSRC()) !=
mflodman@webrtc.orga066cbf2013-05-28 15:00:15 +0000302 ssrcs.end()) {
stefan@webrtc.orgb5865072013-02-01 14:33:42 +0000303 *available_bandwidth /= ssrcs.size();
mflodman@webrtc.org4fd55272013-02-06 17:46:39 +0000304 } else {
305 *available_bandwidth = 0;
stefan@webrtc.orgb5865072013-02-01 14:33:42 +0000306 }
stefan@webrtc.orgb5865072013-02-01 14:33:42 +0000307}
308
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000309} // namespace webrtc