Add REMB functionality to ViE.
This CL only adds support for encoding one stream, but receiving multiple streams. BUG= TEST=video_engine_core_unittest + auto_test/loopback Review URL: http://webrtc-codereview.appspot.com/333011 git-svn-id: http://webrtc.googlecode.com/svn/trunk@1284 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
093ffad26b
commit
84dc3d134d
@ -767,6 +767,11 @@ public:
|
||||
const WebRtc_UWord8 numberOfSSRC,
|
||||
const WebRtc_UWord32* SSRC) = 0;
|
||||
|
||||
// Registers an observer to call when the estimate of the incoming channel
|
||||
// changes.
|
||||
virtual bool SetRemoteBitrateObserver(
|
||||
RtpRemoteBitrateObserver* observer) = 0;
|
||||
|
||||
/*
|
||||
* (IJ) Extended jitter report.
|
||||
*/
|
||||
|
@ -245,6 +245,16 @@ protected:
|
||||
virtual ~RtpRtcpClock() {}
|
||||
};
|
||||
|
||||
// RtpReceiveBitrateUpdate is used to signal changes in bitrate estimates for
|
||||
// the incoming stream.
|
||||
class RtpRemoteBitrateObserver
|
||||
{
|
||||
public:
|
||||
virtual void OnReceiveBitrateChanged(unsigned int ssrc,
|
||||
unsigned int bitrate) = 0;
|
||||
virtual ~RtpRemoteBitrateObserver() {}
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_RTP_RTCP_INTERFACE_RTP_RTCP_DEFINES_H_
|
||||
|
257
src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
Normal file
257
src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
Normal file
@ -0,0 +1,257 @@
|
||||
#include "../testing/gmock/include/gmock/gmock.h"
|
||||
|
||||
#include "modules/interface/module.h"
|
||||
#include "modules/rtp_rtcp/interface/rtp_rtcp.h"
|
||||
#include "modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class MockRtpRtcp : public RtpRtcp {
|
||||
public:
|
||||
MOCK_METHOD1(ChangeUniqueId,
|
||||
WebRtc_Word32(const WebRtc_Word32 id));
|
||||
MOCK_METHOD1(RegisterDefaultModule,
|
||||
WebRtc_Word32(RtpRtcp* module));
|
||||
MOCK_METHOD0(DeRegisterDefaultModule,
|
||||
WebRtc_Word32());
|
||||
MOCK_METHOD0(DefaultModuleRegistered,
|
||||
bool());
|
||||
MOCK_METHOD0(NumberChildModules,
|
||||
WebRtc_UWord32());
|
||||
MOCK_METHOD1(RegisterSyncModule,
|
||||
WebRtc_Word32(RtpRtcp* module));
|
||||
MOCK_METHOD0(DeRegisterSyncModule,
|
||||
WebRtc_Word32());
|
||||
MOCK_METHOD0(InitReceiver,
|
||||
WebRtc_Word32());
|
||||
MOCK_METHOD1(RegisterIncomingDataCallback,
|
||||
WebRtc_Word32(RtpData* incomingDataCallback));
|
||||
MOCK_METHOD1(RegisterIncomingRTPCallback,
|
||||
WebRtc_Word32(RtpFeedback* incomingMessagesCallback));
|
||||
MOCK_METHOD2(SetPacketTimeout,
|
||||
WebRtc_Word32(const WebRtc_UWord32 RTPtimeoutMS, const WebRtc_UWord32 RTCPtimeoutMS));
|
||||
MOCK_METHOD2(SetPeriodicDeadOrAliveStatus,
|
||||
WebRtc_Word32(const bool enable, const WebRtc_UWord8 sampleTimeSeconds));
|
||||
MOCK_METHOD2(PeriodicDeadOrAliveStatus,
|
||||
WebRtc_Word32(bool &enable, WebRtc_UWord8 &sampleTimeSeconds));
|
||||
MOCK_METHOD1(RegisterReceivePayload,
|
||||
WebRtc_Word32(const CodecInst& voiceCodec));
|
||||
MOCK_METHOD1(RegisterReceivePayload,
|
||||
WebRtc_Word32(const VideoCodec& videoCodec));
|
||||
MOCK_METHOD2(ReceivePayloadType,
|
||||
WebRtc_Word32(const CodecInst& voiceCodec, WebRtc_Word8* plType));
|
||||
MOCK_METHOD2(ReceivePayloadType,
|
||||
WebRtc_Word32(const VideoCodec& videoCodec, WebRtc_Word8* plType));
|
||||
MOCK_METHOD1(DeRegisterReceivePayload,
|
||||
WebRtc_Word32(const WebRtc_Word8 payloadType));
|
||||
MOCK_METHOD2(RegisterReceiveRtpHeaderExtension,
|
||||
WebRtc_Word32(const RTPExtensionType type, const WebRtc_UWord8 id));
|
||||
MOCK_METHOD1(DeregisterReceiveRtpHeaderExtension,
|
||||
WebRtc_Word32(const RTPExtensionType type));
|
||||
MOCK_CONST_METHOD0(RemoteTimestamp,
|
||||
WebRtc_UWord32());
|
||||
MOCK_CONST_METHOD1(EstimatedRemoteTimeStamp,
|
||||
WebRtc_Word32(WebRtc_UWord32& timestamp));
|
||||
MOCK_CONST_METHOD0(RemoteSSRC,
|
||||
WebRtc_UWord32());
|
||||
MOCK_CONST_METHOD1(RemoteCSRCs,
|
||||
WebRtc_Word32(WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]));
|
||||
MOCK_CONST_METHOD1(SSRCFilter,
|
||||
WebRtc_Word32(WebRtc_UWord32& allowedSSRC));
|
||||
MOCK_METHOD2(SetSSRCFilter,
|
||||
WebRtc_Word32(const bool enable, const WebRtc_UWord32 allowedSSRC));
|
||||
MOCK_METHOD2(IncomingPacket,
|
||||
WebRtc_Word32(const WebRtc_UWord8* incomingPacket, const WebRtc_UWord16 packetLength));
|
||||
MOCK_METHOD4(IncomingAudioNTP,
|
||||
WebRtc_Word32(const WebRtc_UWord32 audioReceivedNTPsecs, const WebRtc_UWord32 audioReceivedNTPfrac, const WebRtc_UWord32 audioRTCPArrivalTimeSecs, const WebRtc_UWord32 audioRTCPArrivalTimeFrac));
|
||||
MOCK_METHOD0(InitSender,
|
||||
WebRtc_Word32());
|
||||
MOCK_METHOD1(RegisterSendTransport,
|
||||
WebRtc_Word32(Transport* outgoingTransport));
|
||||
MOCK_METHOD1(SetMaxTransferUnit,
|
||||
WebRtc_Word32(const WebRtc_UWord16 size));
|
||||
MOCK_METHOD3(SetTransportOverhead,
|
||||
WebRtc_Word32(const bool TCP, const bool IPV6, const WebRtc_UWord8 authenticationOverhead));
|
||||
MOCK_CONST_METHOD0(MaxPayloadLength,
|
||||
WebRtc_UWord16());
|
||||
MOCK_CONST_METHOD0(MaxDataPayloadLength,
|
||||
WebRtc_UWord16());
|
||||
MOCK_METHOD3(SetRTPKeepaliveStatus,
|
||||
WebRtc_Word32(const bool enable, const WebRtc_Word8 unknownPayloadType, const WebRtc_UWord16 deltaTransmitTimeMS));
|
||||
MOCK_CONST_METHOD3(RTPKeepaliveStatus,
|
||||
WebRtc_Word32(bool* enable, WebRtc_Word8* unknownPayloadType, WebRtc_UWord16* deltaTransmitTimeMS));
|
||||
MOCK_CONST_METHOD0(RTPKeepalive,
|
||||
bool());
|
||||
MOCK_METHOD1(RegisterSendPayload,
|
||||
WebRtc_Word32(const CodecInst& voiceCodec));
|
||||
MOCK_METHOD1(RegisterSendPayload,
|
||||
WebRtc_Word32(const VideoCodec& videoCodec));
|
||||
MOCK_METHOD1(DeRegisterSendPayload,
|
||||
WebRtc_Word32(const WebRtc_Word8 payloadType));
|
||||
MOCK_METHOD2(RegisterSendRtpHeaderExtension,
|
||||
WebRtc_Word32(const RTPExtensionType type, const WebRtc_UWord8 id));
|
||||
MOCK_METHOD1(DeregisterSendRtpHeaderExtension,
|
||||
WebRtc_Word32(const RTPExtensionType type));
|
||||
MOCK_CONST_METHOD0(StartTimestamp,
|
||||
WebRtc_UWord32());
|
||||
MOCK_METHOD1(SetStartTimestamp,
|
||||
WebRtc_Word32(const WebRtc_UWord32 timestamp));
|
||||
MOCK_CONST_METHOD0(SequenceNumber,
|
||||
WebRtc_UWord16());
|
||||
MOCK_METHOD1(SetSequenceNumber,
|
||||
WebRtc_Word32(const WebRtc_UWord16 seq));
|
||||
MOCK_CONST_METHOD0(SSRC,
|
||||
WebRtc_UWord32());
|
||||
MOCK_METHOD1(SetSSRC,
|
||||
WebRtc_Word32(const WebRtc_UWord32 ssrc));
|
||||
MOCK_CONST_METHOD1(CSRCs,
|
||||
WebRtc_Word32(WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]));
|
||||
MOCK_METHOD2(SetCSRCs,
|
||||
WebRtc_Word32(const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize], const WebRtc_UWord8 arrLength));
|
||||
MOCK_METHOD1(SetCSRCStatus,
|
||||
WebRtc_Word32(const bool include));
|
||||
MOCK_METHOD1(SetSendingStatus,
|
||||
WebRtc_Word32(const bool sending));
|
||||
MOCK_CONST_METHOD0(Sending,
|
||||
bool());
|
||||
MOCK_METHOD1(SetSendingMediaStatus,
|
||||
WebRtc_Word32(const bool sending));
|
||||
MOCK_CONST_METHOD0(SendingMedia,
|
||||
bool());
|
||||
MOCK_CONST_METHOD4(BitrateSent,
|
||||
void(WebRtc_UWord32* totalRate, WebRtc_UWord32* videoRate, WebRtc_UWord32* fecRate, WebRtc_UWord32* nackRate));
|
||||
MOCK_METHOD7(SendOutgoingData,
|
||||
WebRtc_Word32(const FrameType frameType, const WebRtc_Word8 payloadType, const WebRtc_UWord32 timeStamp, const WebRtc_UWord8* payloadData, const WebRtc_UWord32 payloadSize, const RTPFragmentationHeader* fragmentation, const RTPVideoHeader* rtpVideoHdr));
|
||||
MOCK_METHOD1(RegisterIncomingRTCPCallback,
|
||||
WebRtc_Word32(RtcpFeedback* incomingMessagesCallback));
|
||||
MOCK_CONST_METHOD0(RTCP,
|
||||
RTCPMethod());
|
||||
MOCK_METHOD1(SetRTCPStatus,
|
||||
WebRtc_Word32(const RTCPMethod method));
|
||||
MOCK_METHOD1(SetCNAME,
|
||||
WebRtc_Word32(const WebRtc_Word8 cName[RTCP_CNAME_SIZE]));
|
||||
MOCK_METHOD1(CNAME,
|
||||
WebRtc_Word32(WebRtc_Word8 cName[RTCP_CNAME_SIZE]));
|
||||
MOCK_CONST_METHOD2(RemoteCNAME,
|
||||
WebRtc_Word32(const WebRtc_UWord32 remoteSSRC, WebRtc_Word8 cName[RTCP_CNAME_SIZE]));
|
||||
MOCK_CONST_METHOD4(RemoteNTP,
|
||||
WebRtc_Word32(WebRtc_UWord32 *ReceivedNTPsecs, WebRtc_UWord32 *ReceivedNTPfrac, WebRtc_UWord32 *RTCPArrivalTimeSecs, WebRtc_UWord32 *RTCPArrivalTimeFrac));
|
||||
MOCK_METHOD2(AddMixedCNAME,
|
||||
WebRtc_Word32(const WebRtc_UWord32 SSRC, const WebRtc_Word8 cName[RTCP_CNAME_SIZE]));
|
||||
MOCK_METHOD1(RemoveMixedCNAME,
|
||||
WebRtc_Word32(const WebRtc_UWord32 SSRC));
|
||||
MOCK_CONST_METHOD5(RTT,
|
||||
WebRtc_Word32(const WebRtc_UWord32 remoteSSRC, WebRtc_UWord16* RTT, WebRtc_UWord16* avgRTT, WebRtc_UWord16* minRTT, WebRtc_UWord16* maxRTT));
|
||||
MOCK_METHOD1(ResetRTT,
|
||||
WebRtc_Word32(const WebRtc_UWord32 remoteSSRC));
|
||||
MOCK_METHOD1(SendRTCP,
|
||||
WebRtc_Word32(WebRtc_UWord32 rtcpPacketType));
|
||||
MOCK_METHOD1(SendRTCPReferencePictureSelection,
|
||||
WebRtc_Word32(const WebRtc_UWord64 pictureID));
|
||||
MOCK_METHOD1(SendRTCPSliceLossIndication,
|
||||
WebRtc_Word32(const WebRtc_UWord8 pictureID));
|
||||
MOCK_METHOD0(ResetStatisticsRTP,
|
||||
WebRtc_Word32());
|
||||
MOCK_CONST_METHOD5(StatisticsRTP,
|
||||
WebRtc_Word32(WebRtc_UWord8 *fraction_lost, WebRtc_UWord32 *cum_lost, WebRtc_UWord32 *ext_max, WebRtc_UWord32 *jitter, WebRtc_UWord32 *max_jitter));
|
||||
MOCK_METHOD0(ResetReceiveDataCountersRTP,
|
||||
WebRtc_Word32());
|
||||
MOCK_METHOD0(ResetSendDataCountersRTP,
|
||||
WebRtc_Word32());
|
||||
MOCK_CONST_METHOD4(DataCountersRTP,
|
||||
WebRtc_Word32(WebRtc_UWord32 *bytesSent, WebRtc_UWord32 *packetsSent, WebRtc_UWord32 *bytesReceived, WebRtc_UWord32 *packetsReceived));
|
||||
MOCK_METHOD1(RemoteRTCPStat,
|
||||
WebRtc_Word32(RTCPSenderInfo* senderInfo));
|
||||
MOCK_METHOD2(RemoteRTCPStat,
|
||||
WebRtc_Word32(const WebRtc_UWord32 remoteSSRC, RTCPReportBlock* receiveBlock));
|
||||
MOCK_METHOD2(AddRTCPReportBlock,
|
||||
WebRtc_Word32(const WebRtc_UWord32 SSRC, const RTCPReportBlock* receiveBlock));
|
||||
MOCK_METHOD1(RemoveRTCPReportBlock,
|
||||
WebRtc_Word32(const WebRtc_UWord32 SSRC));
|
||||
MOCK_METHOD4(SetRTCPApplicationSpecificData,
|
||||
WebRtc_Word32(const WebRtc_UWord8 subType, const WebRtc_UWord32 name, const WebRtc_UWord8* data, const WebRtc_UWord16 length));
|
||||
MOCK_METHOD1(SetRTCPVoIPMetrics,
|
||||
WebRtc_Word32(const RTCPVoIPMetric* VoIPMetric));
|
||||
MOCK_CONST_METHOD0(REMB,
|
||||
bool());
|
||||
MOCK_METHOD1(SetREMBStatus,
|
||||
WebRtc_Word32(const bool enable));
|
||||
MOCK_METHOD3(SetREMBData,
|
||||
WebRtc_Word32(const WebRtc_UWord32 bitrate, const WebRtc_UWord8 numberOfSSRC, const WebRtc_UWord32* SSRC));
|
||||
MOCK_METHOD1(SetRemoteBitrateObserver,
|
||||
bool(RtpRemoteBitrateObserver*));
|
||||
MOCK_CONST_METHOD0(IJ,
|
||||
bool());
|
||||
MOCK_METHOD1(SetIJStatus,
|
||||
WebRtc_Word32(const bool));
|
||||
MOCK_CONST_METHOD0(TMMBR,
|
||||
bool());
|
||||
MOCK_METHOD1(SetTMMBRStatus,
|
||||
WebRtc_Word32(const bool enable));
|
||||
MOCK_METHOD1(OnBandwidthEstimateUpdate,
|
||||
void(WebRtc_UWord16 bandWidthKbit));
|
||||
MOCK_CONST_METHOD0(NACK,
|
||||
NACKMethod());
|
||||
MOCK_METHOD1(SetNACKStatus,
|
||||
WebRtc_Word32(const NACKMethod method));
|
||||
MOCK_METHOD2(SendNACK,
|
||||
WebRtc_Word32(const WebRtc_UWord16* nackList, const WebRtc_UWord16 size));
|
||||
MOCK_METHOD2(SetStorePacketsStatus,
|
||||
WebRtc_Word32(const bool enable, const WebRtc_UWord16 numberToStore));
|
||||
MOCK_METHOD1(RegisterAudioCallback,
|
||||
WebRtc_Word32(RtpAudioFeedback* messagesCallback));
|
||||
MOCK_METHOD1(SetAudioPacketSize,
|
||||
WebRtc_Word32(const WebRtc_UWord16 packetSizeSamples));
|
||||
MOCK_METHOD3(SetTelephoneEventStatus,
|
||||
WebRtc_Word32(const bool enable, const bool forwardToDecoder, const bool detectEndOfTone));
|
||||
MOCK_CONST_METHOD0(TelephoneEvent,
|
||||
bool());
|
||||
MOCK_CONST_METHOD0(TelephoneEventForwardToDecoder,
|
||||
bool());
|
||||
MOCK_CONST_METHOD1(SendTelephoneEventActive,
|
||||
bool(WebRtc_Word8& telephoneEvent));
|
||||
MOCK_METHOD3(SendTelephoneEventOutband,
|
||||
WebRtc_Word32(const WebRtc_UWord8 key, const WebRtc_UWord16 time_ms, const WebRtc_UWord8 level));
|
||||
MOCK_METHOD1(SetSendREDPayloadType,
|
||||
WebRtc_Word32(const WebRtc_Word8 payloadType));
|
||||
MOCK_CONST_METHOD1(SendREDPayloadType,
|
||||
WebRtc_Word32(WebRtc_Word8& payloadType));
|
||||
MOCK_METHOD2(SetRTPAudioLevelIndicationStatus,
|
||||
WebRtc_Word32(const bool enable, const WebRtc_UWord8 ID));
|
||||
MOCK_CONST_METHOD2(GetRTPAudioLevelIndicationStatus,
|
||||
WebRtc_Word32(bool& enable, WebRtc_UWord8& ID));
|
||||
MOCK_METHOD1(SetAudioLevel,
|
||||
WebRtc_Word32(const WebRtc_UWord8 level_dBov));
|
||||
MOCK_METHOD1(RegisterIncomingVideoCallback,
|
||||
WebRtc_Word32(RtpVideoFeedback* incomingMessagesCallback));
|
||||
MOCK_METHOD1(SetCameraDelay,
|
||||
WebRtc_Word32(const WebRtc_Word32 delayMS));
|
||||
MOCK_METHOD3(SetSendBitrate,
|
||||
WebRtc_Word32(const WebRtc_UWord32 startBitrate, const WebRtc_UWord16 minBitrateKbit, const WebRtc_UWord16 maxBitrateKbit));
|
||||
MOCK_METHOD3(SetGenericFECStatus,
|
||||
WebRtc_Word32(const bool enable, const WebRtc_UWord8 payloadTypeRED, const WebRtc_UWord8 payloadTypeFEC));
|
||||
MOCK_METHOD3(GenericFECStatus,
|
||||
WebRtc_Word32(bool& enable, WebRtc_UWord8& payloadTypeRED, WebRtc_UWord8& payloadTypeFEC));
|
||||
MOCK_METHOD2(SetFECCodeRate,
|
||||
WebRtc_Word32(const WebRtc_UWord8 keyFrameCodeRate, const WebRtc_UWord8 deltaFrameCodeRate));
|
||||
MOCK_METHOD2(SetFECUepProtection,
|
||||
WebRtc_Word32(const bool keyUseUepProtection, const bool deltaUseUepProtection));
|
||||
MOCK_METHOD1(SetKeyFrameRequestMethod,
|
||||
WebRtc_Word32(const KeyFrameRequestMethod method));
|
||||
MOCK_METHOD1(RequestKeyFrame,
|
||||
WebRtc_Word32(const FrameType frameType));
|
||||
MOCK_METHOD1(SetH263InverseLogic,
|
||||
WebRtc_Word32(const bool enable));
|
||||
|
||||
MOCK_CONST_METHOD3(Version,
|
||||
int32_t(char* version, uint32_t& remaining_buffer_in_bytes, uint32_t& position));
|
||||
MOCK_METHOD0(TimeUntilNextProcess,
|
||||
int32_t());
|
||||
MOCK_METHOD0(Process,
|
||||
int32_t());
|
||||
|
||||
// Members.
|
||||
unsigned int remote_ssrc_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
@ -1311,11 +1311,14 @@ RTCPReceiver::TriggerCallbacksFromRTCPPacket(RTCPPacketInformation& rtcpPacketIn
|
||||
if(rtcpPacketInformation.reportBlock)
|
||||
{
|
||||
// We only want to trigger one OnNetworkChanged callback per RTCP
|
||||
// packet. The callback is triggered by a SR, RR and TMMBR, so we
|
||||
// don't want to trigger one from here if the packet also contains a
|
||||
// TMMBR block.
|
||||
bool triggerCallback =
|
||||
!(rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpTmmbr);
|
||||
// packet. The callback is triggered by a SR, RR, REMB or TMMBR, so
|
||||
// we don't want to trigger one from here if the packet also
|
||||
// contains a REMB or TMMBR block.
|
||||
bool triggerCallback = true;
|
||||
if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRemb ||
|
||||
rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpTmmbr) {
|
||||
triggerCallback = false;
|
||||
}
|
||||
_rtpRtcp.OnPacketLossStatisticsUpdate(
|
||||
rtcpPacketInformation.fractionLost,
|
||||
rtcpPacketInformation.roundTripTime,
|
||||
@ -1367,7 +1370,7 @@ RTCPReceiver::TriggerCallbacksFromRTCPPacket(RTCPPacketInformation& rtcpPacketIn
|
||||
}
|
||||
if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRemb)
|
||||
{
|
||||
// We need to bounce this to the default channel
|
||||
// We need to bounce this to the default channel.
|
||||
_rtpRtcp.OnReceivedEstimatedMaxBitrate(
|
||||
rtcpPacketInformation.receiverEstimatedMaxBitrate);
|
||||
}
|
||||
|
@ -266,9 +266,26 @@ RTCPSender::SetREMBData(const WebRtc_UWord32 bitrate,
|
||||
{
|
||||
_rembSSRC[i] = SSRC[i];
|
||||
}
|
||||
_sendREMB = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool RTCPSender::SetRemoteBitrateObserver(RtpRemoteBitrateObserver* observer) {
|
||||
CriticalSectionScoped lock(_criticalSectionRTCPSender);
|
||||
if (observer && _bitrate_observer) {
|
||||
return false;
|
||||
}
|
||||
_bitrate_observer = observer;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RTCPSender::UpdateRemoteBitrateEstimate(unsigned int target_bitrate) {
|
||||
CriticalSectionScoped lock(_criticalSectionRTCPSender);
|
||||
if (_bitrate_observer && _remoteSSRC != 0) {
|
||||
_bitrate_observer->OnReceiveBitrateChanged(_remoteSSRC, target_bitrate);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RTCPSender::TMMBR() const
|
||||
{
|
||||
@ -1719,8 +1736,9 @@ RTCPSender::SendRTCP(const WebRtc_UWord32 packetTypeFlags,
|
||||
}
|
||||
if(_REMB && _sendREMB)
|
||||
{
|
||||
// Always attach REMB to SR if that is configured. Note that REMB is
|
||||
// only sent on one of the RTP modules in the REMB group.
|
||||
rtcpPacketTypeFlags |= kRtcpRemb;
|
||||
_sendREMB = false;
|
||||
}
|
||||
if(_xrSendVoIPMetric)
|
||||
{
|
||||
|
@ -84,6 +84,11 @@ public:
|
||||
WebRtc_Word32 SetREMBData(const WebRtc_UWord32 bitrate,
|
||||
const WebRtc_UWord8 numberOfSSRC,
|
||||
const WebRtc_UWord32* SSRC);
|
||||
|
||||
bool SetRemoteBitrateObserver(RtpRemoteBitrateObserver* observer);
|
||||
|
||||
void UpdateRemoteBitrateEstimate(unsigned int target_bitrate);
|
||||
|
||||
/*
|
||||
* TMMBR
|
||||
*/
|
||||
@ -231,6 +236,7 @@ private:
|
||||
WebRtc_UWord8 _sizeRembSSRC;
|
||||
WebRtc_UWord32* _rembSSRC;
|
||||
WebRtc_UWord32 _rembBitrate;
|
||||
RtpRemoteBitrateObserver* _bitrate_observer;
|
||||
|
||||
TMMBRHelp _tmmbrHelp;
|
||||
WebRtc_UWord32 _tmmbr_Send;
|
||||
|
@ -84,6 +84,8 @@
|
||||
'video_codec_information.h',
|
||||
'rtp_format_vp8.cc',
|
||||
'rtp_format_vp8.h',
|
||||
# Mocks
|
||||
'../mocks/mock_rtp_rtcp.h',
|
||||
], # source
|
||||
},
|
||||
],
|
||||
|
@ -453,8 +453,12 @@ WebRtc_Word32 ModuleRtpRtcpImpl::Process()
|
||||
{
|
||||
WebRtc_UWord16 RTT = 0;
|
||||
_rtcpReceiver.RTT(_rtpReceiver.SSRC(), &RTT, NULL, NULL, NULL);
|
||||
if (TMMBR())
|
||||
if (REMB())
|
||||
{
|
||||
unsigned int target_bitrate =
|
||||
_rtcpSender.CalculateNewTargetBitrate(RTT);
|
||||
_rtcpSender.UpdateRemoteBitrateEstimate(target_bitrate);
|
||||
} else if (TMMBR()) {
|
||||
_rtcpSender.CalculateNewTargetBitrate(RTT);
|
||||
}
|
||||
_rtcpSender.SendRTCP(kRtcpReport, 0, 0, RTT);
|
||||
@ -1804,6 +1808,11 @@ WebRtc_Word32 ModuleRtpRtcpImpl::SetREMBData(const WebRtc_UWord32 bitrate,
|
||||
return _rtcpSender.SetREMBData(bitrate, numberOfSSRC, SSRC);
|
||||
}
|
||||
|
||||
bool ModuleRtpRtcpImpl::SetRemoteBitrateObserver(
|
||||
RtpRemoteBitrateObserver* observer) {
|
||||
return _rtcpSender.SetRemoteBitrateObserver(observer);
|
||||
}
|
||||
|
||||
/*
|
||||
* (IJ) Extended jitter report.
|
||||
*/
|
||||
@ -2573,14 +2582,19 @@ RateControlRegion ModuleRtpRtcpImpl::OnOverUseStateUpdate(
|
||||
RateControlRegion region = _rtcpSender.UpdateOverUseState(rateControlInput,
|
||||
firstOverUse);
|
||||
if (firstOverUse) {
|
||||
// Send TMMBR immediately
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -2637,6 +2651,8 @@ void ModuleRtpRtcpImpl::OnReceivedEstimatedMaxBitrate(
|
||||
&newBitrate,
|
||||
&fractionLost,
|
||||
&roundTripTime) == 0) {
|
||||
// TODO(mflodman) When encoding two streams, we need to split the bitrate
|
||||
// between REMB sending channels.
|
||||
// might trigger a OnNetworkChanged in video callback
|
||||
_rtpReceiver.UpdateBandwidthManagement(newBitrate,
|
||||
fractionLost,
|
||||
|
@ -336,6 +336,7 @@ public:
|
||||
const WebRtc_UWord8 numberOfSSRC,
|
||||
const WebRtc_UWord32* SSRC);
|
||||
|
||||
virtual bool SetRemoteBitrateObserver(RtpRemoteBitrateObserver* observer);
|
||||
/*
|
||||
* (IJ) Extended jitter report.
|
||||
*/
|
||||
|
@ -220,6 +220,12 @@ public:
|
||||
// RTCP, implemented based on RFC4585.
|
||||
virtual int SetTMMBRStatus(const int videoChannel, const bool enable) = 0;
|
||||
|
||||
// Enables and disables REMB packets for this channel. |sender| indicates
|
||||
// this channel is encoding, |receiver| tells the bitrate estimate for
|
||||
// this channel should be included in the REMB packet.
|
||||
virtual bool SetRembStatus(int video_channel, bool sender,
|
||||
bool receiver) = 0;
|
||||
|
||||
// The function gets statistics from the received RTCP report.
|
||||
virtual int GetReceivedRTCPStatistics(
|
||||
const int videoChannel, unsigned short& fractionLost,
|
||||
|
@ -204,7 +204,8 @@ int VideoEngineSampleCode(void* window1, void* window2)
|
||||
printf("ERROR in ViERTP_RTCP::SetKeyFrameRequestMethod\n");
|
||||
return -1;
|
||||
}
|
||||
error = ptrViERtpRtcp->SetTMMBRStatus(videoChannel, true);
|
||||
|
||||
error = ptrViERtpRtcp->SetRembStatus(videoChannel, true, true);
|
||||
if (error == -1)
|
||||
{
|
||||
printf("ERROR in ViERTP_RTCP::SetTMMBRStatus\n");
|
||||
|
@ -71,6 +71,7 @@
|
||||
'vie_impl.h',
|
||||
'vie_network_impl.h',
|
||||
'vie_ref_count.h',
|
||||
'vie_remb.h',
|
||||
'vie_render_impl.h',
|
||||
'vie_rtp_rtcp_impl.h',
|
||||
'vie_shared_data.h',
|
||||
@ -117,13 +118,38 @@
|
||||
'vie_manager_base.cc',
|
||||
'vie_performance_monitor.cc',
|
||||
'vie_receiver.cc',
|
||||
'vie_remb.cc',
|
||||
'vie_renderer.cc',
|
||||
'vie_render_manager.cc',
|
||||
'vie_sender.cc',
|
||||
'vie_sync_module.cc',
|
||||
], # source
|
||||
},
|
||||
], # targets
|
||||
'conditions': [
|
||||
['build_with_chromium==0', {
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'video_engine_core_unittests',
|
||||
'type': 'executable',
|
||||
'dependencies': [
|
||||
'video_engine_core',
|
||||
'<(webrtc_root)/../testing/gtest.gyp:gtest',
|
||||
'<(webrtc_root)/../testing/gmock.gyp:gmock',
|
||||
'<(webrtc_root)/../test/test.gyp:test_support_main',
|
||||
],
|
||||
'include_dirs': [
|
||||
'..',
|
||||
'../modules/interface',
|
||||
'../modules/rtp_rtcp/interface',
|
||||
],
|
||||
'sources': [
|
||||
'vie_remb_unittest.cc',
|
||||
],
|
||||
},
|
||||
], # targets
|
||||
}], # build_with_chromium
|
||||
], # conditions
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
|
@ -704,6 +704,14 @@ WebRtc_Word32 ViEChannel::SetKeyFrameRequestMethod(
|
||||
return rtp_rtcp_.SetKeyFrameRequestMethod(method);
|
||||
}
|
||||
|
||||
bool ViEChannel::EnableRemb(bool enable) {
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
|
||||
"ViEChannel::EnableRemb: %d", enable);
|
||||
if (rtp_rtcp_.SetREMBStatus(enable) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
WebRtc_Word32 ViEChannel::EnableTMMBR(const bool enable) {
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
|
||||
"%s: %d", __FUNCTION__, enable);
|
||||
@ -2076,6 +2084,11 @@ WebRtc_Word32 ViEChannel::DeregisterSendRtpRtcpModule() {
|
||||
return rtp_rtcp_.DeRegisterDefaultModule();
|
||||
}
|
||||
|
||||
RtpRtcp* ViEChannel::rtp_rtcp() {
|
||||
return &rtp_rtcp_;
|
||||
}
|
||||
|
||||
|
||||
WebRtc_Word32 ViEChannel::FrameToRender(VideoFrame& video_frame) {
|
||||
CriticalSectionScoped cs(callbackCritsect_);
|
||||
|
||||
|
@ -101,6 +101,7 @@ class ViEChannel
|
||||
const unsigned char payload_typeRED,
|
||||
const unsigned char payload_typeFEC);
|
||||
WebRtc_Word32 SetKeyFrameRequestMethod(const KeyFrameRequestMethod method);
|
||||
bool EnableRemb(bool enable);
|
||||
WebRtc_Word32 EnableTMMBR(const bool enable);
|
||||
WebRtc_Word32 EnableKeyFrameRequestCallback(const bool enable);
|
||||
|
||||
@ -289,6 +290,9 @@ class ViEChannel
|
||||
// the channel.
|
||||
WebRtc_Word32 DeregisterSendRtpRtcpModule();
|
||||
|
||||
// Gets the modules used by the channel.
|
||||
RtpRtcp* rtp_rtcp();
|
||||
|
||||
// Implements VCMReceiveCallback.
|
||||
virtual WebRtc_Word32 FrameToRender(VideoFrame& video_frame);
|
||||
|
||||
|
@ -11,12 +11,14 @@
|
||||
#include "video_engine/vie_channel_manager.h"
|
||||
|
||||
#include "engine_configurations.h"
|
||||
#include "modules/rtp_rtcp/interface/rtp_rtcp.h"
|
||||
#include "modules/utility/interface/process_thread.h"
|
||||
#include "system_wrappers/interface/critical_section_wrapper.h"
|
||||
#include "system_wrappers/interface/trace.h"
|
||||
#include "video_engine/vie_channel.h"
|
||||
#include "video_engine/vie_defines.h"
|
||||
#include "video_engine/vie_encoder.h"
|
||||
#include "video_engine/vie_remb.h"
|
||||
#include "voice_engine/main/interface/voe_video_sync.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -32,6 +34,7 @@ ViEChannelManager::ViEChannelManager(
|
||||
free_channel_ids_(new bool[kViEMaxNumberOfChannels]),
|
||||
free_channel_ids_size_(kViEMaxNumberOfChannels),
|
||||
voice_sync_interface_(NULL),
|
||||
remb_(new VieRemb(engine_id)),
|
||||
voice_engine_(NULL),
|
||||
module_process_thread_(NULL) {
|
||||
WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id),
|
||||
@ -46,6 +49,7 @@ ViEChannelManager::~ViEChannelManager() {
|
||||
WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id_),
|
||||
"ViEChannelManager Destructor, engine_id: %d", engine_id_);
|
||||
|
||||
module_process_thread_->DeRegisterModule(remb_.get());
|
||||
while (channel_map_.Size() != 0) {
|
||||
MapItem* item = channel_map_.First();
|
||||
const int channel_id = item->GetId();
|
||||
@ -71,6 +75,7 @@ void ViEChannelManager::SetModuleProcessThread(
|
||||
ProcessThread& module_process_thread) {
|
||||
assert(!module_process_thread_);
|
||||
module_process_thread_ = &module_process_thread;
|
||||
module_process_thread_->RegisterModule(remb_.get());
|
||||
}
|
||||
|
||||
int ViEChannelManager::CreateChannel(int& channel_id) {
|
||||
@ -348,6 +353,38 @@ VoiceEngine* ViEChannelManager::GetVoiceEngine() {
|
||||
return voice_engine_;
|
||||
}
|
||||
|
||||
bool ViEChannelManager::SetRembStatus(int channel_id, bool sender,
|
||||
bool receiver) {
|
||||
CriticalSectionScoped cs(*channel_id_critsect_);
|
||||
ViEChannel* channel = ViEChannelPtr(channel_id);
|
||||
if (!channel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sender || receiver) {
|
||||
if (!channel->EnableRemb(true)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
channel->EnableRemb(false);
|
||||
}
|
||||
RtpRtcp* rtp_module = channel->rtp_rtcp();
|
||||
// TODO(mflodman) Add when implemented.
|
||||
if (sender) {
|
||||
// remb_->AddSendChannel(rtp_module);
|
||||
} else {
|
||||
// remb_->RemoveSendChannel(rtp_module);
|
||||
}
|
||||
if (receiver) {
|
||||
remb_->AddReceiveChannel(rtp_module);
|
||||
rtp_module->SetRemoteBitrateObserver(remb_.get());
|
||||
} else {
|
||||
remb_->RemoveReceiveChannel(rtp_module);
|
||||
rtp_module->SetRemoteBitrateObserver(NULL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ViEChannel* ViEChannelManager::ViEChannelPtr(int channel_id) const {
|
||||
CriticalSectionScoped cs(*channel_id_critsect_);
|
||||
MapItem* map_item = channel_map_.Find(channel_id);
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "engine_configurations.h"
|
||||
#include "system_wrappers/interface/map_wrapper.h"
|
||||
#include "system_wrappers/interface/scoped_ptr.h"
|
||||
#include "typedefs.h"
|
||||
#include "video_engine/vie_defines.h"
|
||||
#include "video_engine/vie_manager_base.h"
|
||||
@ -24,6 +25,7 @@ class ProcessThread;
|
||||
class ViEChannel;
|
||||
class ViEEncoder;
|
||||
class ViEPerformanceMonitor;
|
||||
class VieRemb;
|
||||
class VoEVideoSync;
|
||||
class VoiceEngine;
|
||||
|
||||
@ -57,6 +59,9 @@ class ViEChannelManager: private ViEManagerBase {
|
||||
|
||||
VoiceEngine* GetVoiceEngine();
|
||||
|
||||
// Adds a channel to include when sending REMB.
|
||||
bool SetRembStatus(int channel_id, bool sender, bool receiver);
|
||||
|
||||
private:
|
||||
// Used by ViEChannelScoped, forcing a manager user to use scoped.
|
||||
// Returns a pointer to the channel with id 'channelId'.
|
||||
@ -92,6 +97,7 @@ class ViEChannelManager: private ViEManagerBase {
|
||||
// Maps Channel id -> ViEEncoder.
|
||||
MapWrapper vie_encoder_map_;
|
||||
VoEVideoSync* voice_sync_interface_;
|
||||
scoped_ptr<VieRemb> remb_;
|
||||
VoiceEngine* voice_engine_;
|
||||
ProcessThread* module_process_thread_;
|
||||
};
|
||||
|
173
src/video_engine/vie_remb.cc
Normal file
173
src/video_engine/vie_remb.cc
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "video_engine/vie_remb.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "modules/rtp_rtcp/interface/rtp_rtcp.h"
|
||||
#include "system_wrappers/interface/critical_section_wrapper.h"
|
||||
#include "system_wrappers/interface/tick_util.h"
|
||||
#include "system_wrappers/interface/trace.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
const int kRembSendIntervallMs = 1000;
|
||||
|
||||
// % threshold for if we should send a new REMB asap.
|
||||
const int kSendThresholdPercent = 97;
|
||||
|
||||
VieRemb::VieRemb(int engine_id)
|
||||
: engine_id_(engine_id),
|
||||
list_crit_(CriticalSectionWrapper::CreateCriticalSection()),
|
||||
last_remb_time_(TickTime::MillisecondTimestamp()),
|
||||
last_send_bitrate_(0) {
|
||||
}
|
||||
|
||||
VieRemb::~VieRemb() {
|
||||
}
|
||||
|
||||
void VieRemb::AddReceiveChannel(RtpRtcp* rtp_rtcp) {
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
|
||||
"VieRemb::AddReceiveChannel");
|
||||
assert(rtp_rtcp);
|
||||
|
||||
CriticalSectionScoped cs(list_crit_.get());
|
||||
for (RtpModules::iterator it = receive_modules_.begin();
|
||||
it != receive_modules_.end(); ++it) {
|
||||
if ((*it) == rtp_rtcp)
|
||||
return;
|
||||
}
|
||||
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVideo, engine_id_, "AddRembChannel");
|
||||
// The module probably doesn't have a remote SSRC yet, so don't add it to the
|
||||
// map.
|
||||
receive_modules_.push_back(rtp_rtcp);
|
||||
}
|
||||
|
||||
void VieRemb::RemoveReceiveChannel(RtpRtcp* rtp_rtcp) {
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
|
||||
"VieRemb::RemoveReceiveChannel");
|
||||
assert(rtp_rtcp);
|
||||
|
||||
CriticalSectionScoped cs(list_crit_.get());
|
||||
unsigned int ssrc = rtp_rtcp->RemoteSSRC();
|
||||
for (RtpModules::iterator it = receive_modules_.begin();
|
||||
it != receive_modules_.end(); ++it) {
|
||||
if ((*it)->RemoteSSRC() == ssrc) {
|
||||
receive_modules_.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
bitrates_.erase(ssrc);
|
||||
}
|
||||
|
||||
void VieRemb::AddSendChannel(RtpRtcp* rtp_rtcp) {
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
|
||||
"VieRemb::AddSendChannel");
|
||||
assert(rtp_rtcp);
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
void VieRemb::RemoveSendChannel(RtpRtcp* rtp_rtcp) {
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
|
||||
"VieRemb::AddSendChannel");
|
||||
assert(rtp_rtcp);
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
void VieRemb::OnReceiveBitrateChanged(unsigned int ssrc, unsigned int bitrate) {
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
|
||||
"VieRemb::UpdateBitrateEstimate(ssrc: %u, bitrate: %u)",
|
||||
ssrc, bitrate);
|
||||
CriticalSectionScoped cs(list_crit_.get());
|
||||
|
||||
// Check if this is a new ssrc and add it to the map if it is.
|
||||
if (bitrates_.find(ssrc) == bitrates_.end()) {
|
||||
bitrates_[ssrc] = bitrate;
|
||||
}
|
||||
|
||||
int new_remb_bitrate = last_send_bitrate_ - bitrates_[ssrc] + bitrate;
|
||||
if (new_remb_bitrate < kSendThresholdPercent * last_send_bitrate_ / 100) {
|
||||
// The new bitrate estimate is less than kSendThresholdPercent % of the last
|
||||
// report. Send a REMB asap.
|
||||
last_remb_time_ = TickTime::MillisecondTimestamp() - kRembSendIntervallMs;
|
||||
}
|
||||
bitrates_[ssrc] = bitrate;
|
||||
}
|
||||
|
||||
WebRtc_Word32 VieRemb::Version(WebRtc_Word8* version,
|
||||
WebRtc_UWord32& remaining_buffer_in_bytes,
|
||||
WebRtc_UWord32& position) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 VieRemb::ChangeUniqueId(const WebRtc_Word32 id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 VieRemb::TimeUntilNextProcess() {
|
||||
return kRembSendIntervallMs -
|
||||
(TickTime::MillisecondTimestamp() - last_remb_time_);
|
||||
}
|
||||
|
||||
WebRtc_Word32 VieRemb::Process() {
|
||||
int64_t now = TickTime::MillisecondTimestamp();
|
||||
if (now - last_remb_time_ < kRembSendIntervallMs)
|
||||
return 0;
|
||||
|
||||
last_remb_time_ = now;
|
||||
|
||||
// Calculate total receive bitrate estimate.
|
||||
list_crit_->Enter();
|
||||
int total_bitrate = 0;
|
||||
int num_bitrates = bitrates_.size();
|
||||
|
||||
if (num_bitrates == 0) {
|
||||
list_crit_->Leave();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO(mflodman) Use std::vector and change RTP module API.
|
||||
unsigned int* ssrcs = new unsigned int[num_bitrates];
|
||||
|
||||
int idx = 0;
|
||||
for (SsrcBitrate::iterator it = bitrates_.begin(); it != bitrates_.end();
|
||||
++it, ++idx) {
|
||||
total_bitrate += it->second;
|
||||
ssrcs[idx] = it->first;
|
||||
}
|
||||
|
||||
// Send a REMB packet.
|
||||
RtpRtcp* sender = NULL;
|
||||
if (!send_modules_.empty()) {
|
||||
sender = send_modules_.front();
|
||||
} else {
|
||||
for (RtpModules::iterator it = receive_modules_.begin();
|
||||
it != receive_modules_.end(); ++it) {
|
||||
if ((*it)->Sending()) {
|
||||
sender = *it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
last_send_bitrate_ = total_bitrate;
|
||||
list_crit_->Leave();
|
||||
|
||||
if (sender) {
|
||||
sender->SetREMBData(total_bitrate, num_bitrates, ssrcs);
|
||||
}
|
||||
delete [] ssrcs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
88
src/video_engine/vie_remb.h
Normal file
88
src/video_engine/vie_remb.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// 1. Register a RtpRtcp module to include in the REMB packet.
|
||||
// 2. When UpdateBitrateEstimate is called for the first time for a SSRC, add it
|
||||
// to the map.
|
||||
// 3. Send a new REMB every kRembSendIntervallMs or if a lower bitrate estimate
|
||||
// for a specified SSRC.
|
||||
|
||||
|
||||
#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_REMB_H_
|
||||
#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_REMB_H_
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include "modules/interface/module.h"
|
||||
#include "modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
|
||||
#include "system_wrappers/interface/scoped_ptr.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class CriticalSectionWrapper;
|
||||
class RtpRtcp;
|
||||
|
||||
class VieRemb : public RtpRemoteBitrateObserver, public Module {
|
||||
public:
|
||||
explicit VieRemb(int engine_id);
|
||||
~VieRemb();
|
||||
|
||||
// Called to add a receive channel to include in the REMB packet.
|
||||
void AddReceiveChannel(RtpRtcp* rtp_rtcp);
|
||||
|
||||
// Removes the specified channel from REMB estimate.
|
||||
void RemoveReceiveChannel(RtpRtcp* rtp_rtcp);
|
||||
|
||||
// Called to add a send channel to include in the REMB packet.
|
||||
void AddSendChannel(RtpRtcp* rtp_rtcp);
|
||||
|
||||
// Removes the specified channel from receiving REMB packet estimates.
|
||||
void RemoveSendChannel(RtpRtcp* rtp_rtcp);
|
||||
|
||||
// Called every time there is a new bitrate estimate for the received stream
|
||||
// with given SSRC. This call will trigger a new RTCP REMB packet if the
|
||||
// bitrate estimate has decreased or if no RTCP REMB packet has been sent for
|
||||
// a certain time interval.
|
||||
// Implements RtpReceiveBitrateUpdate.
|
||||
virtual void OnReceiveBitrateChanged(unsigned int ssrc, unsigned int bitrate);
|
||||
|
||||
// Implements Module.
|
||||
virtual WebRtc_Word32 Version(WebRtc_Word8* version,
|
||||
WebRtc_UWord32& remaining_buffer_in_bytes,
|
||||
WebRtc_UWord32& position) const;
|
||||
virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id);
|
||||
virtual WebRtc_Word32 TimeUntilNextProcess();
|
||||
virtual WebRtc_Word32 Process();
|
||||
|
||||
private:
|
||||
typedef std::list<RtpRtcp*> RtpModules;
|
||||
typedef std::map<unsigned int, unsigned int> SsrcBitrate;
|
||||
|
||||
int engine_id_;
|
||||
scoped_ptr<CriticalSectionWrapper> list_crit_;
|
||||
|
||||
// The last time a REMB was sent.
|
||||
int64_t last_remb_time_;
|
||||
int last_send_bitrate_;
|
||||
|
||||
// All RtpRtcp modules to include in the REMB packet.
|
||||
RtpModules receive_modules_;
|
||||
|
||||
// All modules encoding and sending data.
|
||||
RtpModules send_modules_;
|
||||
|
||||
// The last bitrate update for each SSRC.
|
||||
SsrcBitrate bitrates_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_REMB_H_
|
294
src/video_engine/vie_remb_unittest.cc
Normal file
294
src/video_engine/vie_remb_unittest.cc
Normal file
@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.8
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
// This file includes unit tests for ViERemb.
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "modules/rtp_rtcp/interface/rtp_rtcp.h"
|
||||
#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
|
||||
#include "system_wrappers/interface/scoped_ptr.h"
|
||||
#include "video_engine/vie_remb.h"
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::AnyNumber;
|
||||
using ::testing::Return;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class ViERembTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
vie_remb_.reset(new VieRemb(1234));
|
||||
}
|
||||
scoped_ptr<VieRemb> vie_remb_;
|
||||
};
|
||||
|
||||
TEST_F(ViERembTest, OneModuleTestForSendingRemb)
|
||||
{
|
||||
MockRtpRtcp rtp;
|
||||
EXPECT_CALL(rtp, Sending())
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
vie_remb_->AddReceiveChannel(&rtp);
|
||||
|
||||
const unsigned int bitrate_estimate = 456;
|
||||
unsigned int ssrc[] = { 1234 };
|
||||
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate);
|
||||
EXPECT_CALL(rtp, RemoteSSRC())
|
||||
.WillRepeatedly(Return(ssrc[0]));
|
||||
|
||||
// TODO(mflodman) Add fake clock and remove the lowered bitrate below.
|
||||
usleep(1010000);
|
||||
EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
|
||||
.Times(1);
|
||||
vie_remb_->Process();
|
||||
|
||||
// Lower bitrate to send another REMB packet.
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate - 100);
|
||||
EXPECT_CALL(rtp, SetREMBData(bitrate_estimate - 100, 1, _))
|
||||
.Times(1);
|
||||
vie_remb_->Process();
|
||||
|
||||
vie_remb_->RemoveReceiveChannel(&rtp);
|
||||
}
|
||||
|
||||
TEST_F(ViERembTest, LowerEstimateToSendRemb)
|
||||
{
|
||||
MockRtpRtcp rtp;
|
||||
EXPECT_CALL(rtp, Sending())
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
vie_remb_->AddReceiveChannel(&rtp);
|
||||
|
||||
unsigned int bitrate_estimate = 456;
|
||||
unsigned int ssrc[] = { 1234 };
|
||||
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate);
|
||||
EXPECT_CALL(rtp, RemoteSSRC())
|
||||
.WillRepeatedly(Return(ssrc[0]));
|
||||
|
||||
// Lower the estimate with more than 3% to trigger a call to SetREMBData right
|
||||
// away.
|
||||
bitrate_estimate = bitrate_estimate - 100;
|
||||
EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
|
||||
.Times(1);
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate);
|
||||
vie_remb_->Process();
|
||||
}
|
||||
|
||||
TEST_F(ViERembTest, VerifyCombinedBitrateEstimate)
|
||||
{
|
||||
MockRtpRtcp rtp_0;
|
||||
EXPECT_CALL(rtp_0, Sending())
|
||||
.WillRepeatedly(Return(true));
|
||||
MockRtpRtcp rtp_1;
|
||||
EXPECT_CALL(rtp_1, Sending())
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
vie_remb_->AddReceiveChannel(&rtp_0);
|
||||
vie_remb_->AddReceiveChannel(&rtp_1);
|
||||
|
||||
unsigned int bitrate_estimate[] = { 456, 789 };
|
||||
unsigned int ssrc[] = { 1234, 5678 };
|
||||
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate[0]);
|
||||
EXPECT_CALL(rtp_0, RemoteSSRC())
|
||||
.Times(AnyNumber())
|
||||
.WillRepeatedly(Return(ssrc[0]));
|
||||
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[1], bitrate_estimate[1] + 100);
|
||||
EXPECT_CALL(rtp_1, RemoteSSRC())
|
||||
.Times(AnyNumber())
|
||||
.WillRepeatedly(Return(ssrc[1]));
|
||||
|
||||
// Lower the estimate to trigger a callback.
|
||||
int total_bitrate = bitrate_estimate[0] + bitrate_estimate[1];
|
||||
EXPECT_CALL(rtp_0, SetREMBData(total_bitrate, 2, _))
|
||||
.Times(1);
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[1], bitrate_estimate[1]);
|
||||
vie_remb_->Process();
|
||||
|
||||
vie_remb_->RemoveReceiveChannel(&rtp_0);
|
||||
vie_remb_->RemoveReceiveChannel(&rtp_1);
|
||||
}
|
||||
|
||||
TEST_F(ViERembTest, NoRembForIncreasedBitrate)
|
||||
{
|
||||
MockRtpRtcp rtp_0;
|
||||
EXPECT_CALL(rtp_0, Sending())
|
||||
.WillRepeatedly(Return(true));
|
||||
MockRtpRtcp rtp_1;
|
||||
EXPECT_CALL(rtp_1, Sending())
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
vie_remb_->AddReceiveChannel(&rtp_0);
|
||||
vie_remb_->AddReceiveChannel(&rtp_1);
|
||||
|
||||
unsigned int bitrate_estimate[] = { 456, 789 };
|
||||
unsigned int ssrc[] = { 1234, 5678 };
|
||||
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate[0]);
|
||||
EXPECT_CALL(rtp_0, RemoteSSRC())
|
||||
.Times(AnyNumber())
|
||||
.WillRepeatedly(Return(ssrc[0]));
|
||||
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[1], bitrate_estimate[1]);
|
||||
EXPECT_CALL(rtp_1, RemoteSSRC())
|
||||
.Times(AnyNumber())
|
||||
.WillRepeatedly(Return(ssrc[1]));
|
||||
|
||||
// Trigger a first call to have a running state.
|
||||
// TODO(mflodman) Add fake clock.
|
||||
usleep(1010000);
|
||||
EXPECT_CALL(rtp_0,
|
||||
SetREMBData(bitrate_estimate[0] + bitrate_estimate[1], 2, _))
|
||||
.Times(1);
|
||||
vie_remb_->Process();
|
||||
|
||||
// Increased estimate shouldn't trigger a callback right away.
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate[0] + 1);
|
||||
EXPECT_CALL(rtp_0, SetREMBData(_, _, _))
|
||||
.Times(0);
|
||||
|
||||
// Decresing the estimate less than 3% shouldn't trigger a new callback.
|
||||
int lower_estimate = bitrate_estimate[0] * 98 / 100;
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[0], lower_estimate);
|
||||
EXPECT_CALL(rtp_0, SetREMBData(_, _, _))
|
||||
.Times(0);
|
||||
|
||||
vie_remb_->Process();
|
||||
vie_remb_->RemoveReceiveChannel(&rtp_1);
|
||||
vie_remb_->RemoveReceiveChannel(&rtp_0);
|
||||
}
|
||||
|
||||
TEST_F(ViERembTest, ChangeSendRtpModule)
|
||||
{
|
||||
MockRtpRtcp rtp_0;
|
||||
EXPECT_CALL(rtp_0, Sending())
|
||||
.WillRepeatedly(Return(true));
|
||||
MockRtpRtcp rtp_1;
|
||||
EXPECT_CALL(rtp_1, Sending())
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
vie_remb_->AddReceiveChannel(&rtp_0);
|
||||
vie_remb_->AddReceiveChannel(&rtp_1);
|
||||
|
||||
unsigned int bitrate_estimate[] = { 456, 789 };
|
||||
unsigned int ssrc[] = { 1234, 5678 };
|
||||
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate[0]);
|
||||
EXPECT_CALL(rtp_0, RemoteSSRC())
|
||||
.Times(AnyNumber())
|
||||
.WillRepeatedly(Return(ssrc[0]));
|
||||
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[1], bitrate_estimate[1]);
|
||||
EXPECT_CALL(rtp_1, RemoteSSRC())
|
||||
.Times(AnyNumber())
|
||||
.WillRepeatedly(Return(ssrc[1]));
|
||||
|
||||
// Decrease estimate to trigger a REMB.
|
||||
bitrate_estimate[0] = bitrate_estimate[0] - 100;
|
||||
EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate[0] + bitrate_estimate[1], 2,
|
||||
_))
|
||||
.Times(1);
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate[0]);
|
||||
vie_remb_->Process();
|
||||
|
||||
// Remove the sending module, add it again -> should get remb on the second
|
||||
// module.
|
||||
vie_remb_->RemoveReceiveChannel(&rtp_0);
|
||||
vie_remb_->AddReceiveChannel(&rtp_0);
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate[0]);
|
||||
|
||||
bitrate_estimate[1] = bitrate_estimate[1] - 100;
|
||||
EXPECT_CALL(rtp_1, SetREMBData(bitrate_estimate[0] + bitrate_estimate[1], 2,
|
||||
_))
|
||||
.Times(1);
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[1], bitrate_estimate[1]);
|
||||
vie_remb_->Process();
|
||||
|
||||
vie_remb_->RemoveReceiveChannel(&rtp_0);
|
||||
vie_remb_->RemoveReceiveChannel(&rtp_1);
|
||||
}
|
||||
|
||||
TEST_F(ViERembTest, OnlyOneRembForDoubleProcess)
|
||||
{
|
||||
MockRtpRtcp rtp;
|
||||
EXPECT_CALL(rtp, Sending())
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
unsigned int bitrate_estimate = 456;
|
||||
unsigned int ssrc[] = { 1234 };
|
||||
|
||||
vie_remb_->AddReceiveChannel(&rtp);
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate);
|
||||
EXPECT_CALL(rtp, RemoteSSRC())
|
||||
.WillRepeatedly(Return(ssrc[0]));
|
||||
|
||||
// Lower the estimate, should trigger a call to SetREMBData right away.
|
||||
bitrate_estimate = bitrate_estimate - 100;
|
||||
EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
|
||||
.Times(1);
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate);
|
||||
vie_remb_->Process();
|
||||
|
||||
// Call Process again, this should not trigger a new callback.
|
||||
EXPECT_CALL(rtp, SetREMBData(_, _, _))
|
||||
.Times(0);
|
||||
vie_remb_->Process();
|
||||
vie_remb_->RemoveReceiveChannel(&rtp);
|
||||
}
|
||||
|
||||
TEST_F(ViERembTest, NoOnReceivedBitrateChangedCall)
|
||||
{
|
||||
MockRtpRtcp rtp;
|
||||
EXPECT_CALL(rtp, RemoteSSRC())
|
||||
.WillRepeatedly(Return(1234));
|
||||
|
||||
vie_remb_->AddReceiveChannel(&rtp);
|
||||
// TODO(mflodman) Add fake clock.
|
||||
usleep(1010000);
|
||||
// No bitrate estimate given, no callback expected.
|
||||
EXPECT_CALL(rtp, SetREMBData(_, _, _))
|
||||
.Times(0);
|
||||
vie_remb_->Process();
|
||||
|
||||
vie_remb_->RemoveReceiveChannel(&rtp);
|
||||
}
|
||||
|
||||
TEST_F(ViERembTest, NoSendingRtpModule)
|
||||
{
|
||||
MockRtpRtcp rtp;
|
||||
EXPECT_CALL(rtp, Sending())
|
||||
.WillRepeatedly(Return(false));
|
||||
|
||||
vie_remb_->AddReceiveChannel(&rtp);
|
||||
|
||||
unsigned int bitrate_estimate = 456;
|
||||
unsigned int ssrc[] = { 1234 };
|
||||
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate);
|
||||
EXPECT_CALL(rtp, RemoteSSRC())
|
||||
.WillRepeatedly(Return(ssrc[0]));
|
||||
|
||||
// Lower the estimate. This should normally trigger a callback, but not now
|
||||
// since we have no sending module.
|
||||
bitrate_estimate = bitrate_estimate - 100;
|
||||
EXPECT_CALL(rtp, SetREMBData(_, _, _))
|
||||
.Times(0);
|
||||
vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate);
|
||||
vie_remb_->Process();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
@ -541,6 +541,14 @@ int ViERTP_RTCPImpl::SetTMMBRStatus(const int video_channel,
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ViERTP_RTCPImpl::SetRembStatus(int video_channel, bool sender,
|
||||
bool receiver) {
|
||||
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(instance_id_, video_channel),
|
||||
"ViERTP_RTCPImpl::SetRembStatus(%d, %d, %d)", video_channel,
|
||||
sender, receiver);
|
||||
return channel_manager_.SetRembStatus(video_channel, sender, receiver);
|
||||
}
|
||||
|
||||
int ViERTP_RTCPImpl::GetReceivedRTCPStatistics(const int video_channel,
|
||||
unsigned short& fraction_lost,
|
||||
unsigned int& cumulative_lost,
|
||||
|
@ -65,6 +65,7 @@ class ViERTP_RTCPImpl
|
||||
virtual int SetKeyFrameRequestMethod(const int video_channel,
|
||||
const ViEKeyFrameRequestMethod method);
|
||||
virtual int SetTMMBRStatus(const int video_channel, const bool enable);
|
||||
virtual bool SetRembStatus(int video_channel, bool sender, bool receiver);
|
||||
virtual int GetReceivedRTCPStatistics(const int video_channel,
|
||||
unsigned short& fraction_lost,
|
||||
unsigned int& cumulative_lost,
|
||||
|
Loading…
Reference in New Issue
Block a user