webrtc/video_engine/main/source/vie_channel.cc

3223 lines
109 KiB
C++

/*
* 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(&currentReceiveCodec);
if (_vcm.RegisterExternalDecoder(NULL, plType, false) != VCM_OK)
{
return -1;
}
if (result == 0 && currentReceiveCodec.plType == plType)
{
result = _vcm.RegisterReceiveCodec(&currentReceiveCodec,
_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<ViEChannel*> (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