blob: 92c9e0dbbd78c8b98284dbb786ff4dea912dcd51 [file] [log] [blame]
/*
* 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.
*/
#include "common_types.h"
#include "rtp_rtcp_impl.h"
#include "trace.h"
#ifdef MATLAB
#include "../test/BWEStandAlone/MatlabPlot.h"
extern MatlabEngine eng; // global variable defined elsewhere
#endif
#include <string.h> //memcpy
#include <cassert> //assert
// local for this file
namespace
{
const float FracMS = 4.294967296E6f;
}
#ifdef _WIN32
// disable warning C4355: 'this' : used in base member initializer list
#pragma warning(disable : 4355)
#endif
namespace webrtc {
using namespace RTCPUtility;
RtpRtcp*
RtpRtcp::CreateRtpRtcp(const WebRtc_Word32 id,
const bool audio)
{
if(audio)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id, "CreateRtpRtcp(audio)");
} else
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id, "CreateRtpRtcp(video)");
}
return new ModuleRtpRtcpImpl(id, audio);
}
void RtpRtcp::DestroyRtpRtcp(RtpRtcp* module)
{
if(module)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, static_cast<ModuleRtpRtcpImpl*>(module)->Id(), "DestroyRtpRtcp()");
delete static_cast<ModuleRtpRtcpImpl*>(module);
}
}
ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const WebRtc_Word32 id,
const bool audio):
TMMBRHelp(audio),
_rtpSender(id, audio),
_rtpReceiver(id, audio, *this),
_id(id),
_audio(audio),
_collisionDetected(false),
_lastProcessTime(ModuleRTPUtility::GetTimeInMS()),
_packetOverHead(28), // IPV4 UDP
_criticalSectionModulePtrs(*CriticalSectionWrapper::CreateCriticalSection()),
_criticalSectionModulePtrsFeedback(*CriticalSectionWrapper::CreateCriticalSection()),
_defaultModule(NULL),
_audioModule(NULL),
_videoModule(NULL),
_childModules(),
_deadOrAliveActive(false),
_deadOrAliveTimeoutMS(0),
_deadOrAliveLastTimer(0),
_rtcpReceiver(id,*this),
_bandwidthManagement(id),
_receivedNTPsecsAudio(0),
_receivedNTPfracAudio(0),
_RTCPArrivalTimeSecsAudio(0),
_RTCPArrivalTimeFracAudio(0),
_rtcpSender(id, audio, *this),
_nackMethod(kNackOff),
_nackLastTimeSent(0),
_nackLastSeqNumberSent(0),
_keyFrameReqMethod(kKeyFrameReqFirRtp),
_lastChildBitrateUpdate(0)
#ifdef MATLAB
,_plot1(NULL)
#endif
{
// make sure that RTCP objects are aware of our SSRC
WebRtc_UWord32 SSRC = _rtpSender.SSRC();
_rtcpSender.SetSSRC(SSRC);
WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
}
ModuleRtpRtcpImpl::~ModuleRtpRtcpImpl()
{
WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, _id, "%s deleted", __FUNCTION__);
// make sure to unregister this module from other modules
const bool defaultInstance(_childModules.Empty()?false:true);
if(defaultInstance)
{
// deregister for the default module
// will go in to the child modules and remove it self
ListItem* item = _childModules.First();
while (item)
{
RtpRtcp* module = (RtpRtcp*)item->GetItem();
_childModules.Erase(item);
if(module)
{
module->DeRegisterDefaultModule();
}
item = _childModules.First();
}
} else
{
// deregister for the child modules
// will go in to the default and remove it self
DeRegisterDefaultModule();
}
if(_audio)
{
DeRegisterVideoModule();
} else
{
DeRegisterSyncModule();
}
#ifdef MATLAB
if (_plot1)
{
eng.DeletePlot(_plot1);
_plot1 = NULL;
}
#endif
delete &_criticalSectionModulePtrs;
delete &_criticalSectionModulePtrsFeedback;
}
WebRtc_Word32
ModuleRtpRtcpImpl::Version(WebRtc_Word8* version,
WebRtc_UWord32& remainingBufferInBytes,
WebRtc_UWord32& position) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "Version(bufferLength:%d)", remainingBufferInBytes);
return GetVersion(version, remainingBufferInBytes, position);
}
WebRtc_Word32
RtpRtcp::GetVersion(WebRtc_Word8* version,
WebRtc_UWord32& remainingBufferInBytes,
WebRtc_UWord32& position)
{
if(version == NULL)
{
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1, "Invalid in argument to Version()");
return -1;
}
WebRtc_Word8 ourVersion[] = "Module RTP RTCP 1.3.0";
WebRtc_UWord32 ourLength = (WebRtc_UWord32)strlen(ourVersion);
if(remainingBufferInBytes < ourLength +1)
{
return -1;
}
memcpy(version, ourVersion, ourLength);
version[ourLength] = '\0'; // null terminaion
remainingBufferInBytes -= (ourLength + 1);
position += (ourLength + 1);
return 0;
}
WebRtc_Word32
ModuleRtpRtcpImpl::ChangeUniqueId(const WebRtc_Word32 id)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "ChangeUniqueId(new id:%d)", id);
_id = id;
_rtpReceiver.ChangeUniqueId(id);
_rtcpReceiver.ChangeUniqueId(id);
_rtpSender.ChangeUniqueId(id);
_rtcpSender.ChangeUniqueId(id);
return 0;
}
// default encoder that we need to multiplex out
WebRtc_Word32
ModuleRtpRtcpImpl::RegisterDefaultModule(RtpRtcp* module)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RegisterDefaultModule(module:0x%x)", module);
if(module == NULL)
{
return -1;
}
CriticalSectionScoped lock(_criticalSectionModulePtrs);
if(_defaultModule)
{
_defaultModule->DeRegisterChildModule(this);
}
_defaultModule = (ModuleRtpRtcpPrivate*)module;
_defaultModule->RegisterChildModule(this);
return 0;
}
WebRtc_Word32
ModuleRtpRtcpImpl::DeRegisterDefaultModule()
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "DeRegisterDefaultModule()");
CriticalSectionScoped lock(_criticalSectionModulePtrs);
if(_defaultModule)
{
_defaultModule->DeRegisterChildModule(this);
_defaultModule = NULL;
}
return 0;
}
bool ModuleRtpRtcpImpl::DefaultModuleRegistered()
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "DefaultModuleRegistered()");
CriticalSectionScoped lock(_criticalSectionModulePtrs);
if(_defaultModule)
{
return true;
}
else
{
return false;
}
}
WebRtc_UWord32
ModuleRtpRtcpImpl::NumberChildModules()
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "NumberChildModules");
CriticalSectionScoped lock(_criticalSectionModulePtrs);
CriticalSectionScoped doubleLock(_criticalSectionModulePtrsFeedback);
// we use two locks for protecting _childModules one (_criticalSectionModulePtrsFeedback) for incoming
// messages (BitrateSent and UpdateTMMBR) and _criticalSectionModulePtrs for all outgoing messages sending packets etc
return _childModules.GetSize();
}
void
ModuleRtpRtcpImpl::RegisterChildModule(RtpRtcp* module)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RegisterChildModule(module:0x%x)", module);
CriticalSectionScoped lock(_criticalSectionModulePtrs);
CriticalSectionScoped doubleLock(_criticalSectionModulePtrsFeedback);
// we use two locks for protecting _childModules one (_criticalSectionModulePtrsFeedback) for incoming
// messages (BitrateSent and UpdateTMMBR) and _criticalSectionModulePtrs for all outgoing messages sending packets etc
_childModules.PushFront(module);
}
void
ModuleRtpRtcpImpl::DeRegisterChildModule(RtpRtcp* removeModule)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "DeRegisterChildModule(module:0x%x)", removeModule);
CriticalSectionScoped lock(_criticalSectionModulePtrs);
CriticalSectionScoped doubleLock(_criticalSectionModulePtrsFeedback);
ListItem* item = _childModules.First();
while (item)
{
RtpRtcp* module = (RtpRtcp*)item->GetItem();
if(module == removeModule)
{
_childModules.Erase(item);
return;
}
item = _childModules.Next(item);
}
}
// Lip-sync between voice-video engine,
WebRtc_Word32
ModuleRtpRtcpImpl::RegisterSyncModule(RtpRtcp* audioModule)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RegisterSyncModule(module:0x%x)", audioModule);
if(audioModule == NULL)
{
return -1;
}
if(_audio)
{
return -1;
}
CriticalSectionScoped lock(_criticalSectionModulePtrs);
_audioModule = (ModuleRtpRtcpPrivate*)audioModule;
return _audioModule->RegisterVideoModule(this);
}
WebRtc_Word32
ModuleRtpRtcpImpl::DeRegisterSyncModule()
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "DeRegisterSyncModule()");
CriticalSectionScoped lock(_criticalSectionModulePtrs);
if(_audioModule)
{
ModuleRtpRtcpPrivate* audioModule=_audioModule;
_audioModule = NULL;
_receivedNTPsecsAudio = 0;
_receivedNTPfracAudio = 0;
_RTCPArrivalTimeSecsAudio = 0;
_RTCPArrivalTimeFracAudio = 0;
audioModule->DeRegisterVideoModule();
}
return 0;
}
WebRtc_Word32
ModuleRtpRtcpImpl::RegisterVideoModule(RtpRtcp* videoModule)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RegisterVideoModule(module:0x%x)", videoModule);
if(videoModule == NULL)
{
return -1;
}
if(!_audio)
{
return -1;
}
CriticalSectionScoped lock(_criticalSectionModulePtrs);
_videoModule = (ModuleRtpRtcpPrivate*)videoModule;
return 0;
}
void
ModuleRtpRtcpImpl::DeRegisterVideoModule()
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "DeRegisterVideoModule()");
CriticalSectionScoped lock(_criticalSectionModulePtrs);
if(_videoModule)
{
ModuleRtpRtcpPrivate* videoModule=_videoModule;
_videoModule=NULL;
videoModule->DeRegisterSyncModule();
}
}
// returns the number of milliseconds until the module want a worker thread to call Process
WebRtc_Word32
ModuleRtpRtcpImpl::TimeUntilNextProcess()
{
const WebRtc_UWord32 now = ModuleRTPUtility::GetTimeInMS();
return kRtpRtcpMaxIdleTimeProcess - (now -_lastProcessTime);
}
// Process any pending tasks such as timeouts
// non time critical events
WebRtc_Word32
ModuleRtpRtcpImpl::Process()
{
_lastProcessTime = ModuleRTPUtility::GetTimeInMS();
_rtpReceiver.PacketTimeout();
_rtcpReceiver.PacketTimeout();
_rtpSender.ProcessBitrate();
_rtpReceiver.ProcessBitrate();
ProcessDeadOrAliveTimer();
if(_rtcpSender.TimeToSendRTCPReport())
{
WebRtc_UWord16 RTT = 0;
_rtcpReceiver.RTT(_rtpReceiver.SSRC(), &RTT, NULL,NULL,NULL);
_rtcpSender.SendRTCP(kRtcpReport, 0, 0, RTT);
}
if(_rtpSender.RTPKeepalive())
{
// check time to send RTP keep alive
if( _rtpSender.TimeToSendRTPKeepalive())
{
_rtpSender.SendRTPKeepalivePacket();
}
}
if(UpdateRTCPReceiveInformationTimers())
{
// a receiver has timed out
UpdateTMMBR();
}
return 0;
}
/**
* Receiver
*/
WebRtc_Word32
ModuleRtpRtcpImpl::InitReceiver()
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "InitReceiver()");
_packetOverHead = 28; // default is IPV4 UDP
_receivedNTPsecsAudio = 0;
_receivedNTPfracAudio = 0;
_RTCPArrivalTimeSecsAudio = 0;
_RTCPArrivalTimeFracAudio = 0;
WebRtc_Word32 ret = _rtpReceiver.Init();
if (ret < 0)
{
return ret;
}
_rtpReceiver.SetPacketOverHead(_packetOverHead);
return ret;
}
void
ModuleRtpRtcpImpl::ProcessDeadOrAliveTimer()
{
if(_deadOrAliveActive)
{
const WebRtc_UWord32 now = ModuleRTPUtility::GetTimeInMS();
if(now > _deadOrAliveTimeoutMS +_deadOrAliveLastTimer)
{
_deadOrAliveLastTimer += _deadOrAliveTimeoutMS;
bool RTCPalive = false; // RTCP is alive if we have received a report the last 12 seconds
if(_rtcpReceiver.LastReceived() + 12000 > now)
{
RTCPalive = true;
}
_rtpReceiver.ProcessDeadOrAlive(RTCPalive, now);
}
}
}
// Set periodic dead or alive notification
WebRtc_Word32
ModuleRtpRtcpImpl::SetPeriodicDeadOrAliveStatus(const bool enable,
const WebRtc_UWord8 sampleTimeSeconds)
{
if(enable)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetPeriodicDeadOrAliveStatus(enable, %d)", sampleTimeSeconds);
}else
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetPeriodicDeadOrAliveStatus(disable)");
}
if(sampleTimeSeconds == 0)
{
return -1;
}
_deadOrAliveActive = enable;
_deadOrAliveTimeoutMS = sampleTimeSeconds*1000;
_deadOrAliveLastTimer = ModuleRTPUtility::GetTimeInMS(); // trigger the first after one period
return 0;
}
WebRtc_Word32
ModuleRtpRtcpImpl::PeriodicDeadOrAliveStatus(bool &enable,
WebRtc_UWord8 &sampleTimeSeconds)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "PeriodicDeadOrAliveStatus()");
enable = _deadOrAliveActive;
sampleTimeSeconds = (WebRtc_UWord8)(_deadOrAliveTimeoutMS/1000);
return 0;
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetPacketTimeout(const WebRtc_UWord32 RTPtimeoutMS,
const WebRtc_UWord32 RTCPtimeoutMS)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetPacketTimeout(%u,%u)",RTPtimeoutMS, RTCPtimeoutMS);
if(_rtpReceiver.SetPacketTimeout(RTPtimeoutMS) == 0)
{
return _rtcpReceiver.SetPacketTimeout(RTCPtimeoutMS);
}
return -1;
}
// set codec name and payload type
WebRtc_Word32
ModuleRtpRtcpImpl::RegisterReceivePayload(const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
const WebRtc_Word8 payloadType,
const WebRtc_UWord32 frequency,
const WebRtc_UWord8 channels,
const WebRtc_UWord32 rate)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RegisterReceivePayload()");
return _rtpReceiver.RegisterReceivePayload(payloadName, payloadType, frequency, channels, rate);
}
WebRtc_Word32
ModuleRtpRtcpImpl::DeRegisterReceivePayload(const WebRtc_Word8 payloadType)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "DeRegisterReceivePayload(%d)", payloadType);
return _rtpReceiver.DeRegisterReceivePayload(payloadType);
}
// get configured payload type
WebRtc_Word32
ModuleRtpRtcpImpl::ReceivePayloadType(const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
const WebRtc_UWord32 frequency,
const WebRtc_UWord8 channels,
WebRtc_Word8* payloadType,
const WebRtc_UWord32 rate) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "ReceivePayloadType()");
return _rtpReceiver.ReceivePayloadType(payloadName, frequency, channels, payloadType, rate);
}
WebRtc_Word32
ModuleRtpRtcpImpl::ReceivePayload(const WebRtc_Word8 payloadType,
WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
WebRtc_UWord32* frequency,
WebRtc_UWord8* channels,
WebRtc_UWord32* rate) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "ReceivePayload()");
return _rtpReceiver.ReceivePayload(payloadType, payloadName, frequency, channels, rate);
}
WebRtc_Word32
ModuleRtpRtcpImpl::RemotePayload(WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
WebRtc_Word8* payloadType,
WebRtc_UWord32* frequency,
WebRtc_UWord8* channels) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemotePayload()");
return _rtpReceiver.RemotePayload(payloadName, payloadType, frequency, channels);
}
// get the currently configured SSRC filter
WebRtc_Word32
ModuleRtpRtcpImpl::SSRCFilter(WebRtc_UWord32& allowedSSRC) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SSRCFilter()");
return _rtpReceiver.SSRCFilter(allowedSSRC);
}
// set a SSRC to be used as a filter for incoming RTP streams
WebRtc_Word32
ModuleRtpRtcpImpl::SetSSRCFilter(const bool enable, const WebRtc_UWord32 allowedSSRC)
{
if(enable)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetSSRCFilter(enable, 0x%x)", allowedSSRC);
}else
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetSSRCFilter(disable)");
}
return _rtpReceiver.SetSSRCFilter(enable, allowedSSRC);
}
// Get last received remote timestamp
WebRtc_UWord32
ModuleRtpRtcpImpl::RemoteTimestamp() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemoteTimestamp()");
return _rtpReceiver.TimeStamp();
}
// Get the current estimated remote timestamp
WebRtc_Word32
ModuleRtpRtcpImpl::EstimatedRemoteTimeStamp(WebRtc_UWord32& timestamp) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "EstimatedRemoteTimeStamp()");
return _rtpReceiver.EstimatedRemoteTimeStamp(timestamp);
}
// Get incoming SSRC
WebRtc_UWord32
ModuleRtpRtcpImpl::RemoteSSRC() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemoteSSRC()");
return _rtpReceiver.SSRC();
}
// Get remote CSRC
WebRtc_Word32
ModuleRtpRtcpImpl::RemoteCSRCs( WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemoteCSRCs()");
return _rtpReceiver.CSRCs(arrOfCSRC);
}
// called by the network module when we receive a packet
WebRtc_Word32
ModuleRtpRtcpImpl::IncomingPacket(const WebRtc_UWord8* incomingPacket,
const WebRtc_UWord16 incomingPacketLength)
{
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id, "IncomingPacket(packetLength:%u)", incomingPacketLength);
// minimum RTP is 12 bytes
// minimum RTCP is 8 bytes (RTCP BYE)
if(incomingPacketLength < 8 || incomingPacket == NULL)
{
WEBRTC_TRACE(kTraceDebug, kTraceRtpRtcp, _id, "IncomingPacket invalid buffer or length");
return -1;
}
// check RTP version
const WebRtc_UWord8 version = incomingPacket[0] >> 6 ;
if(version != 2)
{
WEBRTC_TRACE(kTraceDebug, kTraceRtpRtcp, _id, "IncomingPacket invalid RTP version");
return -1;
}
ModuleRTPUtility::RTPHeaderParser rtpParser(incomingPacket, incomingPacketLength);
if(rtpParser.RTCP())
{
RTCPUtility::RTCPParserV2 rtcpParser(incomingPacket,
incomingPacketLength,
true); // Allow receive of non-compound RTCP packets.
const bool validRTCPHeader = rtcpParser.IsValid();
if(!validRTCPHeader)
{
WEBRTC_TRACE(kTraceDebug, kTraceRtpRtcp, _id, "IncomingPacket invalid RTCP packet");
return -1;
}
RTCPHelp::RTCPPacketInformation rtcpPacketInformation;
WebRtc_Word32 retVal = _rtcpReceiver.IncomingRTCPPacket(rtcpPacketInformation,
&rtcpParser);
if(retVal == 0)
{
_rtcpReceiver.TriggerCallbacksFromRTCPPacket(rtcpPacketInformation);
}
return retVal;
} else
{
WebRtcRTPHeader rtpHeader;
memset(&rtpHeader, 0, sizeof(rtpHeader));
const bool validRTPHeader = rtpParser.Parse(rtpHeader);
if(!validRTPHeader)
{
WEBRTC_TRACE(kTraceDebug, kTraceRtpRtcp, _id, "IncomingPacket invalid RTP header");
return -1;
}
return _rtpReceiver.IncomingRTPPacket(&rtpHeader,
incomingPacket,
incomingPacketLength);
}
}
WebRtc_Word32
ModuleRtpRtcpImpl::IncomingAudioNTP(const WebRtc_UWord32 audioReceivedNTPsecs,
const WebRtc_UWord32 audioReceivedNTPfrac,
const WebRtc_UWord32 audioRTCPArrivalTimeSecs,
const WebRtc_UWord32 audioRTCPArrivalTimeFrac)
{
_receivedNTPsecsAudio = audioReceivedNTPsecs;
_receivedNTPfracAudio = audioReceivedNTPfrac;
_RTCPArrivalTimeSecsAudio = audioRTCPArrivalTimeSecs;
_RTCPArrivalTimeFracAudio = audioRTCPArrivalTimeFrac;
return 0;
}
WebRtc_Word32
ModuleRtpRtcpImpl::RegisterIncomingDataCallback(RtpData* incomingDataCallback)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RegisterIncomingDataCallback(incomingDataCallback:0x%x)", incomingDataCallback);
return _rtpReceiver.RegisterIncomingDataCallback(incomingDataCallback);
}
WebRtc_Word32
ModuleRtpRtcpImpl::RegisterIncomingRTPCallback(RtpFeedback* incomingMessagesCallback)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RegisterIncomingRTPCallback(incomingMessagesCallback:0x%x)",incomingMessagesCallback);
return _rtpReceiver.RegisterIncomingRTPCallback(incomingMessagesCallback);
}
WebRtc_Word32
ModuleRtpRtcpImpl::RegisterIncomingRTCPCallback(RtcpFeedback* incomingMessagesCallback)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RegisterIncomingRTCPCallback(incomingMessagesCallback:0x%x)",incomingMessagesCallback);
return _rtcpReceiver.RegisterIncomingRTCPCallback(incomingMessagesCallback);
}
WebRtc_Word32
ModuleRtpRtcpImpl::RegisterIncomingVideoCallback(RtpVideoFeedback* incomingMessagesCallback)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RegisterIncomingVideoCallback(incomingMessagesCallback:0x%x)",incomingMessagesCallback);
if(_rtcpReceiver.RegisterIncomingVideoCallback(incomingMessagesCallback) == 0)
{
return _rtpReceiver.RegisterIncomingVideoCallback(incomingMessagesCallback);
}
return -1;
}
WebRtc_Word32
ModuleRtpRtcpImpl::RegisterAudioCallback(RtpAudioFeedback* messagesCallback)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RegisterAudioCallback(messagesCallback:0x%x)",messagesCallback);
if(_rtpSender.RegisterAudioCallback(messagesCallback) == 0)
{
return _rtpReceiver.RegisterIncomingAudioCallback(messagesCallback);
}
return -1;
}
/**
* Sender
*/
WebRtc_Word32
ModuleRtpRtcpImpl::InitSender()
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "InitSender()");
_collisionDetected = false;
// if we are already receiving inform our sender to avoid collision
if(_rtpSender.Init(_rtpReceiver.SSRC()) != 0)
{
return -1;
}
WebRtc_Word32 retVal = _rtcpSender.Init();
// make sure that RTCP objects are aware of our SSRC (it could have changed due to collision)
WebRtc_UWord32 SSRC = _rtpSender.SSRC();
_rtcpReceiver.SetSSRC(SSRC);
_rtcpSender.SetSSRC(SSRC);
return retVal;
}
bool
ModuleRtpRtcpImpl::RTPKeepalive() const
{
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id, "RTPKeepalive()");
return _rtpSender.RTPKeepalive();
}
WebRtc_Word32
ModuleRtpRtcpImpl::RTPKeepaliveStatus(bool* enable,
WebRtc_Word8* unknownPayloadType,
WebRtc_UWord16* deltaTransmitTimeMS) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RTPKeepaliveStatus()");
return _rtpSender.RTPKeepaliveStatus(enable, unknownPayloadType, deltaTransmitTimeMS);
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetRTPKeepaliveStatus(bool enable, WebRtc_Word8 unknownPayloadType, WebRtc_UWord16 deltaTransmitTimeMS)
{
if (enable)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetRTPKeepaliveStatus(enable, payloadType:%d deltaTransmitTimeMS:%u)",unknownPayloadType,deltaTransmitTimeMS);
// check the transmit keepalive delta time [1,60]
if (deltaTransmitTimeMS < 1000 || deltaTransmitTimeMS > 60000)
{
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "\tinvalid deltaTransmitTimeSeconds (%d)", deltaTransmitTimeMS);
return (-1);
}
// check the payload time [0,127]
if (unknownPayloadType < 0 )
{
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "\tinvalid unknownPayloadType (%d)", unknownPayloadType);
return (-1);
}
// enable RTP keepalive mechanism
return _rtpSender.EnableRTPKeepalive(unknownPayloadType, deltaTransmitTimeMS);
}else
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetRTPKeepaliveStatus(disable)");
return _rtpSender.DisableRTPKeepalive();
}
}
// set codec name and payload type
WebRtc_Word32
ModuleRtpRtcpImpl::RegisterSendPayload(const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
const WebRtc_Word8 payloadType,
const WebRtc_UWord32 frequency,
const WebRtc_UWord8 channels,
const WebRtc_UWord32 rate)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RegisterSendPayload(payloadName:%s payloadType:%d frequency:%u)", payloadName, payloadType, frequency);
return _rtpSender.RegisterPayload(payloadName, payloadType, frequency, channels, rate);
}
WebRtc_Word32
ModuleRtpRtcpImpl::DeRegisterSendPayload(const WebRtc_Word8 payloadType)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "DeRegisterSendPayload(%d)", payloadType);
return _rtpSender.DeRegisterSendPayload(payloadType);
}
WebRtc_Word8
ModuleRtpRtcpImpl::SendPayloadType() const
{
return _rtpSender.SendPayloadType();
}
WebRtc_UWord32
ModuleRtpRtcpImpl::StartTimestamp() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "StartTimestamp()");
return _rtpSender.StartTimestamp();
}
// configure start timestamp, default is a random number
WebRtc_Word32
ModuleRtpRtcpImpl::SetStartTimestamp(const WebRtc_UWord32 timestamp)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetStartTimestamp(%d)", timestamp);
return _rtpSender.SetStartTimestamp(timestamp, true);
}
WebRtc_UWord16
ModuleRtpRtcpImpl::SequenceNumber() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SequenceNumber()");
return _rtpSender.SequenceNumber();
}
// Set SequenceNumber, default is a random number
WebRtc_Word32
ModuleRtpRtcpImpl::SetSequenceNumber(const WebRtc_UWord16 seqNum)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetSequenceNumber(%d)",seqNum);
return _rtpSender.SetSequenceNumber(seqNum);
}
WebRtc_UWord32
ModuleRtpRtcpImpl::SSRC() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SSRC()");
return _rtpSender.SSRC();
}
// configure SSRC, default is a random number
WebRtc_Word32
ModuleRtpRtcpImpl::SetSSRC(const WebRtc_UWord32 ssrc)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetSSRC(%d)", ssrc);
if(_rtpSender.SetSSRC(ssrc) == 0)
{
_rtcpReceiver.SetSSRC(ssrc);
_rtcpSender.SetSSRC(ssrc);
return 0;
}
return -1;
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetCSRCStatus(const bool include)
{
_rtcpSender.SetCSRCStatus(include);
return _rtpSender.SetCSRCStatus(include);
}
WebRtc_Word32
ModuleRtpRtcpImpl::CSRCs( WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "CSRCs()");
return _rtpSender.CSRCs(arrOfCSRC);
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetCSRCs(const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize],
const WebRtc_UWord8 arrLength)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetCSRCs(arrLength:%d)", arrLength);
const bool defaultInstance(_childModules.Empty()?false:true);
if(defaultInstance)
{
// for default we need to update all child modules too
CriticalSectionScoped lock(_criticalSectionModulePtrs);
ListItem* item = _childModules.First();
while (item)
{
RtpRtcp* module = (RtpRtcp*)item->GetItem();
if(module)
{
module->SetCSRCs(arrOfCSRC, arrLength);
}
item = _childModules.Next(item);
}
return 0;
} else
{
for(int i = 0;i < arrLength;i++)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "\tidx:%d CSRC:%u", i, arrOfCSRC[i]);
}
_rtcpSender.SetCSRCs(arrOfCSRC, arrLength);
return _rtpSender.SetCSRCs(arrOfCSRC, arrLength);
}
}
WebRtc_UWord32
ModuleRtpRtcpImpl::PacketCountSent() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "PacketCountSent()");
return _rtpSender.Packets();
}
WebRtc_UWord32
ModuleRtpRtcpImpl::ByteCountSent() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "ByteCountSent()");
return _rtpSender.Bytes();
}
int ModuleRtpRtcpImpl::CurrentSendFrequencyHz() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "CurrentSendFrequencyHz()");
return _rtpSender.SendPayloadFrequency();
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetSendingStatus(const bool sending)
{
if(sending)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetSendingStatus(sending)");
}else
{
if(_rtpSender.RTPKeepalive())
{
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "Can't SetSendingStatus(stopped) when RTP Keepalive is active");
return -1;
}
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetSendingStatus(stopped)");
}
if(_rtcpSender.Sending() != sending)
{
// sends RTCP BYE when going from true to false
WebRtc_Word32 retVal = _rtcpSender.SetSendingStatus(sending);
_collisionDetected = false;
// generate a new timeStamp if true and not configured via API
// generate a new SSRC for the next "call" if false
_rtpSender.SetSendingStatus(sending);
// make sure that RTCP objects are aware of our SSRC (it could have changed due to collision)
WebRtc_UWord32 SSRC = _rtpSender.SSRC();
_rtcpReceiver.SetSSRC(SSRC);
_rtcpSender.SetSSRC(SSRC);
return retVal;
}
return 0;
}
bool
ModuleRtpRtcpImpl::Sending() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "Sending()");
return _rtcpSender.Sending();
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetSendingMediaStatus(const bool sending)
{
if(sending)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetSendingMediaStatus(sending)");
}else
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetSendingMediaStatus(stopped)");
}
_rtpSender.SetSendingMediaStatus(sending);
return 0;
}
bool
ModuleRtpRtcpImpl::SendingMedia() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "Sending()");
const bool haveChildModules(_childModules.Empty()?false:true);
if(!haveChildModules)
{
return _rtpSender.SendingMedia();
}
else
{
CriticalSectionScoped lock(_criticalSectionModulePtrs);
ListItem* item = _childModules.First();
if(item)
{
RTPSender& rtpSender = static_cast<ModuleRtpRtcpImpl*>(item->GetItem())->_rtpSender;
if (rtpSender.SendingMedia())
{
return true;
}
item = _childModules.Next(item);
}
}
return false;
}
WebRtc_Word32
ModuleRtpRtcpImpl::RegisterSendTransport(Transport* outgoingTransport)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RegisterSendTransport(0x%x)", outgoingTransport);
if(_rtpSender.RegisterSendTransport(outgoingTransport) == 0)
{
return _rtcpSender.RegisterSendTransport(outgoingTransport);
}
return -1;
}
WebRtc_Word32
ModuleRtpRtcpImpl::SendOutgoingData(const FrameType frameType,
const WebRtc_Word8 payloadType,
const WebRtc_UWord32 timeStamp,
const WebRtc_UWord8* payloadData,
const WebRtc_UWord32 payloadSize,
const RTPFragmentationHeader* fragmentation,
const RTPVideoTypeHeader* rtpTypeHdr)
{
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
"SendOutgoingData(frameType:%d payloadType:%d timeStamp:%u payloadSize:%u)",
frameType, payloadType, timeStamp, payloadSize);
if(_rtcpSender.TimeToSendRTCPReport(kVideoFrameKey == frameType))
{
WebRtc_UWord16 RTT = 0;
_rtcpReceiver.RTT(_rtpReceiver.SSRC(), &RTT, NULL,NULL,NULL);
_rtcpSender.SendRTCP(kRtcpReport, 0, 0, RTT);
}
const bool haveChildModules(_childModules.Empty()?false:true);
WebRtc_Word32 retVal = -1;
if(!haveChildModules)
{
retVal = _rtpSender.SendOutgoingData(frameType,
payloadType,
timeStamp,
payloadData,
payloadSize,
fragmentation,
NULL,
rtpTypeHdr);
} else
{
CriticalSectionScoped lock(_criticalSectionModulePtrs);
VideoCodecInformation* codecInfo = NULL;
ListItem* item = _childModules.First();
if(item)
{
RTPSender& rtpSender = static_cast<ModuleRtpRtcpImpl*>(item->GetItem())->_rtpSender;
retVal = rtpSender.SendOutgoingData(frameType,
payloadType,
timeStamp,
payloadData,
payloadSize,
fragmentation,
NULL,
rtpTypeHdr);
item = _childModules.Next(item);
}
// send to all remaining "child" modules
while(item)
{
RTPSender& rtpSender = static_cast<ModuleRtpRtcpImpl*>(item->GetItem())->_rtpSender;
retVal = rtpSender.SendOutgoingData(frameType,
payloadType,
timeStamp,
payloadData,
payloadSize,
fragmentation,
codecInfo,
rtpTypeHdr);
item = _childModules.Next(item);
}
}
return retVal;
}
WebRtc_UWord16
ModuleRtpRtcpImpl::MaxPayloadLength() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "MaxPayloadLength()");
return _rtpSender.MaxPayloadLength();
}
WebRtc_UWord16
ModuleRtpRtcpImpl::MaxDataPayloadLength() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "MaxDataPayloadLength()");
WebRtc_UWord16 minDataPayloadLength = IP_PACKET_SIZE-28; // Assuming IP/UDP
const bool defaultInstance(_childModules.Empty() ? false : true);
if (defaultInstance)
{
// for default we need to update all child modules too
CriticalSectionScoped lock(_criticalSectionModulePtrs);
ListItem* item = _childModules.First();
while(item)
{
RtpRtcp* module = static_cast<RtpRtcp*>(item->GetItem());
if (module)
{
WebRtc_UWord16 dataPayloadLength = module->MaxDataPayloadLength();
if (dataPayloadLength < minDataPayloadLength)
{
minDataPayloadLength = dataPayloadLength;
}
}
item = _childModules.Next(item);
}
}
WebRtc_UWord16 dataPayloadLength = _rtpSender.MaxDataPayloadLength();
if (dataPayloadLength < minDataPayloadLength)
{
minDataPayloadLength = dataPayloadLength;
}
return minDataPayloadLength;
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetTransportOverhead(const bool TCP,
const bool IPV6,
const WebRtc_UWord8 authenticationOverhead)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetTransportOverhead(TCP:%d, IPV6:%d authenticationOverhead:%u)",TCP,IPV6,authenticationOverhead);
WebRtc_UWord16 packetOverHead = 0;
if(IPV6)
{
packetOverHead = 40;
} else
{
packetOverHead = 20;
}
if(TCP)
{
// TCP
packetOverHead += 20;
} else
{
// UDP
packetOverHead += 8;
}
packetOverHead += authenticationOverhead;
if(packetOverHead == _packetOverHead)
{
// ok same as before
return 0;
}
// calc diff
WebRtc_Word16 packetOverHeadDiff = packetOverHead - _packetOverHead;
// store new
_packetOverHead = packetOverHead;
_rtpReceiver.SetPacketOverHead(_packetOverHead);
WebRtc_UWord16 length = _rtpSender.MaxPayloadLength() - packetOverHeadDiff;
return _rtpSender.SetMaxPayloadLength(length, _packetOverHead);
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetMaxTransferUnit(const WebRtc_UWord16 MTU)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetMaxTransferUnit(%u)",MTU);
if(MTU > IP_PACKET_SIZE)
{
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "Invalid in argument to SetMaxTransferUnit(%u)",MTU);
return -1;
}
return _rtpSender.SetMaxPayloadLength(MTU - _packetOverHead, _packetOverHead);
}
/*
* RTCP
*/
RTCPMethod
ModuleRtpRtcpImpl::RTCP() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RTCP()");
if(_rtcpSender.Status() != kRtcpOff)
{
return _rtcpReceiver.Status();
}
return kRtcpOff;
}
// configure RTCP status i.e on/off
WebRtc_Word32
ModuleRtpRtcpImpl::SetRTCPStatus(const RTCPMethod method)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetRTCPStatus(%d)",method);
if(_rtcpSender.SetRTCPStatus(method) == 0)
{
return _rtcpReceiver.SetRTCPStatus(method);
}
return -1;
}
// only for internal test
WebRtc_UWord32
ModuleRtpRtcpImpl::LastSendReport(WebRtc_UWord32& lastRTCPTime)
{
return _rtcpSender.LastSendReport(lastRTCPTime);
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetCNAME(const WebRtc_Word8 cName[RTCP_CNAME_SIZE])
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetCNAME(%s)", cName);
return _rtcpSender.SetCNAME(cName);
}
WebRtc_Word32
ModuleRtpRtcpImpl::CNAME(WebRtc_Word8 cName[RTCP_CNAME_SIZE])
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "CNAME()");
return _rtcpSender.CNAME(cName);
}
WebRtc_Word32
ModuleRtpRtcpImpl::AddMixedCNAME(const WebRtc_UWord32 SSRC,
const WebRtc_Word8 cName[RTCP_CNAME_SIZE])
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "AddMixedCNAME(SSRC:%u)", SSRC);
return _rtcpSender.AddMixedCNAME(SSRC, cName);
}
WebRtc_Word32
ModuleRtpRtcpImpl::RemoveMixedCNAME(const WebRtc_UWord32 SSRC)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemoveMixedCNAME(SSRC:%u)", SSRC);
return _rtcpSender.RemoveMixedCNAME(SSRC);
}
WebRtc_Word32
ModuleRtpRtcpImpl::RemoteCNAME(const WebRtc_UWord32 remoteSSRC,
WebRtc_Word8 cName[RTCP_CNAME_SIZE]) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemoteCNAME(SSRC:%u)", remoteSSRC);
return _rtcpReceiver.CNAME(remoteSSRC, cName);
}
WebRtc_UWord16 ModuleRtpRtcpImpl::RemoteSequenceNumber() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemoteSequenceNumber()");
return _rtpReceiver.SequenceNumber();
}
WebRtc_Word32
ModuleRtpRtcpImpl::RemoteNTP(WebRtc_UWord32 *receivedNTPsecs,
WebRtc_UWord32 *receivedNTPfrac,
WebRtc_UWord32 *RTCPArrivalTimeSecs,
WebRtc_UWord32 *RTCPArrivalTimeFrac) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemoteNTP()");
return _rtcpReceiver.NTP(receivedNTPsecs,
receivedNTPfrac,
RTCPArrivalTimeSecs,
RTCPArrivalTimeFrac);
}
// Get RoundTripTime
WebRtc_Word32
ModuleRtpRtcpImpl::RTT(const WebRtc_UWord32 remoteSSRC,
WebRtc_UWord16* RTT,
WebRtc_UWord16* avgRTT,
WebRtc_UWord16* minRTT,
WebRtc_UWord16* maxRTT) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RTT()");
return _rtcpReceiver.RTT(remoteSSRC, RTT, avgRTT, minRTT, maxRTT);
}
// Reset RoundTripTime statistics
WebRtc_Word32
ModuleRtpRtcpImpl::ResetRTT(const WebRtc_UWord32 remoteSSRC)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "ResetRTT(SSRC:%u)", remoteSSRC);
return _rtcpReceiver.ResetRTT(remoteSSRC);
}
// Reset RTP statistics
WebRtc_Word32
ModuleRtpRtcpImpl::ResetStatisticsRTP()
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "ResetStatisticsRTP()");
return _rtpReceiver.ResetStatistics();
}
// Reset RTP data counters for the receiving side
WebRtc_Word32
ModuleRtpRtcpImpl::ResetReceiveDataCountersRTP()
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "ResetReceiveDataCountersRTP()");
return _rtpReceiver.ResetDataCounters();
}
// Reset RTP data counters for the sending side
WebRtc_Word32
ModuleRtpRtcpImpl::ResetSendDataCountersRTP()
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "ResetSendDataCountersRTP()");
return _rtpSender.ResetDataCounters();
}
// Force a send of an RTCP packet
// normal SR and RR are triggered via the process function
WebRtc_Word32
ModuleRtpRtcpImpl::SendRTCP(WebRtc_UWord32 rtcpPacketType)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SendRTCP(0x%x)", rtcpPacketType);
return _rtcpSender.SendRTCP(rtcpPacketType);
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetRTCPApplicationSpecificData(const WebRtc_UWord8 subType,
const WebRtc_UWord32 name,
const WebRtc_UWord8* data,
const WebRtc_UWord16 length)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetRTCPApplicationSpecificData(subType:%d name:0x%x)", subType, name);
return _rtcpSender.SetApplicationSpecificData(subType, name, data, length);
}
/*
* (XR) VOIP metric
*/
WebRtc_Word32
ModuleRtpRtcpImpl::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetRTCPVoIPMetrics()");
return _rtcpSender.SetRTCPVoIPMetrics(VoIPMetric);
}
// our localy created statistics of the received RTP stream
WebRtc_Word32
ModuleRtpRtcpImpl::StatisticsRTP(WebRtc_UWord8 *fraction_lost,
WebRtc_UWord32 *cum_lost,
WebRtc_UWord32 *ext_max,
WebRtc_UWord32 *jitter,
WebRtc_UWord32 *max_jitter) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "StatisticsRTP()");
WebRtc_Word32 retVal =_rtpReceiver.Statistics(fraction_lost,cum_lost,ext_max,jitter, max_jitter,(_rtcpSender.Status() == kRtcpOff));
if(retVal == -1)
{
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "StatisticsRTP() no statisitics availble");
}
return retVal;
}
WebRtc_Word32
ModuleRtpRtcpImpl::DataCountersRTP(WebRtc_UWord32 *bytesSent,
WebRtc_UWord32 *packetsSent,
WebRtc_UWord32 *bytesReceived,
WebRtc_UWord32 *packetsReceived) const
{
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id, "DataCountersRTP()");
if(bytesSent)
{
*bytesSent = _rtpSender.Bytes();
}
if(packetsSent)
{
*packetsSent= _rtpSender.Packets();
}
return _rtpReceiver.DataCounters(bytesReceived, packetsReceived);
}
WebRtc_Word32
ModuleRtpRtcpImpl::ReportBlockStatistics(WebRtc_UWord8 *fraction_lost,
WebRtc_UWord32 *cum_lost,
WebRtc_UWord32 *ext_max,
WebRtc_UWord32 *jitter)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "ReportBlockStatistics()");
WebRtc_Word32 missing = 0;
WebRtc_Word32 ret = _rtpReceiver.Statistics(fraction_lost,cum_lost,ext_max,jitter, NULL, &missing, true);
#ifdef MATLAB
if (_plot1 == NULL)
{
_plot1 = eng.NewPlot(new MatlabPlot());
_plot1->AddTimeLine(30, "b", "lost", TickTime::MillisecondTimestamp());
}
_plot1->Append("lost", missing);
_plot1->Plot();
#endif
return ret;
}
WebRtc_Word32
ModuleRtpRtcpImpl::RemoteRTCPStat( RTCPSenderInfo* senderInfo)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemoteRTCPStat()");
return _rtcpReceiver.SenderInfoReceived(senderInfo);
}
// received RTCP report
WebRtc_Word32
ModuleRtpRtcpImpl::RemoteRTCPStat(const WebRtc_UWord32 remoteSSRC,
RTCPReportBlock* receiveBlock)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemoteRTCPStat()");
return _rtcpReceiver.StatisticsReceived(remoteSSRC, receiveBlock);
}
WebRtc_Word32
ModuleRtpRtcpImpl::AddRTCPReportBlock(const WebRtc_UWord32 SSRC,
const RTCPReportBlock* reportBlock)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "AddRTCPReportBlock()");
return _rtcpSender.AddReportBlock(SSRC, reportBlock);
}
WebRtc_Word32
ModuleRtpRtcpImpl::RemoveRTCPReportBlock(const WebRtc_UWord32 SSRC)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemoveRTCPReportBlock()");
return _rtcpSender.RemoveReportBlock(SSRC);
}
/*
* (TMMBR) Temporary Max Media Bit Rate
*/
bool
ModuleRtpRtcpImpl::TMMBR() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "TMMBR()");
return _rtcpSender.TMMBR();
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetTMMBRStatus(const bool enable)
{
if(enable)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetTMMBRStatus(enable)");
}else
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetTMMBRStatus(disable)");
}
return _rtcpSender.SetTMMBRStatus(enable);
}
WebRtc_Word32
ModuleRtpRtcpImpl::TMMBRReceived(const WebRtc_UWord32 size,
const WebRtc_UWord32 accNumCandidates,
TMMBRSet* candidateSet) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "TMMBRReceived()");
return _rtcpReceiver.TMMBRReceived(size, accNumCandidates, candidateSet);
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetTMMBN(const TMMBRSet* boundingSet,
const WebRtc_UWord32 maxBitrateKbit)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetTMMBN()");
return _rtcpSender.SetTMMBN(boundingSet, maxBitrateKbit);
}
WebRtc_Word32
ModuleRtpRtcpImpl::RequestTMMBR(const WebRtc_UWord32 estimatedBW,
const WebRtc_UWord32 packetOH)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RequestTMMBR()");
return _rtcpSender.RequestTMMBR(estimatedBW, packetOH);
}
/*
* (NACK) Negative acknowledgement
*/
// Is Negative acknowledgement requests on/off?
NACKMethod
ModuleRtpRtcpImpl::NACK() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "NACK()");
NACKMethod childMethod = kNackOff;
const bool defaultInstance(_childModules.Empty() ? false : true);
if (defaultInstance)
{
// for default we need to check all child modules too
CriticalSectionScoped lock(_criticalSectionModulePtrs);
ListItem* item = _childModules.First();
while(item)
{
RtpRtcp* module = static_cast<RtpRtcp*>(item->GetItem());
if (module)
{
NACKMethod nackMethod = module->NACK();
if (nackMethod != kNackOff)
{
childMethod = nackMethod;
break;
}
}
item = _childModules.Next(item);
}
}
NACKMethod method = _nackMethod;
if (childMethod != kNackOff)
{
method = childMethod;
}
return method;
}
// Turn negative acknowledgement requests on/off
WebRtc_Word32
ModuleRtpRtcpImpl::SetNACKStatus(NACKMethod method)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetNACKStatus(%u)",method);
_nackMethod = method;
_rtpReceiver.SetNACKStatus(method);
return 0;
}
// Send a Negative acknowledgement packet
WebRtc_Word32
ModuleRtpRtcpImpl::SendNACK(const WebRtc_UWord16* nackList,
const WebRtc_UWord16 size)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SendNACK(size:%u)", size);
if(size > NACK_PACKETS_MAX_SIZE)
{
RequestKeyFrame(kVideoFrameKey);
return -1;
}
WebRtc_UWord16 avgRTT = 0;
_rtcpReceiver.RTT(_rtpReceiver.SSRC(),NULL, &avgRTT, NULL, NULL);
WebRtc_UWord32 waitTime = 5 +((avgRTT*3)>>1); // 5 + RTT*1.5
if(waitTime==5)
{
waitTime = 100; //During startup we don't have an RTT
}
const WebRtc_UWord32 now = ModuleRTPUtility::GetTimeInMS();
const WebRtc_UWord32 timeLimit = now - waitTime;
if(_nackLastTimeSent < timeLimit)
{
// send list
} else
{
// only send if extended list
if(_nackLastSeqNumberSent == nackList[size-1])
{
// last seq num is the same don't send list
return 0;
}else
{
// send list
}
}
_nackLastTimeSent = now;
_nackLastSeqNumberSent = nackList[size-1];
switch(_nackMethod)
{
case kNackRtcp:
return _rtcpSender.SendRTCP(kRtcpNack, size, nackList);
case kNackOff:
return -1;
default:
assert(false);
};
return -1;
}
// Store the sent packets, needed to answer to a Negative acknowledgement requests
WebRtc_Word32
ModuleRtpRtcpImpl::SetStorePacketsStatus(const bool enable, const WebRtc_UWord16 numberToStore)
{
if(enable)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetStorePacketsStatus(enable, numberToStore:%d)", numberToStore);
}else
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetStorePacketsStatus(disable)");
}
return _rtpSender.SetStorePacketsStatus(enable, numberToStore);
}
/*
* Audio
*/
// Outband TelephoneEvent detection
WebRtc_Word32 ModuleRtpRtcpImpl::SetTelephoneEventStatus(const bool enable,
const bool forwardToDecoder,
const bool detectEndOfTone)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetTelephoneEventStatus(enable:%d forwardToDecoder:%d detectEndOfTone:%d)", enable, forwardToDecoder, detectEndOfTone);
return _rtpReceiver.SetTelephoneEventStatus(enable, forwardToDecoder, detectEndOfTone);
}
// Is outband TelephoneEvent turned on/off?
bool ModuleRtpRtcpImpl::TelephoneEvent() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "TelephoneEvent()");
return _rtpReceiver.TelephoneEvent();
}
// Is forwarding of outband telephone events turned on/off?
bool ModuleRtpRtcpImpl::TelephoneEventForwardToDecoder() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "TelephoneEventForwardToDecoder()");
return _rtpReceiver.TelephoneEventForwardToDecoder();
}
// Send a TelephoneEvent tone using RFC 2833 (4733)
WebRtc_Word32
ModuleRtpRtcpImpl::SendTelephoneEventOutband(const WebRtc_UWord8 key,
const WebRtc_UWord16 timeMs,
const WebRtc_UWord8 level)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SendTelephoneEventOutband(key:%u, timeMs:%u, level:%u)", key, timeMs, level);
return _rtpSender.SendTelephoneEvent(key, timeMs, level);
}
bool
ModuleRtpRtcpImpl::SendTelephoneEventActive(WebRtc_Word8& telephoneEvent) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SendTelephoneEventActive()");
return _rtpSender.SendTelephoneEventActive(telephoneEvent);
}
// set audio packet size, used to determine when it's time to send a DTMF packet in silence (CNG)
WebRtc_Word32
ModuleRtpRtcpImpl::SetAudioPacketSize(const WebRtc_UWord16 packetSizeSamples)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetAudioPacketSize(%u)", packetSizeSamples);
return _rtpSender.SetAudioPacketSize(packetSizeSamples);
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetRTPAudioLevelIndicationStatus(const bool enable,
const WebRtc_UWord8 ID)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id,
"SetRTPAudioLevelIndicationStatus(enable=%d, ID=%u)", enable, ID);
return _rtpSender.SetAudioLevelIndicationStatus(enable, ID);
}
WebRtc_Word32
ModuleRtpRtcpImpl::GetRTPAudioLevelIndicationStatus(bool& enable,
WebRtc_UWord8& ID) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "GetRTPAudioLevelIndicationStatus()");
return _rtpSender.AudioLevelIndicationStatus(enable, ID);
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetAudioLevel(const WebRtc_UWord8 level_dBov)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetAudioLevel(level_dBov:%u)", level_dBov);
return _rtpSender.SetAudioLevel(level_dBov);
}
// Set payload type for Redundant Audio Data RFC 2198
WebRtc_Word32
ModuleRtpRtcpImpl::SetSendREDPayloadType(const WebRtc_Word8 payloadType)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetSendREDPayloadType(%d)", payloadType);
return _rtpSender.SetRED(payloadType);
}
// Get payload type for Redundant Audio Data RFC 2198
WebRtc_Word32
ModuleRtpRtcpImpl::SendREDPayloadType(WebRtc_Word8& payloadType) const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SendREDPayloadType()");
return _rtpSender.RED(payloadType);
}
/*
* Video
*/
RtpVideoCodecTypes
ModuleRtpRtcpImpl::ReceivedVideoCodec() const
{
return _rtpReceiver.VideoCodecType();
}
RtpVideoCodecTypes
ModuleRtpRtcpImpl::SendVideoCodec() const
{
return _rtpSender.VideoCodecType();
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetSendBitrate(const WebRtc_UWord32 startBitrate,
const WebRtc_UWord16 minBitrateKbit,
const WebRtc_UWord16 maxBitrateKbit)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetSendBitrate start:%ubit/s min:%uKbit/s max:%uKbit/s", startBitrate, minBitrateKbit, maxBitrateKbit);
const bool defaultInstance(_childModules.Empty()?false:true);
if(defaultInstance)
{
// for default we need to update all child modules too
CriticalSectionScoped lock(_criticalSectionModulePtrs);
ListItem* item = _childModules.First();
while (item)
{
RtpRtcp* module = (RtpRtcp*)item->GetItem();
if(module)
{
module->SetSendBitrate(startBitrate, minBitrateKbit, maxBitrateKbit);
}
item = _childModules.Next(item);
}
}
_rtpSender.SetTargetSendBitrate(startBitrate);
return _bandwidthManagement.SetSendBitrate(startBitrate, minBitrateKbit, maxBitrateKbit);
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetKeyFrameRequestMethod(const KeyFrameRequestMethod method)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetKeyFrameRequestMethod(method:%u)",method);
_keyFrameReqMethod = method;
return 0;
}
WebRtc_Word32
ModuleRtpRtcpImpl::RequestKeyFrame(const FrameType frameType)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RequestKeyFrame(frameType:%d)",frameType);
switch(_keyFrameReqMethod)
{
case kKeyFrameReqFirRtp:
return _rtpSender.SendRTPIntraRequest();
case kKeyFrameReqPliRtcp:
return _rtcpSender.SendRTCP(kRtcpPli);
case kKeyFrameReqFirRtcp:
{
// conference scenario
WebRtc_UWord16 RTT = 0;
_rtcpReceiver.RTT(_rtpReceiver.SSRC(), &RTT, NULL,NULL,NULL);
return _rtcpSender.SendRTCP(kRtcpFir, 0,NULL, RTT);
}
default:
assert(false);
return -1;
}
}
WebRtc_Word32
ModuleRtpRtcpImpl::SendRTCPSliceLossIndication(const WebRtc_UWord8 pictureID)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SendRTCPSliceLossIndication (pictureID:%d)", pictureID);
return _rtcpSender.SendRTCP(kRtcpSli, 0,0,0, pictureID);
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetCameraDelay(const WebRtc_Word32 delayMS)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetCameraDelay(%d)",delayMS);
const bool defaultInstance(_childModules.Empty()?false:true);
if(defaultInstance)
{
CriticalSectionScoped lock(_criticalSectionModulePtrs);
ListItem* item = _childModules.First();
while (item)
{
RtpRtcp* module = (RtpRtcp*)item->GetItem();
if(module)
{
module->SetCameraDelay(delayMS);
}
item = _childModules.Next(item);
}
return 0;
} else
{
return _rtcpSender.SetCameraDelay(delayMS);
}
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetGenericFECStatus(const bool enable,
const WebRtc_UWord8 payloadTypeRED,
const WebRtc_UWord8 payloadTypeFEC)
{
if(enable)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetGenericFECStatus(enable, %u)", payloadTypeRED);
} else
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetGenericFECStatus(disable)");
}
return _rtpSender.SetGenericFECStatus(enable, payloadTypeRED, payloadTypeFEC);
}
WebRtc_Word32
ModuleRtpRtcpImpl::GenericFECStatus(bool& enable, WebRtc_UWord8& payloadTypeRED, WebRtc_UWord8& payloadTypeFEC)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "GenericFECStatus()");
bool childEnabled = false;
const bool defaultInstance(_childModules.Empty() ? false : true);
if (defaultInstance)
{
// for default we need to check all child modules too
CriticalSectionScoped lock(_criticalSectionModulePtrs);
ListItem* item = _childModules.First();
while(item)
{
RtpRtcp* module = static_cast<RtpRtcp*>(item->GetItem());
if (module)
{
bool enabled = false;
WebRtc_UWord8 dummyPTypeRED = 0;
WebRtc_UWord8 dummyPTypeFEC = 0;
if (module->GenericFECStatus(enabled, dummyPTypeRED, dummyPTypeFEC) == 0 && enabled)
{
childEnabled = true;
break;
}
}
item = _childModules.Next(item);
}
}
WebRtc_Word32 retVal = _rtpSender.GenericFECStatus(enable, payloadTypeRED, payloadTypeFEC);
if (childEnabled)
{
// returns true if enabled for any child module
enable = childEnabled;
}
return retVal;
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetFECCodeRate(const WebRtc_UWord8 keyFrameCodeRate,
const WebRtc_UWord8 deltaFrameCodeRate)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetFECCodeRate(%u, %u)", keyFrameCodeRate, deltaFrameCodeRate);
const bool defaultInstance(_childModules.Empty()?false:true);
if (defaultInstance)
{
// for default we need to update all child modules too
CriticalSectionScoped lock(_criticalSectionModulePtrs);
ListItem* item = _childModules.First();
while (item)
{
RtpRtcp* module = (RtpRtcp*)item->GetItem();
if (module)
{
module->SetFECCodeRate(keyFrameCodeRate, deltaFrameCodeRate);
}
item = _childModules.Next(item);
}
return 0;
} else
{
return _rtpSender.SetFECCodeRate(keyFrameCodeRate, deltaFrameCodeRate);
}
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetFECUepProtection(const bool keyUseUepProtection,
const bool deltaUseUepProtection)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id,
"SetFECUepProtection(%d, %d)", keyUseUepProtection,
deltaUseUepProtection);
const bool defaultInstance(_childModules.Empty()?false:true);
if (defaultInstance)
{
// for default we need to update all child modules too
CriticalSectionScoped lock(_criticalSectionModulePtrs);
ListItem* item = _childModules.First();
while (item)
{
RtpRtcp* module = (RtpRtcp*)item->GetItem();
if (module)
{
module->SetFECUepProtection(keyUseUepProtection,
deltaUseUepProtection);
}
item = _childModules.Next(item);
}
return 0;
} else
{
return _rtpSender.SetFECUepProtection(keyUseUepProtection,
deltaUseUepProtection);
}
}
/*
* Implementation of ModuleRtpRtcpPrivate
*/
void
ModuleRtpRtcpImpl::SetRemoteSSRC(const WebRtc_UWord32 SSRC)
{
// inform about the incoming SSRC
_rtcpSender.SetRemoteSSRC(SSRC);
_rtcpReceiver.SetRemoteSSRC(SSRC);
// check for a SSRC collision
if(_rtpSender.SSRC() == SSRC && !_collisionDetected ) // loopback
{
// if we detect a collision change the SSRC but only once
_collisionDetected = true;
WebRtc_UWord32 newSSRC =_rtpSender.GenerateNewSSRC();
if(newSSRC == 0)
{
// configured via API ignore
return;
}
if(kRtcpOff != _rtcpSender.Status())
{
// send RTCP bye on the current SSRC
_rtcpSender.SendRTCP(kRtcpBye);
}
// change local SSRC
// inform all objects about the new SSRC
_rtcpSender.SetSSRC(newSSRC);
_rtcpReceiver.SetSSRC(newSSRC);
}
}
WebRtc_UWord32
ModuleRtpRtcpImpl::BitrateReceivedNow() const
{
return _rtpReceiver.BitrateNow();
}
WebRtc_UWord32
ModuleRtpRtcpImpl::BitrateSent() const
{
const bool defaultInstance(_childModules.Empty()?false:true);
if(defaultInstance)
{
// for default we need to update the send bitrate
CriticalSectionScoped lock(_criticalSectionModulePtrsFeedback);
ListItem* item = _childModules.First();
WebRtc_UWord32 bitrate = 0;
while (item)
{
RtpRtcp* module = (RtpRtcp*)item->GetItem();
if(module)
{
bitrate = (module->BitrateSent() > bitrate) ?module->BitrateSent():bitrate;
}
item = _childModules.Next(item);
}
return bitrate;
} else
{
return _rtpSender.BitrateLast();
}
}
// for lip sync
void
ModuleRtpRtcpImpl::OnReceivedNTP()
{
// don't do anything if we are the audio module
// video module is responsible for sync
if(!_audio)
{
WebRtc_Word32 diff = 0;
WebRtc_UWord32 receivedNTPsecs = 0;
WebRtc_UWord32 receivedNTPfrac= 0;
WebRtc_UWord32 RTCPArrivalTimeSecs= 0;
WebRtc_UWord32 RTCPArrivalTimeFrac= 0;
if(0 == _rtcpReceiver.NTP(&receivedNTPsecs, &receivedNTPfrac, &RTCPArrivalTimeSecs, &RTCPArrivalTimeFrac))
{
CriticalSectionScoped lock(_criticalSectionModulePtrs);
if(_audioModule)
{
if(0 != _audioModule->RemoteNTP(&_receivedNTPsecsAudio,
&_receivedNTPfracAudio,
&_RTCPArrivalTimeSecsAudio,
&_RTCPArrivalTimeFracAudio))
{
// failed ot get audio NTP
return;
}
}
if(_receivedNTPfracAudio != 0)
{
// ReceivedNTPxxx is NTP at sender side when sent.
// RTCPArrivalTimexxx is NTP at receiver side when received.
// can't use ConvertNTPTimeToMS since calculation can be negative
WebRtc_Word32 NTPdiff = (WebRtc_Word32)((_receivedNTPsecsAudio - receivedNTPsecs)*1000); // ms
NTPdiff += (WebRtc_Word32)(_receivedNTPfracAudio/FracMS - receivedNTPfrac/FracMS); // ms
WebRtc_Word32 RTCPdiff = (WebRtc_Word32)((_RTCPArrivalTimeSecsAudio - RTCPArrivalTimeSecs)*1000); // ms
RTCPdiff += (WebRtc_Word32)((_RTCPArrivalTimeFracAudio/FracMS - RTCPArrivalTimeFrac/FracMS)); // ms
diff = NTPdiff - RTCPdiff;
// if diff is + video is behind
if(diff < -1000 || diff > 1000)
{
// unresonable ignore value.
diff = 0;
return;
}
}
}
// export via callback
// after release of critsect
_rtcpReceiver.UpdateLipSync(diff);
}
}
// our local BW estimate is updated
void
ModuleRtpRtcpImpl::OnBandwidthEstimateUpdate(WebRtc_UWord16 bandWidthKbit)
{
WebRtc_UWord32 maxBitrateKbit = _rtpReceiver.MaxConfiguredBitrate()/1000;
if(maxBitrateKbit)
{
// the app has set a max bitrate
if(maxBitrateKbit < bandWidthKbit)
{
// cap TMMBR at max configured bitrate
bandWidthKbit = (WebRtc_UWord16)maxBitrateKbit;
}
}
if(_rtcpSender.TMMBR())
{
/* Maximum total media bit rate:
The upper limit on total media bit rate for a given media
stream at a particular receiver and for its selected protocol
layer. Note that this value cannot be measured on the
received media stream. Instead, it needs to be calculated or
determined through other means, such as quality of service
(QoS) negotiations or local resource limitations. Also note
that this value is an average (on a timescale that is
reasonable for the application) and that it may be different
from the instantaneous bit rate seen by packets in the media
stream.
*/
/* Overhead:
All protocol header information required to convey a packet
with media data from sender to receiver, from the application
layer down to a pre-defined protocol level (for example, down
to, and including, the IP header). Overhead may include, for
example, IP, UDP, and RTP headers, any layer 2 headers, any
Contributing Sources (CSRCs), RTP padding, and RTP header
extensions. Overhead excludes any RTP payload headers and the
payload itself.
*/
_rtpReceiver.PacketOHReceived();
// call RequestTMMBR when our localy created estimate changes
_rtcpSender.RequestTMMBR(bandWidthKbit, 0);
}
}
RateControlRegion
ModuleRtpRtcpImpl::OnOverUseStateUpdate(const RateControlInput& rateControlInput)
{
bool firstOverUse = false;
const RateControlRegion region = _rtcpSender.UpdateOverUseState(rateControlInput, firstOverUse);
if (firstOverUse && _rtcpSender.Status() == kRtcpNonCompound)
{
// Send TMMBR immediately
WebRtc_UWord16 RTT = 0;
_rtcpReceiver.RTT(_rtpReceiver.SSRC(), &RTT, NULL,NULL,NULL);
_rtcpSender.SendRTCP(kRtcpTmmbr, 0, 0, RTT);
}
return region;
}
// bad state of RTP receiver request a keyframe
void
ModuleRtpRtcpImpl::OnRequestIntraFrame(const FrameType frameType)
{
RequestKeyFrame(frameType);
}
void
ModuleRtpRtcpImpl::OnReceivedIntraFrameRequest(const WebRtc_UWord8 message)
{
if(_defaultModule)
{
CriticalSectionScoped lock(_criticalSectionModulePtrs);
if(_defaultModule)
{
// if we use a default module pass this info to the default module
_defaultModule->OnReceivedIntraFrameRequest(message);
return;
}
}
_rtcpReceiver.OnReceivedIntraFrameRequest(message);
}
// received a request for a new SLI
void
ModuleRtpRtcpImpl::OnReceivedSliceLossIndication(const WebRtc_UWord8 pictureID)
{
if(_defaultModule)
{
CriticalSectionScoped lock(_criticalSectionModulePtrs);
if(_defaultModule)
{
// if we use a default module pass this info to the default module
_defaultModule->OnReceivedSliceLossIndication(pictureID);
return;
}
}
_rtcpReceiver.OnReceivedSliceLossIndication(pictureID);
}
// received a new refereence frame
void
ModuleRtpRtcpImpl::OnReceivedReferencePictureSelectionIndication(const WebRtc_UWord64 pictureID)
{
if(_defaultModule)
{
CriticalSectionScoped lock(_criticalSectionModulePtrs);
if(_defaultModule)
{
// if we use a default module pass this info to the default module
_defaultModule->OnReceivedReferencePictureSelectionIndication(pictureID);
return;
}
}
_rtcpReceiver.OnReceivedReferencePictureSelectionIndication(pictureID);
}
void
ModuleRtpRtcpImpl::OnReceivedBandwidthEstimateUpdate(const WebRtc_UWord16 bwEstimateMinKbit,
const WebRtc_UWord16 bwEstimateMaxKbit)
{
if(_defaultModule)
{
CriticalSectionScoped lock(_criticalSectionModulePtrs);
if(_defaultModule)
{
// if we use a default module pass this info to the default module
_defaultModule->OnReceivedBandwidthEstimateUpdate(bwEstimateMinKbit, bwEstimateMaxKbit);
return;
}
}
if(_audio)
{
_rtcpReceiver.UpdateBandwidthEstimate(bwEstimateMinKbit);
}else
{
WebRtc_UWord32 newBitrate = 0;
WebRtc_UWord8 fractionLost = 0;
WebRtc_UWord16 roundTripTime = 0;
if(_bandwidthManagement.UpdateBandwidthEstimate(bwEstimateMinKbit, bwEstimateMaxKbit, newBitrate, fractionLost,roundTripTime) == 0)
{
// video callback
_rtpReceiver.UpdateBandwidthManagement(newBitrate, newBitrate, fractionLost, roundTripTime, bwEstimateMinKbit, bwEstimateMaxKbit);
const bool defaultInstance = !_childModules.Empty();
if((newBitrate > 0) && !defaultInstance)
{
// update bitrate
_rtpSender.SetTargetSendBitrate(newBitrate);
}
}
}
}
// bw estimation
void
ModuleRtpRtcpImpl::OnPacketLossStatisticsUpdate(const WebRtc_UWord8 fractionLost,
const WebRtc_UWord16 roundTripTime,
const WebRtc_UWord32 lastReceivedExtendedHighSeqNum,
const WebRtc_UWord32 jitter)
{
WebRtc_UWord32 newBitrate = 0;
WebRtc_UWord8 filteredFractionLost = fractionLost;
WebRtc_UWord16 filteredRoundTripTime = roundTripTime;
WebRtc_UWord16 bwEstimateKbitMin = 0;
WebRtc_UWord16 bwEstimateKbitMax = 0;
const bool defaultInstance(_childModules.Empty()?false:true);
{
if(_bandwidthManagement.UpdatePacketLoss(lastReceivedExtendedHighSeqNum,
defaultInstance,
fractionLost,
roundTripTime,
newBitrate,
bwEstimateKbitMin,
bwEstimateKbitMax) != 0)
{
// ignore this update
newBitrate = 0;
}
}
if(newBitrate != 0 &&
!defaultInstance)
{
// We need to do update RTP sender before calling default module in
// case we'll strip any layers.
_rtpSender.SetTargetSendBitrate(newBitrate);
if(_defaultModule)
{
// if we have a default module update it
CriticalSectionScoped lock(_criticalSectionModulePtrs);
if(_defaultModule) // we need to check again inside the critsect
{
// if we use a default module pass this info to the default module
_defaultModule->OnPacketLossStatisticsUpdate(filteredFractionLost,
filteredRoundTripTime,
lastReceivedExtendedHighSeqNum,
jitter);
}
return;
}
// video callback
_rtpReceiver.UpdateBandwidthManagement(newBitrate, newBitrate, filteredFractionLost, filteredRoundTripTime, bwEstimateKbitMin, bwEstimateKbitMax);
}
else if (defaultInstance)
{
// Check if it's time to update bitrate
WebRtc_UWord32 now = ModuleRTPUtility::GetTimeInMS();
if((now - _lastChildBitrateUpdate) > (3*RTCP_INTERVAL_VIDEO_MS/2))
{
WebRtc_UWord32 minBitrateBps = 0xffffffff;
WebRtc_UWord32 maxBitrateBps = 0;
{
// Time to update bitrate estimate,
// get min and max for the sending channels
CriticalSectionScoped lock(_criticalSectionModulePtrs);
ListItem* item = _childModules.First();
while(item)
{
// Get child RTP sender and ask for bitrate estimate
ModuleRtpRtcpPrivate* childModule = (ModuleRtpRtcpPrivate*)item->GetItem();
if (childModule->Sending())
{
RTPSender& childRtpSender = static_cast<ModuleRtpRtcpImpl*>(item->GetItem())->_rtpSender;
WebRtc_UWord32 childEstimateBps = 1000*childRtpSender.TargetSendBitrateKbit();
if (childEstimateBps < minBitrateBps)
{
minBitrateBps = childEstimateBps;
}
if (childEstimateBps > maxBitrateBps)
{
maxBitrateBps = childEstimateBps;
}
}
item = _childModules.Next(item);
}
}
// Limit the bitrate with TMMBR.
if(bwEstimateKbitMin && bwEstimateKbitMin<minBitrateBps/1000)
{
minBitrateBps=bwEstimateKbitMin*1000;
}
if(bwEstimateKbitMax && bwEstimateKbitMax<maxBitrateBps/1000)
{
maxBitrateBps=bwEstimateKbitMax*1000;
}
_bandwidthManagement.SetSendBitrate(minBitrateBps,0,0); // Update default module bitrate. Don't care about min max.
if (maxBitrateBps > 0)
{
// video callback
_rtpReceiver.UpdateBandwidthManagement(minBitrateBps, maxBitrateBps, filteredFractionLost, filteredRoundTripTime, bwEstimateKbitMin, bwEstimateKbitMax);
}
_lastChildBitrateUpdate = now;
}
}
}
void
ModuleRtpRtcpImpl::OnRequestSendReport()
{
_rtcpSender.SendRTCP(kRtcpSr);
}
WebRtc_Word32
ModuleRtpRtcpImpl::SendRTCPReferencePictureSelection(const WebRtc_UWord64 pictureID)
{
return _rtcpSender.SendRTCP(kRtcpRpsi, 0,0,0, pictureID);
}
WebRtc_UWord32
ModuleRtpRtcpImpl::SendTimeOfSendReport(const WebRtc_UWord32 sendReport)
{
return _rtcpSender.SendTimeOfSendReport(sendReport);
}
void
ModuleRtpRtcpImpl::OnReceivedNACK(const WebRtc_UWord16 nackSequenceNumbersLength,
const WebRtc_UWord16* nackSequenceNumbers)
{
if(!_rtpSender.StorePackets() || nackSequenceNumbers == NULL || nackSequenceNumbersLength == 0)
{
return;
}
WebRtc_UWord16 avgRTT = 0;
_rtcpReceiver.RTT(_rtpReceiver.SSRC(), NULL, &avgRTT ,NULL,NULL);
_rtpSender.OnReceivedNACK(nackSequenceNumbersLength, nackSequenceNumbers, avgRTT);
}
WebRtc_Word32
ModuleRtpRtcpImpl::LastReceivedNTP(WebRtc_UWord32& RTCPArrivalTimeSecs, // when we received the last report
WebRtc_UWord32& RTCPArrivalTimeFrac,
WebRtc_UWord32& remoteSR) // NTP inside the last received (mid 16 bits from sec and frac)
{
WebRtc_UWord32 NTPsecs = 0;
WebRtc_UWord32 NTPfrac = 0;
if(-1 == _rtcpReceiver.NTP(&NTPsecs, &NTPfrac, &RTCPArrivalTimeSecs, &RTCPArrivalTimeFrac))
{
return -1;
}
remoteSR = ((NTPsecs & 0x0000ffff) << 16) + ((NTPfrac & 0xffff0000) >> 16);
return 0;
}
void
ModuleRtpRtcpImpl::OnReceivedTMMBR()
{
// we received a TMMBR in a RTCP packet
// answer with a TMMBN
UpdateTMMBR();
}
bool
ModuleRtpRtcpImpl::UpdateRTCPReceiveInformationTimers()
{
// if this returns true this channel has timed out
// periodically check if this is true and if so call UpdateTMMBR
return _rtcpReceiver.UpdateRTCPReceiveInformationTimers();
}
WebRtc_Word32
ModuleRtpRtcpImpl::UpdateTMMBR()
{
WebRtc_Word32 numBoundingSet = 0;
WebRtc_Word32 newBitrates = 0;
int minBitrateKbit = 0;
int maxBitrateKbit = 0;
if(_defaultModule)
{
CriticalSectionScoped lock(_criticalSectionModulePtrs);
// no callbacks allowed inside here
if(_defaultModule)
{
// let the default module do the update
return _defaultModule->UpdateTMMBR();
}
}
WebRtc_UWord32 accNumCandidates = 0;
// Find candidate set
if(!_childModules.Empty())
{
CriticalSectionScoped lock(_criticalSectionModulePtrsFeedback);
// this module is the default module
// loop over all modules using the default codec
WebRtc_UWord32 size = 0;
ListItem* item = _childModules.First();
while(item)
{
ModuleRtpRtcpPrivate* module = (ModuleRtpRtcpPrivate*)item->GetItem();
WebRtc_Word32 tmpSize = module->TMMBRReceived(0,0, NULL);
if(tmpSize > 0)
{
size += tmpSize;
}
item = _childModules.Next(item);
}
TMMBRSet* candidateSet = VerifyAndAllocateCandidateSet(size);
if(candidateSet == NULL)
{
return -1;
}
item = _childModules.First();
while(item)
{
ModuleRtpRtcpPrivate* module = (ModuleRtpRtcpPrivate*)item->GetItem();
if(size > accNumCandidates && module)
{
WebRtc_Word32 accSize = module->TMMBRReceived(size, accNumCandidates, candidateSet);
if (accSize > 0)
{
accNumCandidates = accSize;
}
}
item = _childModules.Next(item);
}
} else
{
// this module don't use the default module and is not the default module
WebRtc_Word32 size = _rtcpReceiver.TMMBRReceived(0,0,NULL);
if(size > 0)
{
TMMBRSet* candidateSet = VerifyAndAllocateCandidateSet(size);
// get candidate set from receiver
accNumCandidates = _rtcpReceiver.TMMBRReceived(size, accNumCandidates, candidateSet);
}
else
{
// candidate set empty
VerifyAndAllocateCandidateSet(0); // resets candidate set
}
}
// Find bounding set
TMMBRSet* boundingSet = NULL;
numBoundingSet = FindTMMBRBoundingSet(boundingSet);
if(numBoundingSet == -1)
{
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "Failed to find TMMBR bounding set.");
return -1;
}
// Set bounding set
// Inform remote clients about the new bandwidth
if(_childModules.Empty())
{
// inform the remote client
_rtcpSender.SetTMMBN(boundingSet, _rtpSender.MaxConfiguredBitrateVideo()/1000); // might trigger a TMMBN
} else
{
// inform child modules using the default codec
CriticalSectionScoped lock(_criticalSectionModulePtrsFeedback);
ListItem* item = _childModules.First();
while(item)
{
ModuleRtpRtcpPrivate* module = (ModuleRtpRtcpPrivate*)item->GetItem();
if( module)
{
module->SetTMMBN(boundingSet, _rtpSender.MaxConfiguredBitrateVideo()/1000);
}
item = _childModules.Next(item);
}
}
if(numBoundingSet == 0)
{
// owner of max bitrate request has timed out
// empty bounding set has been sent
return 0;
}
// Get net bitrate from bounding set depending on sent packet rate
newBitrates = CalcMinMaxBitRate(_rtpSender.PacketRate(),
numBoundingSet,
&minBitrateKbit,
&maxBitrateKbit);
// no critsect when calling out to "unknown" code
if(newBitrates == 0) // we have new bitrates
{
// Set new max bitrate
// we have a new bandwidth estimate on this channel
OnReceivedBandwidthEstimateUpdate((WebRtc_UWord16)minBitrateKbit, (WebRtc_UWord16)maxBitrateKbit);
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id, "Set TMMBR request min:%d kbps max:%d kbps, channel: %d", minBitrateKbit, maxBitrateKbit, _id);
}
return 0;
}
// called from RTCPsender
WebRtc_Word32
ModuleRtpRtcpImpl::BoundingSet(bool &tmmbrOwner,
TMMBRSet*& boundingSet)
{
return _rtcpReceiver.BoundingSet(tmmbrOwner,
boundingSet);
}
WebRtc_Word32
ModuleRtpRtcpImpl::SetH263InverseLogic(const bool enable)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetH263InverseLogic(%s)", enable ? "true":"false");
return _rtpReceiver.SetH263InverseLogic(enable);
}
void
ModuleRtpRtcpImpl::SendKeyFrame()
{
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id, "SendKeyFrame()");
OnReceivedIntraFrameRequest(0);
return;
}
} // namespace webrtc