/* * 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 //memcpy #include //assert // local for this file namespace { const float FracMS = 4.294967296E6f; } // namepace #ifdef _WIN32 // disable warning C4355: 'this' : used in base member initializer list #pragma warning(disable : 4355) #endif namespace webrtc { const WebRtc_UWord16 kDefaultRtt = 200; RtpRtcp* RtpRtcp::CreateRtpRtcp(const RtpRtcp::Configuration& configuration) { if (configuration.clock) { return new ModuleRtpRtcpImpl(configuration); } else { RtpRtcp::Configuration configuration_copy; memcpy(&configuration_copy, &configuration, sizeof(RtpRtcp::Configuration)); configuration_copy.clock = ModuleRTPUtility::GetSystemClock(); ModuleRtpRtcpImpl* rtp_rtcp_instance = new ModuleRtpRtcpImpl(configuration_copy); rtp_rtcp_instance->OwnsClock(); return rtp_rtcp_instance; } } ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration) : _rtpSender(configuration.id, configuration.audio, configuration.clock), _rtpReceiver(configuration.id, configuration.audio, configuration.clock, this), _rtcpSender(configuration.id, configuration.audio, configuration.clock, this), _rtcpReceiver(configuration.id, configuration.clock, this), _owns_clock(false), _clock(*configuration.clock), _id(configuration.id), _audio(configuration.audio), _collisionDetected(false), _lastProcessTime(configuration.clock->GetTimeInMS()), _lastBitrateProcessTime(configuration.clock->GetTimeInMS()), _lastPacketTimeoutProcessTime(configuration.clock->GetTimeInMS()), _packetOverHead(28), // IPV4 UDP _criticalSectionModulePtrs( CriticalSectionWrapper::CreateCriticalSection()), _criticalSectionModulePtrsFeedback( CriticalSectionWrapper::CreateCriticalSection()), _defaultModule( static_cast(configuration.default_module)), _deadOrAliveActive(false), _deadOrAliveTimeoutMS(0), _deadOrAliveLastTimer(0), _nackMethod(kNackOff), _nackLastTimeSent(0), _nackLastSeqNumberSent(0), _simulcast(false), _keyFrameReqMethod(kKeyFrameReqFirRtp) #ifdef MATLAB , _plot1(NULL) #endif { _sendVideoCodec.codecType = kVideoCodecUnknown; if (_defaultModule) { _defaultModule->RegisterChildModule(this); } // TODO(pwestin) move to constructors of each rtp/rtcp sender/receiver object. _rtpReceiver.RegisterIncomingDataCallback(configuration.incoming_data); _rtpReceiver.RegisterIncomingRTPCallback(configuration.incoming_messages); _rtcpReceiver.RegisterRtcpObservers(configuration.intra_frame_callback, configuration.bandwidth_callback, configuration.rtcp_feedback); _rtpSender.RegisterAudioCallback(configuration.audio_messages); _rtpReceiver.RegisterIncomingAudioCallback(configuration.audio_messages); _rtpSender.RegisterSendTransport(configuration.outgoing_transport); _rtcpSender.RegisterSendTransport(configuration.outgoing_transport); _rtcpSender.SetRemoteBitrateObserver(configuration.bitrate_observer); // 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__); // All child modules MUST be deleted before deleting the default. assert(_childModules.empty()); // Deregister for the child modules // will go in to the default and remove it self if (_defaultModule) { _defaultModule->DeRegisterChildModule(this); } #ifdef MATLAB if (_plot1) { eng.DeletePlot(_plot1); _plot1 = NULL; } #endif if (_owns_clock) { delete &_clock; } } void ModuleRtpRtcpImpl::RegisterChildModule(RtpRtcp* module) { WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RegisterChildModule(module:0x%x)", module); CriticalSectionScoped lock(_criticalSectionModulePtrs.get()); CriticalSectionScoped doubleLock(_criticalSectionModulePtrsFeedback.get()); // we use two locks for protecting _childModules one // (_criticalSectionModulePtrsFeedback) for incoming // messages (BitrateSent) 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.get()); CriticalSectionScoped doubleLock(_criticalSectionModulePtrsFeedback.get()); std::list::iterator it = _childModules.begin(); while (it != _childModules.end()) { RtpRtcp* module = *it; if (module == removeModule) { _childModules.erase(it); return; } it++; } } // 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 max_rtt = 0; if (_rtcpSender.Sending()) { std::vector receive_blocks; _rtcpReceiver.StatisticsReceived(&receive_blocks); for (std::vector::iterator it = receive_blocks.begin(); it != receive_blocks.end(); ++it) { WebRtc_UWord16 rtt = 0; _rtcpReceiver.RTT(it->remoteSSRC, &max_rtt, NULL, NULL, NULL); max_rtt = (rtt > max_rtt) ? rtt : max_rtt; } } else { // We're only receiving, i.e. this module doesn't have its own RTT // estimate. Use the RTT set by a sending channel using the same default // module. max_rtt = _rtcpReceiver.RTT(); } if (max_rtt == 0) { // No valid estimate available, i.e. no sending channel using the same // default module or no RTCP received yet. max_rtt = kDefaultRtt; } if (_rtcpSender.ValidBitrateEstimate()) { if (REMB()) { uint32_t target_bitrate = _rtcpSender.CalculateNewTargetBitrate(max_rtt); _rtcpSender.UpdateRemoteBitrateEstimate(target_bitrate); } else if (TMMBR()) { _rtcpSender.CalculateNewTargetBitrate(max_rtt); } } _rtcpSender.SendRTCP(kRtcpReport); } if (UpdateRTCPReceiveInformationTimers()) { // a receiver has timed out _rtcpReceiver.UpdateTMMBR(); } return 0; } /** * Receiver */ 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); } } /** * Sender */ 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.get()); std::list::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 { 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.get()); std::list::const_iterator it = _childModules.begin(); while (it != _childModules.end()) { RTPSender& rtpSender = (*it)->_rtpSender; if (rtpSender.SendingMedia()) { return true; } it++; } return false; } WebRtc_Word32 ModuleRtpRtcpImpl::SendOutgoingData( FrameType frameType, WebRtc_Word8 payloadType, WebRtc_UWord32 timeStamp, const WebRtc_UWord8* payloadData, 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)) { _rtcpSender.SendRTCP(kRtcpReport); } 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.get()); std::list::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.get()); // TODO(pwestin) remove codecInfo from SendOutgoingData VideoCodecInformation* codecInfo = NULL; std::list::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.get()); std::list::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* 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); } /* * (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::SetTMMBN(const TMMBRSet* boundingSet) { WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetTMMBN()"); WebRtc_UWord32 maxBitrateKbit = _rtpSender.MaxConfiguredBitrateVideo() / 1000; return _rtcpSender.SetTMMBN(boundingSet, maxBitrateKbit); } /* * (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.get()); std::list::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(); 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; }; 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(); } void ModuleRtpRtcpImpl::SetTargetSendBitrate(const uint32_t bitrate) { WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetTargetSendBitrate: %ubit", bitrate); const bool haveChildModules(_childModules.empty() ? false : true); if (haveChildModules) { CriticalSectionScoped lock(_criticalSectionModulePtrs.get()); if (_simulcast) { uint32_t bitrate_remainder = bitrate; std::list::iterator it = _childModules.begin(); for (int i = 0; it != _childModules.end() && i < _sendVideoCodec.numberOfSimulcastStreams; ++it, ++i) { RTPSender& rtpSender = (*it)->_rtpSender; if (_sendVideoCodec.simulcastStream[i].maxBitrate > bitrate_remainder) { rtpSender.SetTargetSendBitrate( _sendVideoCodec.simulcastStream[i].maxBitrate); bitrate_remainder -= _sendVideoCodec.simulcastStream[i].maxBitrate; } else { rtpSender.SetTargetSendBitrate(bitrate_remainder); bitrate_remainder = 0; } } } else { std::list::iterator it = _childModules.begin(); for (; it != _childModules.end(); ++it) { RTPSender& rtpSender = (*it)->_rtpSender; rtpSender.SetTargetSendBitrate(bitrate); } } } else { _rtpSender.SetTargetSendBitrate(bitrate); } } WebRtc_Word32 ModuleRtpRtcpImpl::SetKeyFrameRequestMethod( const KeyFrameRequestMethod method) { WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "SetKeyFrameRequestMethod(method:%u)", method); _keyFrameReqMethod = method; return 0; } WebRtc_Word32 ModuleRtpRtcpImpl::RequestKeyFrame() { WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RequestKeyFrame"); switch (_keyFrameReqMethod) { case kKeyFrameReqFirRtp: return _rtpSender.SendRTPIntraRequest(); case kKeyFrameReqPliRtcp: return _rtcpSender.SendRTCP(kRtcpPli); case kKeyFrameReqFirRtcp: return _rtcpSender.SendRTCP(kRtcpFir); } 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, false, 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.get()); std::list::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.get()); std::list::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::SetFecParameters( const FecProtectionParams* delta_params, const FecProtectionParams* key_params) { const bool defaultInstance(_childModules.empty() ? false : true); if (defaultInstance) { // for default we need to update all child modules too CriticalSectionScoped lock(_criticalSectionModulePtrs.get()); std::list::iterator it = _childModules.begin(); while (it != _childModules.end()) { RtpRtcp* module = *it; if (module) { module->SetFecParameters(delta_params, key_params); } it++; } return 0; } return _rtpSender.SetFecParameters(delta_params, key_params); } 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.get()); if (totalRate != NULL) *totalRate = 0; if (videoRate != NULL) *videoRate = 0; if (fecRate != NULL) *fecRate = 0; if (nackRate != NULL) *nackRate = 0; std::list::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(); } int ModuleRtpRtcpImpl::EstimatedReceiveBandwidth( WebRtc_UWord32* available_bandwidth) const { if (!_rtcpSender.ValidBitrateEstimate()) return -1; *available_bandwidth = _rtcpSender.LatestBandwidthEstimate(); return 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() { RequestKeyFrame(); } void ModuleRtpRtcpImpl::OnRequestSendReport() { _rtcpSender.SendRTCP(kRtcpSr); } WebRtc_Word32 ModuleRtpRtcpImpl::SendRTCPReferencePictureSelection( const WebRtc_UWord64 pictureID) { return _rtcpSender.SendRTCP(kRtcpRpsi, 0, 0, false, 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; } 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(); } // called from RTCPsender WebRtc_Word32 ModuleRtpRtcpImpl::BoundingSet(bool& tmmbrOwner, TMMBRSet*& boundingSet) { return _rtcpReceiver.BoundingSet(tmmbrOwner, boundingSet); } } // namespace webrtc