blob: a39dbee43c6609a4d86045ac5622b452c36a64dd [file] [log] [blame]
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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.org281cff82013-05-17 13:44:48 +000011#include "webrtc/video_engine/vie_receiver.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000012
mflodman@webrtc.orgcd1ac8b2013-02-06 17:46:39 +000013#include <vector>
14
pbos@webrtc.org281cff82013-05-17 13:44:48 +000015#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
stefan@webrtc.org6696fba2013-05-29 12:12:51 +000016#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
pbos@webrtc.org281cff82013-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"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000023
24namespace webrtc {
25
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000026ViEReceiver::ViEReceiver(const int32_t channel_id,
27 VideoCodingModule* module_vcm,
28 RemoteBitrateEstimator* remote_bitrate_estimator)
29 : receive_cs_(CriticalSectionWrapper::CreateCriticalSection()),
30 channel_id_(channel_id),
stefan@webrtc.org6696fba2013-05-29 12:12:51 +000031 rtp_header_parser_(RtpHeaderParser::Create()),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000032 rtp_rtcp_(NULL),
33 vcm_(module_vcm),
34 remote_bitrate_estimator_(remote_bitrate_estimator),
35 external_decryption_(NULL),
36 decryption_buffer_(NULL),
37 rtp_dump_(NULL),
38 receiving_(false) {
39 assert(remote_bitrate_estimator);
40}
41
42ViEReceiver::~ViEReceiver() {
43 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 }
52}
53
54int ViEReceiver::RegisterExternalDecryption(Encryption* decryption) {
55 CriticalSectionScoped cs(receive_cs_.get());
56 if (external_decryption_) {
57 return -1;
58 }
pbos@webrtc.org67879bc2013-04-09 13:41:51 +000059 decryption_buffer_ = new uint8_t[kViEMaxMtu];
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000060 if (decryption_buffer_ == NULL) {
61 return -1;
62 }
63 external_decryption_ = decryption;
64 return 0;
65}
66
67int ViEReceiver::DeregisterExternalDecryption() {
68 CriticalSectionScoped cs(receive_cs_.get());
69 if (external_decryption_ == NULL) {
70 return -1;
71 }
72 external_decryption_ = NULL;
73 return 0;
74}
75
76void ViEReceiver::SetRtpRtcpModule(RtpRtcp* module) {
77 rtp_rtcp_ = module;
78}
79
80void ViEReceiver::RegisterSimulcastRtpRtcpModules(
81 const std::list<RtpRtcp*>& rtp_modules) {
82 CriticalSectionScoped cs(receive_cs_.get());
83 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 }
90}
91
stefan@webrtc.org4e5f9832013-05-29 13:28:21 +000092bool ViEReceiver::SetReceiveTimestampOffsetStatus(bool enable, int id) {
stefan@webrtc.org6696fba2013-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.org4e5f9832013-05-29 13:28:21 +0000102bool ViEReceiver::SetReceiveAbsoluteSendTimeStatus(bool enable, int id) {
stefan@webrtc.org6696fba2013-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
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000112int ViEReceiver::ReceivedRTPPacket(const void* rtp_packet,
113 int rtp_packet_length) {
114 if (!receiving_) {
115 return -1;
116 }
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000117 return InsertRTPPacket(static_cast<const int8_t*>(rtp_packet),
118 rtp_packet_length);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000119}
120
121int ViEReceiver::ReceivedRTCPPacket(const void* rtcp_packet,
122 int rtcp_packet_length) {
123 if (!receiving_) {
124 return -1;
125 }
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000126 return InsertRTCPPacket(static_cast<const int8_t*>(rtcp_packet),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000127 rtcp_packet_length);
128}
129
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000130int32_t ViEReceiver::OnReceivedPayloadData(
131 const uint8_t* payload_data, const uint16_t payload_size,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000132 const WebRtcRTPHeader* rtp_header) {
133 if (rtp_header == NULL) {
134 return 0;
135 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000136 if (vcm_->IncomingPacket(payload_data, payload_size, *rtp_header) != 0) {
137 // Check this...
138 return -1;
139 }
140 return 0;
141}
142
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000143int ViEReceiver::InsertRTPPacket(const int8_t* rtp_packet,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000144 int rtp_packet_length) {
145 // TODO(mflodman) Change decrypt to get rid of this cast.
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000146 int8_t* tmp_ptr = const_cast<int8_t*>(rtp_packet);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000147 unsigned char* received_packet = reinterpret_cast<unsigned char*>(tmp_ptr);
148 int received_packet_length = rtp_packet_length;
149
150 {
151 CriticalSectionScoped cs(receive_cs_.get());
152
153 if (external_decryption_) {
154 int decrypted_length = kViEMaxMtu;
155 external_decryption_->decrypt(channel_id_, received_packet,
156 decryption_buffer_, received_packet_length,
157 &decrypted_length);
158 if (decrypted_length <= 0) {
159 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
160 "RTP decryption failed");
161 return -1;
162 } else if (decrypted_length > kViEMaxMtu) {
163 WEBRTC_TRACE(webrtc::kTraceCritical, webrtc::kTraceVideo, channel_id_,
164 "InsertRTPPacket: %d bytes is allocated as RTP decrytption"
165 " output, external decryption used %d bytes. => memory is "
166 " now corrupted", kViEMaxMtu, decrypted_length);
167 return -1;
168 }
169 received_packet = decryption_buffer_;
170 received_packet_length = decrypted_length;
171 }
172
173 if (rtp_dump_) {
174 rtp_dump_->DumpPacket(received_packet,
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000175 static_cast<uint16_t>(received_packet_length));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000176 }
177 }
stefan@webrtc.org6696fba2013-05-29 12:12:51 +0000178 RTPHeader header;
179 if (!rtp_header_parser_->Parse(received_packet, received_packet_length,
180 &header)) {
181 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideo, channel_id_,
182 "IncomingPacket invalid RTP header");
183 return -1;
184 }
stefan@webrtc.orgd8ecee52013-06-04 12:15:40 +0000185 const int payload_size = received_packet_length - header.headerLength;
186 remote_bitrate_estimator_->IncomingPacket(TickTime::MillisecondTimestamp(),
187 payload_size, header);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000188 assert(rtp_rtcp_); // Should be set by owner at construction time.
stefan@webrtc.org6696fba2013-05-29 12:12:51 +0000189 return rtp_rtcp_->IncomingRtpPacket(received_packet, received_packet_length,
190 header);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000191}
192
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000193int ViEReceiver::InsertRTCPPacket(const int8_t* rtcp_packet,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000194 int rtcp_packet_length) {
195 // TODO(mflodman) Change decrypt to get rid of this cast.
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000196 int8_t* tmp_ptr = const_cast<int8_t*>(rtcp_packet);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000197 unsigned char* received_packet = reinterpret_cast<unsigned char*>(tmp_ptr);
198 int received_packet_length = rtcp_packet_length;
199 {
200 CriticalSectionScoped cs(receive_cs_.get());
201
202 if (external_decryption_) {
203 int decrypted_length = kViEMaxMtu;
204 external_decryption_->decrypt_rtcp(channel_id_, received_packet,
205 decryption_buffer_,
206 received_packet_length,
207 &decrypted_length);
208 if (decrypted_length <= 0) {
209 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
210 "RTP decryption failed");
211 return -1;
212 } else if (decrypted_length > kViEMaxMtu) {
213 WEBRTC_TRACE(webrtc::kTraceCritical, webrtc::kTraceVideo, channel_id_,
214 "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;
222 }
223
224 if (rtp_dump_) {
225 rtp_dump_->DumpPacket(
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000226 received_packet, static_cast<uint16_t>(received_packet_length));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000227 }
228 }
229 {
230 CriticalSectionScoped cs(receive_cs_.get());
231 std::list<RtpRtcp*>::iterator it = rtp_rtcp_simulcast_.begin();
232 while (it != rtp_rtcp_simulcast_.end()) {
233 RtpRtcp* rtp_rtcp = *it++;
stefan@webrtc.org6696fba2013-05-29 12:12:51 +0000234 rtp_rtcp->IncomingRtcpPacket(received_packet, received_packet_length);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000235 }
236 }
237 assert(rtp_rtcp_); // Should be set by owner at construction time.
stefan@webrtc.org6696fba2013-05-29 12:12:51 +0000238 return rtp_rtcp_->IncomingRtcpPacket(received_packet, received_packet_length);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000239}
240
241void ViEReceiver::StartReceive() {
242 receiving_ = true;
243}
244
245void ViEReceiver::StopReceive() {
246 receiving_ = false;
247}
248
249int ViEReceiver::StartRTPDump(const char file_nameUTF8[1024]) {
250 CriticalSectionScoped cs(receive_cs_.get());
251 if (rtp_dump_) {
252 // Restart it if it already exists and is started
253 rtp_dump_->Stop();
254 } else {
255 rtp_dump_ = RtpDump::CreateRtpDump();
256 if (rtp_dump_ == NULL) {
257 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
258 "StartRTPDump: Failed to create RTP dump");
259 return -1;
260 }
261 }
262 if (rtp_dump_->Start(file_nameUTF8) != 0) {
263 RtpDump::DestroyRtpDump(rtp_dump_);
264 rtp_dump_ = NULL;
265 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
266 "StartRTPDump: Failed to start RTP dump");
267 return -1;
268 }
269 return 0;
270}
271
272int ViEReceiver::StopRTPDump() {
273 CriticalSectionScoped cs(receive_cs_.get());
274 if (rtp_dump_) {
275 if (rtp_dump_->IsActive()) {
276 rtp_dump_->Stop();
277 } else {
278 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
279 "StopRTPDump: Dump not active");
280 }
281 RtpDump::DestroyRtpDump(rtp_dump_);
282 rtp_dump_ = NULL;
283 } else {
284 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, channel_id_,
285 "StopRTPDump: RTP dump not started");
286 return -1;
287 }
288 return 0;
289}
290
stefan@webrtc.org2a5dbce2013-02-01 14:33:42 +0000291// TODO(holmer): To be moved to ViEChannelGroup.
mflodman@webrtc.orgcd1ac8b2013-02-06 17:46:39 +0000292void ViEReceiver::EstimatedReceiveBandwidth(
stefan@webrtc.org2a5dbce2013-02-01 14:33:42 +0000293 unsigned int* available_bandwidth) const {
294 std::vector<unsigned int> ssrcs;
mflodman@webrtc.orgcd1ac8b2013-02-06 17:46:39 +0000295
296 // LatestEstimate returns an error if there is no valid bitrate estimate, but
297 // ViEReceiver instead returns a zero estimate.
298 remote_bitrate_estimator_->LatestEstimate(&ssrcs, available_bandwidth);
mflodman@webrtc.orge3b52e62013-05-28 15:00:15 +0000299 if (std::find(ssrcs.begin(), ssrcs.end(), rtp_rtcp_->RemoteSSRC()) !=
300 ssrcs.end()) {
stefan@webrtc.org2a5dbce2013-02-01 14:33:42 +0000301 *available_bandwidth /= ssrcs.size();
mflodman@webrtc.orgcd1ac8b2013-02-06 17:46:39 +0000302 } else {
303 *available_bandwidth = 0;
stefan@webrtc.org2a5dbce2013-02-01 14:33:42 +0000304 }
stefan@webrtc.org2a5dbce2013-02-01 14:33:42 +0000305}
306
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000307} // namespace webrtc