2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
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.
11 #include "webrtc/common_types.h"
12 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
13 #include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
14 #include "webrtc/modules/video_coding/main/source/encoded_frame.h"
15 #include "webrtc/modules/video_coding/main/source/jitter_buffer.h"
16 #include "webrtc/modules/video_coding/main/source/packet.h"
17 #include "webrtc/modules/video_coding/main/source/video_coding_impl.h"
18 #include "webrtc/system_wrappers/interface/clock.h"
19 #include "webrtc/system_wrappers/interface/trace.h"
20 #include "webrtc/system_wrappers/interface/trace_event.h"
22 // #define DEBUG_DECODER_BIT_STREAM
27 VideoReceiver::VideoReceiver(const int32_t id,
29 EventFactory* event_factory)
32 process_crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
33 _receiveCritSect(CriticalSectionWrapper::CreateCriticalSection()),
34 _receiverInited(false),
35 _timing(clock_, id, 1),
36 _dualTiming(clock_, id, 2, &_timing),
37 _receiver(&_timing, clock_, event_factory, id, 1, true),
38 _dualReceiver(&_dualTiming, clock_, event_factory, id, 2, false),
39 _decodedFrameCallback(_timing, clock_),
40 _dualDecodedFrameCallback(_dualTiming, clock_),
41 _frameTypeCallback(NULL),
42 _receiveStatsCallback(NULL),
43 _decoderTimingCallback(NULL),
44 _packetRequestCallback(NULL),
45 render_buffer_callback_(NULL),
48 #ifdef DEBUG_DECODER_BIT_STREAM
49 _bitStreamBeforeDecoder(NULL),
52 _keyRequestMode(kKeyOnError),
53 _scheduleKeyRequest(false),
54 max_nack_list_size_(0),
55 pre_decode_image_callback_(NULL),
57 _receiveStatsTimer(1000, clock_),
58 _retransmissionTimer(10, clock_),
59 _keyRequestTimer(500, clock_) {
61 #ifdef DEBUG_DECODER_BIT_STREAM
62 _bitStreamBeforeDecoder = fopen("decoderBitStream.bit", "wb");
66 VideoReceiver::~VideoReceiver() {
67 if (_dualDecoder != NULL) {
68 _codecDataBase.ReleaseDecoder(_dualDecoder);
70 delete _receiveCritSect;
71 #ifdef DEBUG_DECODER_BIT_STREAM
72 fclose(_bitStreamBeforeDecoder);
76 int32_t VideoReceiver::Process() {
77 int32_t returnValue = VCM_OK;
79 // Receive-side statistics
80 if (_receiveStatsTimer.TimeUntilProcess() == 0) {
81 _receiveStatsTimer.Processed();
82 CriticalSectionScoped cs(process_crit_sect_.get());
83 if (_receiveStatsCallback != NULL) {
86 _receiver.ReceiveStatistics(&bitRate, &frameRate);
87 _receiveStatsCallback->OnReceiveStatisticsUpdate(bitRate, frameRate);
90 if (_decoderTimingCallback != NULL) {
96 int min_playout_delay_ms;
98 _timing.GetTimings(&decode_ms,
103 &min_playout_delay_ms,
105 _decoderTimingCallback->OnDecoderTiming(decode_ms,
110 min_playout_delay_ms,
114 // Size of render buffer.
115 if (render_buffer_callback_) {
116 int buffer_size_ms = _receiver.RenderBufferSizeMs();
117 render_buffer_callback_->RenderBufferSizeMs(buffer_size_ms);
121 // Key frame requests
122 if (_keyRequestTimer.TimeUntilProcess() == 0) {
123 _keyRequestTimer.Processed();
124 bool request_key_frame = false;
126 CriticalSectionScoped cs(process_crit_sect_.get());
127 request_key_frame = _scheduleKeyRequest && _frameTypeCallback != NULL;
129 if (request_key_frame) {
130 const int32_t ret = RequestKeyFrame();
131 if (ret != VCM_OK && returnValue == VCM_OK) {
137 // Packet retransmission requests
138 // TODO(holmer): Add API for changing Process interval and make sure it's
139 // disabled when NACK is off.
140 if (_retransmissionTimer.TimeUntilProcess() == 0) {
141 _retransmissionTimer.Processed();
142 bool callback_registered = false;
145 CriticalSectionScoped cs(process_crit_sect_.get());
146 length = max_nack_list_size_;
147 callback_registered = _packetRequestCallback != NULL;
149 if (callback_registered && length > 0) {
150 std::vector<uint16_t> nackList(length);
151 const int32_t ret = NackList(&nackList[0], &length);
152 if (ret != VCM_OK && returnValue == VCM_OK) {
155 if (ret == VCM_OK && length > 0) {
156 CriticalSectionScoped cs(process_crit_sect_.get());
157 if (_packetRequestCallback != NULL) {
158 _packetRequestCallback->ResendPackets(&nackList[0], length);
167 int32_t VideoReceiver::TimeUntilNextProcess() {
168 uint32_t timeUntilNextProcess = _receiveStatsTimer.TimeUntilProcess();
169 if ((_receiver.NackMode() != kNoNack) ||
170 (_dualReceiver.State() != kPassive)) {
171 // We need a Process call more often if we are relying on
173 timeUntilNextProcess =
174 VCM_MIN(timeUntilNextProcess, _retransmissionTimer.TimeUntilProcess());
176 timeUntilNextProcess =
177 VCM_MIN(timeUntilNextProcess, _keyRequestTimer.TimeUntilProcess());
179 return timeUntilNextProcess;
182 int32_t VideoReceiver::SetReceiveChannelParameters(uint32_t rtt) {
183 CriticalSectionScoped receiveCs(_receiveCritSect);
184 _receiver.UpdateRtt(rtt);
188 // Enable or disable a video protection method.
189 // Note: This API should be deprecated, as it does not offer a distinction
190 // between the protection method and decoding with or without errors. If such a
191 // behavior is desired, use the following API: SetReceiverRobustnessMode.
192 int32_t VideoReceiver::SetVideoProtection(VCMVideoProtection videoProtection,
194 // By default, do not decode with errors.
195 _receiver.SetDecodeErrorMode(kNoErrors);
196 // The dual decoder should always be error free.
197 _dualReceiver.SetDecodeErrorMode(kNoErrors);
198 switch (videoProtection) {
199 case kProtectionNack:
200 case kProtectionNackReceiver: {
201 CriticalSectionScoped cs(_receiveCritSect);
203 // Enable NACK and always wait for retransmits.
204 _receiver.SetNackMode(kNack, -1, -1);
206 _receiver.SetNackMode(kNoNack, -1, -1);
211 case kProtectionDualDecoder: {
212 CriticalSectionScoped cs(_receiveCritSect);
214 // Enable NACK but don't wait for retransmissions and don't
215 // add any extra delay.
216 _receiver.SetNackMode(kNack, 0, 0);
217 // Enable NACK and always wait for retransmissions and
218 // compensate with extra delay.
219 _dualReceiver.SetNackMode(kNack, -1, -1);
220 _receiver.SetDecodeErrorMode(kWithErrors);
222 _dualReceiver.SetNackMode(kNoNack, -1, -1);
227 case kProtectionKeyOnLoss: {
228 CriticalSectionScoped cs(_receiveCritSect);
230 _keyRequestMode = kKeyOnLoss;
231 _receiver.SetDecodeErrorMode(kWithErrors);
232 } else if (_keyRequestMode == kKeyOnLoss) {
233 _keyRequestMode = kKeyOnError; // default mode
235 return VCM_PARAMETER_ERROR;
240 case kProtectionKeyOnKeyLoss: {
241 CriticalSectionScoped cs(_receiveCritSect);
243 _keyRequestMode = kKeyOnKeyLoss;
244 } else if (_keyRequestMode == kKeyOnKeyLoss) {
245 _keyRequestMode = kKeyOnError; // default mode
247 return VCM_PARAMETER_ERROR;
252 case kProtectionNackFEC: {
253 CriticalSectionScoped cs(_receiveCritSect);
255 // Enable hybrid NACK/FEC. Always wait for retransmissions
256 // and don't add extra delay when RTT is above
258 _receiver.SetNackMode(kNack, media_optimization::kLowRttNackMs, -1);
259 _receiver.SetDecodeErrorMode(kNoErrors);
260 _receiver.SetDecodeErrorMode(kNoErrors);
262 _receiver.SetNackMode(kNoNack, -1, -1);
266 case kProtectionNackSender:
268 case kProtectionPeriodicKeyFrames:
269 // Ignore encoder modes.
275 // Initialize receiver, resets codec database etc
276 int32_t VideoReceiver::InitializeReceiver() {
277 CriticalSectionScoped receive_cs(_receiveCritSect);
278 CriticalSectionScoped process_cs(process_crit_sect_.get());
279 int32_t ret = _receiver.Initialize();
284 ret = _dualReceiver.Initialize();
288 _codecDataBase.ResetReceiver();
292 _decodedFrameCallback.SetUserReceiveCallback(NULL);
293 _receiverInited = true;
294 _frameTypeCallback = NULL;
295 _receiveStatsCallback = NULL;
296 _decoderTimingCallback = NULL;
297 _packetRequestCallback = NULL;
298 _keyRequestMode = kKeyOnError;
299 _scheduleKeyRequest = false;
304 // Register a receive callback. Will be called whenever there is a new frame
305 // ready for rendering.
306 int32_t VideoReceiver::RegisterReceiveCallback(
307 VCMReceiveCallback* receiveCallback) {
308 CriticalSectionScoped cs(_receiveCritSect);
309 _decodedFrameCallback.SetUserReceiveCallback(receiveCallback);
313 int32_t VideoReceiver::RegisterReceiveStatisticsCallback(
314 VCMReceiveStatisticsCallback* receiveStats) {
315 CriticalSectionScoped cs(process_crit_sect_.get());
316 _receiveStatsCallback = receiveStats;
320 int32_t VideoReceiver::RegisterDecoderTimingCallback(
321 VCMDecoderTimingCallback* decoderTiming) {
322 CriticalSectionScoped cs(process_crit_sect_.get());
323 _decoderTimingCallback = decoderTiming;
327 // Register an externally defined decoder/render object.
328 // Can be a decoder only or a decoder coupled with a renderer.
329 int32_t VideoReceiver::RegisterExternalDecoder(VideoDecoder* externalDecoder,
331 bool internalRenderTiming) {
332 CriticalSectionScoped cs(_receiveCritSect);
333 if (externalDecoder == NULL) {
334 // Make sure the VCM updates the decoder next time it decodes.
336 return _codecDataBase.DeregisterExternalDecoder(payloadType) ? 0 : -1;
338 return _codecDataBase.RegisterExternalDecoder(
339 externalDecoder, payloadType, internalRenderTiming)
344 // Register a frame type request callback.
345 int32_t VideoReceiver::RegisterFrameTypeCallback(
346 VCMFrameTypeCallback* frameTypeCallback) {
347 CriticalSectionScoped cs(process_crit_sect_.get());
348 _frameTypeCallback = frameTypeCallback;
352 int32_t VideoReceiver::RegisterPacketRequestCallback(
353 VCMPacketRequestCallback* callback) {
354 CriticalSectionScoped cs(process_crit_sect_.get());
355 _packetRequestCallback = callback;
359 int VideoReceiver::RegisterRenderBufferSizeCallback(
360 VCMRenderBufferSizeCallback* callback) {
361 CriticalSectionScoped cs(process_crit_sect_.get());
362 render_buffer_callback_ = callback;
366 // Decode next frame, blocking.
367 // Should be called as often as possible to get the most out of the decoder.
368 int32_t VideoReceiver::Decode(uint16_t maxWaitTimeMs) {
369 int64_t nextRenderTimeMs;
371 CriticalSectionScoped cs(_receiveCritSect);
372 if (!_receiverInited) {
373 return VCM_UNINITIALIZED;
375 if (!_codecDataBase.DecoderRegistered()) {
376 return VCM_NO_CODEC_REGISTERED;
380 const bool dualReceiverEnabledNotReceiving = (
381 _dualReceiver.State() != kReceiving && _dualReceiver.NackMode() == kNack);
383 VCMEncodedFrame* frame =
384 _receiver.FrameForDecoding(maxWaitTimeMs,
386 _codecDataBase.SupportsRenderScheduling(),
389 if (dualReceiverEnabledNotReceiving && _dualReceiver.State() == kReceiving) {
390 // Dual receiver is enabled (kNACK enabled), but was not receiving
391 // before the call to FrameForDecoding(). After the call the state
392 // changed to receiving, and therefore we must copy the primary decoder
393 // state to the dual decoder to make it possible for the dual decoder to
394 // start decoding retransmitted frames and recover.
395 CriticalSectionScoped cs(_receiveCritSect);
396 if (_dualDecoder != NULL) {
397 _codecDataBase.ReleaseDecoder(_dualDecoder);
399 _dualDecoder = _codecDataBase.CreateDecoderCopy();
400 if (_dualDecoder != NULL) {
401 _dualDecoder->RegisterDecodeCompleteCallback(&_dualDecodedFrameCallback);
403 _dualReceiver.Reset();
408 return VCM_FRAME_NOT_READY;
410 CriticalSectionScoped cs(_receiveCritSect);
412 // If this frame was too late, we should adjust the delay accordingly
413 _timing.UpdateCurrentDelay(frame->RenderTimeMs(),
414 clock_->TimeInMilliseconds());
416 if (pre_decode_image_callback_) {
417 EncodedImage encoded_image(frame->EncodedImage());
418 pre_decode_image_callback_->Encoded(encoded_image);
421 #ifdef DEBUG_DECODER_BIT_STREAM
422 if (_bitStreamBeforeDecoder != NULL) {
423 // Write bit stream to file for debugging purposes
425 frame->Buffer(), 1, frame->Length(), _bitStreamBeforeDecoder) !=
431 const int32_t ret = Decode(*frame);
432 _receiver.ReleaseFrame(frame);
441 int32_t VideoReceiver::RequestSliceLossIndication(
442 const uint64_t pictureID) const {
443 TRACE_EVENT1("webrtc", "RequestSLI", "picture_id", pictureID);
444 CriticalSectionScoped cs(process_crit_sect_.get());
445 if (_frameTypeCallback != NULL) {
447 _frameTypeCallback->SliceLossIndicationRequest(pictureID);
449 WEBRTC_TRACE(webrtc::kTraceError,
450 webrtc::kTraceVideoCoding,
452 "Failed to request key frame");
456 WEBRTC_TRACE(webrtc::kTraceWarning,
457 webrtc::kTraceVideoCoding,
459 "No frame type request callback registered");
460 return VCM_MISSING_CALLBACK;
465 int32_t VideoReceiver::RequestKeyFrame() {
466 TRACE_EVENT0("webrtc", "RequestKeyFrame");
467 CriticalSectionScoped process_cs(process_crit_sect_.get());
468 if (_frameTypeCallback != NULL) {
469 const int32_t ret = _frameTypeCallback->RequestKeyFrame();
471 WEBRTC_TRACE(webrtc::kTraceError,
472 webrtc::kTraceVideoCoding,
474 "Failed to request key frame");
477 _scheduleKeyRequest = false;
479 WEBRTC_TRACE(webrtc::kTraceWarning,
480 webrtc::kTraceVideoCoding,
482 "No frame type request callback registered");
483 return VCM_MISSING_CALLBACK;
488 int32_t VideoReceiver::DecodeDualFrame(uint16_t maxWaitTimeMs) {
489 CriticalSectionScoped cs(_receiveCritSect);
490 if (_dualReceiver.State() != kReceiving ||
491 _dualReceiver.NackMode() != kNack) {
492 // The dual receiver is currently not receiving or
493 // dual decoder mode is disabled.
496 int64_t dummyRenderTime;
497 int32_t decodeCount = 0;
498 // The dual decoder's state is copied from the main decoder, which may
499 // decode with errors. Make sure that the dual decoder does not introduce
501 _dualReceiver.SetDecodeErrorMode(kNoErrors);
502 VCMEncodedFrame* dualFrame =
503 _dualReceiver.FrameForDecoding(maxWaitTimeMs, dummyRenderTime);
504 if (dualFrame != NULL && _dualDecoder != NULL) {
505 WEBRTC_TRACE(webrtc::kTraceStream,
506 webrtc::kTraceVideoCoding,
508 "Decoding frame %u with dual decoder",
509 dualFrame->TimeStamp());
510 // Decode dualFrame and try to catch up
512 _dualDecoder->Decode(*dualFrame, clock_->TimeInMilliseconds());
513 if (ret != WEBRTC_VIDEO_CODEC_OK) {
514 WEBRTC_TRACE(webrtc::kTraceWarning,
515 webrtc::kTraceVideoCoding,
517 "Failed to decode frame with dual decoder");
518 _dualReceiver.ReleaseFrame(dualFrame);
519 return VCM_CODEC_ERROR;
521 if (_receiver.DualDecoderCaughtUp(dualFrame, _dualReceiver)) {
522 // Copy the complete decoder state of the dual decoder
523 // to the primary decoder.
524 WEBRTC_TRACE(webrtc::kTraceStream,
525 webrtc::kTraceVideoCoding,
527 "Dual decoder caught up");
528 _codecDataBase.CopyDecoder(*_dualDecoder);
529 _codecDataBase.ReleaseDecoder(_dualDecoder);
534 _dualReceiver.ReleaseFrame(dualFrame);
538 // Must be called from inside the receive side critical section.
539 int32_t VideoReceiver::Decode(const VCMEncodedFrame& frame) {
540 TRACE_EVENT_ASYNC_STEP1("webrtc",
546 // Change decoder if payload type has changed
547 const bool renderTimingBefore = _codecDataBase.SupportsRenderScheduling();
549 _codecDataBase.GetDecoder(frame.PayloadType(), &_decodedFrameCallback);
550 if (renderTimingBefore != _codecDataBase.SupportsRenderScheduling()) {
551 // Make sure we reset the decode time estimate since it will
552 // be zero for codecs without render timing.
553 _timing.ResetDecodeTime();
555 if (_decoder == NULL) {
556 return VCM_NO_CODEC_REGISTERED;
559 int32_t ret = _decoder->Decode(frame, clock_->TimeInMilliseconds());
561 // Check for failed decoding, run frame type request callback if needed.
562 bool request_key_frame = false;
564 if (ret == VCM_ERROR_REQUEST_SLI) {
565 return RequestSliceLossIndication(
566 _decodedFrameCallback.LastReceivedPictureID() + 1);
568 WEBRTC_TRACE(webrtc::kTraceError,
569 webrtc::kTraceVideoCoding,
571 "Failed to decode frame %u, requesting key frame",
573 request_key_frame = true;
575 } else if (ret == VCM_REQUEST_SLI) {
576 ret = RequestSliceLossIndication(
577 _decodedFrameCallback.LastReceivedPictureID() + 1);
579 if (!frame.Complete() || frame.MissingFrame()) {
580 switch (_keyRequestMode) {
581 case kKeyOnKeyLoss: {
582 if (frame.FrameType() == kVideoFrameKey) {
583 request_key_frame = true;
589 request_key_frame = true;
596 if (request_key_frame) {
597 CriticalSectionScoped cs(process_crit_sect_.get());
598 _scheduleKeyRequest = true;
600 TRACE_EVENT_ASYNC_END0("webrtc", "Video", frame.TimeStamp());
604 // Reset the decoder state
605 int32_t VideoReceiver::ResetDecoder() {
606 bool reset_key_request = false;
608 CriticalSectionScoped cs(_receiveCritSect);
609 if (_decoder != NULL) {
610 _receiver.Initialize();
612 reset_key_request = true;
615 if (_dualReceiver.State() != kPassive) {
616 _dualReceiver.Initialize();
618 if (_dualDecoder != NULL) {
619 _codecDataBase.ReleaseDecoder(_dualDecoder);
623 if (reset_key_request) {
624 CriticalSectionScoped cs(process_crit_sect_.get());
625 _scheduleKeyRequest = false;
630 // Register possible receive codecs, can be called multiple times
631 int32_t VideoReceiver::RegisterReceiveCodec(const VideoCodec* receiveCodec,
632 int32_t numberOfCores,
633 bool requireKeyFrame) {
634 CriticalSectionScoped cs(_receiveCritSect);
635 if (receiveCodec == NULL) {
636 return VCM_PARAMETER_ERROR;
638 if (!_codecDataBase.RegisterReceiveCodec(
639 receiveCodec, numberOfCores, requireKeyFrame)) {
645 // Get current received codec
646 int32_t VideoReceiver::ReceiveCodec(VideoCodec* currentReceiveCodec) const {
647 CriticalSectionScoped cs(_receiveCritSect);
648 if (currentReceiveCodec == NULL) {
649 return VCM_PARAMETER_ERROR;
651 return _codecDataBase.ReceiveCodec(currentReceiveCodec) ? 0 : -1;
654 // Get current received codec
655 VideoCodecType VideoReceiver::ReceiveCodec() const {
656 CriticalSectionScoped cs(_receiveCritSect);
657 return _codecDataBase.ReceiveCodec();
660 // Incoming packet from network parsed and ready for decode, non blocking.
661 int32_t VideoReceiver::IncomingPacket(const uint8_t* incomingPayload,
662 uint32_t payloadLength,
663 const WebRtcRTPHeader& rtpInfo) {
664 if (rtpInfo.frameType == kVideoFrameKey) {
665 TRACE_EVENT1("webrtc",
666 "VCM::PacketKeyFrame",
668 rtpInfo.header.sequenceNumber);
670 if (incomingPayload == NULL) {
671 // The jitter buffer doesn't handle non-zero payload lengths for packets
673 // TODO(holmer): We should fix this in the jitter buffer.
676 const VCMPacket packet(incomingPayload, payloadLength, rtpInfo);
678 if (_dualReceiver.State() != kPassive) {
679 ret = _dualReceiver.InsertPacket(
680 packet, rtpInfo.type.Video.width, rtpInfo.type.Video.height);
681 if (ret == VCM_FLUSH_INDICATOR) {
684 } else if (ret < 0) {
688 ret = _receiver.InsertPacket(
689 packet, rtpInfo.type.Video.width, rtpInfo.type.Video.height);
690 // TODO(holmer): Investigate if this somehow should use the key frame
691 // request scheduling to throttle the requests.
692 if (ret == VCM_FLUSH_INDICATOR) {
695 } else if (ret < 0) {
701 // Minimum playout delay (used for lip-sync). This is the minimum delay required
702 // to sync with audio. Not included in VideoCodingModule::Delay()
704 int32_t VideoReceiver::SetMinimumPlayoutDelay(uint32_t minPlayoutDelayMs) {
705 _timing.set_min_playout_delay(minPlayoutDelayMs);
709 // The estimated delay caused by rendering, defaults to
710 // kDefaultRenderDelayMs = 10 ms
711 int32_t VideoReceiver::SetRenderDelay(uint32_t timeMS) {
712 _timing.set_render_delay(timeMS);
716 // Current video delay
717 int32_t VideoReceiver::Delay() const { return _timing.TargetVideoDelay(); }
720 int32_t VideoReceiver::NackList(uint16_t* nackList, uint16_t* size) {
721 VCMNackStatus nackStatus = kNackOk;
722 uint16_t nack_list_length = 0;
723 // Collect sequence numbers from the default receiver
724 // if in normal nack mode. Otherwise collect them from
725 // the dual receiver if the dual receiver is receiving.
726 if (_receiver.NackMode() != kNoNack) {
727 nackStatus = _receiver.NackList(nackList, *size, &nack_list_length);
729 if (nack_list_length == 0 && _dualReceiver.State() != kPassive) {
730 nackStatus = _dualReceiver.NackList(nackList, *size, &nack_list_length);
732 *size = nack_list_length;
734 switch (nackStatus) {
735 case kNackNeedMoreMemory: {
736 WEBRTC_TRACE(webrtc::kTraceError,
737 webrtc::kTraceVideoCoding,
742 case kNackKeyFrameRequest: {
743 WEBRTC_TRACE(webrtc::kTraceWarning,
744 webrtc::kTraceVideoCoding,
746 "Failed to get NACK list, requesting key frame");
747 return RequestKeyFrame();
755 int32_t VideoReceiver::ReceivedFrameCount(VCMFrameCount* frameCount) const {
756 _receiver.ReceivedFrameCount(frameCount);
760 uint32_t VideoReceiver::DiscardedPackets() const {
761 return _receiver.DiscardedPackets();
764 int VideoReceiver::SetReceiverRobustnessMode(
765 ReceiverRobustness robustnessMode,
766 VCMDecodeErrorMode decode_error_mode) {
767 CriticalSectionScoped cs(_receiveCritSect);
768 switch (robustnessMode) {
769 case VideoCodingModule::kNone:
770 _receiver.SetNackMode(kNoNack, -1, -1);
771 _dualReceiver.SetNackMode(kNoNack, -1, -1);
772 if (decode_error_mode == kNoErrors) {
773 _keyRequestMode = kKeyOnLoss;
775 _keyRequestMode = kKeyOnError;
778 case VideoCodingModule::kHardNack:
779 // Always wait for retransmissions (except when decoding with errors).
780 _receiver.SetNackMode(kNack, -1, -1);
781 _dualReceiver.SetNackMode(kNoNack, -1, -1);
782 _keyRequestMode = kKeyOnError; // TODO(hlundin): On long NACK list?
784 case VideoCodingModule::kSoftNack:
785 assert(false); // TODO(hlundin): Not completed.
786 return VCM_NOT_IMPLEMENTED;
787 // Enable hybrid NACK/FEC. Always wait for retransmissions and don't add
788 // extra delay when RTT is above kLowRttNackMs.
789 _receiver.SetNackMode(kNack, media_optimization::kLowRttNackMs, -1);
790 _dualReceiver.SetNackMode(kNoNack, -1, -1);
791 _keyRequestMode = kKeyOnError;
793 case VideoCodingModule::kDualDecoder:
794 if (decode_error_mode == kNoErrors) {
795 return VCM_PARAMETER_ERROR;
797 // Enable NACK but don't wait for retransmissions and don't add any extra
799 _receiver.SetNackMode(kNack, 0, 0);
800 // Enable NACK, compensate with extra delay and wait for retransmissions.
801 _dualReceiver.SetNackMode(kNack, -1, -1);
802 _keyRequestMode = kKeyOnError;
804 case VideoCodingModule::kReferenceSelection:
805 assert(false); // TODO(hlundin): Not completed.
806 return VCM_NOT_IMPLEMENTED;
807 if (decode_error_mode == kNoErrors) {
808 return VCM_PARAMETER_ERROR;
810 _receiver.SetNackMode(kNoNack, -1, -1);
811 _dualReceiver.SetNackMode(kNoNack, -1, -1);
814 _receiver.SetDecodeErrorMode(decode_error_mode);
815 // The dual decoder should never decode with errors.
816 _dualReceiver.SetDecodeErrorMode(kNoErrors);
820 void VideoReceiver::SetDecodeErrorMode(VCMDecodeErrorMode decode_error_mode) {
821 CriticalSectionScoped cs(_receiveCritSect);
822 _receiver.SetDecodeErrorMode(decode_error_mode);
825 void VideoReceiver::SetNackSettings(size_t max_nack_list_size,
826 int max_packet_age_to_nack,
827 int max_incomplete_time_ms) {
828 if (max_nack_list_size != 0) {
829 CriticalSectionScoped receive_cs(_receiveCritSect);
830 CriticalSectionScoped process_cs(process_crit_sect_.get());
831 max_nack_list_size_ = max_nack_list_size;
833 _receiver.SetNackSettings(
834 max_nack_list_size, max_packet_age_to_nack, max_incomplete_time_ms);
835 _dualReceiver.SetNackSettings(
836 max_nack_list_size, max_packet_age_to_nack, max_incomplete_time_ms);
839 int VideoReceiver::SetMinReceiverDelay(int desired_delay_ms) {
840 return _receiver.SetMinReceiverDelay(desired_delay_ms);
843 void VideoReceiver::RegisterPreDecodeImageCallback(
844 EncodedImageCallback* observer) {
845 CriticalSectionScoped cs(_receiveCritSect);
846 pre_decode_image_callback_ = observer;
850 } // namespace webrtc