blob: 78a9015eb3f310bdffb4d963dd34061b18ddd8e3 [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_channel.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000012
13#include <algorithm>
14#include <vector>
15
pbos@webrtc.org281cff82013-05-17 13:44:48 +000016#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
17#include "webrtc/modules/pacing/include/paced_sender.h"
18#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
19#include "webrtc/modules/utility/interface/process_thread.h"
20#include "webrtc/modules/video_coding/main/interface/video_coding.h"
21#include "webrtc/modules/video_processing/main/interface/video_processing.h"
andrew@webrtc.org07e96da2012-10-31 05:22:11 +000022#include "webrtc/modules/video_render/include/video_render_defines.h"
pbos@webrtc.org281cff82013-05-17 13:44:48 +000023#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
24#include "webrtc/system_wrappers/interface/thread_wrapper.h"
25#include "webrtc/system_wrappers/interface/trace.h"
26#include "webrtc/video_engine/call_stats.h"
27#include "webrtc/video_engine/include/vie_codec.h"
28#include "webrtc/video_engine/include/vie_errors.h"
29#include "webrtc/video_engine/include/vie_image_process.h"
30#include "webrtc/video_engine/include/vie_rtp_rtcp.h"
31#include "webrtc/video_engine/vie_defines.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000032
33namespace webrtc {
34
35const int kMaxDecodeWaitTimeMs = 50;
36const int kInvalidRtpExtensionId = 0;
mikhal@webrtc.org16196642013-02-01 19:33:21 +000037static const int kMaxTargetDelayMs = 10000;
stefan@webrtc.org06ad3842013-05-07 19:16:33 +000038static const float kMaxIncompleteTimeMultiplier = 3.5f;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000039
mflodman@webrtc.org78696d32012-11-26 12:40:15 +000040// Helper class receiving statistics callbacks.
fischman@webrtc.org0329e592013-02-19 22:09:36 +000041class ChannelStatsObserver : public CallStatsObserver {
mflodman@webrtc.org78696d32012-11-26 12:40:15 +000042 public:
43 explicit ChannelStatsObserver(ViEChannel* owner) : owner_(owner) {}
44 virtual ~ChannelStatsObserver() {}
45
46 // Implements StatsObserver.
47 virtual void OnRttUpdate(uint32_t rtt) {
48 owner_->OnRttUpdate(rtt);
49 }
50
51 private:
52 ViEChannel* owner_;
53};
54
pbos@webrtc.org67879bc2013-04-09 13:41:51 +000055ViEChannel::ViEChannel(int32_t channel_id,
56 int32_t engine_id,
57 uint32_t number_of_cores,
andresp@webrtc.orgac6d9192013-05-13 10:50:50 +000058 const Config& config,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000059 ProcessThread& module_process_thread,
60 RtcpIntraFrameObserver* intra_frame_observer,
61 RtcpBandwidthObserver* bandwidth_observer,
62 RemoteBitrateEstimator* remote_bitrate_estimator,
mflodman@webrtc.org78696d32012-11-26 12:40:15 +000063 RtcpRttObserver* rtt_observer,
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +000064 PacedSender* paced_sender,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000065 RtpRtcp* default_rtp_rtcp,
66 bool sender)
67 : ViEFrameProviderBase(channel_id, engine_id),
68 channel_id_(channel_id),
69 engine_id_(engine_id),
70 number_of_cores_(number_of_cores),
71 num_socket_threads_(kViESocketThreads),
72 callback_cs_(CriticalSectionWrapper::CreateCriticalSection()),
73 rtp_rtcp_cs_(CriticalSectionWrapper::CreateCriticalSection()),
74 default_rtp_rtcp_(default_rtp_rtcp),
75 rtp_rtcp_(NULL),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000076 vcm_(*VideoCodingModule::Create(ViEModuleId(engine_id, channel_id))),
77 vie_receiver_(channel_id, &vcm_, remote_bitrate_estimator),
78 vie_sender_(channel_id),
79 vie_sync_(&vcm_, this),
mflodman@webrtc.org78696d32012-11-26 12:40:15 +000080 stats_observer_(new ChannelStatsObserver(this)),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000081 module_process_thread_(module_process_thread),
82 codec_observer_(NULL),
83 do_key_frame_callbackRequest_(false),
84 rtp_observer_(NULL),
85 rtcp_observer_(NULL),
86 networkObserver_(NULL),
87 intra_frame_observer_(intra_frame_observer),
mflodman@webrtc.org78696d32012-11-26 12:40:15 +000088 rtt_observer_(rtt_observer),
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +000089 paced_sender_(paced_sender),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000090 bandwidth_observer_(bandwidth_observer),
91 rtp_packet_timeout_(false),
92 send_timestamp_extension_id_(kInvalidRtpExtensionId),
solenberg@webrtc.org453f9c02013-05-20 12:00:23 +000093 absolute_send_time_extension_id_(kInvalidRtpExtensionId),
solenberg@webrtc.orgf40e9b62013-05-27 16:02:56 +000094 receive_absolute_send_time_enabled_(false),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000095 using_packet_spread_(false),
96 external_transport_(NULL),
97 decoder_reset_(true),
98 wait_for_key_frame_(false),
99 decode_thread_(NULL),
100 external_encryption_(NULL),
101 effect_filter_(NULL),
102 color_enhancement_(false),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000103 mtu_(0),
mikhal@webrtc.org16196642013-02-01 19:33:21 +0000104 sender_(sender),
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000105 nack_history_size_sender_(kSendSidePacketHistorySize),
106 max_nack_reordering_threshold_(kMaxPacketAgeToNack) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000107 WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id, channel_id),
108 "ViEChannel::ViEChannel(channel_id: %d, engine_id: %d)",
109 channel_id, engine_id);
110
111 RtpRtcp::Configuration configuration;
112 configuration.id = ViEModuleId(engine_id, channel_id);
113 configuration.audio = false;
114 configuration.default_module = default_rtp_rtcp;
115 configuration.incoming_data = &vie_receiver_;
116 configuration.incoming_messages = this;
117 configuration.outgoing_transport = &vie_sender_;
118 configuration.rtcp_feedback = this;
119 configuration.intra_frame_callback = intra_frame_observer;
120 configuration.bandwidth_callback = bandwidth_observer;
mflodman@webrtc.org78696d32012-11-26 12:40:15 +0000121 configuration.rtt_observer = rtt_observer;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000122 configuration.remote_bitrate_estimator = remote_bitrate_estimator;
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +0000123 configuration.paced_sender = paced_sender;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000124
125 rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(configuration));
126 vie_receiver_.SetRtpRtcpModule(rtp_rtcp_.get());
stefan@webrtc.org06ad3842013-05-07 19:16:33 +0000127 vcm_.SetNackSettings(kMaxNackListSize, max_nack_reordering_threshold_, 0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000128}
129
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000130int32_t ViEChannel::Init() {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000131 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
132 "%s: channel_id: %d, engine_id: %d)", __FUNCTION__, channel_id_,
133 engine_id_);
134
135 // RTP/RTCP initialization.
136 if (rtp_rtcp_->SetSendingMediaStatus(false) != 0) {
137 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
138 "%s: RTP::SetSendingMediaStatus failure", __FUNCTION__);
139 return -1;
140 }
141 if (module_process_thread_.RegisterModule(rtp_rtcp_.get()) != 0) {
142 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
143 "%s: RTP::RegisterModule failure", __FUNCTION__);
144 return -1;
145 }
146 if (rtp_rtcp_->SetKeyFrameRequestMethod(kKeyFrameReqFirRtp) != 0) {
147 WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
148 "%s: RTP::SetKeyFrameRequestMethod failure", __FUNCTION__);
149 }
150 if (rtp_rtcp_->SetRTCPStatus(kRtcpCompound) != 0) {
151 WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
152 "%s: RTP::SetRTCPStatus failure", __FUNCTION__);
153 }
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +0000154 if (paced_sender_) {
mikhal@webrtc.org16196642013-02-01 19:33:21 +0000155 if (rtp_rtcp_->SetStorePacketsStatus(true, nack_history_size_sender_) !=
stefan@webrtc.org7fff32c2013-02-01 15:09:57 +0000156 0) {
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +0000157 WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
158 "%s:SetStorePacketsStatus failure", __FUNCTION__);
159 }
160 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000161 // VCM initialization
162 if (vcm_.InitializeReceiver() != 0) {
163 WEBRTC_TRACE(kTraceError, kTraceVideo,
164 ViEId(engine_id_, channel_id_),
165 "%s: VCM::InitializeReceiver failure", __FUNCTION__);
166 return -1;
167 }
mflodman@webrtc.orgb4c89a42013-06-10 15:50:12 +0000168 if (vcm_.SetVideoProtection(kProtectionKeyOnLoss, true)) {
169 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
170 "%s: VCM::SetVideoProtection failure", __FUNCTION__);
171 return -1;
172 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000173 if (vcm_.RegisterReceiveCallback(this) != 0) {
174 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
175 "%s: VCM::RegisterReceiveCallback failure", __FUNCTION__);
176 return -1;
177 }
178 if (vcm_.RegisterFrameTypeCallback(this) != 0) {
179 WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
180 "%s: VCM::RegisterFrameTypeCallback failure", __FUNCTION__);
181 }
182 if (vcm_.RegisterReceiveStatisticsCallback(this) != 0) {
183 WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
184 "%s: VCM::RegisterReceiveStatisticsCallback failure",
185 __FUNCTION__);
186 }
187 if (vcm_.SetRenderDelay(kViEDefaultRenderDelayMs) != 0) {
188 WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
189 "%s: VCM::SetRenderDelay failure", __FUNCTION__);
190 }
191 if (module_process_thread_.RegisterModule(&vcm_) != 0) {
192 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
193 "%s: VCM::RegisterModule(vcm) failure", __FUNCTION__);
194 return -1;
195 }
196#ifdef VIDEOCODEC_VP8
197 VideoCodec video_codec;
198 if (vcm_.Codec(kVideoCodecVP8, &video_codec) == VCM_OK) {
199 rtp_rtcp_->RegisterSendPayload(video_codec);
200 rtp_rtcp_->RegisterReceivePayload(video_codec);
201 vcm_.RegisterReceiveCodec(&video_codec, number_of_cores_);
202 vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
203 rtp_rtcp_->MaxDataPayloadLength());
204 } else {
205 assert(false);
206 }
207#endif
208
209 return 0;
210}
211
212ViEChannel::~ViEChannel() {
213 WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id_, channel_id_),
214 "ViEChannel Destructor, channel_id: %d, engine_id: %d",
215 channel_id_, engine_id_);
216
217 // Make sure we don't get more callbacks from the RTP module.
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000218 module_process_thread_.DeRegisterModule(rtp_rtcp_.get());
219 module_process_thread_.DeRegisterModule(&vcm_);
220 module_process_thread_.DeRegisterModule(&vie_sync_);
221 while (simulcast_rtp_rtcp_.size() > 0) {
222 std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
223 RtpRtcp* rtp_rtcp = *it;
224 module_process_thread_.DeRegisterModule(rtp_rtcp);
225 delete rtp_rtcp;
226 simulcast_rtp_rtcp_.erase(it);
227 }
mflodman@webrtc.org55e6f582013-02-20 16:00:27 +0000228 while (removed_rtp_rtcp_.size() > 0) {
229 std::list<RtpRtcp*>::iterator it = removed_rtp_rtcp_.begin();
230 delete *it;
231 removed_rtp_rtcp_.erase(it);
232 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000233 if (decode_thread_) {
234 StopDecodeThread();
235 }
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +0000236 // Release modules.
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000237 VideoCodingModule::Destroy(&vcm_);
238}
239
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000240int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec,
241 bool new_stream) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000242 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
243 "%s: codec_type: %d", __FUNCTION__, video_codec.codecType);
244
245 if (!sender_) {
246 return 0;
247 }
248 if (video_codec.codecType == kVideoCodecRED ||
249 video_codec.codecType == kVideoCodecULPFEC) {
250 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
251 "%s: codec_type: %d is not a valid send codec.", __FUNCTION__,
252 video_codec.codecType);
253 return -1;
254 }
255 if (kMaxSimulcastStreams < video_codec.numberOfSimulcastStreams) {
256 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
257 "%s: Too many simulcast streams", __FUNCTION__);
258 return -1;
259 }
260 // Update the RTP module with the settings.
261 // Stop and Start the RTP module -> trigger new SSRC, if an SSRC hasn't been
262 // set explicitly.
263 bool restart_rtp = false;
264 if (rtp_rtcp_->Sending() && new_stream) {
265 restart_rtp = true;
266 rtp_rtcp_->SetSendingStatus(false);
mflodman@webrtc.org55e6f582013-02-20 16:00:27 +0000267 for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
268 it != simulcast_rtp_rtcp_.end(); ++it) {
269 (*it)->SetSendingStatus(false);
270 (*it)->SetSendingMediaStatus(false);
271 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000272 }
273 NACKMethod nack_method = rtp_rtcp_->NACK();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000274
275 bool fec_enabled = false;
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000276 uint8_t payload_type_red;
277 uint8_t payload_type_fec;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000278 rtp_rtcp_->GenericFECStatus(fec_enabled, payload_type_red, payload_type_fec);
279
280 CriticalSectionScoped cs(rtp_rtcp_cs_.get());
281
282 if (video_codec.numberOfSimulcastStreams > 0) {
283 // Set correct bitrate to base layer.
284 // Create our simulcast RTP modules.
mflodman@webrtc.org55e6f582013-02-20 16:00:27 +0000285 int num_modules_to_add = video_codec.numberOfSimulcastStreams -
286 simulcast_rtp_rtcp_.size() - 1;
287 if (num_modules_to_add < 0) {
288 num_modules_to_add = 0;
289 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000290
mflodman@webrtc.org55e6f582013-02-20 16:00:27 +0000291 while (removed_rtp_rtcp_.size() > 0 && num_modules_to_add > 0) {
292 RtpRtcp* rtp_rtcp = removed_rtp_rtcp_.front();
293 removed_rtp_rtcp_.pop_front();
294 simulcast_rtp_rtcp_.push_back(rtp_rtcp);
295 rtp_rtcp->SetSendingStatus(rtp_rtcp_->Sending());
296 rtp_rtcp->SetSendingMediaStatus(rtp_rtcp_->SendingMedia());
297 module_process_thread_.RegisterModule(rtp_rtcp);
298 --num_modules_to_add;
299 }
300
301 for (int i = 0; i < num_modules_to_add; ++i) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000302 RtpRtcp::Configuration configuration;
303 configuration.id = ViEModuleId(engine_id_, channel_id_);
304 configuration.audio = false; // Video.
305 configuration.default_module = default_rtp_rtcp_;
306 configuration.outgoing_transport = &vie_sender_;
307 configuration.intra_frame_callback = intra_frame_observer_;
308 configuration.bandwidth_callback = bandwidth_observer_.get();
mflodman@webrtc.org78696d32012-11-26 12:40:15 +0000309 configuration.rtt_observer = rtt_observer_;
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +0000310 configuration.paced_sender = paced_sender_;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000311
312 RtpRtcp* rtp_rtcp = RtpRtcp::CreateRtpRtcp(configuration);
313
314 // Silently ignore error.
315 module_process_thread_.RegisterModule(rtp_rtcp);
316 if (rtp_rtcp->SetRTCPStatus(rtp_rtcp_->RTCP()) != 0) {
317 WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
318 "%s: RTP::SetRTCPStatus failure", __FUNCTION__);
319 }
320 if (nack_method != kNackOff) {
mikhal@webrtc.org16196642013-02-01 19:33:21 +0000321 rtp_rtcp->SetStorePacketsStatus(true, nack_history_size_sender_);
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000322 rtp_rtcp->SetNACKStatus(nack_method, max_nack_reordering_threshold_);
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +0000323 } else if (paced_sender_) {
mikhal@webrtc.org16196642013-02-01 19:33:21 +0000324 rtp_rtcp->SetStorePacketsStatus(true, nack_history_size_sender_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000325 }
326 if (fec_enabled) {
327 rtp_rtcp->SetGenericFECStatus(fec_enabled, payload_type_red,
328 payload_type_fec);
329 }
330 rtp_rtcp->SetSendingMediaStatus(rtp_rtcp_->SendingMedia());
331 simulcast_rtp_rtcp_.push_back(rtp_rtcp);
332 }
333 // Remove last in list if we have too many.
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000334 for (int j = simulcast_rtp_rtcp_.size();
335 j > (video_codec.numberOfSimulcastStreams - 1);
336 j--) {
337 RtpRtcp* rtp_rtcp = simulcast_rtp_rtcp_.back();
338 module_process_thread_.DeRegisterModule(rtp_rtcp);
mflodman@webrtc.org55e6f582013-02-20 16:00:27 +0000339 rtp_rtcp->SetSendingStatus(false);
340 rtp_rtcp->SetSendingMediaStatus(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000341 simulcast_rtp_rtcp_.pop_back();
mflodman@webrtc.org55e6f582013-02-20 16:00:27 +0000342 removed_rtp_rtcp_.push_front(rtp_rtcp);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000343 }
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000344 uint8_t idx = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000345 // Configure all simulcast modules.
346 for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
347 it != simulcast_rtp_rtcp_.end();
348 it++) {
349 idx++;
350 RtpRtcp* rtp_rtcp = *it;
351 rtp_rtcp->DeRegisterSendPayload(video_codec.plType);
352 if (rtp_rtcp->RegisterSendPayload(video_codec) != 0) {
353 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
354 "%s: could not register payload type", __FUNCTION__);
355 return -1;
356 }
357 if (mtu_ != 0) {
358 rtp_rtcp->SetMaxTransferUnit(mtu_);
359 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000360 if (restart_rtp) {
361 rtp_rtcp->SetSendingStatus(true);
mflodman@webrtc.org55e6f582013-02-20 16:00:27 +0000362 rtp_rtcp->SetSendingMediaStatus(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000363 }
364 if (send_timestamp_extension_id_ != kInvalidRtpExtensionId) {
365 // Deregister in case the extension was previously enabled.
366 rtp_rtcp->DeregisterSendRtpHeaderExtension(
367 kRtpExtensionTransmissionTimeOffset);
368 if (rtp_rtcp->RegisterSendRtpHeaderExtension(
369 kRtpExtensionTransmissionTimeOffset,
370 send_timestamp_extension_id_) != 0) {
371 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
372 "%s: could not register transmission time extension",
373 __FUNCTION__);
374 }
375 } else {
376 rtp_rtcp->DeregisterSendRtpHeaderExtension(
377 kRtpExtensionTransmissionTimeOffset);
378 }
solenberg@webrtc.org453f9c02013-05-20 12:00:23 +0000379 if (absolute_send_time_extension_id_ != kInvalidRtpExtensionId) {
380 // Deregister in case the extension was previously enabled.
381 rtp_rtcp->DeregisterSendRtpHeaderExtension(
382 kRtpExtensionAbsoluteSendTime);
383 if (rtp_rtcp->RegisterSendRtpHeaderExtension(
384 kRtpExtensionAbsoluteSendTime,
385 absolute_send_time_extension_id_) != 0) {
386 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
387 "%s: could not register absolute send time extension",
388 __FUNCTION__);
389 }
390 } else {
391 rtp_rtcp->DeregisterSendRtpHeaderExtension(
392 kRtpExtensionAbsoluteSendTime);
393 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000394 }
395 // |RegisterSimulcastRtpRtcpModules| resets all old weak pointers and old
396 // modules can be deleted after this step.
397 vie_receiver_.RegisterSimulcastRtpRtcpModules(simulcast_rtp_rtcp_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000398 } else {
mflodman@webrtc.org55e6f582013-02-20 16:00:27 +0000399 while (!simulcast_rtp_rtcp_.empty()) {
400 RtpRtcp* rtp_rtcp = simulcast_rtp_rtcp_.back();
401 module_process_thread_.DeRegisterModule(rtp_rtcp);
402 rtp_rtcp->SetSendingStatus(false);
403 rtp_rtcp->SetSendingMediaStatus(false);
404 simulcast_rtp_rtcp_.pop_back();
405 removed_rtp_rtcp_.push_front(rtp_rtcp);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000406 }
407 // Clear any previous modules.
408 vie_receiver_.RegisterSimulcastRtpRtcpModules(simulcast_rtp_rtcp_);
409 }
410 // Enable this if H264 is available.
411 // This sets the wanted packetization mode.
412 // if (video_codec.plType == kVideoCodecH264) {
413 // if (video_codec.codecSpecific.H264.packetization == kH264SingleMode) {
414 // rtp_rtcp_->SetH264PacketizationMode(H264_SINGLE_NAL_MODE);
415 // } else {
416 // rtp_rtcp_->SetH264PacketizationMode(H264_NON_INTERLEAVED_MODE);
417 // }
418 // if (video_codec.codecSpecific.H264.configParametersSize > 0) {
419 // rtp_rtcp_->SetH264SendModeNALU_PPS_SPS(true);
420 // }
421 // }
422
423 // Don't log this error, no way to check in advance if this pl_type is
424 // registered or not...
425 rtp_rtcp_->DeRegisterSendPayload(video_codec.plType);
426 if (rtp_rtcp_->RegisterSendPayload(video_codec) != 0) {
427 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
428 "%s: could not register payload type", __FUNCTION__);
429 return -1;
430 }
431 if (restart_rtp) {
432 rtp_rtcp_->SetSendingStatus(true);
mflodman@webrtc.org55e6f582013-02-20 16:00:27 +0000433 for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
434 it != simulcast_rtp_rtcp_.end(); ++it) {
435 (*it)->SetSendingStatus(true);
436 (*it)->SetSendingMediaStatus(true);
437 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000438 }
439 return 0;
440}
441
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000442int32_t ViEChannel::SetReceiveCodec(const VideoCodec& video_codec) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000443 // We will not receive simulcast streams, so no need to handle that use case.
444 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
445 "%s", __FUNCTION__);
446
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000447 int8_t old_pltype = -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000448 if (rtp_rtcp_->ReceivePayloadType(video_codec, &old_pltype) != -1) {
449 rtp_rtcp_->DeRegisterReceivePayload(old_pltype);
450 }
451
452 if (rtp_rtcp_->RegisterReceivePayload(video_codec) != 0) {
453 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
454 "%s: Could not register receive payload type", __FUNCTION__);
455 return -1;
456 }
457
458 if (video_codec.codecType != kVideoCodecRED &&
459 video_codec.codecType != kVideoCodecULPFEC) {
460 // Register codec type with VCM, but do not register RED or ULPFEC.
461 if (vcm_.RegisterReceiveCodec(&video_codec, number_of_cores_,
462 wait_for_key_frame_) != VCM_OK) {
463 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
464 "%s: Could not register decoder", __FUNCTION__);
465 return -1;
466 }
467 }
468 return 0;
469}
470
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000471int32_t ViEChannel::GetReceiveCodec(VideoCodec* video_codec) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000472 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
473 "%s", __FUNCTION__);
474
475 if (vcm_.ReceiveCodec(video_codec) != 0) {
476 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
477 "%s: Could not get receive codec", __FUNCTION__);
478 return -1;
479 }
480 return 0;
481}
482
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000483int32_t ViEChannel::RegisterCodecObserver(ViEDecoderObserver* observer) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000484 CriticalSectionScoped cs(callback_cs_.get());
485 if (observer) {
486 if (codec_observer_) {
487 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
488 "%s: already added", __FUNCTION__);
489 return -1;
490 }
491 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
492 "%s: observer added", __FUNCTION__);
493 codec_observer_ = observer;
494 } else {
495 if (!codec_observer_) {
496 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
497 "%s: no observer added", __FUNCTION__);
498 return -1;
499 }
500 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
501 "%s: observer removed", __FUNCTION__);
502 codec_observer_ = NULL;
503 }
504 return 0;
505}
506
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000507int32_t ViEChannel::RegisterExternalDecoder(const uint8_t pl_type,
508 VideoDecoder* decoder,
509 bool buffered_rendering,
510 int32_t render_delay) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000511 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
512 "%s", __FUNCTION__);
513
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000514 int32_t result;
pbos@webrtc.org208a6482013-04-09 00:34:42 +0000515 result = vcm_.RegisterExternalDecoder(decoder, pl_type, buffered_rendering);
516 if (result != VCM_OK) {
517 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
518 "%s: Could not register external decoder with VCM.",
519 __FUNCTION__);
520 return result;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000521 }
pbos@webrtc.org208a6482013-04-09 00:34:42 +0000522 return vcm_.SetRenderDelay(render_delay);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000523}
524
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000525int32_t ViEChannel::DeRegisterExternalDecoder(
526 const uint8_t pl_type) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000527 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
528 "%s pl_type", __FUNCTION__, pl_type);
529
530 VideoCodec current_receive_codec;
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000531 int32_t result = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000532 result = vcm_.ReceiveCodec(&current_receive_codec);
533 if (vcm_.RegisterExternalDecoder(NULL, pl_type, false) != VCM_OK) {
534 return -1;
535 }
536
537 if (result == 0 && current_receive_codec.plType == pl_type) {
538 result = vcm_.RegisterReceiveCodec(&current_receive_codec, number_of_cores_,
539 wait_for_key_frame_);
540 }
541 return result;
542}
543
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000544int32_t ViEChannel::ReceiveCodecStatistics(
545 uint32_t* num_key_frames, uint32_t* num_delta_frames) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000546 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
547 "%s", __FUNCTION__);
548
549 VCMFrameCount received_frames;
550 if (vcm_.ReceivedFrameCount(received_frames) != VCM_OK) {
551 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
552 "%s: Could not get received frame information", __FUNCTION__);
553 return -1;
554 }
555 *num_key_frames = received_frames.numKeyFrames;
556 *num_delta_frames = received_frames.numDeltaFrames;
557 return 0;
558}
559
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000560uint32_t ViEChannel::DiscardedPackets() const {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000561 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
562 __FUNCTION__);
563 return vcm_.DiscardedPackets();
564}
565
mflodman@webrtc.orgf314c802012-12-14 14:02:10 +0000566int ViEChannel::ReceiveDelay() const {
567 return vcm_.Delay();
568}
569
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000570int32_t ViEChannel::WaitForKeyFrame(bool wait) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000571 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
572 "%s(wait: %d)", __FUNCTION__, wait);
573 wait_for_key_frame_ = wait;
574 return 0;
575}
576
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000577int32_t ViEChannel::SetSignalPacketLossStatus(bool enable,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000578 bool only_key_frames) {
579 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
580 "%s(enable: %d)", __FUNCTION__, enable);
581 if (enable) {
582 if (only_key_frames) {
583 vcm_.SetVideoProtection(kProtectionKeyOnLoss, false);
584 if (vcm_.SetVideoProtection(kProtectionKeyOnKeyLoss, true) != VCM_OK) {
585 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
586 "%s failed %d", __FUNCTION__, enable);
587 return -1;
588 }
589 } else {
590 vcm_.SetVideoProtection(kProtectionKeyOnKeyLoss, false);
591 if (vcm_.SetVideoProtection(kProtectionKeyOnLoss, true) != VCM_OK) {
592 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
593 "%s failed %d", __FUNCTION__, enable);
594 return -1;
595 }
596 }
597 } else {
598 vcm_.SetVideoProtection(kProtectionKeyOnLoss, false);
599 vcm_.SetVideoProtection(kProtectionKeyOnKeyLoss, false);
600 }
601 return 0;
602}
603
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000604int32_t ViEChannel::SetRTCPMode(const RTCPMethod rtcp_mode) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000605 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
606 "%s: %d", __FUNCTION__, rtcp_mode);
607
608 CriticalSectionScoped cs(rtp_rtcp_cs_.get());
609 for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
610 it != simulcast_rtp_rtcp_.end();
611 it++) {
612 RtpRtcp* rtp_rtcp = *it;
613 rtp_rtcp->SetRTCPStatus(rtcp_mode);
614 }
615 return rtp_rtcp_->SetRTCPStatus(rtcp_mode);
616}
617
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000618int32_t ViEChannel::GetRTCPMode(RTCPMethod* rtcp_mode) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000619 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
620 "%s", __FUNCTION__);
621 *rtcp_mode = rtp_rtcp_->RTCP();
622 return 0;
623}
624
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000625int32_t ViEChannel::SetNACKStatus(const bool enable) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000626 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
627 "%s(enable: %d)", __FUNCTION__, enable);
628
629 // Update the decoding VCM.
630 if (vcm_.SetVideoProtection(kProtectionNack, enable) != VCM_OK) {
631 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
632 "%s: Could not set VCM NACK protection: %d", __FUNCTION__,
633 enable);
634 return -1;
635 }
636 if (enable) {
637 // Disable possible FEC.
638 SetFECStatus(false, 0, 0);
639 }
640 // Update the decoding VCM.
641 if (vcm_.SetVideoProtection(kProtectionNack, enable) != VCM_OK) {
642 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
643 "%s: Could not set VCM NACK protection: %d", __FUNCTION__,
644 enable);
645 return -1;
646 }
647 return ProcessNACKRequest(enable);
648}
649
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000650int32_t ViEChannel::ProcessNACKRequest(const bool enable) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000651 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
652 "%s(enable: %d)", __FUNCTION__, enable);
653
654 if (enable) {
655 // Turn on NACK.
656 NACKMethod nackMethod = kNackRtcp;
657 if (rtp_rtcp_->RTCP() == kRtcpOff) {
658 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
659 "%s: Could not enable NACK, RTPC not on ", __FUNCTION__);
660 return -1;
661 }
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000662 if (rtp_rtcp_->SetNACKStatus(nackMethod,
663 max_nack_reordering_threshold_) != 0) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000664 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
665 "%s: Could not set NACK method %d", __FUNCTION__,
666 nackMethod);
667 return -1;
668 }
669 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
670 "%s: Using NACK method %d", __FUNCTION__, nackMethod);
mikhal@webrtc.org16196642013-02-01 19:33:21 +0000671 rtp_rtcp_->SetStorePacketsStatus(true, nack_history_size_sender_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000672
673 vcm_.RegisterPacketRequestCallback(this);
674
675 CriticalSectionScoped cs(rtp_rtcp_cs_.get());
676
677 for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
678 it != simulcast_rtp_rtcp_.end();
679 it++) {
680 RtpRtcp* rtp_rtcp = *it;
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000681 rtp_rtcp->SetNACKStatus(nackMethod, max_nack_reordering_threshold_);
mikhal@webrtc.org16196642013-02-01 19:33:21 +0000682 rtp_rtcp->SetStorePacketsStatus(true, nack_history_size_sender_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000683 }
684 } else {
685 CriticalSectionScoped cs(rtp_rtcp_cs_.get());
686 for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
687 it != simulcast_rtp_rtcp_.end();
688 it++) {
689 RtpRtcp* rtp_rtcp = *it;
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +0000690 if (paced_sender_ == NULL) {
691 rtp_rtcp->SetStorePacketsStatus(false, 0);
692 }
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000693 rtp_rtcp->SetNACKStatus(kNackOff, max_nack_reordering_threshold_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000694 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000695 vcm_.RegisterPacketRequestCallback(NULL);
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +0000696 if (paced_sender_ == NULL) {
697 rtp_rtcp_->SetStorePacketsStatus(false, 0);
698 }
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000699 if (rtp_rtcp_->SetNACKStatus(kNackOff,
700 max_nack_reordering_threshold_) != 0) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000701 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
702 "%s: Could not turn off NACK", __FUNCTION__);
703 return -1;
704 }
705 }
706 return 0;
707}
708
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000709int32_t ViEChannel::SetFECStatus(const bool enable,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000710 const unsigned char payload_typeRED,
711 const unsigned char payload_typeFEC) {
712 // Disable possible NACK.
713 if (enable) {
714 SetNACKStatus(false);
715 }
716
717 return ProcessFECRequest(enable, payload_typeRED, payload_typeFEC);
718}
719
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000720int32_t ViEChannel::ProcessFECRequest(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000721 const bool enable,
722 const unsigned char payload_typeRED,
723 const unsigned char payload_typeFEC) {
724 WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(engine_id_, channel_id_),
725 "%s(enable: %d, payload_typeRED: %u, payload_typeFEC: %u)",
726 __FUNCTION__, enable, payload_typeRED, payload_typeFEC);
727
728 if (rtp_rtcp_->SetGenericFECStatus(enable, payload_typeRED,
729 payload_typeFEC) != 0) {
730 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
731 "%s: Could not change FEC status to %d", __FUNCTION__,
732 enable);
733 return -1;
734 }
735 CriticalSectionScoped cs(rtp_rtcp_cs_.get());
736 for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
737 it != simulcast_rtp_rtcp_.end();
738 it++) {
739 RtpRtcp* rtp_rtcp = *it;
740 rtp_rtcp->SetGenericFECStatus(enable, payload_typeRED, payload_typeFEC);
741 }
742 return 0;
743}
744
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000745int32_t ViEChannel::SetHybridNACKFECStatus(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000746 const bool enable,
747 const unsigned char payload_typeRED,
748 const unsigned char payload_typeFEC) {
749 // Update the decoding VCM with hybrid mode.
750 if (vcm_.SetVideoProtection(kProtectionNackFEC, enable) != VCM_OK) {
751 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
752 "%s: Could not set VCM NACK protection: %d", __FUNCTION__,
753 enable);
754 return -1;
755 }
756
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000757 int32_t ret_val = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000758 ret_val = ProcessNACKRequest(enable);
759 if (ret_val < 0) {
760 return ret_val;
761 }
762 return ProcessFECRequest(enable, payload_typeRED, payload_typeFEC);
763}
764
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000765int ViEChannel::SetSenderBufferingMode(int target_delay_ms) {
mikhal@webrtc.org16196642013-02-01 19:33:21 +0000766 if ((target_delay_ms < 0) || (target_delay_ms > kMaxTargetDelayMs)) {
767 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000768 "%s: Target sender buffering delay out of bounds: %d",
769 __FUNCTION__, target_delay_ms);
mikhal@webrtc.org16196642013-02-01 19:33:21 +0000770 return -1;
771 }
772 if (target_delay_ms == 0) {
773 // Real-time mode.
774 nack_history_size_sender_ = kSendSidePacketHistorySize;
mikhal@webrtc.org16196642013-02-01 19:33:21 +0000775 } else {
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000776 nack_history_size_sender_ = GetRequiredNackListSize(target_delay_ms);
mikhal@webrtc.org16196642013-02-01 19:33:21 +0000777 // Don't allow a number lower than the default value.
778 if (nack_history_size_sender_ < kSendSidePacketHistorySize) {
779 nack_history_size_sender_ = kSendSidePacketHistorySize;
780 }
mikhal@webrtc.org16196642013-02-01 19:33:21 +0000781 }
782 // Setting nack_history_size_.
783 // First disabling (forcing free) and then resetting to desired value.
784 if (rtp_rtcp_->SetStorePacketsStatus(false, 0) != 0) {
785 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
786 "%s:SetStorePacketsStatus failure", __FUNCTION__);
787 return -1;
788 }
789 if (rtp_rtcp_->SetStorePacketsStatus(true, nack_history_size_sender_) != 0) {
790 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
791 "%s:SetStorePacketsStatus failure", __FUNCTION__);
792 return -1;
793 }
794 return 0;
795}
796
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000797int ViEChannel::SetReceiverBufferingMode(int target_delay_ms) {
798 if ((target_delay_ms < 0) || (target_delay_ms > kMaxTargetDelayMs)) {
799 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
800 "%s: Target receiver buffering delay out of bounds: %d",
801 __FUNCTION__, target_delay_ms);
802 return -1;
803 }
804 int max_nack_list_size;
stefan@webrtc.org06ad3842013-05-07 19:16:33 +0000805 int max_incomplete_time_ms;
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000806 if (target_delay_ms == 0) {
807 // Real-time mode - restore default settings.
808 max_nack_reordering_threshold_ = kMaxPacketAgeToNack;
809 max_nack_list_size = kMaxNackListSize;
stefan@webrtc.org06ad3842013-05-07 19:16:33 +0000810 max_incomplete_time_ms = 0;
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000811 } else {
mikhal@webrtc.org08998cd2013-02-19 19:42:35 +0000812 max_nack_list_size = 3 * GetRequiredNackListSize(target_delay_ms) / 4;
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000813 max_nack_reordering_threshold_ = max_nack_list_size;
stefan@webrtc.org06ad3842013-05-07 19:16:33 +0000814 // Calculate the max incomplete time and round to int.
815 max_incomplete_time_ms = static_cast<int>(kMaxIncompleteTimeMultiplier *
816 target_delay_ms + 0.5f);
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000817 }
stefan@webrtc.org06ad3842013-05-07 19:16:33 +0000818 vcm_.SetNackSettings(max_nack_list_size, max_nack_reordering_threshold_,
819 max_incomplete_time_ms);
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000820 vcm_.SetMinReceiverDelay(target_delay_ms);
mikhal@webrtc.org78e450f2013-03-06 23:29:33 +0000821 if (vie_sync_.SetTargetBufferingDelay(target_delay_ms) < 0)
822 return -1;
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000823 return 0;
824}
825
826int ViEChannel::GetRequiredNackListSize(int target_delay_ms) {
827 // The max size of the nack list should be large enough to accommodate the
828 // the number of packets (frames) resulting from the increased delay.
mikhal@webrtc.orgb793abe2013-03-13 20:52:49 +0000829 // Roughly estimating for ~40 packets per frame @ 30fps.
830 return target_delay_ms * 40 * 30 / 1000;
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000831}
832
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000833int32_t ViEChannel::SetKeyFrameRequestMethod(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000834 const KeyFrameRequestMethod method) {
835 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
836 "%s: %d", __FUNCTION__, method);
837 return rtp_rtcp_->SetKeyFrameRequestMethod(method);
838}
839
840bool ViEChannel::EnableRemb(bool enable) {
841 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
842 "ViEChannel::EnableRemb: %d", enable);
843 if (rtp_rtcp_->SetREMBStatus(enable) != 0)
844 return false;
845 return true;
846}
847
848int ViEChannel::SetSendTimestampOffsetStatus(bool enable, int id) {
849 CriticalSectionScoped cs(rtp_rtcp_cs_.get());
850 int error = 0;
851 if (enable) {
852 // Enable the extension, but disable possible old id to avoid errors.
853 send_timestamp_extension_id_ = id;
854 rtp_rtcp_->DeregisterSendRtpHeaderExtension(
855 kRtpExtensionTransmissionTimeOffset);
856 error = rtp_rtcp_->RegisterSendRtpHeaderExtension(
857 kRtpExtensionTransmissionTimeOffset, id);
858 for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
859 it != simulcast_rtp_rtcp_.end(); it++) {
860 (*it)->DeregisterSendRtpHeaderExtension(
861 kRtpExtensionTransmissionTimeOffset);
862 error |= (*it)->RegisterSendRtpHeaderExtension(
863 kRtpExtensionTransmissionTimeOffset, id);
864 }
865 } else {
866 // Disable the extension.
867 send_timestamp_extension_id_ = kInvalidRtpExtensionId;
868 rtp_rtcp_->DeregisterSendRtpHeaderExtension(
869 kRtpExtensionTransmissionTimeOffset);
870 for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
871 it != simulcast_rtp_rtcp_.end(); it++) {
872 (*it)->DeregisterSendRtpHeaderExtension(
873 kRtpExtensionTransmissionTimeOffset);
874 }
875 }
876 return error;
877}
878
879int ViEChannel::SetReceiveTimestampOffsetStatus(bool enable, int id) {
stefan@webrtc.org4e5f9832013-05-29 13:28:21 +0000880 return vie_receiver_.SetReceiveTimestampOffsetStatus(enable, id) ? 0 : -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000881}
882
solenberg@webrtc.org453f9c02013-05-20 12:00:23 +0000883int ViEChannel::SetSendAbsoluteSendTimeStatus(bool enable, int id) {
884 CriticalSectionScoped cs(rtp_rtcp_cs_.get());
885 int error = 0;
886 if (enable) {
887 // Enable the extension, but disable possible old id to avoid errors.
888 absolute_send_time_extension_id_ = id;
889 rtp_rtcp_->DeregisterSendRtpHeaderExtension(
890 kRtpExtensionAbsoluteSendTime);
891 error = rtp_rtcp_->RegisterSendRtpHeaderExtension(
892 kRtpExtensionAbsoluteSendTime, id);
893 for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
894 it != simulcast_rtp_rtcp_.end(); it++) {
895 (*it)->DeregisterSendRtpHeaderExtension(
896 kRtpExtensionAbsoluteSendTime);
897 error |= (*it)->RegisterSendRtpHeaderExtension(
898 kRtpExtensionAbsoluteSendTime, id);
899 }
900 } else {
901 // Disable the extension.
902 absolute_send_time_extension_id_ = kInvalidRtpExtensionId;
903 rtp_rtcp_->DeregisterSendRtpHeaderExtension(
904 kRtpExtensionAbsoluteSendTime);
905 for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
906 it != simulcast_rtp_rtcp_.end(); it++) {
907 (*it)->DeregisterSendRtpHeaderExtension(
908 kRtpExtensionAbsoluteSendTime);
909 }
910 }
911 return error;
912}
913
914int ViEChannel::SetReceiveAbsoluteSendTimeStatus(bool enable, int id) {
solenberg@webrtc.orgf40e9b62013-05-27 16:02:56 +0000915 receive_absolute_send_time_enabled_ = enable;
stefan@webrtc.org4e5f9832013-05-29 13:28:21 +0000916 return vie_receiver_.SetReceiveAbsoluteSendTimeStatus(enable, id) ? 0 : -1;
solenberg@webrtc.orgf40e9b62013-05-27 16:02:56 +0000917}
918
919bool ViEChannel::GetReceiveAbsoluteSendTimeStatus() const {
920 return receive_absolute_send_time_enabled_;
solenberg@webrtc.org453f9c02013-05-20 12:00:23 +0000921}
922
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000923void ViEChannel::SetTransmissionSmoothingStatus(bool enable) {
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +0000924 assert(paced_sender_ && "No paced sender registered.");
925 paced_sender_->SetStatus(enable);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000926}
927
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000928int32_t ViEChannel::EnableTMMBR(const bool enable) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000929 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
930 "%s: %d", __FUNCTION__, enable);
931 return rtp_rtcp_->SetTMMBRStatus(enable);
932}
933
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000934int32_t ViEChannel::EnableKeyFrameRequestCallback(const bool enable) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000935 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
936 "%s: %d", __FUNCTION__, enable);
937
938 CriticalSectionScoped cs(callback_cs_.get());
939 if (enable && !codec_observer_) {
940 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
941 "%s: No ViECodecObserver set", __FUNCTION__, enable);
942 return -1;
943 }
944 do_key_frame_callbackRequest_ = enable;
945 return 0;
946}
947
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000948int32_t ViEChannel::SetSSRC(const uint32_t SSRC,
stefan@webrtc.org695ff2a2013-06-04 09:36:56 +0000949 const StreamType usage,
950 const uint8_t simulcast_idx) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000951 WEBRTC_TRACE(webrtc::kTraceInfo,
952 webrtc::kTraceVideo,
953 ViEId(engine_id_, channel_id_),
954 "%s(usage:%d, SSRC: 0x%x, idx:%u)",
955 __FUNCTION__, usage, SSRC, simulcast_idx);
956 if (simulcast_idx == 0) {
stefan@webrtc.orgeef4fd52013-05-23 13:48:22 +0000957 if (usage == kViEStreamTypeRtx) {
958 return rtp_rtcp_->SetRTXSendStatus(kRtxRetransmitted, true, SSRC);
959 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000960 return rtp_rtcp_->SetSSRC(SSRC);
961 }
962 CriticalSectionScoped cs(rtp_rtcp_cs_.get());
963 if (simulcast_idx > simulcast_rtp_rtcp_.size()) {
964 return -1;
965 }
966 std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
967 for (int i = 1; i < simulcast_idx; ++i, ++it) {
968 if (it == simulcast_rtp_rtcp_.end()) {
969 return -1;
970 }
971 }
stefan@webrtc.org54b6ebc2013-05-29 14:07:54 +0000972 RtpRtcp* rtp_rtcp_module = *it;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000973 if (usage == kViEStreamTypeRtx) {
stefan@webrtc.org54b6ebc2013-05-29 14:07:54 +0000974 return rtp_rtcp_module->SetRTXSendStatus(kRtxRetransmitted, true, SSRC);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000975 }
stefan@webrtc.org54b6ebc2013-05-29 14:07:54 +0000976 return rtp_rtcp_module->SetSSRC(SSRC);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000977}
978
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000979int32_t ViEChannel::SetRemoteSSRCType(const StreamType usage,
stefan@webrtc.org695ff2a2013-06-04 09:36:56 +0000980 const uint32_t SSRC) const {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000981 WEBRTC_TRACE(webrtc::kTraceInfo,
982 webrtc::kTraceVideo,
983 ViEId(engine_id_, channel_id_),
984 "%s(usage:%d, SSRC: 0x%x)",
985 __FUNCTION__, usage, SSRC);
986
987 return rtp_rtcp_->SetRTXReceiveStatus(true, SSRC);
988}
989
mflodman@webrtc.orgb6d9cfc2012-10-25 11:30:29 +0000990// TODO(mflodman) Add kViEStreamTypeRtx.
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000991int32_t ViEChannel::GetLocalSSRC(uint8_t idx, unsigned int* ssrc) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000992 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
993 "%s", __FUNCTION__);
mflodman@webrtc.orgb6d9cfc2012-10-25 11:30:29 +0000994
995 if (idx == 0) {
996 *ssrc = rtp_rtcp_->SSRC();
997 return 0;
998 }
999 CriticalSectionScoped cs(rtp_rtcp_cs_.get());
1000 if (idx > simulcast_rtp_rtcp_.size()) {
1001 return -1;
1002 }
1003 std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
1004 for (int i = 1; i < idx; ++i, ++it) {
1005 if (it == simulcast_rtp_rtcp_.end()) {
1006 return -1;
1007 }
1008 }
1009 *ssrc = (*it)->SSRC();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001010 return 0;
1011}
1012
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001013int32_t ViEChannel::GetRemoteSSRC(uint32_t* ssrc) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001014 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1015 __FUNCTION__);
1016
1017 *ssrc = rtp_rtcp_->RemoteSSRC();
1018 return 0;
1019}
1020
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001021int32_t ViEChannel::GetRemoteCSRC(uint32_t CSRCs[kRtpCsrcSize]) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001022 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1023 __FUNCTION__);
1024
1025 uint32_t arrayCSRC[kRtpCsrcSize];
1026 memset(arrayCSRC, 0, sizeof(arrayCSRC));
1027
1028 int num_csrcs = rtp_rtcp_->RemoteCSRCs(arrayCSRC);
1029 if (num_csrcs > 0) {
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001030 memcpy(CSRCs, arrayCSRC, num_csrcs * sizeof(uint32_t));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001031 for (int idx = 0; idx < num_csrcs; idx++) {
1032 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1033 "\tCSRC[%d] = %lu", idx, CSRCs[idx]);
1034 }
1035 } else {
1036 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1037 "%s: CSRC list is empty", __FUNCTION__);
1038 }
1039 return 0;
1040}
1041
mflodman@webrtc.org7bc7e022013-04-12 14:55:46 +00001042int ViEChannel::SetRtxSendPayloadType(int payload_type) {
1043 if (rtp_rtcp_->Sending()) {
1044 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1045 "%s: already sending", __FUNCTION__);
1046 return -1;
1047 }
1048 rtp_rtcp_->SetRtxSendPayloadType(payload_type);
1049 CriticalSectionScoped cs(rtp_rtcp_cs_.get());
1050 for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
1051 it != simulcast_rtp_rtcp_.end(); it++) {
1052 (*it)->SetRtxSendPayloadType(payload_type);
1053 }
1054 return 0;
1055}
1056
1057void ViEChannel::SetRtxReceivePayloadType(int payload_type) {
1058 rtp_rtcp_->SetRtxReceivePayloadType(payload_type);
1059 CriticalSectionScoped cs(rtp_rtcp_cs_.get());
1060 for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
1061 it != simulcast_rtp_rtcp_.end(); it++) {
1062 (*it)->SetRtxReceivePayloadType(payload_type);
1063 }
1064}
1065
1066int32_t ViEChannel::SetStartSequenceNumber(uint16_t sequence_number) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001067 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1068 __FUNCTION__);
1069
1070 if (rtp_rtcp_->Sending()) {
1071 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1072 "%s: already sending", __FUNCTION__);
1073 return -1;
1074 }
1075 return rtp_rtcp_->SetSequenceNumber(sequence_number);
1076}
1077
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001078int32_t ViEChannel::SetRTCPCName(const char rtcp_cname[]) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001079 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1080 "%s", __FUNCTION__);
1081 if (rtp_rtcp_->Sending()) {
1082 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1083 "%s: already sending", __FUNCTION__);
1084 return -1;
1085 }
1086 return rtp_rtcp_->SetCNAME(rtcp_cname);
1087}
1088
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001089int32_t ViEChannel::GetRTCPCName(char rtcp_cname[]) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001090 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1091 "%s", __FUNCTION__);
1092 return rtp_rtcp_->CNAME(rtcp_cname);
1093}
1094
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001095int32_t ViEChannel::GetRemoteRTCPCName(char rtcp_cname[]) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001096 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1097 __FUNCTION__);
1098
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001099 uint32_t remoteSSRC = rtp_rtcp_->RemoteSSRC();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001100 return rtp_rtcp_->RemoteCNAME(remoteSSRC, rtcp_cname);
1101}
1102
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001103int32_t ViEChannel::RegisterRtpObserver(ViERTPObserver* observer) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001104 CriticalSectionScoped cs(callback_cs_.get());
1105 if (observer) {
1106 if (rtp_observer_) {
1107 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1108 "%s: observer alread added", __FUNCTION__);
1109 return -1;
1110 }
1111 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1112 "%s: observer added", __FUNCTION__);
1113 rtp_observer_ = observer;
1114 } else {
1115 if (!rtp_observer_) {
1116 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1117 "%s: no observer added", __FUNCTION__);
1118 return -1;
1119 }
1120 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1121 "%s: observer removed", __FUNCTION__);
1122 rtp_observer_ = NULL;
1123 }
1124 return 0;
1125}
1126
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001127int32_t ViEChannel::RegisterRtcpObserver(ViERTCPObserver* observer) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001128 CriticalSectionScoped cs(callback_cs_.get());
1129 if (observer) {
1130 if (rtcp_observer_) {
1131 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1132 "%s: observer alread added", __FUNCTION__);
1133 return -1;
1134 }
1135 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1136 "%s: observer added", __FUNCTION__);
1137 rtcp_observer_ = observer;
1138 } else {
1139 if (!rtcp_observer_) {
1140 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1141 "%s: no observer added", __FUNCTION__);
1142 return -1;
1143 }
1144 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1145 "%s: observer removed", __FUNCTION__);
1146 rtcp_observer_ = NULL;
1147 }
1148 return 0;
1149}
1150
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001151int32_t ViEChannel::SendApplicationDefinedRTCPPacket(
1152 const uint8_t sub_type,
1153 uint32_t name,
1154 const uint8_t* data,
1155 uint16_t data_length_in_bytes) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001156 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1157 __FUNCTION__);
1158 if (!rtp_rtcp_->Sending()) {
1159 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1160 "%s: not sending", __FUNCTION__);
1161 return -1;
1162 }
1163 if (!data) {
1164 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1165 "%s: no input argument", __FUNCTION__);
1166 return -1;
1167 }
1168 if (data_length_in_bytes % 4 != 0) {
1169 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1170 "%s: input length error", __FUNCTION__);
1171 return -1;
1172 }
1173 RTCPMethod rtcp_method = rtp_rtcp_->RTCP();
1174 if (rtcp_method == kRtcpOff) {
1175 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1176 "%s: RTCP not enabled", __FUNCTION__);
1177 return -1;
1178 }
1179 // Create and send packet.
1180 if (rtp_rtcp_->SetRTCPApplicationSpecificData(sub_type, name, data,
1181 data_length_in_bytes) != 0) {
1182 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1183 "%s: Could not send RTCP application data", __FUNCTION__);
1184 return -1;
1185 }
1186 return 0;
1187}
1188
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001189int32_t ViEChannel::GetSendRtcpStatistics(uint16_t* fraction_lost,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001190 uint32_t* cumulative_lost,
1191 uint32_t* extended_max,
1192 uint32_t* jitter_samples,
1193 int32_t* rtt_ms) {
1194 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1195 __FUNCTION__);
1196
1197 // TODO(pwestin) how do we do this for simulcast ? average for all
1198 // except cumulative_lost that is the sum ?
1199 // CriticalSectionScoped cs(rtp_rtcp_cs_.get());
1200
1201 // for (std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
1202 // it != simulcast_rtp_rtcp_.end();
1203 // it++) {
1204 // RtpRtcp* rtp_rtcp = *it;
1205 // }
1206 uint32_t remote_ssrc = rtp_rtcp_->RemoteSSRC();
1207
1208 // Get all RTCP receiver report blocks that have been received on this
1209 // channel. If we receive RTP packets from a remote source we know the
1210 // remote SSRC and use the report block from him.
1211 // Otherwise use the first report block.
1212 std::vector<RTCPReportBlock> remote_stats;
1213 if (rtp_rtcp_->RemoteRTCPStat(&remote_stats) != 0 || remote_stats.empty()) {
1214 WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
1215 "%s: Could not get remote stats", __FUNCTION__);
1216 return -1;
1217 }
1218 std::vector<RTCPReportBlock>::const_iterator statistics =
1219 remote_stats.begin();
1220 for (; statistics != remote_stats.end(); ++statistics) {
1221 if (statistics->remoteSSRC == remote_ssrc)
1222 break;
1223 }
1224
1225 if (statistics == remote_stats.end()) {
1226 // If we have not received any RTCP packets from this SSRC it probably means
1227 // we have not received any RTP packets.
1228 // Use the first received report block instead.
1229 statistics = remote_stats.begin();
1230 remote_ssrc = statistics->remoteSSRC;
1231 }
1232
1233 *fraction_lost = statistics->fractionLost;
1234 *cumulative_lost = statistics->cumulativeLost;
1235 *extended_max = statistics->extendedHighSeqNum;
1236 *jitter_samples = statistics->jitter;
1237
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001238 uint16_t dummy;
1239 uint16_t rtt = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001240 if (rtp_rtcp_->RTT(remote_ssrc, &rtt, &dummy, &dummy, &dummy) != 0) {
1241 WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
1242 "%s: Could not get RTT", __FUNCTION__);
1243 return -1;
1244 }
1245 *rtt_ms = rtt;
1246 return 0;
1247}
1248
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001249int32_t ViEChannel::GetReceivedRtcpStatistics(uint16_t* fraction_lost,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001250 uint32_t* cumulative_lost,
1251 uint32_t* extended_max,
1252 uint32_t* jitter_samples,
1253 int32_t* rtt_ms) {
1254 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1255 "%s", __FUNCTION__);
1256
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001257 uint8_t frac_lost = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001258 if (rtp_rtcp_->StatisticsRTP(&frac_lost, cumulative_lost, extended_max,
1259 jitter_samples) != 0) {
1260 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1261 "%s: Could not get received RTP statistics", __FUNCTION__);
1262 return -1;
1263 }
1264 *fraction_lost = frac_lost;
1265
1266 uint32_t remote_ssrc = rtp_rtcp_->RemoteSSRC();
1267 uint16_t dummy = 0;
1268 uint16_t rtt = 0;
1269 if (rtp_rtcp_->RTT(remote_ssrc, &rtt, &dummy, &dummy, &dummy) != 0) {
1270 WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1271 "%s: Could not get RTT", __FUNCTION__);
1272 }
1273 *rtt_ms = rtt;
1274 return 0;
1275}
1276
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001277int32_t ViEChannel::GetRtpStatistics(uint32_t* bytes_sent,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001278 uint32_t* packets_sent,
1279 uint32_t* bytes_received,
1280 uint32_t* packets_received) const {
1281 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1282 __FUNCTION__);
1283
1284 if (rtp_rtcp_->DataCountersRTP(bytes_sent,
1285 packets_sent,
1286 bytes_received,
1287 packets_received) != 0) {
1288 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1289 "%s: Could not get counters", __FUNCTION__);
1290 return -1;
1291 }
1292 CriticalSectionScoped cs(rtp_rtcp_cs_.get());
1293 for (std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
1294 it != simulcast_rtp_rtcp_.end();
1295 it++) {
1296 uint32_t bytes_sent_temp = 0;
1297 uint32_t packets_sent_temp = 0;
1298 RtpRtcp* rtp_rtcp = *it;
1299 rtp_rtcp->DataCountersRTP(&bytes_sent_temp, &packets_sent_temp, NULL, NULL);
1300 bytes_sent += bytes_sent_temp;
1301 packets_sent += packets_sent_temp;
1302 }
1303 return 0;
1304}
1305
1306void ViEChannel::GetBandwidthUsage(uint32_t* total_bitrate_sent,
1307 uint32_t* video_bitrate_sent,
1308 uint32_t* fec_bitrate_sent,
1309 uint32_t* nackBitrateSent) const {
1310 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1311 __FUNCTION__);
1312
1313 rtp_rtcp_->BitrateSent(total_bitrate_sent, video_bitrate_sent,
1314 fec_bitrate_sent, nackBitrateSent);
1315 CriticalSectionScoped cs(rtp_rtcp_cs_.get());
1316 for (std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
1317 it != simulcast_rtp_rtcp_.end(); it++) {
1318 uint32_t stream_rate = 0;
1319 uint32_t video_rate = 0;
1320 uint32_t fec_rate = 0;
1321 uint32_t nackRate = 0;
1322 RtpRtcp* rtp_rtcp = *it;
1323 rtp_rtcp->BitrateSent(&stream_rate, &video_rate, &fec_rate, &nackRate);
1324 *total_bitrate_sent += stream_rate;
1325 *fec_bitrate_sent += fec_rate;
1326 *nackBitrateSent += nackRate;
1327 }
1328}
1329
mflodman@webrtc.orgcd1ac8b2013-02-06 17:46:39 +00001330void ViEChannel::GetEstimatedReceiveBandwidth(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001331 uint32_t* estimated_bandwidth) const {
mflodman@webrtc.orgcd1ac8b2013-02-06 17:46:39 +00001332 vie_receiver_.EstimatedReceiveBandwidth(estimated_bandwidth);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001333}
1334
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001335int32_t ViEChannel::StartRTPDump(const char file_nameUTF8[1024],
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001336 RTPDirections direction) {
1337 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1338 __FUNCTION__);
1339
1340 if (direction != kRtpIncoming && direction != kRtpOutgoing) {
1341 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1342 "%s: invalid input", __FUNCTION__);
1343 return -1;
1344 }
1345
1346 if (direction == kRtpIncoming) {
1347 return vie_receiver_.StartRTPDump(file_nameUTF8);
1348 } else {
1349 return vie_sender_.StartRTPDump(file_nameUTF8);
1350 }
1351}
1352
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001353int32_t ViEChannel::StopRTPDump(RTPDirections direction) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001354 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1355 "%s", __FUNCTION__);
1356
1357 if (direction != kRtpIncoming && direction != kRtpOutgoing) {
1358 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1359 "%s: invalid input", __FUNCTION__);
1360 return -1;
1361 }
1362
1363 if (direction == kRtpIncoming) {
1364 return vie_receiver_.StopRTPDump();
1365 } else {
1366 return vie_sender_.StopRTPDump();
1367 }
1368}
1369
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001370int32_t ViEChannel::StartSend() {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001371 CriticalSectionScoped cs(callback_cs_.get());
1372 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1373 "%s", __FUNCTION__);
1374
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +00001375 if (!external_transport_) {
pwestin@webrtc.org065b64d2013-04-02 20:37:14 +00001376 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1377 "%s: send sockets not initialized", __FUNCTION__);
1378 return -1;
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +00001379 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001380 rtp_rtcp_->SetSendingMediaStatus(true);
1381
1382 if (rtp_rtcp_->Sending()) {
1383 // Already sending.
1384 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1385 "%s: Already sending", __FUNCTION__);
1386 return kViEBaseAlreadySending;
1387 }
1388 if (rtp_rtcp_->SetSendingStatus(true) != 0) {
1389 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1390 "%s: Could not start sending RTP", __FUNCTION__);
1391 return -1;
1392 }
1393 CriticalSectionScoped cs_rtp(rtp_rtcp_cs_.get());
1394 for (std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
1395 it != simulcast_rtp_rtcp_.end();
1396 it++) {
1397 RtpRtcp* rtp_rtcp = *it;
1398 rtp_rtcp->SetSendingMediaStatus(true);
1399 rtp_rtcp->SetSendingStatus(true);
1400 }
1401 return 0;
1402}
1403
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001404int32_t ViEChannel::StopSend() {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001405 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1406 __FUNCTION__);
1407
1408 CriticalSectionScoped cs(rtp_rtcp_cs_.get());
1409 rtp_rtcp_->SetSendingMediaStatus(false);
1410 for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
1411 it != simulcast_rtp_rtcp_.end();
1412 it++) {
1413 RtpRtcp* rtp_rtcp = *it;
1414 rtp_rtcp->SetSendingMediaStatus(false);
1415 }
1416 if (!rtp_rtcp_->Sending()) {
1417 WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
1418 "%s: Not sending", __FUNCTION__);
1419 return kViEBaseNotSending;
1420 }
1421
1422 // Reset.
1423 rtp_rtcp_->ResetSendDataCountersRTP();
1424 if (rtp_rtcp_->SetSendingStatus(false) != 0) {
1425 WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
1426 "%s: could not stop RTP sending", __FUNCTION__);
1427 return -1;
1428 }
1429 for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
1430 it != simulcast_rtp_rtcp_.end();
1431 it++) {
1432 RtpRtcp* rtp_rtcp = *it;
1433 rtp_rtcp->ResetSendDataCountersRTP();
1434 rtp_rtcp->SetSendingStatus(false);
1435 }
1436 return 0;
1437}
1438
1439bool ViEChannel::Sending() {
1440 return rtp_rtcp_->Sending();
1441}
1442
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001443int32_t ViEChannel::StartReceive() {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001444 CriticalSectionScoped cs(callback_cs_.get());
1445 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1446 __FUNCTION__);
1447
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001448 if (StartDecodeThread() != 0) {
1449 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1450 "%s: could not start decoder thread", __FUNCTION__);
1451
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001452 vie_receiver_.StopReceive();
1453 return -1;
1454 }
1455 vie_receiver_.StartReceive();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001456 return 0;
1457}
1458
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001459int32_t ViEChannel::StopReceive() {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001460 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1461 __FUNCTION__);
1462
1463 vie_receiver_.StopReceive();
1464 StopDecodeThread();
1465 vcm_.ResetDecoder();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001466 return 0;
1467}
1468
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001469int32_t ViEChannel::RegisterSendTransport(Transport* transport) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001470 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1471 __FUNCTION__);
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +00001472
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +00001473 if (rtp_rtcp_->Sending()) {
1474 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1475 "%s: Sending", __FUNCTION__);
1476 return -1;
1477 }
1478
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001479 CriticalSectionScoped cs(callback_cs_.get());
1480 if (external_transport_) {
1481 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1482 "%s: transport already registered", __FUNCTION__);
1483 return -1;
1484 }
1485 external_transport_ = transport;
1486 vie_sender_.RegisterSendTransport(transport);
1487 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1488 "%s: Transport registered: 0x%p", __FUNCTION__,
1489 &external_transport_);
1490
1491 return 0;
1492}
1493
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001494int32_t ViEChannel::DeregisterSendTransport() {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001495 CriticalSectionScoped cs(callback_cs_.get());
1496 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1497 __FUNCTION__);
1498
1499 if (!external_transport_) {
1500 WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
1501 "%s: no transport registered", __FUNCTION__);
1502 return -1;
1503 }
1504 if (rtp_rtcp_->Sending()) {
1505 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1506 "%s: Sending", __FUNCTION__);
1507 return -1;
1508 }
1509 external_transport_ = NULL;
1510 vie_sender_.DeregisterSendTransport();
1511 return 0;
1512}
1513
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001514int32_t ViEChannel::ReceivedRTPPacket(
1515 const void* rtp_packet, const int32_t rtp_packet_length) {
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +00001516 {
1517 CriticalSectionScoped cs(callback_cs_.get());
1518 if (!external_transport_) {
1519 return -1;
1520 }
1521 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001522 return vie_receiver_.ReceivedRTPPacket(rtp_packet, rtp_packet_length);
1523}
1524
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001525int32_t ViEChannel::ReceivedRTCPPacket(
1526 const void* rtcp_packet, const int32_t rtcp_packet_length) {
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +00001527 {
1528 CriticalSectionScoped cs(callback_cs_.get());
1529 if (!external_transport_) {
1530 return -1;
1531 }
1532 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001533 return vie_receiver_.ReceivedRTCPPacket(rtcp_packet, rtcp_packet_length);
1534}
1535
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001536int32_t ViEChannel::SetMTU(uint16_t mtu) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001537 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1538 __FUNCTION__);
1539 if (rtp_rtcp_->SetMaxTransferUnit(mtu) != 0) {
1540 // Logging done.
1541 return -1;
1542 }
1543 CriticalSectionScoped cs(rtp_rtcp_cs_.get());
1544 for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
1545 it != simulcast_rtp_rtcp_.end();
1546 it++) {
1547 RtpRtcp* rtp_rtcp = *it;
1548 rtp_rtcp->SetMaxTransferUnit(mtu);
1549 }
1550 mtu_ = mtu;
1551 return 0;
1552}
1553
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001554uint16_t ViEChannel::MaxDataPayloadLength() const {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001555 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1556 "%s", __FUNCTION__);
1557 return rtp_rtcp_->MaxDataPayloadLength();
1558}
1559
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001560int32_t ViEChannel::SetPacketTimeoutNotification(
1561 bool enable, uint32_t timeout_seconds) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001562 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1563 __FUNCTION__);
1564 if (enable) {
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001565 uint32_t timeout_ms = 1000 * timeout_seconds;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001566 if (rtp_rtcp_->SetPacketTimeout(timeout_ms, 0) != 0) {
1567 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1568 "%s", __FUNCTION__);
1569 return -1;
1570 }
1571 } else {
1572 if (rtp_rtcp_->SetPacketTimeout(0, 0) != 0) {
1573 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1574 "%s", __FUNCTION__);
1575 return -1;
1576 }
1577 }
1578 return 0;
1579}
1580
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001581int32_t ViEChannel::RegisterNetworkObserver(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001582 ViENetworkObserver* observer) {
1583 CriticalSectionScoped cs(callback_cs_.get());
1584 if (observer) {
1585 if (networkObserver_) {
1586 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1587 "%s: observer alread added", __FUNCTION__);
1588 return -1;
1589 }
1590 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1591 "%s: observer added", __FUNCTION__);
1592 networkObserver_ = observer;
1593 } else {
1594 if (!networkObserver_) {
1595 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1596 "%s: no observer added", __FUNCTION__);
1597 return -1;
1598 }
1599 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1600 "%s: observer removed", __FUNCTION__);
1601 networkObserver_ = NULL;
1602 }
1603 return 0;
1604}
1605
1606bool ViEChannel::NetworkObserverRegistered() {
1607 CriticalSectionScoped cs(callback_cs_.get());
1608 return networkObserver_ != NULL;
1609}
1610
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001611int32_t ViEChannel::SetPeriodicDeadOrAliveStatus(
1612 const bool enable, const uint32_t sample_time_seconds) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001613 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1614 __FUNCTION__);
1615
1616 CriticalSectionScoped cs(callback_cs_.get());
1617 if (!networkObserver_) {
1618 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1619 "%s: no observer added", __FUNCTION__);
1620 return -1;
1621 }
1622
1623 bool enabled = false;
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001624 uint8_t current_sampletime_seconds = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001625
1626 // Get old settings.
1627 rtp_rtcp_->PeriodicDeadOrAliveStatus(enabled, current_sampletime_seconds);
1628 // Set new settings.
1629 if (rtp_rtcp_->SetPeriodicDeadOrAliveStatus(
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001630 enable, static_cast<uint8_t>(sample_time_seconds)) != 0) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001631 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1632 "%s: Could not set periodic dead-or-alive status",
1633 __FUNCTION__);
1634 return -1;
1635 }
1636 if (!enable) {
1637 // Restore last utilized sample time.
1638 // Without this trick, the sample time would always be reset to default
1639 // (2 sec), each time dead-or-alive was disabled without sample-time
1640 // parameter.
1641 rtp_rtcp_->SetPeriodicDeadOrAliveStatus(enable, current_sampletime_seconds);
1642 }
1643 return 0;
1644}
1645
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001646int32_t ViEChannel::EnableColorEnhancement(bool enable) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001647 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1648 "%s(enable: %d)", __FUNCTION__, enable);
1649
1650 CriticalSectionScoped cs(callback_cs_.get());
1651 color_enhancement_ = enable;
1652 return 0;
1653}
1654
1655RtpRtcp* ViEChannel::rtp_rtcp() {
1656 return rtp_rtcp_.get();
1657}
1658
fischman@webrtc.org0329e592013-02-19 22:09:36 +00001659CallStatsObserver* ViEChannel::GetStatsObserver() {
mflodman@webrtc.org78696d32012-11-26 12:40:15 +00001660 return stats_observer_.get();
1661}
1662
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001663int32_t ViEChannel::FrameToRender(
mikhal@webrtc.org3bbed742012-10-24 18:33:04 +00001664 I420VideoFrame& video_frame) { // NOLINT
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001665 CriticalSectionScoped cs(callback_cs_.get());
1666
1667 if (decoder_reset_) {
1668 // Trigger a callback to the user if the incoming codec has changed.
1669 if (codec_observer_) {
1670 VideoCodec decoder;
1671 memset(&decoder, 0, sizeof(decoder));
1672 if (vcm_.ReceiveCodec(&decoder) == VCM_OK) {
1673 // VCM::ReceiveCodec returns the codec set by
1674 // RegisterReceiveCodec, which might not be the size we're
1675 // actually decoding.
mikhal@webrtc.org3bbed742012-10-24 18:33:04 +00001676 decoder.width = static_cast<uint16_t>(video_frame.width());
1677 decoder.height = static_cast<uint16_t>(video_frame.height());
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001678 codec_observer_->IncomingCodecChanged(channel_id_, decoder);
1679 } else {
1680 assert(false);
1681 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1682 "%s: Could not get receive codec", __FUNCTION__);
1683 }
1684 }
1685 decoder_reset_ = false;
1686 }
1687 if (effect_filter_) {
mikhal@webrtc.org3bbed742012-10-24 18:33:04 +00001688 unsigned int length = CalcBufferSize(kI420,
1689 video_frame.width(),
1690 video_frame.height());
1691 scoped_array<uint8_t> video_buffer(new uint8_t[length]);
1692 ExtractBuffer(video_frame, length, video_buffer.get());
1693 effect_filter_->Transform(length, video_buffer.get(),
1694 video_frame.timestamp(), video_frame.width(),
1695 video_frame.height());
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001696 }
1697 if (color_enhancement_) {
1698 VideoProcessingModule::ColorEnhancement(&video_frame);
1699 }
1700
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001701 uint32_t arr_ofCSRC[kRtpCsrcSize];
1702 int32_t no_of_csrcs = rtp_rtcp_->RemoteCSRCs(arr_ofCSRC);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001703 if (no_of_csrcs <= 0) {
1704 arr_ofCSRC[0] = rtp_rtcp_->RemoteSSRC();
1705 no_of_csrcs = 1;
1706 }
1707 WEBRTC_TRACE(kTraceStream, kTraceVideo, ViEId(engine_id_, channel_id_),
mikhal@webrtc.org3bbed742012-10-24 18:33:04 +00001708 "%s(timestamp:%u)", __FUNCTION__, video_frame.timestamp());
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001709 DeliverFrame(&video_frame, no_of_csrcs, arr_ofCSRC);
1710 return 0;
1711}
1712
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001713int32_t ViEChannel::ReceivedDecodedReferenceFrame(
1714 const uint64_t picture_id) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001715 return rtp_rtcp_->SendRTCPReferencePictureSelection(picture_id);
1716}
1717
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001718int32_t ViEChannel::StoreReceivedFrame(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001719 const EncodedVideoData& frame_to_store) {
1720 return 0;
1721}
1722
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001723int32_t ViEChannel::ReceiveStatistics(const uint32_t bit_rate,
1724 const uint32_t frame_rate) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001725 CriticalSectionScoped cs(callback_cs_.get());
1726 if (codec_observer_) {
1727 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1728 "%s: bitrate %u, framerate %u", __FUNCTION__, bit_rate,
1729 frame_rate);
1730 codec_observer_->IncomingRate(channel_id_, frame_rate, bit_rate);
1731 }
1732 return 0;
1733}
1734
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001735int32_t ViEChannel::RequestKeyFrame() {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001736 WEBRTC_TRACE(kTraceStream, kTraceVideo, ViEId(engine_id_, channel_id_),
1737 "%s", __FUNCTION__);
1738 {
1739 CriticalSectionScoped cs(callback_cs_.get());
1740 if (codec_observer_ && do_key_frame_callbackRequest_) {
1741 codec_observer_->RequestNewKeyFrame(channel_id_);
1742 }
1743 }
1744 return rtp_rtcp_->RequestKeyFrame();
1745}
1746
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001747int32_t ViEChannel::SliceLossIndicationRequest(
1748 const uint64_t picture_id) {
1749 return rtp_rtcp_->SendRTCPSliceLossIndication((uint8_t) picture_id);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001750}
1751
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001752int32_t ViEChannel::ResendPackets(const uint16_t* sequence_numbers,
1753 uint16_t length) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001754 WEBRTC_TRACE(kTraceStream, kTraceVideo, ViEId(engine_id_, channel_id_),
1755 "%s(length: %d)", __FUNCTION__, length);
1756 return rtp_rtcp_->SendNACK(sequence_numbers, length);
1757}
1758
1759bool ViEChannel::ChannelDecodeThreadFunction(void* obj) {
1760 return static_cast<ViEChannel*>(obj)->ChannelDecodeProcess();
1761}
1762
1763bool ViEChannel::ChannelDecodeProcess() {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001764 vcm_.Decode(kMaxDecodeWaitTimeMs);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001765 return true;
1766}
1767
mflodman@webrtc.org78696d32012-11-26 12:40:15 +00001768void ViEChannel::OnRttUpdate(uint32_t rtt) {
1769 vcm_.SetReceiveChannelParameters(rtt);
1770 if (!sender_)
1771 rtp_rtcp_->SetRtt(rtt);
1772}
1773
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001774int32_t ViEChannel::StartDecodeThread() {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001775 // Start the decode thread
1776 if (decode_thread_) {
1777 // Already started.
1778 return 0;
1779 }
1780 decode_thread_ = ThreadWrapper::CreateThread(ChannelDecodeThreadFunction,
1781 this, kHighestPriority,
1782 "DecodingThread");
1783 if (!decode_thread_) {
1784 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1785 "%s: could not create decode thread", __FUNCTION__);
1786 return -1;
1787 }
1788
1789 unsigned int thread_id;
1790 if (decode_thread_->Start(thread_id) == false) {
1791 delete decode_thread_;
1792 decode_thread_ = NULL;
1793 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1794 "%s: could not start decode thread", __FUNCTION__);
1795 return -1;
1796 }
1797
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001798 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1799 "%s: decode thread with id %u started", __FUNCTION__);
1800 return 0;
1801}
1802
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001803int32_t ViEChannel::StopDecodeThread() {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001804 if (!decode_thread_) {
1805 WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
1806 "%s: decode thread not running", __FUNCTION__);
1807 return 0;
1808 }
1809
1810 decode_thread_->SetNotAlive();
1811 if (decode_thread_->Stop()) {
1812 delete decode_thread_;
1813 } else {
1814 // Couldn't stop the thread, leak instead of crash.
1815 WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
1816 "%s: could not stop decode thread", __FUNCTION__);
1817 assert(false && "could not stop decode thread");
1818 }
1819 decode_thread_ = NULL;
1820 return 0;
1821}
1822
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001823int32_t ViEChannel::RegisterExternalEncryption(Encryption* encryption) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001824 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1825 __FUNCTION__);
1826
1827 CriticalSectionScoped cs(callback_cs_.get());
1828 if (external_encryption_) {
1829 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1830 "%s: external encryption already registered", __FUNCTION__);
1831 return -1;
1832 }
1833
1834 external_encryption_ = encryption;
1835
1836 vie_receiver_.RegisterExternalDecryption(encryption);
1837 vie_sender_.RegisterExternalEncryption(encryption);
1838
1839 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1840 "%s", "external encryption object registerd with channel=%d",
1841 channel_id_);
1842 return 0;
1843}
1844
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001845int32_t ViEChannel::DeRegisterExternalEncryption() {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001846 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1847 __FUNCTION__);
1848
1849 CriticalSectionScoped cs(callback_cs_.get());
1850 if (!external_encryption_) {
1851 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1852 "%s: external encryption is not registered", __FUNCTION__);
1853 return -1;
1854 }
1855
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +00001856 external_transport_ = NULL;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001857 vie_receiver_.DeregisterExternalDecryption();
1858 vie_sender_.DeregisterExternalEncryption();
1859 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1860 "%s external encryption object de-registerd with channel=%d",
1861 __FUNCTION__, channel_id_);
1862 return 0;
1863}
1864
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001865int32_t ViEChannel::SetVoiceChannel(int32_t ve_channel_id,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001866 VoEVideoSync* ve_sync_interface) {
1867 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1868 "%s, audio channel %d, video channel %d", __FUNCTION__,
1869 ve_channel_id, channel_id_);
1870
1871 if (ve_sync_interface) {
1872 // Register lip sync
1873 module_process_thread_.RegisterModule(&vie_sync_);
1874 } else {
1875 module_process_thread_.DeRegisterModule(&vie_sync_);
1876 }
1877 return vie_sync_.ConfigureSync(ve_channel_id, ve_sync_interface,
1878 rtp_rtcp_.get());
1879}
1880
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001881int32_t ViEChannel::VoiceChannel() {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001882 return vie_sync_.VoiceChannel();
1883}
1884
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001885int32_t ViEChannel::RegisterEffectFilter(ViEEffectFilter* effect_filter) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001886 CriticalSectionScoped cs(callback_cs_.get());
1887 if (!effect_filter) {
1888 if (!effect_filter_) {
1889 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1890 "%s: no effect filter added for channel %d",
1891 __FUNCTION__, channel_id_);
1892 return -1;
1893 }
1894 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1895 "%s: deregister effect filter for device %d", __FUNCTION__,
1896 channel_id_);
1897 } else {
1898 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1899 "%s: register effect filter for device %d", __FUNCTION__,
1900 channel_id_);
1901 if (effect_filter_) {
1902 WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
1903 "%s: effect filter already added for channel %d",
1904 __FUNCTION__, channel_id_);
1905 return -1;
1906 }
1907 }
1908 effect_filter_ = effect_filter;
1909 return 0;
1910}
1911
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001912void ViEChannel::OnApplicationDataReceived(const int32_t id,
1913 const uint8_t sub_type,
1914 const uint32_t name,
1915 const uint16_t length,
1916 const uint8_t* data) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001917 if (channel_id_ != ChannelId(id)) {
1918 WEBRTC_TRACE(kTraceStream, kTraceVideo, ViEId(engine_id_, channel_id_),
1919 "%s, incorrect id", __FUNCTION__, id);
1920 return;
1921 }
1922 CriticalSectionScoped cs(callback_cs_.get());
1923 {
1924 if (rtcp_observer_) {
1925 rtcp_observer_->OnApplicationDataReceived(
1926 channel_id_, sub_type, name, reinterpret_cast<const char*>(data),
1927 length);
1928 }
1929 }
1930}
1931
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001932int32_t ViEChannel::OnInitializeDecoder(
1933 const int32_t id,
1934 const int8_t payload_type,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001935 const char payload_name[RTP_PAYLOAD_NAME_SIZE],
1936 const int frequency,
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001937 const uint8_t channels,
1938 const uint32_t rate) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001939 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1940 "%s: payload_type %d, payload_name %s", __FUNCTION__,
1941 payload_type, payload_name);
1942 vcm_.ResetDecoder();
1943
1944 callback_cs_->Enter();
1945 decoder_reset_ = true;
1946 callback_cs_->Leave();
1947 return 0;
1948}
1949
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001950void ViEChannel::OnPacketTimeout(const int32_t id) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001951 assert(ChannelId(id) == channel_id_);
1952 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1953 __FUNCTION__);
1954
1955 CriticalSectionScoped cs(callback_cs_.get());
1956 if (networkObserver_) {
pwestin@webrtc.org065b64d2013-04-02 20:37:14 +00001957 networkObserver_->PacketTimeout(channel_id_, NoPacket);
1958 rtp_packet_timeout_ = true;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001959 }
1960}
1961
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001962void ViEChannel::OnReceivedPacket(const int32_t id,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001963 const RtpRtcpPacketType packet_type) {
1964 assert(ChannelId(id) == channel_id_);
1965 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
1966 __FUNCTION__);
1967 if (rtp_packet_timeout_ && packet_type == kPacketRtp) {
1968 CriticalSectionScoped cs(callback_cs_.get());
1969 if (networkObserver_) {
1970 networkObserver_->PacketTimeout(channel_id_, PacketReceived);
1971 }
1972
1973 // Reset even if no observer set, might have been removed during timeout.
1974 rtp_packet_timeout_ = false;
1975 }
1976}
1977
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001978void ViEChannel::OnPeriodicDeadOrAlive(const int32_t id,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001979 const RTPAliveType alive) {
1980 assert(ChannelId(id) == channel_id_);
1981 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
1982 "%s(id=%d, alive=%d)", __FUNCTION__, id, alive);
1983
1984 CriticalSectionScoped cs(callback_cs_.get());
1985 if (!networkObserver_) {
1986 return;
1987 }
1988 bool is_alive = true;
1989 if (alive == kRtpDead) {
1990 is_alive = false;
1991 }
1992 networkObserver_->OnPeriodicDeadOrAlive(channel_id_, is_alive);
1993 return;
1994}
1995
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001996void ViEChannel::OnIncomingSSRCChanged(const int32_t id,
1997 const uint32_t SSRC) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001998 if (channel_id_ != ChannelId(id)) {
1999 assert(false);
2000 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
2001 "%s, incorrect id", __FUNCTION__, id);
2002 return;
2003 }
2004
2005 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
2006 "%s: %u", __FUNCTION__, SSRC);
2007
2008 CriticalSectionScoped cs(callback_cs_.get());
2009 {
2010 if (rtp_observer_) {
2011 rtp_observer_->IncomingSSRCChanged(channel_id_, SSRC);
2012 }
2013 }
2014}
2015
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00002016void ViEChannel::OnIncomingCSRCChanged(const int32_t id,
2017 const uint32_t CSRC,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002018 const bool added) {
2019 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
2020 "%s: %u added: %d", __FUNCTION__, CSRC, added);
2021
2022 if (channel_id_ != ChannelId(id)) {
2023 assert(false);
2024 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
2025 "%s, incorrect id", __FUNCTION__, id);
2026 return;
2027 }
2028
2029 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
2030 "%s: %u", __FUNCTION__, CSRC);
2031
2032 CriticalSectionScoped cs(callback_cs_.get());
2033 {
2034 if (rtp_observer_) {
2035 rtp_observer_->IncomingCSRCChanged(channel_id_, CSRC, added);
2036 }
2037 }
2038}
2039
2040} // namespace webrtc