diff --git a/video_engine/main/interface/vie_rtp_rtcp.h b/video_engine/main/interface/vie_rtp_rtcp.h index 70bf3b4809..f12d504934 100644 --- a/video_engine/main/interface/vie_rtp_rtcp.h +++ b/video_engine/main/interface/vie_rtp_rtcp.h @@ -171,7 +171,7 @@ public: unsigned int name, const char* data, unsigned short dataLengthInBytes) = 0; - // This function enables Negative Acknowledgement (NACK) using RTCP, + // This function enables Negative Acknowledgment (NACK) using RTCP, // implemented based on RFC 4585. NACK retransmits RTP packets if lost on // the network. This creates a lossless transport at the expense of delay. // If using NACK, NACK should be enabled on both endpoints in a call. @@ -185,6 +185,19 @@ public: const unsigned char payloadTypeRED, const unsigned char payloadTypeFEC) = 0; + // This function enables hybrid Negative Acknowledgment using RTCP + // and Forward Error Correction (FEC) implemented based on RFC 5109, + // to improve packet loss robustness. Extra + // FEC packets are sent together with the usual media packets, hence will + // part of the bitrate be used for FEC packets. + // The hybrid mode will choose between nack only, fec only and both based on + // network conditions. When both are applied, only packets that were not + // recovered by the FEC will be nacked. + virtual int SetHybridNACKFECStatus(const int videoChannel, + const bool enable, + const unsigned char payloadTypeRED, + const unsigned char payloadTypeFEC) = 0; + // This function enables RTCP key frame requests. virtual int SetKeyFrameRequestMethod( const int videoChannel, const ViEKeyFrameRequestMethod method) = 0; diff --git a/video_engine/main/source/vie_channel.cc b/video_engine/main/source/vie_channel.cc index aeaf9ffe6b..5afcb17d8a 100644 --- a/video_engine/main/source/vie_channel.cc +++ b/video_engine/main/source/vie_channel.cc @@ -419,7 +419,7 @@ WebRtc_Word32 ViEChannel::RegisterCodecObserver(ViEDecoderObserver* observer) if (_codecObserver) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, - ViEId(_engineId, _channelId), "%s: alread added", + ViEId(_engineId, _channelId), "%s: already added", __FUNCTION__); return -1; } @@ -615,23 +615,44 @@ WebRtc_Word32 ViEChannel::GetRTCPMode(RTCPMethod& rtcpMode) WebRtc_Word32 ViEChannel::SetNACKStatus(const bool enable) { - WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), - "%s(enable: %d)", __FUNCTION__, enable); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s(enable: %d)", __FUNCTION__, enable); // Update the decoding VCM if (_vcm.SetVideoProtection(kProtectionNack, enable) != VCM_OK) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, - ViEId(_engineId, _channelId), - "%s: Could not set VCM NACK protection: %d", __FUNCTION__, - enable); + ViEId(_engineId, _channelId), + "%s: Could not set VCM NACK protection: %d", __FUNCTION__, + enable); return -1; } if (enable) { // Disable possible FEC SetFECStatus(false, 0, 0); + } + // Update the decoding VCM + if (_vcm.SetVideoProtection(kProtectionNack, enable) != VCM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not set VCM NACK protection: %d", __FUNCTION__, + enable); + return -1; + } + return ProcessNACKRequest(enable); +} +WebRtc_Word32 ViEChannel::ProcessNACKRequest(const bool enable) +{ + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s(enable: %d)", __FUNCTION__, enable); + + if (enable) + { // Turn on NACK, NACKMethod nackMethod = kNackRtcp; if (_rtpRtcp.RTCP() == kRtcpOff) @@ -649,8 +670,9 @@ WebRtc_Word32 ViEChannel::SetNACKStatus(const bool enable) nackMethod); return -1; } - WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), - "%s: Using NACK method %d", __FUNCTION__, nackMethod); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Using NACK method %d", __FUNCTION__, nackMethod); _rtpRtcp.SetStorePacketsStatus(true, kNackHistorySize); _vcm.RegisterPacketRequestCallback(this); } @@ -677,16 +699,25 @@ WebRtc_Word32 ViEChannel::SetFECStatus(const bool enable, const unsigned char payloadTypeRED, const unsigned char payloadTypeFEC) { - WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_engineId, _channelId), - "%s(enable: %d, payloadTypeRED: %u, payloadTypeFEC: %u)", - __FUNCTION__, enable, payloadTypeRED, payloadTypeFEC); - // Disable possible NACK if (enable) { SetNACKStatus(false); } + return ProcessFECRequest(enable, payloadTypeRED, payloadTypeFEC); + +} +WebRtc_Word32 +ViEChannel::ProcessFECRequest(const bool enable, + const unsigned char payloadTypeRED, + const unsigned char payloadTypeFEC) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s(enable: %d, payloadTypeRED: %u, payloadTypeFEC: %u)", + __FUNCTION__, enable, payloadTypeRED, payloadTypeFEC); + if (_rtpRtcp.SetGenericFECStatus(enable, payloadTypeRED, payloadTypeFEC) != 0) { @@ -700,6 +731,34 @@ WebRtc_Word32 ViEChannel::SetFECStatus(const bool enable, return 0; } +// ---------------------------------------------------------------------------- +// EnableNACKFECStatus +// ---------------------------------------------------------------------------- + +WebRtc_Word32 +ViEChannel::SetHybridNACKFECStatus(const bool enable, + const unsigned char payloadTypeRED, + const unsigned char payloadTypeFEC) +{ + // Update the decoding VCM with hybrid mode + if (_vcm.SetVideoProtection(kProtectionNackFEC, enable) != VCM_OK) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Could not set VCM NACK protection: %d", __FUNCTION__, + enable); + return -1; + } + + WebRtc_Word32 retVal = 0; + retVal = ProcessNACKRequest(enable); + if (retVal < 0) + { + return retVal; + } + return ProcessFECRequest(enable, payloadTypeRED, payloadTypeFEC); +} + // ---------------------------------------------------------------------------- // KeyFrameRequestMethod // ---------------------------------------------------------------------------- diff --git a/video_engine/main/source/vie_channel.h b/video_engine/main/source/vie_channel.h index c4908dbfb7..a4746b83bd 100644 --- a/video_engine/main/source/vie_channel.h +++ b/video_engine/main/source/vie_channel.h @@ -111,6 +111,9 @@ public: WebRtc_Word32 SetFECStatus(const bool enable, const unsigned char payloadTypeRED, const unsigned char payloadTypeFEC); + WebRtc_Word32 SetHybridNACKFECStatus(const bool enable, + const unsigned char payloadTypeRED, + const unsigned char payloadTypeFEC); WebRtc_Word32 SetKeyFrameRequestMethod(const KeyFrameRequestMethod method); @@ -410,6 +413,13 @@ private: WebRtc_Word32 StartDecodeThread(); WebRtc_Word32 StopDecodeThread(); + // Protection + WebRtc_Word32 ProcessNACKRequest(const bool enable); + + WebRtc_Word32 ProcessFECRequest(const bool enable, + const unsigned char payloadTypeRED, + const unsigned char payloadTypeFEC); + // General members WebRtc_Word32 _channelId; WebRtc_Word32 _engineId; diff --git a/video_engine/main/source/vie_encoder.cc b/video_engine/main/source/vie_encoder.cc index 82c3889ee4..602d5d88ce 100644 --- a/video_engine/main/source/vie_encoder.cc +++ b/video_engine/main/source/vie_encoder.cc @@ -40,8 +40,10 @@ ViEEncoder::ViEEncoder(WebRtc_Word32 engineId, WebRtc_Word32 channelId, _engineId(engineId), _channelId(channelId), _numberOfCores(numberOfCores), - _vcm(*webrtc::VideoCodingModule::Create(ViEModuleId(engineId, channelId))), - _vpm(*webrtc::VideoProcessingModule::Create(ViEModuleId(engineId, channelId))), + _vcm(*webrtc::VideoCodingModule::Create(ViEModuleId(engineId, + channelId))), + _vpm(*webrtc::VideoProcessingModule::Create(ViEModuleId(engineId, + channelId))), _rtpRtcp(*RtpRtcp::CreateRtpRtcp(ViEModuleId(engineId, channelId), false)), @@ -49,14 +51,15 @@ ViEEncoder::ViEEncoder(WebRtc_Word32 engineId, WebRtc_Word32 channelId, _dataCritsect(*CriticalSectionWrapper::CreateCriticalSection()), _paused(false), _timeLastIntraRequestMs(0), _channelsDroppingDeltaFrames(0), _dropNextFrame(false), - _fecEnabled(false), _codecObserver(NULL), _effectFilter(NULL), - _moduleProcessThread(moduleProcessThread), _hasReceivedSLI(false), - _pictureIdSLI(0), _hasReceivedRPSI(false), _pictureIdRPSI(0), - _fileRecorder(channelId) + _fecEnabled(false), _nackEnabled(false), _codecObserver(NULL), + _effectFilter(NULL), _moduleProcessThread(moduleProcessThread), + _hasReceivedSLI(false), _pictureIdSLI(0), _hasReceivedRPSI(false), + _pictureIdRPSI(0), _fileRecorder(channelId) { - WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(engineId, channelId), - "%s(engineId: %d) 0x%p - Constructor", __FUNCTION__, engineId, - this); + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, + ViEId(engineId, channelId), + "%s(engineId: %d) 0x%p - Constructor", __FUNCTION__, engineId, + this); _vcm.InitializeSender(); _vpm.EnableTemporalDecimation(true); @@ -80,7 +83,8 @@ ViEEncoder::ViEEncoder(WebRtc_Word32 engineId, WebRtc_Word32 channelId, VideoCodec videoCodec; if (_vcm.Codec(webrtc::kVideoCodecVP8, &videoCodec) == VCM_OK) { - _vcm.RegisterSendCodec(&videoCodec, _numberOfCores, _rtpRtcp.MaxDataPayloadLength()); + _vcm.RegisterSendCodec(&videoCodec, _numberOfCores, + _rtpRtcp.MaxDataPayloadLength()); _rtpRtcp.RegisterSendPayload(videoCodec.plName, videoCodec.plType); } else @@ -91,7 +95,8 @@ ViEEncoder::ViEEncoder(WebRtc_Word32 engineId, WebRtc_Word32 channelId, VideoCodec videoCodec; if (_vcm.Codec(webrtc::kVideoCodecI420, &videoCodec) == VCM_OK) { - _vcm.RegisterSendCodec(&videoCodec, _numberOfCores, _rtpRtcp.MaxDataPayloadLength()); + _vcm.RegisterSendCodec(&videoCodec, _numberOfCores, + _rtpRtcp.MaxDataPayloadLength()); _rtpRtcp.RegisterSendPayload(videoCodec.plName, videoCodec.plType); } else @@ -127,8 +132,9 @@ ViEEncoder::ViEEncoder(WebRtc_Word32 engineId, WebRtc_Word32 channelId, ViEEncoder::~ViEEncoder() { - WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(_engineId, _channelId), - "ViEEncoder Destructor 0x%p, engineId: %d", this, _engineId); + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "ViEEncoder Destructor 0x%p, engineId: %d", this, _engineId); if (_rtpRtcp.NumberChildModules() > 0) { @@ -161,16 +167,18 @@ ViEEncoder::~ViEEncoder() void ViEEncoder::Pause() { - WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), - "%s", __FUNCTION__); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s", __FUNCTION__); CriticalSectionScoped cs(_dataCritsect); _paused = true; } void ViEEncoder::Restart() { - WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), - "%s", __FUNCTION__); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s", __FUNCTION__); CriticalSectionScoped cs(_dataCritsect); _paused = false; } @@ -183,8 +191,9 @@ void ViEEncoder::Restart() WebRtc_Word32 ViEEncoder::DropDeltaAfterKey(bool enable) { - WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), - "%s(%d)", __FUNCTION__, enable); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s(%d)", __FUNCTION__, enable); CriticalSectionScoped cs(_dataCritsect); if (enable) @@ -196,9 +205,9 @@ WebRtc_Word32 ViEEncoder::DropDeltaAfterKey(bool enable) if (_channelsDroppingDeltaFrames < 0) { _channelsDroppingDeltaFrames = 0; - WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, - _channelId), - "%s: Called too many times", __FUNCTION__, enable); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Called too many times", __FUNCTION__, enable); return -1; } } @@ -238,12 +247,12 @@ WebRtc_Word32 ViEEncoder::GetCodec(WebRtc_UWord8 listIndex, // ---------------------------------------------------------------------------- // External encoder // ---------------------------------------------------------------------------- -WebRtc_Word32 ViEEncoder::RegisterExternalEncoder( - webrtc::VideoEncoder* encoder, +WebRtc_Word32 ViEEncoder::RegisterExternalEncoder(webrtc::VideoEncoder* encoder, WebRtc_UWord8 plType) { - WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), - "%s: pltype %u", __FUNCTION__, plType); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: pltype %u", __FUNCTION__, plType); if (encoder == NULL) return -1; @@ -260,8 +269,9 @@ WebRtc_Word32 ViEEncoder::RegisterExternalEncoder( WebRtc_Word32 ViEEncoder::DeRegisterExternalEncoder(WebRtc_UWord8 plType) { - WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), - "%s: pltype %u", __FUNCTION__, plType); + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: pltype %u", __FUNCTION__, plType); webrtc::VideoCodec currentSendCodec; if (_vcm.SendCodec(¤tSendCodec) == VCM_OK) @@ -284,9 +294,9 @@ WebRtc_Word32 ViEEncoder::DeRegisterExternalEncoder(WebRtc_UWord8 plType) if (_vcm.RegisterSendCodec(¤tSendCodec, _numberOfCores, maxDataPayloadLength) != VCM_OK) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, - _channelId), - "Could not use internal encoder"); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "Could not use internal encoder"); return -1; } } @@ -299,8 +309,9 @@ WebRtc_Word32 ViEEncoder::DeRegisterExternalEncoder(WebRtc_UWord8 plType) WebRtc_Word32 ViEEncoder::SetEncoder(const webrtc::VideoCodec& videoCodec) { - WEBRTC_TRACE( webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), - "%s: CodecType: %d, width: %u, height: %u, maxPayloadLength: %u", + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: CodecType: %d, width: %u, height: %u, maxPayloadLength: %u", __FUNCTION__, videoCodec.codecType, videoCodec.width, videoCodec.height); @@ -687,6 +698,7 @@ WebRtc_Word32 ViEEncoder::UpdateProtectionMethod() WebRtc_UWord8 dummyPTypeRed = 0; WebRtc_UWord8 dummyPTypeFEC = 0; + // check if fec is enabled WebRtc_Word32 error = _rtpRtcp.GenericFECStatus(fecEnabled, dummyPTypeRed, dummyPTypeFEC); if (error) @@ -694,19 +706,35 @@ WebRtc_Word32 ViEEncoder::UpdateProtectionMethod() return -1; } - if (_fecEnabled != fecEnabled) + // check if nack is enabled + bool nackEnabled = (_rtpRtcp.NACK() == kNackOff) ? false : true; + if (_fecEnabled == fecEnabled && _nackEnabled == nackEnabled) { - WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), - "%s: FEC status ", __FUNCTION__, fecEnabled); + // no change to current state + return 0; + } + _fecEnabled = fecEnabled; + _nackEnabled = nackEnabled; - _vcm.SetVideoProtection(webrtc::kProtectionFEC, fecEnabled); - if (fecEnabled) - { - _vcm.RegisterProtectionCallback(this); - } else - { - _vcm.RegisterProtectionCallback(NULL); - } + // Set Video Protection for VCM + if (fecEnabled && nackEnabled) + { + _vcm.SetVideoProtection(webrtc::kProtectionNackFEC, true); + } + else + { + _vcm.SetVideoProtection(webrtc::kProtectionFEC, _fecEnabled); + _vcm.SetVideoProtection(webrtc::kProtectionNack, _nackEnabled); + _vcm.SetVideoProtection(webrtc::kProtectionNackFEC, false); + } + + // If nack and/or fec is enalbed, the following should be triggered + if (fecEnabled || nackEnabled) + { + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: FEC status ", __FUNCTION__, fecEnabled); + _vcm.RegisterProtectionCallback(this); // Need to reregister the send codec in order to set the new MTU webrtc::VideoCodec codec; if (_vcm.SendCodec(&codec) == 0) @@ -715,19 +743,20 @@ WebRtc_Word32 ViEEncoder::UpdateProtectionMethod() codec.startBitrate = _vcm.Bitrate(); if (_vcm.RegisterSendCodec(&codec, _numberOfCores, maxPayLoad) != 0) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, - _channelId), - "%s: Failed to update Sendcodec when enabling FEC", - __FUNCTION__, fecEnabled); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_engineId, _channelId), + "%s: Failed to update Sendcodec when enabling FEC", + __FUNCTION__, fecEnabled); return -1; } } - _fecEnabled = fecEnabled; + return 0; + } + else + { + // FEC and NACK are disabled + _vcm.RegisterProtectionCallback(NULL); } - - // Update NACK status - _vcm.SetVideoProtection(webrtc::kProtectionNack, _rtpRtcp.NACK() != kNackOff); - return 0; } diff --git a/video_engine/main/source/vie_encoder.h b/video_engine/main/source/vie_encoder.h index 42d297818a..e10b6d5347 100644 --- a/video_engine/main/source/vie_encoder.h +++ b/video_engine/main/source/vie_encoder.h @@ -162,6 +162,7 @@ private: bool _dropNextFrame; //Loss protection bool _fecEnabled; + bool _nackEnabled; // Uses ViEEncoderObserver* _codecObserver; ViEEffectFilter* _effectFilter; diff --git a/video_engine/main/source/vie_receiver.cc b/video_engine/main/source/vie_receiver.cc index 2ec47fac2b..bf14d1534c 100644 --- a/video_engine/main/source/vie_receiver.cc +++ b/video_engine/main/source/vie_receiver.cc @@ -279,12 +279,7 @@ WebRtc_Word32 ViEReceiver::OnReceivedPayloadData(const WebRtc_UWord8* payloadDat { return 0; } - if (rtpHeader->frameType == webrtc::kFrameEmpty) - { - // Don't care about empty rtp packets, we might - // get this e.g. when using FEC - return 0; - } + if (_vcm.IncomingPacket(payloadData, payloadSize, *rtpHeader) != 0) { // Check this... diff --git a/video_engine/main/source/vie_rtp_rtcp_impl.cc b/video_engine/main/source/vie_rtp_rtcp_impl.cc index c4c0f9ff2b..7b6ec3787d 100644 --- a/video_engine/main/source/vie_rtp_rtcp_impl.cc +++ b/video_engine/main/source/vie_rtp_rtcp_impl.cc @@ -651,6 +651,7 @@ int ViERTP_RTCPImpl::SetFECStatus(const int videoChannel, const bool enable, const unsigned char payloadTypeRED, const unsigned char payloadTypeFEC) { + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId, videoChannel), "%s(channel: %d, enable: %d, payloadTypeRED: %u, " @@ -698,6 +699,64 @@ int ViERTP_RTCPImpl::SetFECStatus(const int videoChannel, const bool enable, return 0; } +// ---------------------------------------------------------------------------- +// SetHybridNACKFECStatus +// +// Enables/disables hybrid NACK/FEC and sets the payloadtypes +// ---------------------------------------------------------------------------- + +int ViERTP_RTCPImpl::SetHybridNACKFECStatus(const int videoChannel, + const bool enable, + const unsigned char payloadTypeRED, + const unsigned char payloadTypeFEC) +{ + WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s(channel: %d, enable: %d, payloadTypeRED: %u, " + "payloadTypeFEC: %u)", + __FUNCTION__, videoChannel, enable, payloadTypeRED, + payloadTypeFEC); + + // Get the channel + ViEChannelManagerScoped cs(_channelManager); + ViEChannel* ptrViEChannel = cs.Channel(videoChannel); + if (ptrViEChannel == NULL) + { + // The channel doesn't exists + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Channel %d doesn't exist", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + // Update the channel status with hybrid NACK FEC mode + if (ptrViEChannel->SetHybridNACKFECStatus(enable, payloadTypeRED, + payloadTypeFEC) != 0) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: failed for channel %d", __FUNCTION__, videoChannel); + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + + // Update the encoder + ViEEncoder* ptrViEEncoder = cs.Encoder(videoChannel); + if (ptrViEEncoder == NULL) + { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, + ViEId(_instanceId, videoChannel), + "%s: Could not get encoder for channel %d", __FUNCTION__, + videoChannel); + SetLastError(kViERtpRtcpUnknownError); + return -1; + } + ptrViEEncoder->UpdateProtectionMethod(); + return 0; +} + // ---------------------------------------------------------------------------- // SetKeyFrameRequestMethod // diff --git a/video_engine/main/source/vie_rtp_rtcp_impl.h b/video_engine/main/source/vie_rtp_rtcp_impl.h index 8c429ed3b7..9750a34f41 100644 --- a/video_engine/main/source/vie_rtp_rtcp_impl.h +++ b/video_engine/main/source/vie_rtp_rtcp_impl.h @@ -76,6 +76,9 @@ public: virtual int SetFECStatus(const int videoChannel, const bool enable, const unsigned char payloadTypeRED, const unsigned char payloadTypeFEC); + virtual int SetHybridNACKFECStatus(const int videoChannel, const bool enable, + const unsigned char payloadTypeRED, + const unsigned char payloadTypeFEC); virtual int SetKeyFrameRequestMethod(const int videoChannel, const ViEKeyFrameRequestMethod method);