| /* |
| * Copyright (c) 2012 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) |
| { |
| return CreateRtpRtcp(id, audio, ModuleRTPUtility::GetSystemClock()); |
| } |
| |
| RtpRtcp* |
| RtpRtcp::CreateRtpRtcp(const WebRtc_Word32 id, |
| const bool audio, |
| RtpRtcpClock* clock) |
| { |
| if(audio) |
| { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| id, |
| "CreateRtpRtcp(audio)"); |
| } else |
| { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| id, |
| "CreateRtpRtcp(video)"); |
| } |
| return new ModuleRtpRtcpImpl(id, audio, clock); |
| } |
| |
| 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, |
| RtpRtcpClock* clock): |
| TMMBRHelp(audio), |
| _rtpSender(id, audio, clock), |
| _rtpReceiver(id, audio, clock, this), |
| _rtcpSender(id, audio, clock, this), |
| _rtcpReceiver(id, clock, this), |
| _clock(*clock), |
| _id(id), |
| _audio(audio), |
| _collisionDetected(false), |
| _lastProcessTime(clock->GetTimeInMS()), |
| _lastBitrateProcessTime(clock->GetTimeInMS()), |
| _lastPacketTimeoutProcessTime(clock->GetTimeInMS()), |
| |
| _packetOverHead(28), // IPV4 UDP |
| _criticalSectionModulePtrs(CriticalSectionWrapper::CreateCriticalSection()), |
| _criticalSectionModulePtrsFeedback( |
| CriticalSectionWrapper::CreateCriticalSection()), |
| _defaultModule(NULL), |
| _audioModule(NULL), |
| _videoModule(NULL), |
| _deadOrAliveActive(false), |
| _deadOrAliveTimeoutMS(0), |
| _deadOrAliveLastTimer(0), |
| _bandwidthManagement(id), |
| _receivedNTPsecsAudio(0), |
| _receivedNTPfracAudio(0), |
| _RTCPArrivalTimeSecsAudio(0), |
| _RTCPArrivalTimeFracAudio(0), |
| _nackMethod(kNackOff), |
| _nackLastTimeSent(0), |
| _nackLastSeqNumberSent(0), |
| _simulcast(false), |
| _keyFrameReqMethod(kKeyFrameReqFirRtp) |
| #ifdef MATLAB |
| ,_plot1(NULL) |
| #endif |
| { |
| _sendVideoCodec.codecType = kVideoCodecUnknown; |
| // 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 |
| std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin(); |
| while (it != _childModules.end()) |
| { |
| RtpRtcp* module = *it; |
| _childModules.erase(it); |
| if(module) |
| { |
| module->DeRegisterDefaultModule(); |
| } |
| it = _childModules.begin(); |
| } |
| } 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::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; |
| } |
| if(module == this) |
| { |
| WEBRTC_TRACE(kTraceError, |
| kTraceRtpRtcp, |
| _id, |
| "RegisterDefaultModule can't register self as default"); |
| return -1; |
| } |
| CriticalSectionScoped lock(_criticalSectionModulePtrs); |
| |
| if(_defaultModule) |
| { |
| _defaultModule->DeRegisterChildModule(this); |
| } |
| _defaultModule = (ModuleRtpRtcpImpl*)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; |
| } |
| 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.size(); |
| } |
| |
| 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.push_back((ModuleRtpRtcpImpl*)module); |
| } |
| |
| void ModuleRtpRtcpImpl::DeRegisterChildModule(RtpRtcp* removeModule) |
| { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| _id, |
| "DeRegisterChildModule(module:0x%x)", removeModule); |
| |
| CriticalSectionScoped lock(_criticalSectionModulePtrs); |
| |
| CriticalSectionScoped doubleLock(_criticalSectionModulePtrsFeedback); |
| |
| std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin(); |
| while (it != _childModules.end()) |
| { |
| RtpRtcp* module = *it; |
| if(module == removeModule) |
| { |
| _childModules.erase(it); |
| return; |
| } |
| it++; |
| } |
| } |
| |
| // 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 = (ModuleRtpRtcpImpl*)audioModule; |
| return _audioModule->RegisterVideoModule(this); |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::DeRegisterSyncModule() |
| { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| _id, |
| "DeRegisterSyncModule()"); |
| |
| CriticalSectionScoped lock(_criticalSectionModulePtrs); |
| if(_audioModule) |
| { |
| ModuleRtpRtcpImpl* 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 = (ModuleRtpRtcpImpl*)videoModule; |
| return 0; |
| } |
| |
| void ModuleRtpRtcpImpl::DeRegisterVideoModule() |
| { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| _id, |
| "DeRegisterVideoModule()"); |
| |
| CriticalSectionScoped lock(_criticalSectionModulePtrs); |
| if(_videoModule) |
| { |
| ModuleRtpRtcpImpl* 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 = _clock.GetTimeInMS(); |
| return kRtpRtcpMaxIdleTimeProcess - (now -_lastProcessTime); |
| } |
| |
| // Process any pending tasks such as timeouts |
| // non time critical events |
| WebRtc_Word32 ModuleRtpRtcpImpl::Process() { |
| const WebRtc_UWord32 now = _clock.GetTimeInMS(); |
| _lastProcessTime = now; |
| |
| _rtpSender.ProcessSendToNetwork(); |
| |
| if (now >= _lastPacketTimeoutProcessTime + |
| kRtpRtcpPacketTimeoutProcessTimeMs) { |
| _rtpReceiver.PacketTimeout(); |
| _rtcpReceiver.PacketTimeout(); |
| _lastPacketTimeoutProcessTime = now; |
| } |
| |
| if (now >= _lastBitrateProcessTime + kRtpRtcpBitrateProcessTimeMs) { |
| _rtpSender.ProcessBitrate(); |
| _rtpReceiver.ProcessBitrate(); |
| _lastBitrateProcessTime = now; |
| } |
| |
| ProcessDeadOrAliveTimer(); |
| |
| const bool defaultInstance(_childModules.empty() ? false : true); |
| if(!defaultInstance &&_rtcpSender.TimeToSendRTCPReport()) |
| { |
| WebRtc_UWord16 RTT = 0; |
| _rtcpReceiver.RTT(_rtpReceiver.SSRC(), &RTT, NULL, NULL, NULL); |
| if (REMB() && _rtcpSender.ValidBitrateEstimate()) |
| { |
| unsigned int target_bitrate = |
| _rtcpSender.CalculateNewTargetBitrate(RTT); |
| _rtcpSender.UpdateRemoteBitrateEstimate(target_bitrate); |
| } else if (TMMBR()) { |
| _rtcpSender.CalculateNewTargetBitrate(RTT); |
| } |
| _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 = _clock.GetTimeInMS(); |
| if(now > _deadOrAliveTimeoutMS +_deadOrAliveLastTimer) |
| { |
| // RTCP is alive if we have received a report the last 12 seconds |
| _deadOrAliveLastTimer += _deadOrAliveTimeoutMS; |
| |
| bool RTCPalive = false; |
| if(_rtcpReceiver.LastReceived() + 12000 > now) |
| { |
| RTCPalive = true; |
| } |
| _rtpReceiver.ProcessDeadOrAlive(RTCPalive, now); |
| } |
| } |
| } |
| |
| 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; |
| // trigger the first after one period |
| _deadOrAliveLastTimer = _clock.GetTimeInMS(); |
| 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; |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::RegisterReceivePayload( |
| const CodecInst& voiceCodec) |
| { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| _id, |
| "RegisterReceivePayload(voiceCodec)"); |
| |
| return _rtpReceiver.RegisterReceivePayload( |
| voiceCodec.plname, |
| voiceCodec.pltype, |
| voiceCodec.plfreq, |
| voiceCodec.channels, |
| (voiceCodec.rate < 0) ? 0 : voiceCodec.rate); |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::RegisterReceivePayload( |
| const VideoCodec& videoCodec) |
| { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| _id, |
| "RegisterReceivePayload(videoCodec)"); |
| |
| return _rtpReceiver.RegisterReceivePayload(videoCodec.plName, |
| videoCodec.plType, |
| 90000, |
| 0, |
| videoCodec.maxBitrate); |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::ReceivePayloadType( |
| const CodecInst& voiceCodec, |
| WebRtc_Word8* plType) |
| { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| _id, |
| "ReceivePayloadType(voiceCodec)"); |
| |
| return _rtpReceiver.ReceivePayloadType( |
| voiceCodec.plname, |
| voiceCodec.plfreq, |
| voiceCodec.channels, |
| (voiceCodec.rate < 0) ? 0 : voiceCodec.rate, |
| plType); |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::ReceivePayloadType( |
| const VideoCodec& videoCodec, |
| WebRtc_Word8* plType) |
| { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| _id, |
| "ReceivePayloadType(videoCodec)"); |
| |
| return _rtpReceiver.ReceivePayloadType(videoCodec.plName, |
| 90000, |
| 0, |
| videoCodec.maxBitrate, |
| plType); |
| } |
| |
| WebRtc_Word32 |
| ModuleRtpRtcpImpl::DeRegisterReceivePayload(const WebRtc_Word8 payloadType) |
| { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| _id, |
| "DeRegisterReceivePayload(%d)", |
| payloadType); |
| |
| return _rtpReceiver.DeRegisterReceivePayload(payloadType); |
| } |
| |
| // 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); |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::SetRTXSendStatus( |
| const bool enable, |
| const bool setSSRC, |
| const WebRtc_UWord32 SSRC) { |
| _rtpSender.SetRTXStatus(enable, setSSRC, SSRC); |
| return 0; |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::RTXSendStatus(bool* enable, |
| WebRtc_UWord32* SSRC) const { |
| _rtpSender.RTXStatus(enable, SSRC); |
| return 0; |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::SetRTXReceiveStatus( |
| const bool enable, |
| const WebRtc_UWord32 SSRC) { |
| _rtpReceiver.SetRTXStatus(enable, SSRC); |
| return 0; |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::RTXReceiveStatus(bool* enable, |
| WebRtc_UWord32* SSRC) const { |
| _rtpReceiver.RTXStatus(enable, SSRC); |
| return 0; |
| } |
| |
| // 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()) |
| { |
| // Allow receive of non-compound RTCP packets. |
| RTCPUtility::RTCPParserV2 rtcpParser(incomingPacket, |
| incomingPacketLength, |
| true); |
| |
| 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)); |
| |
| RtpHeaderExtensionMap map; |
| _rtpReceiver.GetHeaderExtensionMapCopy(&map); |
| |
| const bool validRTPHeader = rtpParser.Parse(rtpHeader, &map); |
| 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(true, plType:%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(); |
| } |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::RegisterSendPayload( |
| const CodecInst& voiceCodec) |
| { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| _id, |
| "RegisterSendPayload(plName:%s plType:%d frequency:%u)", |
| voiceCodec.plname, |
| voiceCodec.pltype, |
| voiceCodec.plfreq); |
| |
| return _rtpSender.RegisterPayload( |
| voiceCodec.plname, |
| voiceCodec.pltype, |
| voiceCodec.plfreq, |
| voiceCodec.channels, |
| (voiceCodec.rate < 0) ? 0 : voiceCodec.rate); |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::RegisterSendPayload( |
| const VideoCodec& videoCodec) |
| { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| _id, |
| "RegisterSendPayload(plName:%s plType:%d)", |
| videoCodec.plName, |
| videoCodec.plType); |
| |
| _sendVideoCodec = videoCodec; |
| _simulcast = (videoCodec.numberOfSimulcastStreams > 1) ? true : false; |
| return _rtpSender.RegisterPayload(videoCodec.plName, |
| videoCodec.plType, |
| 90000, |
| 0, |
| videoCodec.maxBitrate); |
| } |
| |
| 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); |
| |
| std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin(); |
| while (it != _childModules.end()) |
| { |
| RtpRtcp* module = *it; |
| if(module) |
| { |
| module->SetCSRCs(arrOfCSRC, arrLength); |
| } |
| it++; |
| } |
| 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 |
| if (_rtcpSender.SetSendingStatus(sending) != 0) { |
| WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, |
| "Failed to send RTCP BYE"); |
| } |
| |
| _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 0; |
| } |
| 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(); |
| } |
| |
| CriticalSectionScoped lock(_criticalSectionModulePtrs); |
| std::list<ModuleRtpRtcpImpl*>::const_iterator it = _childModules.begin(); |
| while (it != _childModules.end()) |
| { |
| RTPSender& rtpSender = (*it)->_rtpSender; |
| if (rtpSender.SendingMedia()) |
| { |
| return true; |
| } |
| it++; |
| } |
| 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 RTPVideoHeader* rtpVideoHdr) |
| { |
| WEBRTC_TRACE( |
| kTraceStream, |
| kTraceRtpRtcp, |
| _id, |
| "SendOutgoingData(frameType:%d payloadType:%d timeStamp:%u size:%u)", |
| frameType, payloadType, timeStamp, payloadSize); |
| |
| const bool haveChildModules(_childModules.empty() ? false : true); |
| if(!haveChildModules) |
| { |
| // Don't sent RTCP from default module |
| if(_rtcpSender.TimeToSendRTCPReport(kVideoFrameKey == frameType)) |
| { |
| WebRtc_UWord16 RTT = 0; |
| _rtcpReceiver.RTT(_rtpReceiver.SSRC(), &RTT, NULL, NULL, NULL); |
| _rtcpSender.SendRTCP(kRtcpReport, 0, 0, RTT); |
| } |
| return _rtpSender.SendOutgoingData(frameType, |
| payloadType, |
| timeStamp, |
| payloadData, |
| payloadSize, |
| fragmentation, |
| NULL, |
| &(rtpVideoHdr->codecHeader)); |
| } |
| WebRtc_Word32 retVal = -1; |
| if (_simulcast) |
| { |
| if (rtpVideoHdr == NULL) |
| { |
| return -1; |
| } |
| int idx = 0; |
| CriticalSectionScoped lock(_criticalSectionModulePtrs); |
| std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin(); |
| for (; idx < rtpVideoHdr->simulcastIdx; idx++) |
| { |
| it++; |
| if (it == _childModules.end()) |
| { |
| return -1; |
| } |
| } |
| RTPSender& rtpSender = (*it)->_rtpSender; |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| _id, |
| "SendOutgoingData(SimulcastIdx:%u size:%u, ssrc:0x%x)", |
| idx, payloadSize, rtpSender.SSRC()); |
| return rtpSender.SendOutgoingData(frameType, |
| payloadType, |
| timeStamp, |
| payloadData, |
| payloadSize, |
| fragmentation, |
| NULL, |
| &(rtpVideoHdr->codecHeader)); |
| } else |
| { |
| CriticalSectionScoped lock(_criticalSectionModulePtrs); |
| // TODO(pwestin) remove codecInfo from SendOutgoingData |
| VideoCodecInformation* codecInfo = NULL; |
| |
| std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin(); |
| if (it != _childModules.end()) |
| { |
| RTPSender& rtpSender = (*it)->_rtpSender; |
| retVal = rtpSender.SendOutgoingData(frameType, |
| payloadType, |
| timeStamp, |
| payloadData, |
| payloadSize, |
| fragmentation, |
| NULL, |
| &(rtpVideoHdr->codecHeader)); |
| |
| it++; |
| } |
| |
| // send to all remaining "child" modules |
| while (it != _childModules.end()) |
| { |
| RTPSender& rtpSender = (*it)->_rtpSender; |
| retVal = rtpSender.SendOutgoingData(frameType, |
| payloadType, |
| timeStamp, |
| payloadData, |
| payloadSize, |
| fragmentation, |
| codecInfo, |
| &(rtpVideoHdr->codecHeader)); |
| |
| it++; |
| } |
| } |
| 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); |
| std::list<ModuleRtpRtcpImpl*>::const_iterator it = |
| _childModules.begin(); |
| while (it != _childModules.end()) |
| { |
| RtpRtcp* module = *it; |
| if (module) |
| { |
| WebRtc_UWord16 dataPayloadLength = |
| module->MaxDataPayloadLength(); |
| if (dataPayloadLength < minDataPayloadLength) |
| { |
| minDataPayloadLength = dataPayloadLength; |
| } |
| } |
| it++; |
| } |
| } |
| |
| 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 char cName[RTCP_CNAME_SIZE]) { |
| WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetCNAME(%s)", cName); |
| return _rtcpSender.SetCNAME(cName); |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::CNAME(char cName[RTCP_CNAME_SIZE]) { |
| WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "CNAME()"); |
| return _rtcpSender.CNAME(cName); |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::AddMixedCNAME( |
| const WebRtc_UWord32 SSRC, |
| const char 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, |
| char 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_UWord32 jitter_transmission_time_offset = 0; |
| |
| WebRtc_Word32 retVal =_rtpReceiver.Statistics(fraction_lost, cum_lost, |
| ext_max, jitter, max_jitter, &jitter_transmission_time_offset, |
| (_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_UWord32 *jitter_transmission_time_offset) |
| { |
| WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "ReportBlockStatistics()"); |
| WebRtc_Word32 missing = 0; |
| WebRtc_Word32 ret = _rtpReceiver.Statistics(fraction_lost, |
| cum_lost, |
| ext_max, |
| jitter, |
| NULL, |
| jitter_transmission_time_offset, |
| &missing, |
| true); |
| |
| #ifdef MATLAB |
| if (_plot1 == NULL) |
| { |
| _plot1 = eng.NewPlot(new MatlabPlot()); |
| _plot1->AddTimeLine(30, "b", "lost", _clock.GetTimeInMS()); |
| } |
| _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( |
| std::vector<RTCPReportBlock>* receiveBlocks) const { |
| WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemoteRTCPStat()"); |
| |
| return _rtcpReceiver.StatisticsReceived(receiveBlocks); |
| } |
| |
| 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); |
| } |
| |
| /* |
| * (REMB) Receiver Estimated Max Bitrate |
| */ |
| bool ModuleRtpRtcpImpl::REMB() const |
| { |
| WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "REMB()"); |
| |
| return _rtcpSender.REMB(); |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::SetREMBStatus(const bool enable) |
| { |
| if(enable) |
| { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| _id, |
| "SetREMBStatus(enable)"); |
| } else |
| { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| _id, |
| "SetREMBStatus(disable)"); |
| } |
| return _rtcpSender.SetREMBStatus(enable); |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::SetREMBData(const WebRtc_UWord32 bitrate, |
| const WebRtc_UWord8 numberOfSSRC, |
| const WebRtc_UWord32* SSRC) |
| { |
| WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetREMBData(bitrate:%d,?,?)", bitrate); |
| return _rtcpSender.SetREMBData(bitrate, numberOfSSRC, SSRC); |
| } |
| |
| bool ModuleRtpRtcpImpl::SetRemoteBitrateObserver( |
| RtpRemoteBitrateObserver* observer) { |
| return _rtcpSender.SetRemoteBitrateObserver(observer); |
| } |
| |
| /* |
| * (IJ) Extended jitter report. |
| */ |
| bool ModuleRtpRtcpImpl::IJ() const |
| { |
| WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "IJ()"); |
| |
| return _rtcpSender.IJ(); |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::SetIJStatus(const bool enable) |
| { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| _id, |
| "SetIJStatus(%s)", enable ? "true" : "false"); |
| |
| return _rtcpSender.SetIJStatus(enable); |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::RegisterSendRtpHeaderExtension( |
| const RTPExtensionType type, |
| const WebRtc_UWord8 id) |
| { |
| return _rtpSender.RegisterRtpHeaderExtension(type, id); |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::DeregisterSendRtpHeaderExtension( |
| const RTPExtensionType type) |
| { |
| return _rtpSender.DeregisterRtpHeaderExtension(type); |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::RegisterReceiveRtpHeaderExtension( |
| const RTPExtensionType type, |
| const WebRtc_UWord8 id) |
| { |
| return _rtpReceiver.RegisterRtpHeaderExtension(type, id); |
| } |
| |
| WebRtc_Word32 ModuleRtpRtcpImpl::DeregisterReceiveRtpHeaderExtension( |
| const RTPExtensionType type) |
| { |
| return _rtpReceiver.DeregisterRtpHeaderExtension(type); |
| } |
| |
| void ModuleRtpRtcpImpl::SetTransmissionSmoothingStatus(const bool enable) { |
| _rtpSender.SetTransmissionSmoothingStatus(enable); |
| } |
| |
| bool ModuleRtpRtcpImpl::TransmissionSmoothingStatus() const { |
| return _rtpSender.TransmissionSmoothingStatus(); |
| } |
| |
| /* |
| * (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); |
| std::list<ModuleRtpRtcpImpl*>::const_iterator it = |
| _childModules.begin(); |
| while (it != _childModules.end()) |
| { |
| RtpRtcp* module = *it; |
| if (module) |
| { |
| NACKMethod nackMethod = module->NACK(); |
| if (nackMethod != kNackOff) |
| { |
| childMethod = nackMethod; |
| break; |
| } |
| } |
| it++; |
| } |
| } |
| |
| 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; |
| } |
| |
| // Returns the currently configured retransmission mode. |
| int ModuleRtpRtcpImpl::SelectiveRetransmissions() const { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| _id, |
| "SelectiveRetransmissions()"); |
| return _rtpSender.SelectiveRetransmissions(); |
| } |
| |
| // Enable or disable a retransmission mode, which decides which packets will |
| // be retransmitted if NACKed. |
| int ModuleRtpRtcpImpl::SetSelectiveRetransmissions(uint8_t settings) { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| _id, |
| "SetSelectiveRetransmissions(%u)", |
| settings); |
| return _rtpSender.SetSelectiveRetransmissions(settings); |
| } |
| |
| // 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 = _clock.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); |
| |
| if (enable) { |
| _rtpReceiver.RegisterRtpHeaderExtension(kRtpExtensionAudioLevel, ID); |
| } else { |
| _rtpReceiver.DeregisterRtpHeaderExtension(kRtpExtensionAudioLevel); |
| } |
| 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); |
| |
| std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin(); |
| while (it != _childModules.end()) { |
| RtpRtcp* module = *it; |
| if (module) { |
| module->SetSendBitrate(startBitrate, |
| minBitrateKbit, |
| maxBitrateKbit); |
| } |
| it++; |
| } |
| } |
| _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); |
| |
| std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin(); |
| while (it != _childModules.end()) { |
| RtpRtcp* module = *it; |
| if (module) { |
| module->SetCameraDelay(delayMS); |
| } |
| it++; |
| } |
| return 0; |
| } |
| 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); |
| std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin(); |
| while (it != _childModules.end()) { |
| RtpRtcp* module = *it; |
| if (module) { |
| bool enabled = false; |
| WebRtc_UWord8 dummyPTypeRED = 0; |
| WebRtc_UWord8 dummyPTypeFEC = 0; |
| if (module->GenericFECStatus(enabled, |
| dummyPTypeRED, |
| dummyPTypeFEC) == 0 && enabled) { |
| childEnabled = true; |
| break; |
| } |
| } |
| it++; |
| } |
| } |
| 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); |
| |
| std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin(); |
| while (it != _childModules.end()) { |
| RtpRtcp* module = *it; |
| if (module) { |
| module->SetFECCodeRate(keyFrameCodeRate, deltaFrameCodeRate); |
| } |
| it++; |
| } |
| return 0; |
| } |
| 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); |
| |
| std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin(); |
| while (it != _childModules.end()) { |
| RtpRtcp* module = *it; |
| if (module) { |
| module->SetFECUepProtection(keyUseUepProtection, |
| deltaUseUepProtection); |
| } |
| it++; |
| } |
| return 0; |
| } |
| return _rtpSender.SetFECUepProtection(keyUseUepProtection, |
| deltaUseUepProtection); |
| } |
| |
| 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) { |
| // 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(); |
| } |
| |
| void ModuleRtpRtcpImpl::BitrateSent(WebRtc_UWord32* totalRate, |
| WebRtc_UWord32* videoRate, |
| WebRtc_UWord32* fecRate, |
| WebRtc_UWord32* nackRate) const { |
| const bool defaultInstance(_childModules.empty() ? false : true); |
| |
| if (defaultInstance) { |
| // for default we need to update the send bitrate |
| CriticalSectionScoped lock(_criticalSectionModulePtrsFeedback); |
| |
| if (totalRate != NULL) |
| *totalRate = 0; |
| if (videoRate != NULL) |
| *videoRate = 0; |
| if (fecRate != NULL) |
| *fecRate = 0; |
| if (nackRate != NULL) |
| *nackRate = 0; |
| |
| std::list<ModuleRtpRtcpImpl*>::const_iterator it = |
| _childModules.begin(); |
| while (it != _childModules.end()) { |
| RtpRtcp* module = *it; |
| if (module) { |
| WebRtc_UWord32 childTotalRate = 0; |
| WebRtc_UWord32 childVideoRate = 0; |
| WebRtc_UWord32 childFecRate = 0; |
| WebRtc_UWord32 childNackRate = 0; |
| module->BitrateSent(&childTotalRate, |
| &childVideoRate, |
| &childFecRate, |
| &childNackRate); |
| if (totalRate != NULL && childTotalRate > *totalRate) |
| *totalRate = childTotalRate; |
| if (videoRate != NULL && childVideoRate > *videoRate) |
| *videoRate = childVideoRate; |
| if (fecRate != NULL && childFecRate > *fecRate) |
| *fecRate = childFecRate; |
| if (nackRate != NULL && childNackRate > *nackRate) |
| *nackRate = childNackRate; |
| } |
| it++; |
| } |
| return; |
| } |
| if (totalRate != NULL) |
| *totalRate = _rtpSender.BitrateLast(); |
| if (videoRate != NULL) |
| *videoRate = _rtpSender.VideoBitrateSent(); |
| if (fecRate != NULL) |
| *fecRate = _rtpSender.FecOverheadRate(); |
| if (nackRate != NULL) |
| *nackRate = _rtpSender.NackOverheadRate(); |
| } |
| |
| // 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); |
| |
| WebRtc_Word32 RTCPdiff = (WebRtc_Word32) |
| ((_RTCPArrivalTimeSecsAudio - RTCPArrivalTimeSecs)*1000); |
| RTCPdiff += (WebRtc_Word32) |
| (_RTCPArrivalTimeFracAudio/FracMS - |
| RTCPArrivalTimeFrac/FracMS); |
| |
| 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; |
| RateControlRegion region = _rtcpSender.UpdateOverUseState(rateControlInput, |
| firstOverUse); |
| if (firstOverUse) { |
| // Send TMMBR or REMB immediately. |
| WebRtc_UWord16 RTT = 0; |
| _rtcpReceiver.RTT(_rtpReceiver.SSRC(), &RTT, NULL, NULL, NULL); |
| // About to send TMMBR, first run remote rate control |
| // to get a target bit rate. |
| unsigned int target_bitrate = |
| _rtcpSender.CalculateNewTargetBitrate(RTT); |
| if (REMB()) { |
| _rtcpSender.UpdateRemoteBitrateEstimate(target_bitrate); |
| } else if (TMMBR()) { |
| _rtcpSender.SendRTCP(kRtcpTmmbr); |
| } |
| } |
| return region; |
| } |
| |
| // bad state of RTP receiver request a keyframe |
| void ModuleRtpRtcpImpl::OnRequestIntraFrame(const FrameType frameType) { |
| RequestKeyFrame(frameType); |
| } |
| |
| void ModuleRtpRtcpImpl::OnReceivedIntraFrameRequest(const RtpRtcp* caller) { |
| if (_defaultModule) { |
| CriticalSectionScoped lock(_criticalSectionModulePtrs); |
| if (_defaultModule) { |
| // if we use a default module pass this info to the default module |
| _defaultModule->OnReceivedIntraFrameRequest(caller); |
| return; |
| } |
| } |
| |
| WebRtc_UWord8 streamIdx = 0; |
| FrameType frameType = kVideoFrameKey; |
| if (_simulcast) { |
| CriticalSectionScoped lock(_criticalSectionModulePtrs); |
| // loop though child modules and count idx |
| std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin(); |
| while (it != _childModules.end()) { |
| ModuleRtpRtcpImpl* childModule = *it; |
| if (childModule == caller) { |
| break; |
| } |
| streamIdx++; |
| it++; |
| } |
| } |
| _rtcpReceiver.OnReceivedIntraFrameRequest(frameType, streamIdx); |
| } |
| |
| void ModuleRtpRtcpImpl::OnReceivedEstimatedMaxBitrate( |
| const WebRtc_UWord32 maxBitrate) { |
| |
| // We received a REMB. |
| if (_defaultModule) { |
| // Let the default module handle this. |
| CriticalSectionScoped lock(_criticalSectionModulePtrs); |
| if (_defaultModule) { |
| // if we use a default module pass this info to the default module |
| _defaultModule->OnReceivedEstimatedMaxBitrate(maxBitrate); |
| return; |
| } |
| } |
| WebRtc_UWord32 newBitrate = 0; |
| WebRtc_UWord8 fractionLost = 0; |
| WebRtc_UWord16 roundTripTime = 0; |
| WebRtc_UWord16 bwEstimateKbit = WebRtc_UWord16(maxBitrate / 1000); |
| if (_bandwidthManagement.UpdateBandwidthEstimate(bwEstimateKbit, |
| &newBitrate, |
| &fractionLost, |
| &roundTripTime) == 0) { |
| // TODO(mflodman) When encoding two streams, we need to split the |
| // bitrate between REMB sending channels. |
| _rtpReceiver.UpdateBandwidthManagement(newBitrate, |
| fractionLost, |
| roundTripTime); |
| |
| // We've received a new bandwidth estimate lower than the current send |
| // bitrate. For simulcast we need to update the sending bitrate for all |
| // streams. |
| if (_simulcast) { |
| CriticalSectionScoped lock(_criticalSectionModulePtrsFeedback); |
| WebRtc_UWord8 idx = 0; |
| for (std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin(); |
| it != _childModules.end(); ++it) { |
| // sanity |
| if (idx >= (_sendVideoCodec.numberOfSimulcastStreams - 1)) { |
| return; |
| } |
| ModuleRtpRtcpImpl* module = *it; |
| if (newBitrate >= _sendVideoCodec.simulcastStream[idx].maxBitrate) { |
| module->_bandwidthManagement.SetSendBitrate( |
| _sendVideoCodec.simulcastStream[idx].maxBitrate, 0, 0); |
| module->_rtpSender.SetTargetSendBitrate( |
| _sendVideoCodec.simulcastStream[idx].maxBitrate); |
| |
| newBitrate -= _sendVideoCodec.simulcastStream[idx].maxBitrate; |
| } else { |
| module->_bandwidthManagement.SetSendBitrate(newBitrate, 0, 0); |
| module->_rtpSender.SetTargetSendBitrate(newBitrate); |
| newBitrate -= newBitrate; |
| } |
| idx++; |
| } |
| } |
| } |
| // For non-simulcast, update all child modules with the new bandwidth estimate |
| // regardless of the new estimate. |
| if (!_simulcast) { |
| // Update all child modules with the new max bitrate before exiting. |
| CriticalSectionScoped lock(_criticalSectionModulePtrsFeedback); |
| for (std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin(); |
| it != _childModules.end(); ++it) { |
| // Update all child modules with the maximum bitrate estimate. |
| ModuleRtpRtcpImpl* module = *it; |
| WebRtc_UWord32 ignoreBitrate = 0; |
| WebRtc_UWord8 ignoreFractionLost = 0; |
| WebRtc_UWord16 ignoreRoundTripTime = 0; |
| module->_bandwidthManagement.UpdateBandwidthEstimate( |
| bwEstimateKbit, |
| &ignoreBitrate, |
| &ignoreFractionLost, |
| &ignoreRoundTripTime); |
| // We don't need to take care of a possible lowered bitrate, that is |
| // handled earlier in this function for the default module. |
| } |
| } |
| } |
| |
| // 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 bwEstimateKbit) { |
| |
| // We received a TMMBR |
| const bool defaultInstance(_childModules.empty() ? false : true); |
| if (defaultInstance) { |
| ProcessDefaultModuleBandwidth(); |
| return; |
| } |
| if (_audio) { |
| _rtcpReceiver.UpdateBandwidthEstimate(bwEstimateKbit); |
| } else { |
| WebRtc_UWord32 newBitrate = 0; |
| WebRtc_UWord8 fractionLost = 0; |
| WebRtc_UWord16 roundTripTime = 0; |
| if (_bandwidthManagement.UpdateBandwidthEstimate(bwEstimateKbit, |
| &newBitrate, |
| &fractionLost, |
| &roundTripTime) == 0) { |
| if (!_defaultModule) { |
| // No default module check if we should trigger OnNetworkChanged |
| // via video callback |
| _rtpReceiver.UpdateBandwidthManagement(newBitrate, |
| fractionLost, |
| roundTripTime); |
| } |
| if (newBitrate > 0) { |
| // update bitrate |
| _rtpSender.SetTargetSendBitrate(newBitrate); |
| } |
| } |
| } |
| if (_defaultModule) { |
| CriticalSectionScoped lock(_criticalSectionModulePtrs); |
| if (_defaultModule) { |
| // if we use a default module pass this info to the default module |
| _defaultModule->OnReceivedBandwidthEstimateUpdate(bwEstimateKbit); |
| return; |
| } |
| } |
| } |
| |
| // bw estimation |
| // We received a RTCP report block |
| void ModuleRtpRtcpImpl::OnPacketLossStatisticsUpdate( |
| const WebRtc_UWord8 fractionLost, |
| const WebRtc_UWord16 roundTripTime, |
| const WebRtc_UWord32 lastReceivedExtendedHighSeqNum) { |
| |
| const bool defaultInstance(_childModules.empty() ? false : true); |
| if (!defaultInstance) { |
| WebRtc_UWord32 newBitrate = 0; |
| WebRtc_UWord8 loss = fractionLost; // local copy since it can change |
| WebRtc_UWord32 videoRate = 0; |
| WebRtc_UWord32 fecRate = 0; |
| WebRtc_UWord32 nackRate = 0; |
| BitrateSent(NULL, &videoRate, &fecRate, &nackRate); |
| if (_bandwidthManagement.UpdatePacketLoss( |
| lastReceivedExtendedHighSeqNum, |
| videoRate + fecRate + nackRate, |
| roundTripTime, |
| &loss, |
| &newBitrate, |
| _clock.GetTimeInMS()) != 0) { |
| // ignore this update |
| return; |
| } |
| // We need to do update RTP sender before calling default module in |
| // case we'll strip any layers. |
| if (!_simulcast) { |
| // the default module will inform all child modules about |
| // their bitrate |
| _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( |
| loss, // send in the filtered loss |
| roundTripTime, |
| lastReceivedExtendedHighSeqNum); |
| } |
| return; |
| } |
| _rtpReceiver.UpdateBandwidthManagement(newBitrate, |
| fractionLost, |
| roundTripTime); |
| } else { |
| if (!_simulcast) { |
| ProcessDefaultModuleBandwidth(); |
| } else { |
| // default and simulcast |
| WebRtc_UWord32 newBitrate = 0; |
| WebRtc_UWord8 loss = fractionLost; // local copy |
| WebRtc_UWord32 videoRate = 0; |
| WebRtc_UWord32 fecRate = 0; |
| WebRtc_UWord32 nackRate = 0; |
| BitrateSent(NULL, &videoRate, &fecRate, &nackRate); |
| if (_bandwidthManagement.UpdatePacketLoss(0, // we can't use this |
| videoRate + fecRate + nackRate, |
| roundTripTime, |
| &loss, |
| &newBitrate, |
| _clock.GetTimeInMS()) != 0) { |
| // ignore this update |
| return; |
| } |
| _rtpSender.SetTargetSendBitrate(newBitrate); |
| _rtpReceiver.UpdateBandwidthManagement(newBitrate, |
| loss, |
| roundTripTime); |
| // sanity |
| if (_sendVideoCodec.codecType == kVideoCodecUnknown) { |
| return; |
| } |
| CriticalSectionScoped lock(_criticalSectionModulePtrsFeedback); |
| std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin(); |
| WebRtc_UWord8 idx = 0; |
| while (it != _childModules.end()) { |
| // sanity |
| if (idx >= (_sendVideoCodec.numberOfSimulcastStreams - 1)) { |
| return; |
| } |
| ModuleRtpRtcpImpl* module = *it; |
| // update all child modules |
| if (newBitrate >= |
| _sendVideoCodec.simulcastStream[idx].maxBitrate) { |
| module->_bandwidthManagement.SetSendBitrate( |
| _sendVideoCodec.simulcastStream[idx].maxBitrate, 0, 0); |
| module->_rtpSender.SetTargetSendBitrate( |
| _sendVideoCodec.simulcastStream[idx].maxBitrate); |
| |
| newBitrate -= |
| _sendVideoCodec.simulcastStream[idx].maxBitrate; |
| } else { |
| module->_bandwidthManagement.SetSendBitrate(newBitrate, |
| 0, |
| 0); |
| module->_rtpSender.SetTargetSendBitrate(newBitrate); |
| newBitrate -= newBitrate; |
| } |
| idx++; |
| } |
| } |
| } |
| } |
| |
| void ModuleRtpRtcpImpl::ProcessDefaultModuleBandwidth() { |
| |
| WebRtc_UWord32 minBitrateBps = 0xffffffff; |
| WebRtc_UWord32 maxBitrateBps = 0; |
| WebRtc_UWord32 count = 0; |
| WebRtc_UWord32 fractionLostAcc = 0; |
| WebRtc_UWord16 maxRoundTripTime = 0; |
| { |
| // get min and max for the sending channels |
| CriticalSectionScoped lock(_criticalSectionModulePtrs); |
| |
| std::list<ModuleRtpRtcpImpl*>::iterator it = |
| _childModules.begin(); |
| while (it != _childModules.end()) { |
| // Get child RTP sender and ask for bitrate estimate |
| ModuleRtpRtcpImpl* childModule = *it; |
| if (childModule->Sending()) { |
| count++; |
| RTPSender& childRtpSender = (*it)->_rtpSender; |
| const WebRtc_UWord32 childEstimateBps = |
| 1000 * childRtpSender.TargetSendBitrateKbit(); |
| if (childEstimateBps < minBitrateBps) { |
| minBitrateBps = childEstimateBps; |
| } |
| if (childEstimateBps > maxBitrateBps) { |
| maxBitrateBps = childEstimateBps; |
| } |
| WebRtc_UWord16 RTT = 0; |
| WebRtc_UWord8 fractionLost = 0; |
| RTPReceiver& childRtpReceiver = (*it)->_rtpReceiver; |
| RTCPReceiver& childRtcpReceiver = (*it)->_rtcpReceiver; |
| childRtpReceiver.Statistics(&fractionLost, |
| NULL, |
| NULL, |
| NULL, |
| NULL, |
| NULL, |
| false); |
| fractionLostAcc += fractionLost; |
| childRtcpReceiver.RTT(childRtpReceiver.SSRC(), |
| &RTT, |
| NULL, |
| NULL, |
| NULL); |
| maxRoundTripTime = |
| (RTT > maxRoundTripTime) ? RTT : maxRoundTripTime; |
| } |
| it++; |
| } |
| } // end critsect |
| |
| if (count == 0) { |
| // No sending modules and no bitrate estimate. |
| return; |
| } |
| _bandwidthManagement.SetSendBitrate(minBitrateBps, 0, 0); |
| |
| // Update default module bitrate. Don't care about min max. |
| WebRtc_UWord8 fractionLostAvg = WebRtc_UWord8(fractionLostAcc / count); |
| _rtpReceiver.UpdateBandwidthManagement(minBitrateBps, |
| fractionLostAvg , |
| maxRoundTripTime); |
| } |
| |
| 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) { |
| // remote SR: 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; |
| WebRtc_UWord32 minBitrateKbit = 0; |
| WebRtc_UWord32 maxBitrateKbit = 0; |
| WebRtc_UWord32 accNumCandidates = 0; |
| |
| if (!_childModules.empty()) { |
| // Default module should not handle this |
| return -1; |
| } |
| |
| 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 |
| // inform the remote client |
| _rtcpSender.SetTMMBN(boundingSet, |
| _rtpSender.MaxConfiguredBitrateVideo()/1000); |
| // might trigger a TMMBN |
| 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(), |
| (WebRtc_UWord32)numBoundingSet, |
| minBitrateKbit, |
| maxBitrateKbit); |
| |
| // no critsect when calling out to "unknown" code |
| if (newBitrates == 0) { |
| // we have new bitrate |
| // Set new max bitrate |
| // we have a new bandwidth estimate on this channel |
| OnReceivedBandwidthEstimateUpdate((WebRtc_UWord16)minBitrateKbit); |
| 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); |
| } |
| |
| void ModuleRtpRtcpImpl::SendKeyFrame() { |
| WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id, "SendKeyFrame()"); |
| OnReceivedIntraFrameRequest(0); |
| } |
| } // namespace webrtc |