/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * ViEChannel.cpp */ #include "vie_channel.h" #include "vie_defines.h" #include "critical_section_wrapper.h" #include "rtp_rtcp.h" #include "udp_transport.h" #include "video_coding.h" #include "video_processing.h" #include "video_render_defines.h" #ifdef WEBRTC_SRTP #include "SrtpModule.h" #endif #include "process_thread.h" #include "trace.h" #include "thread_wrapper.h" #include "vie_codec.h" #include "vie_errors.h" #include "vie_image_process.h" #include "vie_rtp_rtcp.h" #include "vie_receiver.h" #include "vie_sender.h" #include "vie_sync_module.h" namespace webrtc { // ---------------------------------------------------------------------------- // Constructor // ---------------------------------------------------------------------------- ViEChannel::ViEChannel(WebRtc_Word32 channelId, WebRtc_Word32 engineId, WebRtc_UWord32 numberOfCores, ProcessThread& moduleProcessThread) : ViEFrameProviderBase(channelId, engineId), _channelId(channelId), _engineId(engineId), _numberOfCores(numberOfCores), _numSocketThreads(kViESocketThreads), _callbackCritsect(*CriticalSectionWrapper::CreateCriticalSection()), _dataCritsect(*CriticalSectionWrapper::CreateCriticalSection()), _rtpRtcp(*RtpRtcp::CreateRtpRtcp( ViEModuleId(engineId, channelId), false)), #ifndef WEBRTC_EXTERNAL_TRANSPORT _socketTransport( *UdpTransport::Create( ViEModuleId(engineId, channelId), _numSocketThreads)), #endif _vcm(*VideoCodingModule::Create( ViEModuleId(engineId, channelId))), _vieReceiver(*(new ViEReceiver(engineId, channelId, _rtpRtcp, _vcm))), _vieSender(*(new ViESender(engineId, channelId, _rtpRtcp))), _vieSync(*(new ViESyncModule(ViEId(engineId, channelId), _vcm, _rtpRtcp))), _moduleProcessThread(moduleProcessThread), _codecObserver(NULL), _doKeyFrameCallbackRequest(false), _rtpObserver(NULL), _rtcpObserver(NULL), _networkObserver(NULL), _rtpPacketTimeout(false), _usingPacketSpread(false), _ptrExternalTransport(NULL), _decoderReset(true), _waitForKeyFrame(false), _ptrDecodeThread(false), _ptrSrtpModuleEncryption(NULL), _ptrSrtpModuleDecryption(NULL), _ptrExternalEncryption(NULL), _effectFilter(NULL), _colorEnhancement(true), _vcmRTTReported(TickTime::Now()), _fileRecorder(channelId) { WEBRTC_TRACE( webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(engineId, channelId), "ViEChannel::ViEChannel(channelId: %d, engineId: %d) - Constructor", channelId, engineId); } WebRtc_Word32 ViEChannel::Init() { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: channelId: %d, engineId: %d)", __FUNCTION__, _channelId, _engineId); // RTP/RTCP initialization if (_rtpRtcp.InitSender() != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: RTP::InitSender failure", __FUNCTION__); return -1; } if (_rtpRtcp.SetSendingMediaStatus(false) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: RTP::SetSendingMediaStatus failure", __FUNCTION__); return -1; } if (_rtpRtcp.InitReceiver() != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: RTP::InitReceiver failure", __FUNCTION__); return -1; } if (_rtpRtcp.RegisterIncomingDataCallback((RtpData*) &_vieReceiver) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: RTP::RegisterIncomingDataCallback failure", __FUNCTION__); return -1; } if (_rtpRtcp.RegisterSendTransport((Transport*) &_vieSender) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: RTP::RegisterSendTransport failure", __FUNCTION__); return -1; } if (_moduleProcessThread.RegisterModule(&_rtpRtcp) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: RTP::RegisterModule failure", __FUNCTION__); return -1; } if (_rtpRtcp.SetKeyFrameRequestMethod(kKeyFrameReqFirRtp) != 0) { WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId,_channelId), "%s: RTP::SetKeyFrameRequestMethod failure", __FUNCTION__); } if (_rtpRtcp.SetRTCPStatus(kRtcpCompound) != 0) { WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: RTP::SetRTCPStatus failure", __FUNCTION__); } if (_rtpRtcp.RegisterIncomingRTPCallback(this) != 0) { WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: RTP::RegisterIncomingRTPCallback failure", __FUNCTION__); return -1; } if (_rtpRtcp.RegisterIncomingRTCPCallback(this) != 0) { WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: RTP::RegisterIncomingRTCPCallback failure", __FUNCTION__); return -1; } // VCM initialization if (_vcm.InitializeReceiver() != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: VCM::InitializeReceiver failure", __FUNCTION__); return -1; } if (_vcm.RegisterReceiveCallback(this) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: VCM::RegisterReceiveCallback failure", __FUNCTION__); return -1; } if (_vcm.RegisterFrameTypeCallback(this) != 0) { WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: VCM::RegisterFrameTypeCallback failure", __FUNCTION__); } if (_vcm.RegisterReceiveStatisticsCallback(this) != 0) { WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: VCM::RegisterReceiveStatisticsCallback failure", __FUNCTION__); } if (_vcm.SetRenderDelay(kViEDefaultRenderDelayMs) != 0) { WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: VCM::SetRenderDelay failure", __FUNCTION__); } if (_moduleProcessThread.RegisterModule(&_vcm) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: VCM::RegisterModule(vcm) failure", __FUNCTION__); return -1; } #ifdef VIDEOCODEC_VP8 VideoCodec videoCodec; if (_vcm.Codec(kVideoCodecVP8, &videoCodec) == VCM_OK) { _rtpRtcp.RegisterSendPayload(videoCodec.plName, videoCodec.plType); _rtpRtcp.RegisterReceivePayload(videoCodec.plName, videoCodec.plType); _vcm.RegisterReceiveCodec(&videoCodec, _numberOfCores); _vcm.RegisterSendCodec(&videoCodec, _numberOfCores, _rtpRtcp.MaxDataPayloadLength()); } else { assert(false); } #endif return 0; } // ---------------------------------------------------------------------------- // Destructor // ---------------------------------------------------------------------------- ViEChannel::~ViEChannel() { WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "ViEChannel Destructor, channelId: %d, engineId: %d", _channelId, _engineId); // Make sure we don't get more callbacks from the RTP module. _rtpRtcp.RegisterIncomingRTPCallback(NULL); _rtpRtcp.RegisterSendTransport(NULL); #ifndef WEBRTC_EXTERNAL_TRANSPORT _socketTransport.StopReceiving(); #endif _moduleProcessThread.DeRegisterModule(&_rtpRtcp); _moduleProcessThread.DeRegisterModule(&_vcm); _moduleProcessThread.DeRegisterModule(&_vieSync); if (_ptrDecodeThread) { StopDecodeThread(); } delete &_vieReceiver; delete &_vieSender; delete &_vieSync; delete &_callbackCritsect; delete &_dataCritsect; // Release modules RtpRtcp::DestroyRtpRtcp(&_rtpRtcp); #ifndef WEBRTC_EXTERNAL_TRANSPORT UdpTransport::Destroy( &_socketTransport); #endif VideoCodingModule::Destroy(&_vcm); } // ============================================================================ // Codec // ============================================================================ // ---------------------------------------------------------------------------- // SetSendCodec // // videoCodec: encoder settings // newStream: the encoder type has changed and we should start a new RTP stream // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetSendCodec(const VideoCodec& videoCodec, bool newStream) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: codecType: %d", __FUNCTION__, videoCodec.codecType); if (videoCodec.codecType == kVideoCodecRED || videoCodec.codecType == kVideoCodecULPFEC) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: codecType: %d is not a valid send codec.", __FUNCTION__, videoCodec.codecType); return -1; } // Update the RTP module with the settigns // Stop and Start the RTP module -> trigger new SSRC bool restartRtp = false; if (_rtpRtcp.Sending() && newStream) { restartRtp = true; _rtpRtcp.SetSendingStatus(false); } if (_rtpRtcp.SetSendBitrate(videoCodec.startBitrate * 1000, videoCodec.minBitrate, videoCodec.maxBitrate) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: could not set send bitrates", __FUNCTION__); return -1; } /* TODO Enable this if H264 is available. * This sets the wanted packetization mode. if(videoCodec.plType==kVideoCodecH264) { if (videoCodec.codecSpecific.H264.packetization == kH264SingleMode) { _rtpRtcp.SetH264PacketizationMode (H264_SINGLE_NAL_MODE); } else { _rtpRtcp.SetH264PacketizationMode(H264_NON_INTERLEAVED_MODE); } if (videoCodec.codecSpecific.H264.configParametersSize > 0) { _rtpRtcp.SetH264SendModeNALU_PPS_SPS(true); } }*/ // Don't log this error, no way to chek in advance if this plType is // registered or not... _rtpRtcp.DeRegisterSendPayload(videoCodec.plType); if (_rtpRtcp.RegisterSendPayload(videoCodec.plName, videoCodec.plType) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: could not register payload type", __FUNCTION__); return -1; } if (restartRtp) { _rtpRtcp.SetSendingStatus(true); } return 0; } // ---------------------------------------------------------------------------- // SetReceiveCodec // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetReceiveCodec(const VideoCodec& videoCodec) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); _rtpRtcp.DeRegisterReceivePayload(videoCodec.plType); if (_rtpRtcp.RegisterReceivePayload(videoCodec.plName, videoCodec.plType) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not register receive payload type", __FUNCTION__); return -1; } if (videoCodec.codecType != kVideoCodecRED && videoCodec.codecType != kVideoCodecULPFEC) { //Register codec type with VCM. But do not register RED or ULPFEC if (_vcm.RegisterReceiveCodec(&videoCodec, _numberOfCores, _waitForKeyFrame) != VCM_OK) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not register decoder", __FUNCTION__); return -1; } } return 0; } // ---------------------------------------------------------------------------- // GetReceiveCodec // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetReceiveCodec(VideoCodec& videoCodec) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); if (_vcm.ReceiveCodec(&videoCodec) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not get receive codec", __FUNCTION__); return -1; } return 0; } // ---------------------------------------------------------------------------- // RegisterCodecObserver // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::RegisterCodecObserver(ViEDecoderObserver* observer) { CriticalSectionScoped cs(_callbackCritsect); if (observer) { if (_codecObserver) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: alread added", __FUNCTION__); return -1; } WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: observer added", __FUNCTION__); _codecObserver = observer; } else { if (!_codecObserver) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: no observer added", __FUNCTION__); return -1; } WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: observer removed", __FUNCTION__); _codecObserver = NULL; } return 0; } // ---------------------------------------------------------------------------- // RegisterExternalDecoder // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::RegisterExternalDecoder( const WebRtc_UWord8 plType, VideoDecoder* decoder, bool decoderRender, //Decoder also render WebRtc_Word32 renderDelay) // Decode and render delay { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); WebRtc_Word32 result = 0; result = _vcm.RegisterExternalDecoder(decoder, plType, decoderRender); if (decoderRender && result == 0) { // Let VCM know how long before the actual render time the decoder needs // to get a frame for decoding. result = _vcm.SetRenderDelay(renderDelay); } return result; } // ---------------------------------------------------------------------------- // DeRegisterExternalDecoder // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::DeRegisterExternalDecoder(const WebRtc_UWord8 plType) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s plType", __FUNCTION__, plType); VideoCodec currentReceiveCodec; WebRtc_Word32 result = 0; result = _vcm.ReceiveCodec(¤tReceiveCodec); if (_vcm.RegisterExternalDecoder(NULL, plType, false) != VCM_OK) { return -1; } if (result == 0 && currentReceiveCodec.plType == plType) { result = _vcm.RegisterReceiveCodec(¤tReceiveCodec, _numberOfCores, _waitForKeyFrame); } return result; } // ---------------------------------------------------------------------------- // ReceiveCodecStatistics // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::ReceiveCodecStatistics(WebRtc_UWord32& numKeyFrames, WebRtc_UWord32& numDeltaFrames) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); VCMFrameCount receivedFrames; if (_vcm.ReceivedFrameCount(receivedFrames) != VCM_OK) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not get received frame information", __FUNCTION__); return -1; } numKeyFrames = receivedFrames.numKeyFrames; numDeltaFrames = receivedFrames.numDeltaFrames; return 0; } // ---------------------------------------------------------------------------- // WaitForKeyFrame // // Only affects calls to SetReceiveCodec done after this call. // Default = false // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::WaitForKeyFrame(bool wait) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s(wait: %d)", __FUNCTION__, wait); _waitForKeyFrame = wait; return 0; } // ---------------------------------------------------------------------------- // SetSignalPacketLossStatus // // If enabled, a key frame request will be sent as soon as there are lost // packets. If onlyKeyFrames are set, requests are only sent for loss in key // frames. // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetSignalPacketLossStatus(bool enable, bool onlyKeyFrames) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s(enable: %d)", __FUNCTION__, enable); if (enable) { if (onlyKeyFrames) { _vcm.SetVideoProtection(kProtectionKeyOnLoss, false); if (_vcm.SetVideoProtection(kProtectionKeyOnKeyLoss, true) != VCM_OK) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s failed %d", __FUNCTION__, enable); return -1; } } else { _vcm.SetVideoProtection(kProtectionKeyOnKeyLoss, false); if (_vcm.SetVideoProtection(kProtectionKeyOnLoss, true) != VCM_OK) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s failed %d", __FUNCTION__, enable); return -1; } } } else { _vcm.SetVideoProtection(kProtectionKeyOnLoss, false); _vcm.SetVideoProtection(kProtectionKeyOnKeyLoss, false); } return 0; } // ============================================================================ // RTP/RTCP // ============================================================================ // ---------------------------------------------------------------------------- // SetRTCPMode // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetRTCPMode(const RTCPMethod rtcpMode) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: %d", __FUNCTION__, rtcpMode); return _rtpRtcp.SetRTCPStatus(rtcpMode); } // ---------------------------------------------------------------------------- // GetRTCPMode // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetRTCPMode(RTCPMethod& rtcpMode) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); rtcpMode = _rtpRtcp.RTCP(); return 0; } // ---------------------------------------------------------------------------- // EnableNACKStatus // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetNACKStatus(const bool 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); return -1; } if (enable) { // Disable possible FEC SetFECStatus(false, 0, 0); // Turn on NACK, NACKMethod nackMethod = kNackRtcp; if (_rtpRtcp.RTCP() == kRtcpOff) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not enable NACK, RTPC not on ", __FUNCTION__); return -1; } if (_rtpRtcp.SetNACKStatus(nackMethod) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not set NACK method %d", __FUNCTION__, nackMethod); return -1; } WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Using NACK method %d", __FUNCTION__, nackMethod); _rtpRtcp.SetStorePacketsStatus(true, kNackHistorySize); _vcm.RegisterPacketRequestCallback(this); } else { _rtpRtcp.SetStorePacketsStatus(false); _vcm.RegisterPacketRequestCallback(NULL); if (_rtpRtcp.SetNACKStatus(kNackOff) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not turn off NACK", __FUNCTION__); return -1; } } return 0; } // ---------------------------------------------------------------------------- // SetFECStatus // ---------------------------------------------------------------------------- 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); } if (_rtpRtcp.SetGenericFECStatus(enable, payloadTypeRED, payloadTypeFEC) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not change FEC status to %d", __FUNCTION__, enable); return -1; } return 0; } // ---------------------------------------------------------------------------- // KeyFrameRequestMethod // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetKeyFrameRequestMethod( const KeyFrameRequestMethod method) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: %d", __FUNCTION__, method); return _rtpRtcp.SetKeyFrameRequestMethod(method); } // ---------------------------------------------------------------------------- // EnableTMMBR // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::EnableTMMBR(const bool enable) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: %d", __FUNCTION__, enable); return _rtpRtcp.SetTMMBRStatus(enable); } // ---------------------------------------------------------------------------- // EnableKeyFrameRequestCallback // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::EnableKeyFrameRequestCallback(const bool enable) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: %d", __FUNCTION__, enable); CriticalSectionScoped cs(_callbackCritsect); if (enable && _codecObserver == NULL) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: No ViECodecObserver set", __FUNCTION__, enable); return -1; } _doKeyFrameCallbackRequest = enable; return 0; } // ---------------------------------------------------------------------------- // SetSSRC // // Sets SSRC for outgoing stream // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetSSRC(const WebRtc_UWord32 SSRC) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s(SSRC: %u)", __FUNCTION__, SSRC); return _rtpRtcp.SetSSRC(SSRC); } // ---------------------------------------------------------------------------- // SetSSRC // // Gets SSRC for outgoing stream // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetLocalSSRC(WebRtc_UWord32& SSRC) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); SSRC = _rtpRtcp.SSRC(); return 0; } // ---------------------------------------------------------------------------- // GetRemoteSSRC // // Gets SSRC for the incoming stream // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetRemoteSSRC(WebRtc_UWord32& SSRC) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); SSRC = _rtpRtcp.RemoteSSRC(); return 0; } // ---------------------------------------------------------------------------- // GetRemoteCSRC // // Gets the CSRC for the incoming stream // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetRemoteCSRC(unsigned int CSRCs[kRtpCsrcSize]) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); WebRtc_UWord32 arrayCSRC[kRtpCsrcSize]; memset(arrayCSRC, 0, sizeof(arrayCSRC)); WebRtc_Word32 numCSRCs = _rtpRtcp.RemoteCSRCs(arrayCSRC); if (numCSRCs > 0) { memcpy(CSRCs, arrayCSRC, numCSRCs * sizeof(WebRtc_UWord32)); for (int idx = 0; idx < numCSRCs; idx++) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "\tCSRC[%d] = %lu", idx, CSRCs[idx]); } } else { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: CSRC list is empty", __FUNCTION__); } return 0; } // ---------------------------------------------------------------------------- // SetStartSequenceNumber // // Sets the starting sequence number, must be called before StartSend. // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetStartSequenceNumber(WebRtc_UWord16 sequenceNumber) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); if (_rtpRtcp.Sending()) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: already sending", __FUNCTION__); return -1; } return _rtpRtcp.SetSequenceNumber(sequenceNumber); } // ---------------------------------------------------------------------------- // SetRTCPCName // // Sets the CName for the outgoing stream on the channel // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetRTCPCName(const WebRtc_Word8 rtcpCName[]) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); if (_rtpRtcp.Sending()) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: already sending", __FUNCTION__); return -1; } return _rtpRtcp.SetCNAME(rtcpCName); } // ---------------------------------------------------------------------------- // GetRTCPCName // // Gets the CName for the outgoing stream on the channel // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetRTCPCName(WebRtc_Word8 rtcpCName[]) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); return _rtpRtcp.CNAME(rtcpCName); } // ---------------------------------------------------------------------------- // GetRemoteRTCPCName // // Gets the CName of the incoming stream // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetRemoteRTCPCName(WebRtc_Word8 rtcpCName[]) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); WebRtc_UWord32 remoteSSRC = _rtpRtcp.RemoteSSRC(); return _rtpRtcp.RemoteCNAME(remoteSSRC, rtcpCName); } // ---------------------------------------------------------------------------- // RegisterRtpObserver // // Registers an RTP observer // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::RegisterRtpObserver(ViERTPObserver* observer) { CriticalSectionScoped cs(_callbackCritsect); if (observer) { if (_rtpObserver) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: observer alread added", __FUNCTION__); return -1; } WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: observer added", __FUNCTION__); _rtpObserver = observer; } else { if (!_rtpObserver) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: no observer added", __FUNCTION__); return -1; } WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: observer removed", __FUNCTION__); _rtpObserver = NULL; } return 0; } // ---------------------------------------------------------------------------- // RegisterRtcpObserver // // Registers an RTPC observer // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::RegisterRtcpObserver(ViERTCPObserver* observer) { CriticalSectionScoped cs(_callbackCritsect); if (observer) { if (_rtcpObserver) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: observer alread added", __FUNCTION__); return -1; } WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: observer added", __FUNCTION__); _rtcpObserver = observer; } else { if (!_rtcpObserver) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: no observer added", __FUNCTION__); return -1; } WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: observer removed", __FUNCTION__); _rtcpObserver = NULL; } return 0; } // ---------------------------------------------------------------------------- // SendApplicationDefinedRTCPPacket // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SendApplicationDefinedRTCPPacket( const WebRtc_UWord8 subType, WebRtc_UWord32 name, const WebRtc_UWord8* data, WebRtc_UWord16 dataLengthInBytes) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); // Sanity checks if (!_rtpRtcp.Sending()) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not sending", __FUNCTION__); return -1; } if (data == NULL) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: no input argument", __FUNCTION__); return -1; } if (dataLengthInBytes % 4 != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: input length error", __FUNCTION__); return -1; } RTCPMethod rtcpMethod = _rtpRtcp.RTCP(); if (rtcpMethod == kRtcpOff) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: RTCP not enabled", __FUNCTION__); return -1; } // Create and send packet if (_rtpRtcp.SetRTCPApplicationSpecificData(subType, name, data, dataLengthInBytes) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not send RTCP application data", __FUNCTION__); return -1; } return 0; } // ---------------------------------------------------------------------------- // GetSendRtcpStatistics // // Gets statistics sent in RTCP packets to remote side // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetSendRtcpStatistics(WebRtc_UWord16& fractionLost, WebRtc_UWord32& cumulativeLost, WebRtc_UWord32& extendedMax, WebRtc_UWord32& jitterSamples, WebRtc_Word32& rttMs) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); WebRtc_UWord32 remoteSSRC = _rtpRtcp.RemoteSSRC(); RTCPReportBlock remoteStat; if (_rtpRtcp.RemoteRTCPStat(remoteSSRC, &remoteStat) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not get remote stats", __FUNCTION__); return -1; } fractionLost = remoteStat.fractionLost; cumulativeLost = remoteStat.cumulativeLost; extendedMax = remoteStat.extendedHighSeqNum; jitterSamples = remoteStat.jitter; WebRtc_UWord16 dummy; WebRtc_UWord16 rtt = 0; if (_rtpRtcp.RTT(remoteSSRC, &rtt, &dummy, &dummy, &dummy) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not get RTT", __FUNCTION__); return -1; } rttMs = rtt; return 0; } // ---------------------------------------------------------------------------- // GetSendRtcpStatistics // // Gets statistics received in RTCP packets from remote side // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetReceivedRtcpStatistics( WebRtc_UWord16& fractionLost, WebRtc_UWord32& cumulativeLost, WebRtc_UWord32& extendedMax, WebRtc_UWord32& jitterSamples, WebRtc_Word32& rttMs) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); WebRtc_UWord8 fracLost = 0; if (_rtpRtcp.StatisticsRTP(&fracLost, &cumulativeLost, &extendedMax, &jitterSamples) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not get received RTP statistics", __FUNCTION__); return -1; } fractionLost = fracLost; WebRtc_UWord32 remoteSSRC = _rtpRtcp.RemoteSSRC(); WebRtc_UWord16 dummy = 0; WebRtc_UWord16 rtt = 0; if (_rtpRtcp.RTT(remoteSSRC, &rtt, &dummy, &dummy, &dummy) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not get RTT", __FUNCTION__); return -1; } rttMs = rtt; return 0; } // ---------------------------------------------------------------------------- // GetRtpStatistics // // Gets sent/received packets statistics // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetRtpStatistics( WebRtc_UWord32& bytesSent, WebRtc_UWord32& packetsSent, WebRtc_UWord32& bytesReceived, WebRtc_UWord32& packetsReceived) const { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); if (_rtpRtcp.DataCountersRTP(&bytesSent, &packetsSent, &bytesReceived, &packetsReceived) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not get RTT", __FUNCTION__); return -1; } return 0; } // ---------------------------------------------------------------------------- // SetKeepAliveStatus // // Enables/disbles RTP keeoalive // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetKeepAliveStatus( const bool enable, const WebRtc_Word8 unknownPayloadType, const WebRtc_UWord16 deltaTransmitTimeMS) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); if (enable && _rtpRtcp.RTPKeepalive()) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: RTP keepalive already enabled", __FUNCTION__); return -1; } else if (!enable && !_rtpRtcp.RTPKeepalive()) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: RTP keepalive already disabled", __FUNCTION__); return -1; } if (_rtpRtcp.SetRTPKeepaliveStatus(enable, unknownPayloadType, deltaTransmitTimeMS) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not set RTP keepalive status %d", __FUNCTION__, enable); if (enable == false && !_rtpRtcp.DefaultModuleRegistered()) { // Not sending media and we try to disable keep alive _rtpRtcp.ResetSendDataCountersRTP(); _rtpRtcp.SetSendingStatus(false); } return -1; } if (enable && !_rtpRtcp.Sending()) { // Enable sending to start sending Sender reports instead of receive // reports if (_rtpRtcp.SetSendingStatus(true) != 0) { _rtpRtcp.SetRTPKeepaliveStatus(false, 0, 0); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not start sending", __FUNCTION__); return -1; } } else if (!enable && !_rtpRtcp.SendingMedia()) { // Not sending media and we're disabling keep alive _rtpRtcp.ResetSendDataCountersRTP(); if (_rtpRtcp.SetSendingStatus(false) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not stop sending", __FUNCTION__); return -1; } } return 0; } // ---------------------------------------------------------------------------- // GetKeepAliveStatus // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetKeepAliveStatus( bool& enabled, WebRtc_Word8& unknownPayloadType, WebRtc_UWord16& deltaTransmitTimeMs) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); if (_rtpRtcp.RTPKeepaliveStatus(&enabled, &unknownPayloadType, &deltaTransmitTimeMs) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not get RTP keepalive status", __FUNCTION__); return -1; } WEBRTC_TRACE( webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: enabled = %d, unknownPayloadType = %d, deltaTransmitTimeMs = %ul", __FUNCTION__, enabled, (WebRtc_Word32) unknownPayloadType, deltaTransmitTimeMs); return 0; } // ---------------------------------------------------------------------------- // StartRTPDump // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::StartRTPDump(const char fileNameUTF8[1024], RTPDirections direction) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); if (direction != kRtpIncoming && direction != kRtpOutgoing) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: invalid input", __FUNCTION__); return -1; } RtpDump* rtpDump = NULL; if (direction == kRtpIncoming) { return _vieReceiver.StartRTPDump(fileNameUTF8); } else { return _vieSender.StartRTPDump(fileNameUTF8); } } // ---------------------------------------------------------------------------- // StopRTPDump // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::StopRTPDump(RTPDirections direction) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); if (direction != kRtpIncoming && direction != kRtpOutgoing) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: invalid input", __FUNCTION__); return -1; } RtpDump* rtpDump = NULL; if (direction == kRtpIncoming) { return _vieReceiver.StopRTPDump(); } else { return _vieSender.StopRTPDump(); } } // ============================================================================ // Network // ============================================================================ // ---------------------------------------------------------------------------- // SetLocalReceiver // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetLocalReceiver(const WebRtc_UWord16 rtpPort, const WebRtc_UWord16 rtcpPort, const WebRtc_Word8* ipAddress) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); _callbackCritsect.Enter(); if (_ptrExternalTransport) { _callbackCritsect.Leave(); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: external transport registered", __FUNCTION__); return -1; } _callbackCritsect.Leave(); #ifndef WEBRTC_EXTERNAL_TRANSPORT if (_socketTransport.Receiving()) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: already receiving", __FUNCTION__); return -1; } const WebRtc_Word8* multicastIpAddress = NULL; if (_socketTransport.InitializeReceiveSockets(&_vieReceiver, rtpPort, ipAddress, multicastIpAddress, rtcpPort) != 0) { WebRtc_Word32 socketError = _socketTransport.LastError(); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: could not initialize receive sockets. Socket error: %d", __FUNCTION__, socketError); return -1; } return 0; #else WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not available for external transport", __FUNCTION__); return -1; #endif } // ---------------------------------------------------------------------------- // GetLocalReceiver // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetLocalReceiver(WebRtc_UWord16& rtpPort, WebRtc_UWord16& rtcpPort, WebRtc_Word8* ipAddress) const { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); _callbackCritsect.Enter(); if (_ptrExternalTransport) { _callbackCritsect.Leave(); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: external transport registered", __FUNCTION__); return -1; } _callbackCritsect.Leave(); #ifndef WEBRTC_EXTERNAL_TRANSPORT if (_socketTransport.ReceiveSocketsInitialized() == false) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: receive sockets not initialized", __FUNCTION__); return -1; } WebRtc_Word8 multicastIpAddress[UdpTransport:: kIpAddressVersion6Length]; if (_socketTransport.ReceiveSocketInformation(ipAddress, rtpPort, rtcpPort, multicastIpAddress) != 0) { WebRtc_Word32 socketError = _socketTransport.LastError(); WEBRTC_TRACE( webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: could not get receive socket information. Socket error: %d", __FUNCTION__, socketError); return -1; } return 0; #else WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not available for external transport", __FUNCTION__); return -1; #endif } // ---------------------------------------------------------------------------- // SetSendDestination // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetSendDestination( const WebRtc_Word8* ipAddress, const WebRtc_UWord16 rtpPort, const WebRtc_UWord16 rtcpPort, const WebRtc_UWord16 sourceRtpPort, const WebRtc_UWord16 sourceRtcpPort) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); _callbackCritsect.Enter(); if (_ptrExternalTransport) { _callbackCritsect.Leave(); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: external transport registered", __FUNCTION__); return -1; } _callbackCritsect.Leave(); #ifndef WEBRTC_EXTERNAL_TRANSPORT const bool isIPv6 = _socketTransport.IpV6Enabled(); if (UdpTransport::IsIpAddressValid(ipAddress, isIPv6) == false) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Not a valid IP address: %s", __FUNCTION__, ipAddress); return -1; } if (_socketTransport.InitializeSendSockets(ipAddress, rtpPort, rtcpPort) != 0) { WebRtc_Word32 socketError = _socketTransport.LastError(); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: could not initialize send socket. Socket error: %d", __FUNCTION__, socketError); return -1; } if (sourceRtpPort != 0) { WebRtc_UWord16 receiveRtpPort = 0; WebRtc_UWord16 receiveRtcpPort = 0; if (_socketTransport.ReceiveSocketInformation(NULL, receiveRtpPort, receiveRtcpPort, NULL) != 0) { WebRtc_Word32 socketError = _socketTransport.LastError(); WEBRTC_TRACE( webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: could not get receive port information. Socket error: %d", __FUNCTION__, socketError); return -1; } // Initialize an extra socket only if send port differs from receive // port if (sourceRtpPort != receiveRtpPort) { if (_socketTransport.InitializeSourcePorts(sourceRtpPort, sourceRtcpPort) != 0) { WebRtc_Word32 socketError = _socketTransport.LastError(); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: could not set source ports. Socket error: %d", __FUNCTION__, socketError); return -1; } } } _vieSender.RegisterSendTransport(&_socketTransport); // Workaround to avoid SSRC colision detection in loppback tests if (!isIPv6) { WebRtc_UWord32 localHostAddress = 0; const WebRtc_UWord32 currentIpAddress = UdpTransport::InetAddrIPV4(ipAddress); if ((UdpTransport::LocalHostAddress(localHostAddress) == 0 && localHostAddress == currentIpAddress) || strncmp("127.0.0.1", ipAddress, 9) == 0) { _rtpRtcp.SetSSRC(0xFFFFFFFF); WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "Running in loopback. Forcing fixed SSRC"); } } else { WebRtc_UWord8 localHostAddress[16]; WebRtc_UWord8 currentIpAddress[16]; WebRtc_Word32 convResult = UdpTransport::LocalHostAddressIPV6(localHostAddress); convResult += _socketTransport.InetPresentationToNumeric(23, ipAddress, currentIpAddress); if (convResult == 0) { bool localHost = true; for (WebRtc_Word32 i = 0; i < 16; i++) { if (localHostAddress[i] != currentIpAddress[i]) { localHost = false; break; } } if (!localHost) { localHost = true; for (WebRtc_Word32 i = 0; i < 15; i++) { if (currentIpAddress[i] != 0) { localHost = false; break; } } if (localHost == true && currentIpAddress[15] != 1) { localHost = false; } } if (localHost) { _rtpRtcp.SetSSRC(0xFFFFFFFF); WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "Running in loopback. Forcing fixed SSRC"); } } } return 0; #else WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not available for external transport", __FUNCTION__); return -1; #endif } // ---------------------------------------------------------------------------- // GetSendDestination // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetSendDestination( WebRtc_Word8* ipAddress, WebRtc_UWord16& rtpPort, WebRtc_UWord16& rtcpPort, WebRtc_UWord16& sourceRtpPort, WebRtc_UWord16& sourceRtcpPort) const { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); _callbackCritsect.Enter(); if (_ptrExternalTransport) { _callbackCritsect.Leave(); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: external transport registered", __FUNCTION__); return -1; } _callbackCritsect.Leave(); #ifndef WEBRTC_EXTERNAL_TRANSPORT if (_socketTransport.SendSocketsInitialized() == false) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: send sockets not initialized", __FUNCTION__); return -1; } if (_socketTransport.SendSocketInformation(ipAddress, rtpPort, rtcpPort) != 0) { WebRtc_Word32 socketError = _socketTransport.LastError(); WEBRTC_TRACE( webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: could not get send socket information. Socket error: %d", __FUNCTION__, socketError); return -1; } sourceRtpPort = 0; sourceRtcpPort = 0; if (_socketTransport.SourcePortsInitialized()) { _socketTransport.SourcePorts(sourceRtpPort, sourceRtcpPort); } return 0; #else WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not available for external transport", __FUNCTION__); return -1; #endif } // ---------------------------------------------------------------------------- // StartSend // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::StartSend() { CriticalSectionScoped cs(_callbackCritsect); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); #ifndef WEBRTC_EXTERNAL_TRANSPORT if (!_ptrExternalTransport) { if (_socketTransport.SendSocketsInitialized() == false) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId,_channelId), "%s: send sockets not initialized", __FUNCTION__); return -1; } } #endif _rtpRtcp.SetSendingMediaStatus(true); if (_rtpRtcp.Sending() && !_rtpRtcp.RTPKeepalive()) { if (_rtpRtcp.RTPKeepalive()) { // Sending Keep alive, don't trigger an error return 0; } // Already sending WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Already sending", __FUNCTION__); return kViEBaseAlreadySending; } if (_rtpRtcp.SetSendingStatus(true) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not start sending RTP", __FUNCTION__); return -1; } return 0; } // ---------------------------------------------------------------------------- // StopSend // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::StopSend() { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); _rtpRtcp.SetSendingMediaStatus(false); if (_rtpRtcp.RTPKeepalive()) { // Don't turn off sending since we'll send keep alive packets return 0; } if (!_rtpRtcp.Sending()) { WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Not sending", __FUNCTION__); return kViEBaseNotSending; } // Reset _rtpRtcp.ResetSendDataCountersRTP(); if (_rtpRtcp.SetSendingStatus(false) != 0) { WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: could not stop RTP sending", __FUNCTION__); return -1; } return 0; } // ---------------------------------------------------------------------------- // Sending // ---------------------------------------------------------------------------- bool ViEChannel::Sending() { return _rtpRtcp.Sending(); } // ---------------------------------------------------------------------------- // StartReceive // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::StartReceive() { CriticalSectionScoped cs(_callbackCritsect); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); #ifndef WEBRTC_EXTERNAL_TRANSPORT if (!_ptrExternalTransport) { if (_socketTransport.Receiving()) { // Warning, don't return error WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: already receiving", __FUNCTION__); return 0; } if (_socketTransport.ReceiveSocketsInitialized() == false) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: receive sockets not initialized", __FUNCTION__); return -1; } if (_socketTransport.StartReceiving(kViENumReceiveSocketBuffers) != 0) { WebRtc_Word32 socketError = _socketTransport.LastError(); WEBRTC_TRACE( webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: could not get receive socket information. Socket error:%d", __FUNCTION__, socketError); return -1; } } #endif if (StartDecodeThread() != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: could not start decoder thread", __FUNCTION__); #ifndef WEBRTC_EXTERNAL_TRANSPORT _socketTransport.StopReceiving(); #endif _vieReceiver.StopReceive(); return -1; } _vieReceiver.StartReceive(); return 0; } // ---------------------------------------------------------------------------- // StopReceive // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::StopReceive() { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); _vieReceiver.StopReceive(); StopDecodeThread(); _vcm.ResetDecoder(); { CriticalSectionScoped cs(_callbackCritsect); if (_ptrExternalTransport) { return 0; } } #ifndef WEBRTC_EXTERNAL_TRANSPORT if (_socketTransport.Receiving() == false) { // Warning, don't return error WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not receiving", __FUNCTION__); return 0; } if (_socketTransport.StopReceiving() != 0) { WebRtc_Word32 socketError = _socketTransport.LastError(); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Socket error: %d", __FUNCTION__, socketError); return -1; } #endif return 0; } bool ViEChannel::Receiving() { #ifndef WEBRTC_EXTERNAL_TRANSPORT return _socketTransport.Receiving(); #else return false; #endif } // ---------------------------------------------------------------------------- // GetSourceInfo // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetSourceInfo(WebRtc_UWord16& rtpPort, WebRtc_UWord16& rtcpPort, WebRtc_Word8* ipAddress, WebRtc_UWord32 ipAddressLength) { { CriticalSectionScoped cs(_callbackCritsect); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); if (_ptrExternalTransport) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: external transport registered", __FUNCTION__); return -1; } } #ifndef WEBRTC_EXTERNAL_TRANSPORT if (_socketTransport.IpV6Enabled() && ipAddressLength < UdpTransport::kIpAddressVersion6Length) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: IP address length is too small for IPv6", __FUNCTION__); return -1; } else if (ipAddressLength < UdpTransport::kIpAddressVersion4Length) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: IP address length is too small for IPv4", __FUNCTION__); return -1; } if (_socketTransport.RemoteSocketInformation(ipAddress, rtpPort, rtcpPort) != 0) { WebRtc_Word32 socketError = _socketTransport.LastError(); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Error getting source ports. Socket error: %d", __FUNCTION__, socketError); return -1; } return 0; #else WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not available for external transport", __FUNCTION__); return -1; #endif } // ---------------------------------------------------------------------------- // RegisterSendTransport // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::RegisterSendTransport(Transport& transport) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); #ifndef WEBRTC_EXTERNAL_TRANSPORT if (_socketTransport.SendSocketsInitialized() || _socketTransport.ReceiveSocketsInitialized()) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: socket transport already initialized", __FUNCTION__); return -1; } #endif if (_rtpRtcp.Sending()) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Sending", __FUNCTION__); return -1; } CriticalSectionScoped cs(_callbackCritsect); if (_ptrExternalTransport) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: transport already registered", __FUNCTION__); return -1; } _ptrExternalTransport = &transport; _vieSender.RegisterSendTransport(&transport); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Transport registered: 0x%p", __FUNCTION__, &_ptrExternalTransport); return 0; } // ---------------------------------------------------------------------------- // DeregisterSendTransport // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::DeregisterSendTransport() { CriticalSectionScoped cs(_callbackCritsect); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); if (_ptrExternalTransport == NULL) { WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: no transport registered", __FUNCTION__); return -1; } if (_rtpRtcp.Sending()) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Sending", __FUNCTION__); return -1; } _ptrExternalTransport = NULL; _vieSender.DeregisterSendTransport(); return 0; } // ---------------------------------------------------------------------------- // ReceivedRTPPacket // // Incoming packet from external transport // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::ReceivedRTPPacket(const void* rtpPacket, const WebRtc_Word32 rtpPacketLength) { { CriticalSectionScoped cs(_callbackCritsect); if (!_ptrExternalTransport) { return -1; } } return _vieReceiver.ReceivedRTPPacket(rtpPacket, rtpPacketLength); } // ---------------------------------------------------------------------------- // ReceivedRTPPacket // // Incoming packet from external transport // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::ReceivedRTCPPacket( const void* rtcpPacket, const WebRtc_Word32 rtcpPacketLength) { { CriticalSectionScoped cs(_callbackCritsect); if (!_ptrExternalTransport) { return -1; } } return _vieReceiver.ReceivedRTCPPacket(rtcpPacket, rtcpPacketLength); } // ---------------------------------------------------------------------------- // EnableIPv6 // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::EnableIPv6() { _callbackCritsect.Enter(); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); if (_ptrExternalTransport) { _callbackCritsect.Leave(); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: External transport registered", __FUNCTION__); return -1; } _callbackCritsect.Leave(); #ifndef WEBRTC_EXTERNAL_TRANSPORT if (_socketTransport.IpV6Enabled()) { WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: IPv6 already enabled", __FUNCTION__); return -1; } if (_socketTransport.EnableIpV6() != 0) { WebRtc_Word32 socketError = _socketTransport.LastError(); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: could not enable IPv6. Socket error: %d", __FUNCTION__, socketError); return -1; } return 0; #else WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not available for external transport", __FUNCTION__); return -1; #endif } // ---------------------------------------------------------------------------- // IsIPv6Enabled // ---------------------------------------------------------------------------- bool ViEChannel::IsIPv6Enabled() { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); { CriticalSectionScoped cs(_callbackCritsect); if (_ptrExternalTransport) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: External transport registered", __FUNCTION__); return false; } } #ifndef WEBRTC_EXTERNAL_TRANSPORT return _socketTransport.IpV6Enabled(); #else WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not available for external transport", __FUNCTION__); return false; #endif } // ---------------------------------------------------------------------------- // SetSourceFilter // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetSourceFilter(const WebRtc_UWord16 rtpPort, const WebRtc_UWord16 rtcpPort, const WebRtc_Word8* ipAddress) { _callbackCritsect.Enter(); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); if (_ptrExternalTransport) { _callbackCritsect.Leave(); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: External transport registered", __FUNCTION__); return -1; } _callbackCritsect.Leave(); #ifndef WEBRTC_EXTERNAL_TRANSPORT if (_socketTransport.SetFilterIP(ipAddress) != 0) { // Logging done in module return -1; } if (_socketTransport.SetFilterPorts(rtpPort, rtcpPort) != 0) { // Logging done return -1; } return 0; #else WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not available for external transport", __FUNCTION__); return -1; #endif } // ---------------------------------------------------------------------------- // GetSourceFilter // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetSourceFilter(WebRtc_UWord16& rtpPort, WebRtc_UWord16& rtcpPort, WebRtc_Word8* ipAddress) const { _callbackCritsect.Enter(); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); if (_ptrExternalTransport) { _callbackCritsect.Leave(); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: External transport registered", __FUNCTION__); return -1; } _callbackCritsect.Leave(); #ifndef WEBRTC_EXTERNAL_TRANSPORT if (_socketTransport.FilterIP(ipAddress) != 0) { // Logging done in module return -1; } if (_socketTransport.FilterPorts(rtpPort, rtcpPort) != 0) { // Logging done in module return -1; } return 0; #else WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not available for external transport", __FUNCTION__); return -1; #endif } // ---------------------------------------------------------------------------- // SetToS // ---------------------------------------------------------------------------- // ToS WebRtc_Word32 ViEChannel::SetToS(const WebRtc_Word32 DSCP, const bool useSetSockOpt) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); { CriticalSectionScoped cs(_callbackCritsect); if (_ptrExternalTransport) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: External transport registered", __FUNCTION__); return -1; } } #ifndef WEBRTC_EXTERNAL_TRANSPORT if (_socketTransport.SetToS(DSCP, useSetSockOpt) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Socket error: %d", __FUNCTION__, _socketTransport.LastError()); return -1; } return 0; #else WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not available for external transport", __FUNCTION__); return -1; #endif } // ---------------------------------------------------------------------------- // GetToS // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetToS(WebRtc_Word32& DSCP, bool& useSetSockOpt) const { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); { CriticalSectionScoped cs(_callbackCritsect); if (_ptrExternalTransport) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: External transport registered", __FUNCTION__); return -1; } } #ifndef WEBRTC_EXTERNAL_TRANSPORT if (_socketTransport.ToS(DSCP, useSetSockOpt) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Socket error: %d", __FUNCTION__, _socketTransport.LastError()); return -1; } return 0; #else WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not available for external transport", __FUNCTION__); return -1; #endif } // ---------------------------------------------------------------------------- // SetSendGQoS // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetSendGQoS(const bool enable, const WebRtc_Word32 serviceType, const WebRtc_UWord32 maxBitrate, const WebRtc_Word32 overrideDSCP) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); { CriticalSectionScoped cs(_callbackCritsect); if (_ptrExternalTransport) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: External transport registered", __FUNCTION__); return -1; } } #ifndef WEBRTC_EXTERNAL_TRANSPORT if (_socketTransport.SetQoS(enable, serviceType, maxBitrate, overrideDSCP, false) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Socket error: %d", __FUNCTION__, _socketTransport.LastError()); return -1; } return 0; #else WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not available for external transport", __FUNCTION__); return -1; #endif } // ---------------------------------------------------------------------------- // GetSendGQoS // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::GetSendGQoS(bool& enabled, WebRtc_Word32& serviceType, WebRtc_Word32& overrideDSCP) const { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); { CriticalSectionScoped cs(_callbackCritsect); if (_ptrExternalTransport) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: External transport registered", __FUNCTION__); return -1; } } #ifndef WEBRTC_EXTERNAL_TRANSPORT if (_socketTransport.QoS(enabled, serviceType, overrideDSCP) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Socket error: %d", __FUNCTION__, _socketTransport.LastError()); return -1; } return 0; #else WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not available for external transport", __FUNCTION__); return -1; #endif } // ---------------------------------------------------------------------------- // SetMTU // // Sets the maximum transfer unit size for the network link, i.e. including // IP, UDP[/TCP] and RTP headers, // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetMTU(WebRtc_UWord16 mtu) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); if (_rtpRtcp.SetMaxTransferUnit(mtu) != 0) { // Logging done return -1; } return 0; } // ---------------------------------------------------------------------------- // GetMaxDataPayloadLength // // maxDataPayloadLength: maximum allowed payload size, i.e. the maximum // allowed size of encoded data in each packet. // ---------------------------------------------------------------------------- WebRtc_UWord16 ViEChannel::MaxDataPayloadLength() const { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); return _rtpRtcp.MaxDataPayloadLength(); } // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // SetPacketTimeoutNotification // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetPacketTimeoutNotification( bool enable, WebRtc_UWord32 timeoutSeconds) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); if (enable) { WebRtc_UWord32 timeoutMs = 1000 * timeoutSeconds; if (_rtpRtcp.SetPacketTimeout(timeoutMs, 0) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); return -1; } } else { if (_rtpRtcp.SetPacketTimeout(0, 0) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId,_channelId), "%s", __FUNCTION__); return -1; } } return 0; } // ---------------------------------------------------------------------------- // RegisterObserver // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::RegisterNetworkObserver( ViENetworkObserver* observer) { CriticalSectionScoped cs(_callbackCritsect); if (observer) { if (_networkObserver) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: observer alread added", __FUNCTION__); return -1; } WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: observer added", __FUNCTION__); _networkObserver = observer; } else { if (!_networkObserver) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: no observer added", __FUNCTION__); return -1; } WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: observer removed", __FUNCTION__); _networkObserver = NULL; } return 0; } bool ViEChannel::NetworkObserverRegistered() { CriticalSectionScoped cs(_callbackCritsect); return _networkObserver != NULL; } // ---------------------------------------------------------------------------- // SetPeriodicDeadOrAliveStatus // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SetPeriodicDeadOrAliveStatus( const bool enable, const WebRtc_UWord32 sampleTimeSeconds) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); CriticalSectionScoped cs(_callbackCritsect); if (_networkObserver == NULL) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: no observer added", __FUNCTION__); return -1; } bool enabled = false; WebRtc_UWord8 currentSampletimeSeconds = 0; // Get old settings _rtpRtcp.PeriodicDeadOrAliveStatus(enabled, currentSampletimeSeconds); // Set new settings if (_rtpRtcp.SetPeriodicDeadOrAliveStatus( enable, (WebRtc_UWord8) sampleTimeSeconds) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not set periodic dead-or-alive status", __FUNCTION__); return -1; } if (!enable) { // Restore last utilized sample time. // Without this trick, the sample time would always be reset to default // (2 sec), each time dead-or-alive was disabled without sample-time // parameter. _rtpRtcp.SetPeriodicDeadOrAliveStatus(enable, currentSampletimeSeconds); } return 0; } // ---------------------------------------------------------------------------- // SendUDPPacket // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::SendUDPPacket(const WebRtc_Word8* data, const WebRtc_UWord32 length, WebRtc_Word32& transmittedBytes, bool useRtcpSocket) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); { CriticalSectionScoped cs(_callbackCritsect); if (_ptrExternalTransport) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: External transport registered", __FUNCTION__); return -1; } } #ifndef WEBRTC_EXTERNAL_TRANSPORT transmittedBytes = _socketTransport.SendRaw(data, length, useRtcpSocket); if (transmittedBytes == -1) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); return -1; } return 0; #else WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not available for external transport", __FUNCTION__); return -1; #endif } // ============================================================================ // Color enahncement // ============================================================================ // ---------------------------------------------------------------------------- // EnableColorEnhancement // // Enables/disables color enhancement for all decoded frames // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::EnableColorEnhancement(bool enable) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s(enable: %d)", __FUNCTION__, enable); CriticalSectionScoped cs(_callbackCritsect); if (enable && _colorEnhancement) { WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Already enabled", __FUNCTION__); return -1; } else if (enable == false && _colorEnhancement == false) { WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: not enabled", __FUNCTION__); return -1; } _colorEnhancement = enable; return 0; } // ============================================================================ // Register sender // ============================================================================ // ---------------------------------------------------------------------------- // RegisterSendRtpRtcpModule // // Register send RTP RTCP module, which will deliver the frames to send // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::RegisterSendRtpRtcpModule( RtpRtcp& sendRtpRtcpModule) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); return _rtpRtcp.RegisterDefaultModule(&sendRtpRtcpModule); } // ---------------------------------------------------------------------------- // RegisterSendDeregisterSendRtpRtcpModuleRtpRtcpModule // // Deregisters the send RTP RTCP module, which will stop the encoder input to // the channel // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::DeregisterSendRtpRtcpModule() { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); return _rtpRtcp.DeRegisterDefaultModule(); } // ============================================================================ // FrameToRender // Called by VCM when a frame have been decoded. // ============================================================================ WebRtc_Word32 ViEChannel::FrameToRender(VideoFrame& videoFrame) { CriticalSectionScoped cs(_callbackCritsect); if (_decoderReset) { // Trigger a callback to the user if the incoming codec has changed. if (_codecObserver) { VideoCodec decoder; memset(&decoder, 0, sizeof(decoder)); if (_vcm.ReceiveCodec(&decoder) == VCM_OK) { // VCM::ReceiveCodec returns the codec set by // RegisterReceiveCodec, which might not be the size we're // actually decoding decoder.width = (unsigned short) videoFrame.Width(); decoder.height = (unsigned short) videoFrame.Height(); _codecObserver->IncomingCodecChanged(_channelId, decoder); } else { assert(false); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Could not get receive codec", __FUNCTION__); } } _decoderReset = false; } if (_effectFilter) { _effectFilter->Transform(videoFrame.Length(), videoFrame.Buffer(), videoFrame.TimeStamp(), videoFrame.Width(), videoFrame.Height()); } if (_colorEnhancement) { VideoProcessingModule::ColorEnhancement(videoFrame); } // Record videoframe _fileRecorder.RecordVideoFrame(videoFrame); WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]; WebRtc_Word32 noOfCSRCs = _rtpRtcp.RemoteCSRCs(arrOfCSRC); if (noOfCSRCs <= 0) { arrOfCSRC[0] = _rtpRtcp.RemoteSSRC(); noOfCSRCs = 1; } DeliverFrame(videoFrame, noOfCSRCs, arrOfCSRC); return 0; } WebRtc_Word32 ViEChannel::ReceivedDecodedReferenceFrame( const WebRtc_UWord64 pictureId) { return _rtpRtcp.SendRTCPReferencePictureSelection(pictureId); } // ============================================================================ // StoreReceivedFrame // Called by VCM before a frame have been decoded. could be used for recording // incoming video. // ============================================================================ WebRtc_Word32 ViEChannel::StoreReceivedFrame( const EncodedVideoData& frameToStore) { return 0; } // ---------------------------------------------------------------------------- // ReceiveStatistics // // Called by VCM with information about received video stream // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::ReceiveStatistics(const WebRtc_UWord32 bitRate, const WebRtc_UWord32 frameRate) { CriticalSectionScoped cs(_callbackCritsect); if (_codecObserver) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: bitrate %u, framerate %u", __FUNCTION__, bitRate, frameRate); _codecObserver->IncomingRate(_channelId, frameRate, bitRate); } return 0; } // ---------------------------------------------------------------------------- // FrameTypeRequest // // Called by VCM when a certain frame type is needed to continue decoding // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::FrameTypeRequest(const FrameType frameType) { WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s(frameType: %d)", __FUNCTION__, frameType); { CriticalSectionScoped cs(_callbackCritsect); if (_codecObserver && _doKeyFrameCallbackRequest) { _codecObserver->RequestNewKeyFrame(_channelId); } } return _rtpRtcp.RequestKeyFrame(frameType); } WebRtc_Word32 ViEChannel::SliceLossIndicationRequest( const WebRtc_UWord64 pictureId) { return _rtpRtcp.SendRTCPSliceLossIndication((WebRtc_UWord8) pictureId); } // ---------------------------------------------------------------------------- // ResendPackets // // Called by VCM when VCM wants to request resend of packets (NACK) // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::ResendPackets(const WebRtc_UWord16* sequenceNumbers, WebRtc_UWord16 length) { WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s(length: %d)", __FUNCTION__, length); return _rtpRtcp.SendNACK(sequenceNumbers, length); } // ============================================================================ // Protected methods // ============================================================================ // ---------------------------------------------------------------------------- // ChannelDecodeThreadFunction // ---------------------------------------------------------------------------- bool ViEChannel::ChannelDecodeThreadFunction(void* obj) { return static_cast (obj)->ChannelDecodeProcess(); } // ---------------------------------------------------------------------------- // ChannelDecodeThreadFunction // ---------------------------------------------------------------------------- bool ViEChannel::ChannelDecodeProcess() { // Decode is blocking, but sleep some time anyway to not get a spin _vcm.Decode(50); if ((TickTime::Now() - _vcmRTTReported).Milliseconds() > 1000) { WebRtc_UWord16 RTT; WebRtc_UWord16 avgRTT; WebRtc_UWord16 minRTT; WebRtc_UWord16 maxRTT; if (_rtpRtcp.RTT(_rtpRtcp.RemoteSSRC(), &RTT, &avgRTT, &minRTT, &maxRTT) == 0) { _vcm.SetReceiveChannelParameters(RTT); } _vcmRTTReported = TickTime::Now(); } return true; } // ============================================================================ // Private methods // ============================================================================ // ---------------------------------------------------------------------------- // StartDecodeThread // // Assumed to be critsect protected if needed // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::StartDecodeThread() { // Start the decode thread if (_ptrDecodeThread) { // Already started return 0; } _ptrDecodeThread = ThreadWrapper::CreateThread(ChannelDecodeThreadFunction, this, kHighestPriority, "DecodingThread"); if (_ptrDecodeThread == NULL) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: could not create decode thread", __FUNCTION__); return -1; } unsigned int threadId; if (_ptrDecodeThread->Start(threadId) == false) { delete _ptrDecodeThread; _ptrDecodeThread = NULL; WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: could not start decode thread", __FUNCTION__); return -1; } WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: decode thread with id %u started", __FUNCTION__); return 0; } // ---------------------------------------------------------------------------- // StopDecodeThread // // Assumed to be critsect protected if needed // ---------------------------------------------------------------------------- WebRtc_Word32 ViEChannel::StopDecodeThread() { if (_ptrDecodeThread == NULL) { WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: decode thread not running", __FUNCTION__); return 0; } _ptrDecodeThread->SetNotAlive(); if (_ptrDecodeThread->Stop()) { delete _ptrDecodeThread; } else { // Couldn't stop the thread, leak instead of crash... WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: could not stop decode thread", __FUNCTION__); assert(!"could not stop decode thread"); } _ptrDecodeThread = NULL; return 0; } #ifdef WEBRTC_SRTP WebRtc_Word32 ViEChannel::EnableSRTPSend(const SrtpModule::CipherTypes cipherType, const unsigned int cipherKeyLength, const SrtpModule::AuthenticationTypes authType, const unsigned int authKeyLength, const unsigned int authTagLength, const SrtpModule::SecurityLevels level, const WebRtc_UWord8* key, const bool useForRTCP) { _callbackCritsect.Enter(); if (_ptrExternalEncryption) { _callbackCritsect.Leave(); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: external encryption already registered", __FUNCTION__); return -1; } _callbackCritsect.Leave(); if (!_ptrSrtpModuleEncryption) { _ptrSrtpModuleEncryption = SrtpModule::CreateSrtpModule( ViEModuleId(_engineId, _channelId)); if(!_ptrSrtpModuleEncryption) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "Failed to create SRTP module"); return -1; } } const WebRtc_Word32 result = _ptrSrtpModuleEncryption->EnableSRTPEncrypt( !useForRTCP, cipherType, cipherKeyLength, authType, authKeyLength, authTagLength,level,key); if (0 != result) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "EnableSRTPEncrypt result %d, Apply To RTCP %d", result, useForRTCP); } else { _vieSender.RegisterSRTPModule(_ptrSrtpModuleEncryption); if (useForRTCP) { _vieSender.RegisterSRTCPModule(_ptrSrtpModuleEncryption); } } return result; } WebRtc_Word32 ViEChannel::DisableSRTPSend() { WebRtc_Word32 result = -1; if (_ptrSrtpModuleEncryption) { result = _ptrSrtpModuleEncryption->DisableSRTPEncrypt(); _vieSender.DeregisterSRTPModule(); _vieSender.DeregisterSRTCPModule(); } } WebRtc_Word32 ViEChannel::EnableSRTPReceive(const SrtpModule::CipherTypes cipherType, const unsigned int cipherKeyLength, const SrtpModule::AuthenticationTypes authType, const unsigned int authKeyLength, const unsigned int authTagLength, const SrtpModule::SecurityLevels level, const WebRtc_UWord8* key, const bool useForRTCP) { _callbackCritsect.Enter(); if (_ptrExternalEncryption) { _callbackCritsect.Leave(); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: external encryption already registered", __FUNCTION__); return -1; } _callbackCritsect.Leave(); if (!_ptrSrtpModuleDecryption) { _ptrSrtpModuleDecryption = SrtpModule::CreateSrtpModule( ViEModuleId(_engineId, _channelId)); if(!_ptrSrtpModuleDecryption) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "Failed to create SRTP module"); return -1; } } const WebRtc_Word32 result = _ptrSrtpModuleDecryption->EnableSRTPDecrypt( !useForRTCP, cipherType, cipherKeyLength, authType, authKeyLength, authTagLength,level,key); if (0 != result) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "EnableSRTPEncrypt result %d, Apply To RTCP %d", result, useForRTCP); } else { _vieReceiver.RegisterSRTPModule(_ptrSrtpModuleDecryption); if (useForRTCP) { _vieReceiver.RegisterSRTCPModule(_ptrSrtpModuleDecryption); } } return result; } WebRtc_Word32 ViEChannel::DisableSRTPReceive() { WebRtc_Word32 result = -1; if (_ptrSrtpModuleDecryption) { result = _ptrSrtpModuleDecryption->DisableSRTPDecrypt(); _vieReceiver.DeregisterSRTPModule(); _vieReceiver.DeregisterSRTPModule(); } return result; } #endif WebRtc_Word32 ViEChannel::RegisterExternalEncryption( Encryption* encryption) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); CriticalSectionScoped cs(_callbackCritsect); if (_ptrExternalEncryption) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: external encryption already registered", __FUNCTION__); return -1; } _ptrExternalEncryption = encryption; _vieReceiver.RegisterExternalDecryption(encryption); _vieSender.RegisterExternalEncryption(encryption); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", "external encryption object registerd with channel=%d", _channelId); return 0; } WebRtc_Word32 ViEChannel::DeRegisterExternalEncryption() { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); CriticalSectionScoped cs(_callbackCritsect); if (!_ptrExternalEncryption) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: external encryption is not registered", __FUNCTION__); return -1; } _ptrExternalTransport = NULL; _vieReceiver.DeregisterExternalDecryption(); _vieSender.DeregisterExternalEncryption(); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s external encryption object de-registerd with channel=%d", __FUNCTION__, _channelId); return 0; } WebRtc_Word32 ViEChannel::SetVoiceChannel(WebRtc_Word32 veChannelId, VoEVideoSync* veSyncInterface) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s, audio channel %d, video channel %d", __FUNCTION__, veChannelId, _channelId); if (veSyncInterface) { // Register lip sync _moduleProcessThread.RegisterModule(&_vieSync); } else { _moduleProcessThread.DeRegisterModule(&_vieSync); } return _vieSync.SetVoiceChannel(veChannelId, veSyncInterface); } WebRtc_Word32 ViEChannel::VoiceChannel() { return _vieSync.VoiceChannel(); } WebRtc_Word32 ViEChannel::RegisterEffectFilter(ViEEffectFilter* effectFilter) { CriticalSectionScoped cs(_callbackCritsect); if (effectFilter == NULL) { if (_effectFilter == NULL) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: no effect filter added for channel %d", __FUNCTION__, _channelId); return -1; } WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: deregister effect filter for device %d", __FUNCTION__, _channelId); } else { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: register effect filter for device %d", __FUNCTION__, _channelId); if (_effectFilter) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: effect filter already added for channel %d", __FUNCTION__, _channelId); return -1; } } _effectFilter = effectFilter; return 0; } ViEFileRecorder& ViEChannel::GetIncomingFileRecorder() { // Start getting callback of all frames before they are decoded _vcm.RegisterFrameStorageCallback(this); return _fileRecorder; } void ViEChannel::ReleaseIncomingFileRecorder() { // Stop getting callback of all frames before they are decoded _vcm.RegisterFrameStorageCallback(NULL); } void ViEChannel::OnLipSyncUpdate(const WebRtc_Word32 id, const WebRtc_Word32 audioVideoOffset) { if (_channelId != ChannelId(id)) { WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s, incorrect id", __FUNCTION__, id); return; } _vieSync.SetNetworkDelay(audioVideoOffset); } void ViEChannel::OnApplicationDataReceived(const WebRtc_Word32 id, const WebRtc_UWord8 subType, const WebRtc_UWord32 name, const WebRtc_UWord16 length, const WebRtc_UWord8* data) { if (_channelId != ChannelId(id)) { WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s, incorrect id", __FUNCTION__, id); return; } CriticalSectionScoped cs(_callbackCritsect); { if (_rtcpObserver) { _rtcpObserver->OnApplicationDataReceived(_channelId, subType, name, (const char*) data, length); } } } WebRtc_Word32 ViEChannel::OnInitializeDecoder( const WebRtc_Word32 id, const WebRtc_Word8 payloadType, const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE], const WebRtc_UWord32 frequency, const WebRtc_UWord8 channels, const WebRtc_UWord32 rate) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: payloadType %d, payloadName %s", __FUNCTION__, payloadType, payloadName); _vcm.ResetDecoder(); _callbackCritsect.Enter(); _decoderReset = true; _callbackCritsect.Leave(); return 0; } void ViEChannel::OnPacketTimeout(const WebRtc_Word32 id) { assert(ChannelId(id) == _channelId); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); CriticalSectionScoped cs(_callbackCritsect); if (_networkObserver) { #ifndef WEBRTC_EXTERNAL_TRANSPORT if (_socketTransport.Receiving() || _ptrExternalTransport) #else if (_ptrExternalTransport) #endif { _networkObserver->PacketTimeout(_channelId, NoPacket); _rtpPacketTimeout = true; } } } // // Called by the rtp module when the first packet is received and // when first packet after a timeout is received. // void ViEChannel::OnReceivedPacket(const WebRtc_Word32 id, const RtpRtcpPacketType packetType) { assert(ChannelId(id) == _channelId); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s", __FUNCTION__); if (_rtpPacketTimeout && packetType == kPacketRtp) { CriticalSectionScoped cs(_callbackCritsect); if (_networkObserver) { _networkObserver->PacketTimeout(_channelId, PacketReceived); } // Reset even if no observer set, might have been removed during timeout _rtpPacketTimeout = false; } } void ViEChannel::OnPeriodicDeadOrAlive(const WebRtc_Word32 id, const RTPAliveType alive) { assert(ChannelId(id) == _channelId); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s(id=%d, alive=%d)", __FUNCTION__, id, alive); CriticalSectionScoped cs(_callbackCritsect); if (!_networkObserver) { return; } bool isAlive = true; if (alive == kRtpDead) { isAlive = false; } _networkObserver->OnPeriodicDeadOrAlive(_channelId, isAlive); return; } void ViEChannel::OnIncomingSSRCChanged(const WebRtc_Word32 id, const WebRtc_UWord32 SSRC) { if (_channelId != ChannelId(id)) { assert(false); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s, incorrect id", __FUNCTION__, id); return; } WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: %u", __FUNCTION__, SSRC); CriticalSectionScoped cs(_callbackCritsect); { if (_rtpObserver) { _rtpObserver->IncomingSSRCChanged(_channelId, SSRC); } } } void ViEChannel::OnIncomingCSRCChanged(const WebRtc_Word32 id, const WebRtc_UWord32 CSRC, const bool added) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: %u added: %d", __FUNCTION__, CSRC, added); if (_channelId != ChannelId(id)) { assert(false); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s, incorrect id", __FUNCTION__, id); return; } WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: %u", __FUNCTION__, CSRC); CriticalSectionScoped cs(_callbackCritsect); { if (_rtpObserver) { _rtpObserver->IncomingCSRCChanged(_channelId, CSRC, added); } } } WebRtc_Word32 ViEChannel::SetInverseH263Logic(const bool enable) { return _rtpRtcp.SetH263InverseLogic(enable); } } // namespace webrtc