blob: 3b69e75e7e682374f3c9e3c10fa0b406e9c96f7e [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
2 * Copyright (c) 2011 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
niklase@google.com470e71d2011-07-07 08:21:25 +000011#include "vie_receiver.h"
12
13#include "critical_section_wrapper.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000014#include "rtp_dump.h"
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000015#include "rtp_rtcp.h"
16#include "video_coding.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000017#include "trace.h"
18
19namespace webrtc {
20
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000021ViEReceiver::ViEReceiver(int engine_id, int channel_id,
22 RtpRtcp& rtp_rtcp,
23 VideoCodingModule& module_vcm)
24 : receive_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
25 engine_id_(engine_id),
26 channel_id_(channel_id),
27 rtp_rtcp_(rtp_rtcp),
28 vcm_(module_vcm),
29 external_decryption_(NULL),
30 decryption_buffer_(NULL),
31 rtp_dump_(NULL),
32 receiving_(false) {
niklase@google.com470e71d2011-07-07 08:21:25 +000033}
34
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000035ViEReceiver::~ViEReceiver() {
36 delete &receive_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +000037
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000038 if (decryption_buffer_) {
39 delete[] decryption_buffer_;
40 decryption_buffer_ = NULL;
41 }
42 if (rtp_dump_) {
43 rtp_dump_->Stop();
44 RtpDump::DestroyRtpDump(rtp_dump_);
45 rtp_dump_ = NULL;
46 }
niklase@google.com470e71d2011-07-07 08:21:25 +000047}
48
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000049int ViEReceiver::RegisterExternalDecryption(Encryption* decryption) {
50 CriticalSectionScoped cs(receive_critsect_);
51 if (external_decryption_) {
52 return -1;
53 }
54 decryption_buffer_ = new WebRtc_UWord8[kViEMaxMtu];
55 if (decryption_buffer_ == NULL) {
56 return -1;
57 }
58 external_decryption_ = decryption;
59 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000060}
61
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000062int ViEReceiver::DeregisterExternalDecryption() {
63 CriticalSectionScoped cs(receive_critsect_);
64 if (external_decryption_ == NULL) {
65 return -1;
66 }
67 external_decryption_ = NULL;
68 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000069}
70
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +000071void ViEReceiver::RegisterSimulcastRtpRtcpModules(
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000072 const std::list<RtpRtcp*>& rtp_modules) {
73 CriticalSectionScoped cs(receive_critsect_);
74 rtp_rtcp_simulcast_.clear();
75
76 if (!rtp_modules.empty()) {
77 rtp_rtcp_simulcast_.insert(rtp_rtcp_simulcast_.begin(),
78 rtp_modules.begin(),
79 rtp_modules.end());
80 }
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +000081}
82
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000083void ViEReceiver::IncomingRTPPacket(const WebRtc_Word8* rtp_packet,
84 const WebRtc_Word32 rtp_packet_length,
85 const WebRtc_Word8* from_ip,
86 const WebRtc_UWord16 from_port) {
87 InsertRTPPacket(rtp_packet, rtp_packet_length);
88}
niklase@google.com470e71d2011-07-07 08:21:25 +000089
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000090void ViEReceiver::IncomingRTCPPacket(const WebRtc_Word8* rtcp_packet,
91 const WebRtc_Word32 rtcp_packet_length,
92 const WebRtc_Word8* from_ip,
93 const WebRtc_UWord16 from_port) {
94 InsertRTCPPacket(rtcp_packet, rtcp_packet_length);
95}
niklase@google.com470e71d2011-07-07 08:21:25 +000096
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +000097int ViEReceiver::ReceivedRTPPacket(const void* rtp_packet,
98 int rtp_packet_length) {
99 if (!receiving_) {
100 return -1;
101 }
102 return InsertRTPPacket((const WebRtc_Word8*) rtp_packet, rtp_packet_length);
103}
104
105int ViEReceiver::ReceivedRTCPPacket(const void* rtcp_packet,
106 int rtcp_packet_length) {
107 if (!receiving_) {
108 return -1;
109 }
110 return InsertRTCPPacket((const WebRtc_Word8*) rtcp_packet,
111 rtcp_packet_length);
112}
113
114WebRtc_Word32 ViEReceiver::OnReceivedPayloadData(
115 const WebRtc_UWord8* payload_data, const WebRtc_UWord16 payload_size,
116 const WebRtcRTPHeader* rtp_header) {
117 if (rtp_header == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000118 return 0;
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000119 }
120
121 if (vcm_.IncomingPacket(payload_data, payload_size, *rtp_header) != 0) {
122 // Check this...
123 return -1;
124 }
125 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000126}
127
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000128int ViEReceiver::InsertRTPPacket(const WebRtc_Word8* rtp_packet,
129 int rtp_packet_length) {
130 // TODO(mflodman) Change decrypt to get rid of this cast.
131 WebRtc_Word8* tmp_ptr = const_cast<WebRtc_Word8*>(rtp_packet);
132 unsigned char* received_packet = reinterpret_cast<unsigned char*>(tmp_ptr);
133 int received_packet_length = rtp_packet_length;
niklase@google.com470e71d2011-07-07 08:21:25 +0000134
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000135 {
136 CriticalSectionScoped cs(receive_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000137
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000138 if (external_decryption_) {
139 int decrypted_length = 0;
140 external_decryption_->decrypt(channel_id_, received_packet,
141 decryption_buffer_, received_packet_length,
142 &decrypted_length);
143 if (decrypted_length <= 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000144 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000145 ViEId(engine_id_, channel_id_), "RTP decryption failed");
niklase@google.com470e71d2011-07-07 08:21:25 +0000146 return -1;
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000147 } else if (decrypted_length > kViEMaxMtu) {
148 WEBRTC_TRACE(webrtc::kTraceCritical, webrtc::kTraceVideo,
149 ViEId(engine_id_, channel_id_),
150 "InsertRTPPacket: %d bytes is allocated as RTP decrytption"
151 " output, external decryption used %d bytes. => memory is "
152 " now corrupted", kViEMaxMtu, decrypted_length);
153 return -1;
154 }
155 received_packet = decryption_buffer_;
156 received_packet_length = decrypted_length;
niklase@google.com470e71d2011-07-07 08:21:25 +0000157 }
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000158
159 if (rtp_dump_) {
160 rtp_dump_->DumpPacket(received_packet,
161 static_cast<WebRtc_UWord16>(received_packet_length));
162 }
163 }
164 return rtp_rtcp_.IncomingPacket(received_packet, received_packet_length);
niklase@google.com470e71d2011-07-07 08:21:25 +0000165}
166
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000167int ViEReceiver::InsertRTCPPacket(const WebRtc_Word8* rtcp_packet,
168 int rtcp_packet_length) {
169 // TODO(mflodman) Change decrypt to get rid of this cast.
170 WebRtc_Word8* tmp_ptr = const_cast<WebRtc_Word8*>(rtcp_packet);
171 unsigned char* received_packet = reinterpret_cast<unsigned char*>(tmp_ptr);
172 int received_packet_length = rtcp_packet_length;
173 {
174 CriticalSectionScoped cs(receive_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000175
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000176 if (external_decryption_) {
177 int decrypted_length = 0;
178 external_decryption_->decrypt_rtcp(channel_id_, received_packet,
179 decryption_buffer_,
180 received_packet_length,
181 &decrypted_length);
182 if (decrypted_length <= 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000183 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000184 ViEId(engine_id_, channel_id_), "RTP decryption failed");
niklase@google.com470e71d2011-07-07 08:21:25 +0000185 return -1;
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000186 } else if (decrypted_length > kViEMaxMtu) {
187 WEBRTC_TRACE(webrtc::kTraceCritical, webrtc::kTraceVideo,
188 ViEId(engine_id_, channel_id_),
189 "InsertRTCPPacket: %d bytes is allocated as RTP "
190 " decrytption output, external decryption used %d bytes. "
191 " => memory is now corrupted",
192 kViEMaxMtu, decrypted_length);
193 return -1;
194 }
195 received_packet = decryption_buffer_;
196 received_packet_length = decrypted_length;
niklase@google.com470e71d2011-07-07 08:21:25 +0000197 }
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000198
199 if (rtp_dump_) {
200 rtp_dump_->DumpPacket(
201 received_packet, static_cast<WebRtc_UWord16>(received_packet_length));
202 }
203 }
204 {
205 CriticalSectionScoped cs(receive_critsect_);
206 std::list<RtpRtcp*>::iterator it = rtp_rtcp_simulcast_.begin();
207 while (it != rtp_rtcp_simulcast_.end()) {
208 RtpRtcp* rtp_rtcp = *it++;
209 rtp_rtcp->IncomingPacket(received_packet, received_packet_length);
210 }
211 }
212 return rtp_rtcp_.IncomingPacket(received_packet, received_packet_length);
niklase@google.com470e71d2011-07-07 08:21:25 +0000213}
mflodman@webrtc.orgad4ee362011-11-28 22:39:24 +0000214
215void ViEReceiver::StartReceive() {
216 receiving_ = true;
217}
218
219void ViEReceiver::StopReceive() {
220 receiving_ = false;
221}
222
223int ViEReceiver::StartRTPDump(const char file_nameUTF8[1024]) {
224 CriticalSectionScoped cs(receive_critsect_);
225 if (rtp_dump_) {
226 // Restart it if it already exists and is started
227 rtp_dump_->Stop();
228 } else {
229 rtp_dump_ = RtpDump::CreateRtpDump();
230 if (rtp_dump_ == NULL) {
231 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
232 ViEId(engine_id_, channel_id_),
233 "StartRTPDump: Failed to create RTP dump");
234 return -1;
235 }
236 }
237 if (rtp_dump_->Start(file_nameUTF8) != 0) {
238 RtpDump::DestroyRtpDump(rtp_dump_);
239 rtp_dump_ = NULL;
240 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
241 ViEId(engine_id_, channel_id_),
242 "StartRTPDump: Failed to start RTP dump");
243 return -1;
244 }
245 return 0;
246}
247
248int ViEReceiver::StopRTPDump() {
249 CriticalSectionScoped cs(receive_critsect_);
250 if (rtp_dump_) {
251 if (rtp_dump_->IsActive()) {
252 rtp_dump_->Stop();
253 } else {
254 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
255 ViEId(engine_id_, channel_id_),
256 "StopRTPDump: Dump not active");
257 }
258 RtpDump::DestroyRtpDump(rtp_dump_);
259 rtp_dump_ = NULL;
260 } else {
261 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
262 ViEId(engine_id_, channel_id_),
263 "StopRTPDump: RTP dump not started");
264 return -1;
265 }
266 return 0;
267}
268
269} // namespace webrtc