| /* |
| * 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 |