stefan@webrtc.org 20ed36dada Break out RtpClock to system_wrappers and make it more generic.
The goal with this new clock interface is to have something which is used all
over WebRTC to make it easier to switch clock implementation depending on where
the components are used. This is a first step in that direction.

Next steps will be to, step by step, move all modules, video engine and voice
engine over to the new interface, effectively deprecating the old clock
interfaces. Long-term my vision is that we should be able to deprecate the clock
of WebRTC and rely on the user providing the implementation.

TEST=vie_auto_test, rtp_rtcp_unittests, trybots

Review URL: https://webrtc-codereview.appspot.com/1041004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3381 4adac7df-926f-26a2-2b94-8c16560cd09d
2013-01-17 14:01:20 +00:00

1442 lines
50 KiB
C++

/*
* 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 "rtcp_receiver.h"
#include <string.h> //memset
#include <cassert> //assert
#include "trace.h"
#include "critical_section_wrapper.h"
#include "rtcp_utility.h"
#include "rtp_rtcp_impl.h"
namespace
{
const float FRAC = 4.294967296E9;
}
namespace webrtc {
using namespace RTCPUtility;
using namespace RTCPHelp;
// The number of RTCP time intervals needed to trigger a timeout.
const int kRrTimeoutIntervals = 3;
RTCPReceiver::RTCPReceiver(const WebRtc_Word32 id, Clock* clock,
ModuleRtpRtcpImpl* owner)
: TMMBRHelp(),
_id(id),
_clock(*clock),
_method(kRtcpOff),
_lastReceived(0),
_rtpRtcp(*owner),
_criticalSectionFeedbacks(
CriticalSectionWrapper::CreateCriticalSection()),
_cbRtcpFeedback(NULL),
_cbRtcpBandwidthObserver(NULL),
_cbRtcpIntraFrameObserver(NULL),
_criticalSectionRTCPReceiver(
CriticalSectionWrapper::CreateCriticalSection()),
_SSRC(0),
_remoteSSRC(0),
_remoteSenderInfo(),
_lastReceivedSRNTPsecs(0),
_lastReceivedSRNTPfrac(0),
_receivedInfoMap(),
_packetTimeOutMS(0),
_lastReceivedRrMs(0),
_lastIncreasedSequenceNumberMs(0),
_rtt(0) {
memset(&_remoteSenderInfo, 0, sizeof(_remoteSenderInfo));
WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
}
RTCPReceiver::~RTCPReceiver() {
delete _criticalSectionRTCPReceiver;
delete _criticalSectionFeedbacks;
while (!_receivedReportBlockMap.empty()) {
std::map<WebRtc_UWord32, RTCPReportBlockInformation*>::iterator first =
_receivedReportBlockMap.begin();
delete first->second;
_receivedReportBlockMap.erase(first);
}
while (!_receivedInfoMap.empty()) {
std::map<WebRtc_UWord32, RTCPReceiveInformation*>::iterator first =
_receivedInfoMap.begin();
delete first->second;
_receivedInfoMap.erase(first);
}
while (!_receivedCnameMap.empty()) {
std::map<WebRtc_UWord32, RTCPCnameInformation*>::iterator first =
_receivedCnameMap.begin();
delete first->second;
_receivedCnameMap.erase(first);
}
WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, _id,
"%s deleted", __FUNCTION__);
}
void
RTCPReceiver::ChangeUniqueId(const WebRtc_Word32 id)
{
_id = id;
}
RTCPMethod
RTCPReceiver::Status() const
{
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
return _method;
}
WebRtc_Word32
RTCPReceiver::SetRTCPStatus(const RTCPMethod method)
{
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
_method = method;
return 0;
}
WebRtc_Word64
RTCPReceiver::LastReceived()
{
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
return _lastReceived;
}
WebRtc_Word32
RTCPReceiver::SetRemoteSSRC( const WebRtc_UWord32 ssrc)
{
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
// new SSRC reset old reports
memset(&_remoteSenderInfo, 0, sizeof(_remoteSenderInfo));
_lastReceivedSRNTPsecs = 0;
_lastReceivedSRNTPfrac = 0;
_remoteSSRC = ssrc;
return 0;
}
void RTCPReceiver::RegisterRtcpObservers(
RtcpIntraFrameObserver* intra_frame_callback,
RtcpBandwidthObserver* bandwidth_callback,
RtcpFeedback* feedback_callback) {
CriticalSectionScoped lock(_criticalSectionFeedbacks);
_cbRtcpIntraFrameObserver = intra_frame_callback;
_cbRtcpBandwidthObserver = bandwidth_callback;
_cbRtcpFeedback = feedback_callback;
}
void RTCPReceiver::SetSSRC(const WebRtc_UWord32 ssrc) {
WebRtc_UWord32 old_ssrc = 0;
{
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
old_ssrc = _SSRC;
_SSRC = ssrc;
}
{
CriticalSectionScoped lock(_criticalSectionFeedbacks);
if (_cbRtcpIntraFrameObserver && old_ssrc != ssrc) {
_cbRtcpIntraFrameObserver->OnLocalSsrcChanged(old_ssrc, ssrc);
}
}
}
WebRtc_Word32 RTCPReceiver::ResetRTT(const WebRtc_UWord32 remoteSSRC) {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
RTCPReportBlockInformation* reportBlock =
GetReportBlockInformation(remoteSSRC);
if (reportBlock == NULL) {
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
"\tfailed to GetReportBlockInformation(%u)", remoteSSRC);
return -1;
}
reportBlock->RTT = 0;
reportBlock->avgRTT = 0;
reportBlock->minRTT = 0;
reportBlock->maxRTT = 0;
return 0;
}
WebRtc_Word32 RTCPReceiver::RTT(const WebRtc_UWord32 remoteSSRC,
WebRtc_UWord16* RTT,
WebRtc_UWord16* avgRTT,
WebRtc_UWord16* minRTT,
WebRtc_UWord16* maxRTT) const {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
RTCPReportBlockInformation* reportBlock =
GetReportBlockInformation(remoteSSRC);
if (reportBlock == NULL) {
return -1;
}
if (RTT) {
*RTT = reportBlock->RTT;
}
if (avgRTT) {
*avgRTT = reportBlock->avgRTT;
}
if (minRTT) {
*minRTT = reportBlock->minRTT;
}
if (maxRTT) {
*maxRTT = reportBlock->maxRTT;
}
return 0;
}
WebRtc_UWord16 RTCPReceiver::RTT() const {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
if (!_receivedReportBlockMap.empty()) {
return 0;
}
return _rtt;
}
int RTCPReceiver::SetRTT(WebRtc_UWord16 rtt) {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
if (!_receivedReportBlockMap.empty()) {
return -1;
}
_rtt = rtt;
return 0;
}
WebRtc_Word32
RTCPReceiver::NTP(WebRtc_UWord32 *ReceivedNTPsecs,
WebRtc_UWord32 *ReceivedNTPfrac,
WebRtc_UWord32 *RTCPArrivalTimeSecs,
WebRtc_UWord32 *RTCPArrivalTimeFrac,
WebRtc_UWord32 *rtcp_timestamp) const
{
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
if(ReceivedNTPsecs)
{
*ReceivedNTPsecs = _remoteSenderInfo.NTPseconds; // NTP from incoming SendReport
}
if(ReceivedNTPfrac)
{
*ReceivedNTPfrac = _remoteSenderInfo.NTPfraction;
}
if(RTCPArrivalTimeFrac)
{
*RTCPArrivalTimeFrac = _lastReceivedSRNTPfrac; // local NTP time when we received a RTCP packet with a send block
}
if(RTCPArrivalTimeSecs)
{
*RTCPArrivalTimeSecs = _lastReceivedSRNTPsecs;
}
if (rtcp_timestamp) {
*rtcp_timestamp = _remoteSenderInfo.RTPtimeStamp;
}
return 0;
}
WebRtc_Word32
RTCPReceiver::SenderInfoReceived(RTCPSenderInfo* senderInfo) const
{
if(senderInfo == NULL)
{
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
return -1;
}
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
if(_lastReceivedSRNTPsecs == 0)
{
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "%s No received SR", __FUNCTION__);
return -1;
}
memcpy(senderInfo, &(_remoteSenderInfo), sizeof(RTCPSenderInfo));
return 0;
}
// statistics
// we can get multiple receive reports when we receive the report from a CE
WebRtc_Word32 RTCPReceiver::StatisticsReceived(
std::vector<RTCPReportBlock>* receiveBlocks) const {
assert(receiveBlocks);
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
std::map<WebRtc_UWord32, RTCPReportBlockInformation*>::const_iterator it =
_receivedReportBlockMap.begin();
while (it != _receivedReportBlockMap.end()) {
receiveBlocks->push_back(it->second->remoteReceiveBlock);
it++;
}
return 0;
}
WebRtc_Word32
RTCPReceiver::IncomingRTCPPacket(RTCPPacketInformation& rtcpPacketInformation,
RTCPUtility::RTCPParserV2* rtcpParser)
{
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
_lastReceived = _clock.TimeInMilliseconds();
RTCPUtility::RTCPPacketTypes pktType = rtcpParser->Begin();
while (pktType != RTCPUtility::kRtcpNotValidCode)
{
// Each "case" is responsible for iterate the parser to the
// next top level packet.
switch (pktType)
{
case RTCPUtility::kRtcpSrCode:
case RTCPUtility::kRtcpRrCode:
HandleSenderReceiverReport(*rtcpParser, rtcpPacketInformation);
break;
case RTCPUtility::kRtcpSdesCode:
HandleSDES(*rtcpParser);
break;
case RTCPUtility::kRtcpXrVoipMetricCode:
HandleXRVOIPMetric(*rtcpParser, rtcpPacketInformation);
break;
case RTCPUtility::kRtcpByeCode:
HandleBYE(*rtcpParser);
break;
case RTCPUtility::kRtcpRtpfbNackCode:
HandleNACK(*rtcpParser, rtcpPacketInformation);
break;
case RTCPUtility::kRtcpRtpfbTmmbrCode:
HandleTMMBR(*rtcpParser, rtcpPacketInformation);
break;
case RTCPUtility::kRtcpRtpfbTmmbnCode:
HandleTMMBN(*rtcpParser, rtcpPacketInformation);
break;
case RTCPUtility::kRtcpRtpfbSrReqCode:
HandleSR_REQ(*rtcpParser, rtcpPacketInformation);
break;
case RTCPUtility::kRtcpPsfbPliCode:
HandlePLI(*rtcpParser, rtcpPacketInformation);
break;
case RTCPUtility::kRtcpPsfbSliCode:
HandleSLI(*rtcpParser, rtcpPacketInformation);
break;
case RTCPUtility::kRtcpPsfbRpsiCode:
HandleRPSI(*rtcpParser, rtcpPacketInformation);
break;
case RTCPUtility::kRtcpExtendedIjCode:
HandleIJ(*rtcpParser, rtcpPacketInformation);
break;
case RTCPUtility::kRtcpPsfbFirCode:
HandleFIR(*rtcpParser, rtcpPacketInformation);
break;
case RTCPUtility::kRtcpPsfbAppCode:
HandlePsfbApp(*rtcpParser, rtcpPacketInformation);
break;
case RTCPUtility::kRtcpAppCode:
// generic application messages
HandleAPP(*rtcpParser, rtcpPacketInformation);
break;
case RTCPUtility::kRtcpAppItemCode:
// generic application messages
HandleAPPItem(*rtcpParser, rtcpPacketInformation);
break;
default:
rtcpParser->Iterate();
break;
}
pktType = rtcpParser->PacketType();
}
return 0;
}
// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleSenderReceiverReport(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPPacketInformation& rtcpPacketInformation)
{
RTCPUtility::RTCPPacketTypes rtcpPacketType = rtcpParser.PacketType();
const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
assert((rtcpPacketType == RTCPUtility::kRtcpRrCode) || (rtcpPacketType == RTCPUtility::kRtcpSrCode));
// SR.SenderSSRC
// The synchronization source identifier for the originator of this SR packet
// rtcpPacket.RR.SenderSSRC
// The source of the packet sender, same as of SR? or is this a CE?
const WebRtc_UWord32 remoteSSRC = (rtcpPacketType == RTCPUtility::kRtcpRrCode) ? rtcpPacket.RR.SenderSSRC:rtcpPacket.SR.SenderSSRC;
const WebRtc_UWord8 numberOfReportBlocks = (rtcpPacketType == RTCPUtility::kRtcpRrCode) ? rtcpPacket.RR.NumberOfReportBlocks:rtcpPacket.SR.NumberOfReportBlocks;
rtcpPacketInformation.remoteSSRC = remoteSSRC;
RTCPReceiveInformation* ptrReceiveInfo = CreateReceiveInformation(remoteSSRC);
if (!ptrReceiveInfo)
{
rtcpParser.Iterate();
return;
}
if (rtcpPacketType == RTCPUtility::kRtcpSrCode)
{
WEBRTC_TRACE(kTraceDebug, kTraceRtpRtcp, _id,
"Received SR(%d). SSRC:0x%x, from SSRC:0x%x, to us %d.", _id, _SSRC, remoteSSRC, (_remoteSSRC == remoteSSRC)?1:0);
if (_remoteSSRC == remoteSSRC) // have I received RTP packets from this party
{
// only signal that we have received a SR when we accept one
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpSr;
rtcpPacketInformation.ntp_secs = rtcpPacket.SR.NTPMostSignificant;
rtcpPacketInformation.ntp_frac = rtcpPacket.SR.NTPLeastSignificant;
rtcpPacketInformation.rtp_timestamp = rtcpPacket.SR.RTPTimestamp;
// We will only store the send report from one source, but
// we will store all the receive block
// Save the NTP time of this report
_remoteSenderInfo.NTPseconds = rtcpPacket.SR.NTPMostSignificant;
_remoteSenderInfo.NTPfraction = rtcpPacket.SR.NTPLeastSignificant;
_remoteSenderInfo.RTPtimeStamp = rtcpPacket.SR.RTPTimestamp;
_remoteSenderInfo.sendPacketCount = rtcpPacket.SR.SenderPacketCount;
_remoteSenderInfo.sendOctetCount = rtcpPacket.SR.SenderOctetCount;
_clock.CurrentNtp(_lastReceivedSRNTPsecs, _lastReceivedSRNTPfrac);
}
else
{
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpRr;
}
} else
{
WEBRTC_TRACE(kTraceDebug, kTraceRtpRtcp, _id,
"Received RR(%d). SSRC:0x%x, from SSRC:0x%x", _id, _SSRC, remoteSSRC);
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpRr;
}
UpdateReceiveInformation(*ptrReceiveInfo);
rtcpPacketType = rtcpParser.Iterate();
while (rtcpPacketType == RTCPUtility::kRtcpReportBlockItemCode)
{
HandleReportBlock(rtcpPacket, rtcpPacketInformation, remoteSSRC, numberOfReportBlocks);
rtcpPacketType = rtcpParser.Iterate();
}
}
// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleReportBlock(const RTCPUtility::RTCPPacket& rtcpPacket,
RTCPPacketInformation& rtcpPacketInformation,
const WebRtc_UWord32 remoteSSRC,
const WebRtc_UWord8 numberOfReportBlocks) {
// This will be called once per report block in the RTCP packet.
// We filter out all report blocks that are not for us.
// Each packet has max 31 RR blocks.
//
// We can calc RTT if we send a send report and get a report block back.
// |rtcpPacket.ReportBlockItem.SSRC| is the SSRC identifier of the source to
// which the information in this reception report block pertains.
// Filter out all report blocks that are not for us.
if (rtcpPacket.ReportBlockItem.SSRC != _SSRC) {
// This block is not for us ignore it.
return;
}
// To avoid problem with acquiring _criticalSectionRTCPSender while holding
// _criticalSectionRTCPReceiver.
_criticalSectionRTCPReceiver->Leave();
WebRtc_UWord32 sendTimeMS =
_rtpRtcp.SendTimeOfSendReport(rtcpPacket.ReportBlockItem.LastSR);
_criticalSectionRTCPReceiver->Enter();
RTCPReportBlockInformation* reportBlock =
CreateReportBlockInformation(remoteSSRC);
if (reportBlock == NULL) {
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
"\tfailed to CreateReportBlockInformation(%u)", remoteSSRC);
return;
}
_lastReceivedRrMs = _clock.TimeInMilliseconds();
const RTCPPacketReportBlockItem& rb = rtcpPacket.ReportBlockItem;
reportBlock->remoteReceiveBlock.remoteSSRC = remoteSSRC;
reportBlock->remoteReceiveBlock.sourceSSRC = rb.SSRC;
reportBlock->remoteReceiveBlock.fractionLost = rb.FractionLost;
reportBlock->remoteReceiveBlock.cumulativeLost =
rb.CumulativeNumOfPacketsLost;
if (rb.ExtendedHighestSequenceNumber >
reportBlock->remoteReceiveBlock.extendedHighSeqNum) {
// We have successfully delivered new RTP packets to the remote side after
// the last RR was sent from the remote side.
_lastIncreasedSequenceNumberMs = _lastReceivedRrMs;
}
reportBlock->remoteReceiveBlock.extendedHighSeqNum =
rb.ExtendedHighestSequenceNumber;
reportBlock->remoteReceiveBlock.jitter = rb.Jitter;
reportBlock->remoteReceiveBlock.delaySinceLastSR = rb.DelayLastSR;
reportBlock->remoteReceiveBlock.lastSR = rb.LastSR;
if (rtcpPacket.ReportBlockItem.Jitter > reportBlock->remoteMaxJitter) {
reportBlock->remoteMaxJitter = rtcpPacket.ReportBlockItem.Jitter;
}
WebRtc_UWord32 delaySinceLastSendReport =
rtcpPacket.ReportBlockItem.DelayLastSR;
// local NTP time when we received this
WebRtc_UWord32 lastReceivedRRNTPsecs = 0;
WebRtc_UWord32 lastReceivedRRNTPfrac = 0;
_clock.CurrentNtp(lastReceivedRRNTPsecs, lastReceivedRRNTPfrac);
// time when we received this in MS
WebRtc_UWord32 receiveTimeMS = ModuleRTPUtility::ConvertNTPTimeToMS(
lastReceivedRRNTPsecs, lastReceivedRRNTPfrac);
// Estimate RTT
WebRtc_UWord32 d = (delaySinceLastSendReport & 0x0000ffff) * 1000;
d /= 65536;
d += ((delaySinceLastSendReport & 0xffff0000) >> 16) * 1000;
WebRtc_Word32 RTT = 0;
if (sendTimeMS > 0) {
RTT = receiveTimeMS - d - sendTimeMS;
if (RTT <= 0) {
RTT = 1;
}
if (RTT > reportBlock->maxRTT) {
// store max RTT
reportBlock->maxRTT = (WebRtc_UWord16) RTT;
}
if (reportBlock->minRTT == 0) {
// first RTT
reportBlock->minRTT = (WebRtc_UWord16) RTT;
} else if (RTT < reportBlock->minRTT) {
// Store min RTT
reportBlock->minRTT = (WebRtc_UWord16) RTT;
}
// store last RTT
reportBlock->RTT = (WebRtc_UWord16) RTT;
// store average RTT
if (reportBlock->numAverageCalcs != 0) {
float ac = static_cast<float> (reportBlock->numAverageCalcs);
float newAverage = ((ac / (ac + 1)) * reportBlock->avgRTT)
+ ((1 / (ac + 1)) * RTT);
reportBlock->avgRTT = static_cast<int> (newAverage + 0.5f);
} else {
// first RTT
reportBlock->avgRTT = (WebRtc_UWord16) RTT;
}
reportBlock->numAverageCalcs++;
}
WEBRTC_TRACE(kTraceDebug, kTraceRtpRtcp, _id,
" -> Received report block(%d), from SSRC:0x%x, RTT:%d, loss:%d",
_id, remoteSSRC, RTT, rtcpPacket.ReportBlockItem.FractionLost);
// rtcpPacketInformation
rtcpPacketInformation.AddReportInfo(
reportBlock->remoteReceiveBlock.fractionLost, (WebRtc_UWord16) RTT,
reportBlock->remoteReceiveBlock.extendedHighSeqNum,
reportBlock->remoteReceiveBlock.jitter);
}
RTCPReportBlockInformation*
RTCPReceiver::CreateReportBlockInformation(WebRtc_UWord32 remoteSSRC) {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
std::map<WebRtc_UWord32, RTCPReportBlockInformation*>::iterator it =
_receivedReportBlockMap.find(remoteSSRC);
RTCPReportBlockInformation* ptrReportBlockInfo = NULL;
if (it != _receivedReportBlockMap.end()) {
ptrReportBlockInfo = it->second;
} else {
ptrReportBlockInfo = new RTCPReportBlockInformation;
_receivedReportBlockMap[remoteSSRC] = ptrReportBlockInfo;
}
return ptrReportBlockInfo;
}
RTCPReportBlockInformation*
RTCPReceiver::GetReportBlockInformation(WebRtc_UWord32 remoteSSRC) const {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
std::map<WebRtc_UWord32, RTCPReportBlockInformation*>::const_iterator it =
_receivedReportBlockMap.find(remoteSSRC);
if (it == _receivedReportBlockMap.end()) {
return NULL;
}
return it->second;
}
RTCPCnameInformation*
RTCPReceiver::CreateCnameInformation(WebRtc_UWord32 remoteSSRC) {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
std::map<WebRtc_UWord32, RTCPCnameInformation*>::iterator it =
_receivedCnameMap.find(remoteSSRC);
if (it != _receivedCnameMap.end()) {
return it->second;
}
RTCPCnameInformation* cnameInfo = new RTCPCnameInformation;
memset(cnameInfo->name, 0, RTCP_CNAME_SIZE);
_receivedCnameMap[remoteSSRC] = cnameInfo;
return cnameInfo;
}
RTCPCnameInformation*
RTCPReceiver::GetCnameInformation(WebRtc_UWord32 remoteSSRC) const {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
std::map<WebRtc_UWord32, RTCPCnameInformation*>::const_iterator it =
_receivedCnameMap.find(remoteSSRC);
if (it == _receivedCnameMap.end()) {
return NULL;
}
return it->second;
}
RTCPReceiveInformation*
RTCPReceiver::CreateReceiveInformation(WebRtc_UWord32 remoteSSRC) {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
std::map<WebRtc_UWord32, RTCPReceiveInformation*>::iterator it =
_receivedInfoMap.find(remoteSSRC);
if (it != _receivedInfoMap.end()) {
return it->second;
}
RTCPReceiveInformation* receiveInfo = new RTCPReceiveInformation;
_receivedInfoMap[remoteSSRC] = receiveInfo;
return receiveInfo;
}
RTCPReceiveInformation*
RTCPReceiver::GetReceiveInformation(WebRtc_UWord32 remoteSSRC) {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
std::map<WebRtc_UWord32, RTCPReceiveInformation*>::iterator it =
_receivedInfoMap.find(remoteSSRC);
if (it == _receivedInfoMap.end()) {
return NULL;
}
return it->second;
}
void RTCPReceiver::UpdateReceiveInformation(
RTCPReceiveInformation& receiveInformation) {
// Update that this remote is alive
receiveInformation.lastTimeReceived = _clock.TimeInMilliseconds();
}
bool RTCPReceiver::RtcpRrTimeout(int64_t rtcp_interval_ms) {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
if (_lastReceivedRrMs == 0)
return false;
int64_t time_out_ms = kRrTimeoutIntervals * rtcp_interval_ms;
if (_clock.TimeInMilliseconds() > _lastReceivedRrMs + time_out_ms) {
// Reset the timer to only trigger one log.
_lastReceivedRrMs = 0;
return true;
}
return false;
}
bool RTCPReceiver::RtcpRrSequenceNumberTimeout(int64_t rtcp_interval_ms) {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
if (_lastIncreasedSequenceNumberMs == 0)
return false;
int64_t time_out_ms = kRrTimeoutIntervals * rtcp_interval_ms;
if (_clock.TimeInMilliseconds() > _lastIncreasedSequenceNumberMs +
time_out_ms) {
// Reset the timer to only trigger one log.
_lastIncreasedSequenceNumberMs = 0;
return true;
}
return false;
}
bool RTCPReceiver::UpdateRTCPReceiveInformationTimers() {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
bool updateBoundingSet = false;
WebRtc_Word64 timeNow = _clock.TimeInMilliseconds();
std::map<WebRtc_UWord32, RTCPReceiveInformation*>::iterator receiveInfoIt =
_receivedInfoMap.begin();
while (receiveInfoIt != _receivedInfoMap.end()) {
RTCPReceiveInformation* receiveInfo = receiveInfoIt->second;
if (receiveInfo == NULL) {
return updateBoundingSet;
}
// time since last received rtcp packet
// when we dont have a lastTimeReceived and the object is marked
// readyForDelete it's removed from the map
if (receiveInfo->lastTimeReceived) {
/// use audio define since we don't know what interval the remote peer is
// using
if ((timeNow - receiveInfo->lastTimeReceived) >
5 * RTCP_INTERVAL_AUDIO_MS) {
// no rtcp packet for the last five regular intervals, reset limitations
receiveInfo->TmmbrSet.clearSet();
// prevent that we call this over and over again
receiveInfo->lastTimeReceived = 0;
// send new TMMBN to all channels using the default codec
updateBoundingSet = true;
}
receiveInfoIt++;
} else if (receiveInfo->readyForDelete) {
// store our current receiveInfoItem
std::map<WebRtc_UWord32, RTCPReceiveInformation*>::iterator
receiveInfoItemToBeErased = receiveInfoIt;
receiveInfoIt++;
delete receiveInfoItemToBeErased->second;
_receivedInfoMap.erase(receiveInfoItemToBeErased);
} else {
receiveInfoIt++;
}
}
return updateBoundingSet;
}
WebRtc_Word32 RTCPReceiver::BoundingSet(bool &tmmbrOwner,
TMMBRSet* boundingSetRec) {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
std::map<WebRtc_UWord32, RTCPReceiveInformation*>::iterator receiveInfoIt =
_receivedInfoMap.find(_remoteSSRC);
if (receiveInfoIt == _receivedInfoMap.end()) {
return -1;
}
RTCPReceiveInformation* receiveInfo = receiveInfoIt->second;
if (receiveInfo == NULL) {
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
"%s failed to get RTCPReceiveInformation",
__FUNCTION__);
return -1;
}
if (receiveInfo->TmmbnBoundingSet.lengthOfSet() > 0) {
boundingSetRec->VerifyAndAllocateSet(
receiveInfo->TmmbnBoundingSet.lengthOfSet() + 1);
for(WebRtc_UWord32 i=0; i< receiveInfo->TmmbnBoundingSet.lengthOfSet();
i++) {
if(receiveInfo->TmmbnBoundingSet.Ssrc(i) == _SSRC) {
// owner of bounding set
tmmbrOwner = true;
}
boundingSetRec->SetEntry(i,
receiveInfo->TmmbnBoundingSet.Tmmbr(i),
receiveInfo->TmmbnBoundingSet.PacketOH(i),
receiveInfo->TmmbnBoundingSet.Ssrc(i));
}
}
return receiveInfo->TmmbnBoundingSet.lengthOfSet();
}
// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleSDES(RTCPUtility::RTCPParserV2& rtcpParser)
{
RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
while (pktType == RTCPUtility::kRtcpSdesChunkCode)
{
HandleSDESChunk(rtcpParser);
pktType = rtcpParser.Iterate();
}
}
// no need for critsect we have _criticalSectionRTCPReceiver
void RTCPReceiver::HandleSDESChunk(RTCPUtility::RTCPParserV2& rtcpParser) {
const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
RTCPCnameInformation* cnameInfo =
CreateCnameInformation(rtcpPacket.CName.SenderSSRC);
assert(cnameInfo);
cnameInfo->name[RTCP_CNAME_SIZE - 1] = 0;
strncpy(cnameInfo->name, rtcpPacket.CName.CName, RTCP_CNAME_SIZE - 1);
}
// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleNACK(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPPacketInformation& rtcpPacketInformation)
{
const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
if (_SSRC != rtcpPacket.NACK.MediaSSRC)
{
// Not to us.
rtcpParser.Iterate();
return;
}
rtcpPacketInformation.ResetNACKPacketIdArray();
RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
while (pktType == RTCPUtility::kRtcpRtpfbNackItemCode)
{
HandleNACKItem(rtcpPacket, rtcpPacketInformation);
pktType = rtcpParser.Iterate();
}
}
// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleNACKItem(const RTCPUtility::RTCPPacket& rtcpPacket,
RTCPPacketInformation& rtcpPacketInformation)
{
rtcpPacketInformation.AddNACKPacket(rtcpPacket.NACKItem.PacketID);
WebRtc_UWord16 bitMask = rtcpPacket.NACKItem.BitMask;
if(bitMask)
{
for(int i=1; i <= 16; ++i)
{
if(bitMask & 0x01)
{
rtcpPacketInformation.AddNACKPacket(rtcpPacket.NACKItem.PacketID + i);
}
bitMask = bitMask >>1;
}
}
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpNack;
}
// no need for critsect we have _criticalSectionRTCPReceiver
void RTCPReceiver::HandleBYE(RTCPUtility::RTCPParserV2& rtcpParser) {
const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
// clear our lists
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
std::map<WebRtc_UWord32, RTCPReportBlockInformation*>::iterator
reportBlockInfoIt = _receivedReportBlockMap.find(
rtcpPacket.BYE.SenderSSRC);
if (reportBlockInfoIt != _receivedReportBlockMap.end()) {
delete reportBlockInfoIt->second;
_receivedReportBlockMap.erase(reportBlockInfoIt);
}
// we can't delete it due to TMMBR
std::map<WebRtc_UWord32, RTCPReceiveInformation*>::iterator receiveInfoIt =
_receivedInfoMap.find(rtcpPacket.BYE.SenderSSRC);
if (receiveInfoIt != _receivedInfoMap.end()) {
receiveInfoIt->second->readyForDelete = true;
}
std::map<WebRtc_UWord32, RTCPCnameInformation*>::iterator cnameInfoIt =
_receivedCnameMap.find(rtcpPacket.BYE.SenderSSRC);
if (cnameInfoIt != _receivedCnameMap.end()) {
delete cnameInfoIt->second;
_receivedCnameMap.erase(cnameInfoIt);
}
rtcpParser.Iterate();
}
// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleXRVOIPMetric(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPPacketInformation& rtcpPacketInformation)
{
const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
if(rtcpPacket.XRVOIPMetricItem.SSRC == _SSRC)
{
// Store VoIP metrics block if it's about me
// from OriginatorSSRC do we filter it?
// rtcpPacket.XR.OriginatorSSRC;
RTCPVoIPMetric receivedVoIPMetrics;
receivedVoIPMetrics.burstDensity = rtcpPacket.XRVOIPMetricItem.burstDensity;
receivedVoIPMetrics.burstDuration = rtcpPacket.XRVOIPMetricItem.burstDuration;
receivedVoIPMetrics.discardRate = rtcpPacket.XRVOIPMetricItem.discardRate;
receivedVoIPMetrics.endSystemDelay = rtcpPacket.XRVOIPMetricItem.endSystemDelay;
receivedVoIPMetrics.extRfactor = rtcpPacket.XRVOIPMetricItem.extRfactor;
receivedVoIPMetrics.gapDensity = rtcpPacket.XRVOIPMetricItem.gapDensity;
receivedVoIPMetrics.gapDuration = rtcpPacket.XRVOIPMetricItem.gapDuration;
receivedVoIPMetrics.Gmin = rtcpPacket.XRVOIPMetricItem.Gmin;
receivedVoIPMetrics.JBabsMax = rtcpPacket.XRVOIPMetricItem.JBabsMax;
receivedVoIPMetrics.JBmax = rtcpPacket.XRVOIPMetricItem.JBmax;
receivedVoIPMetrics.JBnominal = rtcpPacket.XRVOIPMetricItem.JBnominal;
receivedVoIPMetrics.lossRate = rtcpPacket.XRVOIPMetricItem.lossRate;
receivedVoIPMetrics.MOSCQ = rtcpPacket.XRVOIPMetricItem.MOSCQ;
receivedVoIPMetrics.MOSLQ = rtcpPacket.XRVOIPMetricItem.MOSLQ;
receivedVoIPMetrics.noiseLevel = rtcpPacket.XRVOIPMetricItem.noiseLevel;
receivedVoIPMetrics.RERL = rtcpPacket.XRVOIPMetricItem.RERL;
receivedVoIPMetrics.Rfactor = rtcpPacket.XRVOIPMetricItem.Rfactor;
receivedVoIPMetrics.roundTripDelay = rtcpPacket.XRVOIPMetricItem.roundTripDelay;
receivedVoIPMetrics.RXconfig = rtcpPacket.XRVOIPMetricItem.RXconfig;
receivedVoIPMetrics.signalLevel = rtcpPacket.XRVOIPMetricItem.signalLevel;
rtcpPacketInformation.AddVoIPMetric(&receivedVoIPMetrics);
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpXrVoipMetric; // received signal
}
rtcpParser.Iterate();
}
// no need for critsect we have _criticalSectionRTCPReceiver
void RTCPReceiver::HandlePLI(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPPacketInformation& rtcpPacketInformation) {
const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
if (_SSRC == rtcpPacket.PLI.MediaSSRC) {
// Received a signal that we need to send a new key frame.
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpPli;
}
rtcpParser.Iterate();
}
// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleTMMBR(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPPacketInformation& rtcpPacketInformation)
{
const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
WebRtc_UWord32 senderSSRC = rtcpPacket.TMMBR.SenderSSRC;
RTCPReceiveInformation* ptrReceiveInfo = GetReceiveInformation(senderSSRC);
if (ptrReceiveInfo == NULL)
{
// This remote SSRC must be saved before.
rtcpParser.Iterate();
return;
}
if(rtcpPacket.TMMBR.MediaSSRC)
{
// rtcpPacket.TMMBR.MediaSSRC SHOULD be 0 if same as SenderSSRC
// in relay mode this is a valid number
senderSSRC = rtcpPacket.TMMBR.MediaSSRC;
}
// Use packet length to calc max number of TMMBR blocks
// each TMMBR block is 8 bytes
ptrdiff_t maxNumOfTMMBRBlocks = rtcpParser.LengthLeft() / 8;
// sanity
if(maxNumOfTMMBRBlocks > 200) // we can't have more than what's in one packet
{
assert(false);
rtcpParser.Iterate();
return;
}
ptrReceiveInfo->VerifyAndAllocateTMMBRSet((WebRtc_UWord32)maxNumOfTMMBRBlocks);
RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
while (pktType == RTCPUtility::kRtcpRtpfbTmmbrItemCode)
{
HandleTMMBRItem(*ptrReceiveInfo, rtcpPacket, rtcpPacketInformation, senderSSRC);
pktType = rtcpParser.Iterate();
}
}
// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleTMMBRItem(RTCPReceiveInformation& receiveInfo,
const RTCPUtility::RTCPPacket& rtcpPacket,
RTCPPacketInformation& rtcpPacketInformation,
const WebRtc_UWord32 senderSSRC)
{
if (_SSRC == rtcpPacket.TMMBRItem.SSRC &&
rtcpPacket.TMMBRItem.MaxTotalMediaBitRate > 0)
{
receiveInfo.InsertTMMBRItem(senderSSRC, rtcpPacket.TMMBRItem,
_clock.TimeInMilliseconds());
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpTmmbr;
}
}
// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleTMMBN(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPPacketInformation& rtcpPacketInformation)
{
const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
RTCPReceiveInformation* ptrReceiveInfo = GetReceiveInformation(rtcpPacket.TMMBN.SenderSSRC);
if (ptrReceiveInfo == NULL)
{
// This remote SSRC must be saved before.
rtcpParser.Iterate();
return;
}
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpTmmbn;
// Use packet length to calc max number of TMMBN blocks
// each TMMBN block is 8 bytes
ptrdiff_t maxNumOfTMMBNBlocks = rtcpParser.LengthLeft() / 8;
// sanity
if(maxNumOfTMMBNBlocks > 200) // we cant have more than what's in one packet
{
assert(false);
rtcpParser.Iterate();
return;
}
ptrReceiveInfo->VerifyAndAllocateBoundingSet((WebRtc_UWord32)maxNumOfTMMBNBlocks);
RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
while (pktType == RTCPUtility::kRtcpRtpfbTmmbnItemCode)
{
HandleTMMBNItem(*ptrReceiveInfo, rtcpPacket);
pktType = rtcpParser.Iterate();
}
}
// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleSR_REQ(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPPacketInformation& rtcpPacketInformation)
{
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpSrReq;
rtcpParser.Iterate();
}
// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleTMMBNItem(RTCPReceiveInformation& receiveInfo,
const RTCPUtility::RTCPPacket& rtcpPacket)
{
receiveInfo.TmmbnBoundingSet.AddEntry(
rtcpPacket.TMMBNItem.MaxTotalMediaBitRate,
rtcpPacket.TMMBNItem.MeasuredOverhead,
rtcpPacket.TMMBNItem.SSRC);
}
// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleSLI(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPPacketInformation& rtcpPacketInformation)
{
const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
while (pktType == RTCPUtility::kRtcpPsfbSliItemCode)
{
HandleSLIItem(rtcpPacket, rtcpPacketInformation);
pktType = rtcpParser.Iterate();
}
}
// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleSLIItem(const RTCPUtility::RTCPPacket& rtcpPacket,
RTCPPacketInformation& rtcpPacketInformation)
{
// in theory there could be multiple slices lost
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpSli; // received signal that we need to refresh a slice
rtcpPacketInformation.sliPictureId = rtcpPacket.SLIItem.PictureId;
}
void
RTCPReceiver::HandleRPSI(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPHelp::RTCPPacketInformation& rtcpPacketInformation)
{
const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
if(pktType == RTCPUtility::kRtcpPsfbRpsiCode)
{
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpRpsi; // received signal that we have a confirmed reference picture
if(rtcpPacket.RPSI.NumberOfValidBits%8 != 0)
{
// to us unknown
// continue
rtcpParser.Iterate();
return;
}
rtcpPacketInformation.rpsiPictureId = 0;
// convert NativeBitString to rpsiPictureId
WebRtc_UWord8 numberOfBytes = rtcpPacket.RPSI.NumberOfValidBits /8;
for(WebRtc_UWord8 n = 0; n < (numberOfBytes-1); n++)
{
rtcpPacketInformation.rpsiPictureId += (rtcpPacket.RPSI.NativeBitString[n] & 0x7f);
rtcpPacketInformation.rpsiPictureId <<= 7; // prepare next
}
rtcpPacketInformation.rpsiPictureId += (rtcpPacket.RPSI.NativeBitString[numberOfBytes-1] & 0x7f);
}
}
// no need for critsect we have _criticalSectionRTCPReceiver
void RTCPReceiver::HandlePsfbApp(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPPacketInformation& rtcpPacketInformation) {
RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
if (pktType == RTCPUtility::kRtcpPsfbRembCode) {
pktType = rtcpParser.Iterate();
if (pktType == RTCPUtility::kRtcpPsfbRembItemCode) {
HandleREMBItem(rtcpParser, rtcpPacketInformation);
rtcpParser.Iterate();
}
}
}
// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleIJ(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPPacketInformation& rtcpPacketInformation)
{
const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
while (pktType == RTCPUtility::kRtcpExtendedIjItemCode)
{
HandleIJItem(rtcpPacket, rtcpPacketInformation);
pktType = rtcpParser.Iterate();
}
}
void
RTCPReceiver::HandleIJItem(const RTCPUtility::RTCPPacket& rtcpPacket,
RTCPPacketInformation& rtcpPacketInformation)
{
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpTransmissionTimeOffset;
rtcpPacketInformation.interArrivalJitter =
rtcpPacket.ExtendedJitterReportItem.Jitter;
}
void RTCPReceiver::HandleREMBItem(
RTCPUtility::RTCPParserV2& rtcpParser,
RTCPPacketInformation& rtcpPacketInformation) {
const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpRemb;
rtcpPacketInformation.receiverEstimatedMaxBitrate =
rtcpPacket.REMBItem.BitRate;
}
// no need for critsect we have _criticalSectionRTCPReceiver
void RTCPReceiver::HandleFIR(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPPacketInformation& rtcpPacketInformation) {
const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
RTCPReceiveInformation* ptrReceiveInfo =
GetReceiveInformation(rtcpPacket.FIR.SenderSSRC);
RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
while (pktType == RTCPUtility::kRtcpPsfbFirItemCode) {
HandleFIRItem(ptrReceiveInfo, rtcpPacket, rtcpPacketInformation);
pktType = rtcpParser.Iterate();
}
}
// no need for critsect we have _criticalSectionRTCPReceiver
void RTCPReceiver::HandleFIRItem(RTCPReceiveInformation* receiveInfo,
const RTCPUtility::RTCPPacket& rtcpPacket,
RTCPPacketInformation& rtcpPacketInformation) {
// Is it our sender that is requested to generate a new keyframe
if (_SSRC != rtcpPacket.FIRItem.SSRC) {
return;
}
// rtcpPacket.FIR.MediaSSRC SHOULD be 0 but we ignore to check it
// we don't know who this originate from
if (receiveInfo) {
// check if we have reported this FIRSequenceNumber before
if (rtcpPacket.FIRItem.CommandSequenceNumber !=
receiveInfo->lastFIRSequenceNumber) {
WebRtc_Word64 now = _clock.TimeInMilliseconds();
// sanity; don't go crazy with the callbacks
if ((now - receiveInfo->lastFIRRequest) > RTCP_MIN_FRAME_LENGTH_MS) {
receiveInfo->lastFIRRequest = now;
receiveInfo->lastFIRSequenceNumber =
rtcpPacket.FIRItem.CommandSequenceNumber;
// received signal that we need to send a new key frame
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpFir;
}
}
} else {
// received signal that we need to send a new key frame
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpFir;
}
}
void
RTCPReceiver::HandleAPP(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPPacketInformation& rtcpPacketInformation)
{
const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpApp;
rtcpPacketInformation.applicationSubType = rtcpPacket.APP.SubType;
rtcpPacketInformation.applicationName = rtcpPacket.APP.Name;
rtcpParser.Iterate();
}
void
RTCPReceiver::HandleAPPItem(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPPacketInformation& rtcpPacketInformation)
{
const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
rtcpPacketInformation.AddApplicationData(rtcpPacket.APP.Data, rtcpPacket.APP.Size);
rtcpParser.Iterate();
}
WebRtc_Word32 RTCPReceiver::UpdateTMMBR() {
WebRtc_Word32 numBoundingSet = 0;
WebRtc_UWord32 bitrate = 0;
WebRtc_UWord32 accNumCandidates = 0;
WebRtc_Word32 size = TMMBRReceived(0, 0, NULL);
if (size > 0) {
TMMBRSet* candidateSet = VerifyAndAllocateCandidateSet(size);
// Get candidate set from receiver.
accNumCandidates = 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
_rtpRtcp.SetTMMBN(boundingSet);
// 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
if (CalcMinBitRate(&bitrate)) {
// we have a new bandwidth estimate on this channel
CriticalSectionScoped lock(_criticalSectionFeedbacks);
if (_cbRtcpBandwidthObserver) {
_cbRtcpBandwidthObserver->OnReceivedEstimatedBitrate(bitrate * 1000);
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
"Set TMMBR request:%d kbps", bitrate);
}
}
return 0;
}
// Holding no Critical section
void RTCPReceiver::TriggerCallbacksFromRTCPPacket(
RTCPPacketInformation& rtcpPacketInformation) {
// Process TMMBR and REMB first to avoid multiple callbacks
// to OnNetworkChanged.
if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpTmmbr) {
WEBRTC_TRACE(kTraceStateInfo, kTraceRtpRtcp, _id,
"SIG [RTCP] Incoming TMMBR to id:%d", _id);
// Might trigger a OnReceivedBandwidthEstimateUpdate.
UpdateTMMBR();
}
unsigned int local_ssrc = 0;
{
// We don't want to hold this critsect when triggering the callbacks below.
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
local_ssrc = _SSRC;
}
if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSrReq) {
_rtpRtcp.OnRequestSendReport();
}
if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpNack) {
if (rtcpPacketInformation.nackSequenceNumbersLength > 0) {
WEBRTC_TRACE(kTraceStateInfo, kTraceRtpRtcp, _id,
"SIG [RTCP] Incoming NACK length:%d",
rtcpPacketInformation.nackSequenceNumbersLength);
_rtpRtcp.OnReceivedNACK(
rtcpPacketInformation.nackSequenceNumbersLength,
rtcpPacketInformation.nackSequenceNumbers);
}
}
{
CriticalSectionScoped lock(_criticalSectionFeedbacks);
// We need feedback that we have received a report block(s) so that we
// can generate a new packet in a conference relay scenario, one received
// report can generate several RTCP packets, based on number relayed/mixed
// a send report block should go out to all receivers.
if (_cbRtcpIntraFrameObserver) {
if ((rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpPli) ||
(rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpFir)) {
if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpPli) {
WEBRTC_TRACE(kTraceStateInfo, kTraceRtpRtcp, _id,
"SIG [RTCP] Incoming PLI from SSRC:0x%x",
rtcpPacketInformation.remoteSSRC);
} else {
WEBRTC_TRACE(kTraceStateInfo, kTraceRtpRtcp, _id,
"SIG [RTCP] Incoming FIR from SSRC:0x%x",
rtcpPacketInformation.remoteSSRC);
}
_cbRtcpIntraFrameObserver->OnReceivedIntraFrameRequest(local_ssrc);
}
if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSli) {
_cbRtcpIntraFrameObserver->OnReceivedSLI(
local_ssrc, rtcpPacketInformation.sliPictureId);
}
if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRpsi) {
_cbRtcpIntraFrameObserver->OnReceivedRPSI(
local_ssrc, rtcpPacketInformation.rpsiPictureId);
}
}
if (_cbRtcpBandwidthObserver) {
if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRemb) {
WEBRTC_TRACE(kTraceStateInfo, kTraceRtpRtcp, _id,
"SIG [RTCP] Incoming REMB:%d",
rtcpPacketInformation.receiverEstimatedMaxBitrate);
_cbRtcpBandwidthObserver->OnReceivedEstimatedBitrate(
rtcpPacketInformation.receiverEstimatedMaxBitrate);
}
if ((rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSr ||
rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRr) &&
rtcpPacketInformation.reportBlock) {
WebRtc_Word64 now = _clock.TimeInMilliseconds();
_cbRtcpBandwidthObserver->OnReceivedRtcpReceiverReport(
rtcpPacketInformation.remoteSSRC,
rtcpPacketInformation.fractionLost,
rtcpPacketInformation.roundTripTime,
rtcpPacketInformation.lastReceivedExtendedHighSeqNum,
now);
}
}
if(_cbRtcpFeedback) {
if(rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSr) {
_cbRtcpFeedback->OnSendReportReceived(_id,
rtcpPacketInformation.remoteSSRC,
rtcpPacketInformation.ntp_secs,
rtcpPacketInformation.ntp_frac,
rtcpPacketInformation.rtp_timestamp);
} else {
_cbRtcpFeedback->OnReceiveReportReceived(_id,
rtcpPacketInformation.remoteSSRC);
}
if(rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpXrVoipMetric) {
_cbRtcpFeedback->OnXRVoIPMetricReceived(_id,
rtcpPacketInformation.VoIPMetric);
}
if(rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpApp) {
_cbRtcpFeedback->OnApplicationDataReceived(_id,
rtcpPacketInformation.applicationSubType,
rtcpPacketInformation.applicationName,
rtcpPacketInformation.applicationLength,
rtcpPacketInformation.applicationData);
}
}
}
}
WebRtc_Word32 RTCPReceiver::CNAME(const WebRtc_UWord32 remoteSSRC,
char cName[RTCP_CNAME_SIZE]) const {
assert(cName);
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
RTCPCnameInformation* cnameInfo = GetCnameInformation(remoteSSRC);
if (cnameInfo == NULL) {
return -1;
}
cName[RTCP_CNAME_SIZE - 1] = 0;
strncpy(cName, cnameInfo->name, RTCP_CNAME_SIZE - 1);
return 0;
}
// no callbacks allowed inside this function
WebRtc_Word32 RTCPReceiver::TMMBRReceived(const WebRtc_UWord32 size,
const WebRtc_UWord32 accNumCandidates,
TMMBRSet* candidateSet) const {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
std::map<WebRtc_UWord32, RTCPReceiveInformation*>::const_iterator
receiveInfoIt = _receivedInfoMap.begin();
if (receiveInfoIt == _receivedInfoMap.end()) {
return -1;
}
WebRtc_UWord32 num = accNumCandidates;
if (candidateSet) {
while( num < size && receiveInfoIt != _receivedInfoMap.end()) {
RTCPReceiveInformation* receiveInfo = receiveInfoIt->second;
if (receiveInfo == NULL) {
return 0;
}
for (WebRtc_UWord32 i = 0;
(num < size) && (i < receiveInfo->TmmbrSet.lengthOfSet()); i++) {
if (receiveInfo->GetTMMBRSet(i, num, candidateSet,
_clock.TimeInMilliseconds()) == 0) {
num++;
}
}
receiveInfoIt++;
}
} else {
while (receiveInfoIt != _receivedInfoMap.end()) {
RTCPReceiveInformation* receiveInfo = receiveInfoIt->second;
if(receiveInfo == NULL) {
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
"%s failed to get RTCPReceiveInformation",
__FUNCTION__);
return -1;
}
num += receiveInfo->TmmbrSet.lengthOfSet();
receiveInfoIt++;
}
}
return num;
}
WebRtc_Word32
RTCPReceiver::SetPacketTimeout(const WebRtc_UWord32 timeoutMS)
{
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
_packetTimeOutMS = timeoutMS;
return 0;
}
void RTCPReceiver::PacketTimeout()
{
if(_packetTimeOutMS == 0)
{
// not configured
return;
}
bool packetTimeOut = false;
{
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
if(_lastReceived == 0)
{
// not active
return;
}
WebRtc_Word64 now = _clock.TimeInMilliseconds();
if(now - _lastReceived > _packetTimeOutMS)
{
packetTimeOut = true;
_lastReceived = 0; // only one callback
}
}
CriticalSectionScoped lock(_criticalSectionFeedbacks);
if(packetTimeOut && _cbRtcpFeedback)
{
_cbRtcpFeedback->OnRTCPPacketTimeout(_id);
}
}
} // namespace webrtc