174 lines
7.3 KiB
C
174 lines
7.3 KiB
C
|
/*
|
||
|
*
|
||
|
* @APPLE_LICENSE_HEADER_START@
|
||
|
*
|
||
|
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
|
||
|
*
|
||
|
* This file contains Original Code and/or Modifications of Original Code
|
||
|
* as defined in and that are subject to the Apple Public Source License
|
||
|
* Version 2.0 (the 'License'). You may not use this file except in
|
||
|
* compliance with the License. Please obtain a copy of the License at
|
||
|
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||
|
* file.
|
||
|
*
|
||
|
* The Original Code and all software distributed under the License are
|
||
|
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||
|
* Please see the License for the specific language governing rights and
|
||
|
* limitations under the License.
|
||
|
*
|
||
|
* @APPLE_LICENSE_HEADER_END@
|
||
|
*
|
||
|
*/
|
||
|
/*
|
||
|
File: RTPBandwidthTracker.h
|
||
|
|
||
|
Contains: Uses Karns Algorithm to measure round trip times. This also
|
||
|
tracks the current window size based on input from the caller.
|
||
|
|
||
|
ref:
|
||
|
|
||
|
Improving Round-Trip Time Estimates in Reliable Transport Protocols, ACM SIGCOMM, ???
|
||
|
|
||
|
Congestion Avoidance and Control - Van Jacobson, November 1988 -- Preoceedings of SIGCOMM '88
|
||
|
|
||
|
Internetworking with TCP/IP Comer and Stevens, Chap 14, prentice hall 1991
|
||
|
*/
|
||
|
|
||
|
#ifndef __RTP_BANDWIDTH_TRACKER_H__
|
||
|
#define __RTP_BANDWIDTH_TRACKER_H__
|
||
|
|
||
|
#include "OSHeaders.h"
|
||
|
|
||
|
class RTPBandwidthTracker
|
||
|
{
|
||
|
public:
|
||
|
RTPBandwidthTracker(Bool16 inUseSlowStart)
|
||
|
: fRunningAverageMSecs(0),
|
||
|
fRunningMeanDevationMSecs(0),
|
||
|
fCurRetransmitTimeout( kMinRetransmitIntervalMSecs ),
|
||
|
fUnadjustedRTO( kMinRetransmitIntervalMSecs ),
|
||
|
fCongestionWindow(kMaximumSegmentSize),
|
||
|
fSlowStartThreshold(0),
|
||
|
fSlowStartByteCount(0),
|
||
|
fClientWindow(0),
|
||
|
fBytesInList(0),
|
||
|
fAckTimeout(kMinAckTimeout),
|
||
|
fUseSlowStart(inUseSlowStart),
|
||
|
fMaxCongestionWindowSize(0),
|
||
|
fMinCongestionWindowSize(1000000),
|
||
|
fMaxRTO(0),
|
||
|
fMinRTO(24000),
|
||
|
fTotalCongestionWindowSize(0),
|
||
|
fTotalRTO(0),
|
||
|
fNumStatsSamples(0)
|
||
|
{}
|
||
|
|
||
|
~RTPBandwidthTracker() {}
|
||
|
|
||
|
//
|
||
|
// Initialization - give the client's window size.
|
||
|
void SetWindowSize(SInt32 clientWindowSize);
|
||
|
|
||
|
//
|
||
|
// Each RTT sample you get, let the tracker know what it is
|
||
|
// so it can keep a good running average.
|
||
|
void AddToRTTEstimate( SInt32 rttSampleMSecs );
|
||
|
|
||
|
//
|
||
|
// Before sending new data, let the tracker know
|
||
|
// how much data you are sending so it can adjust the window.
|
||
|
void FillWindow(UInt32 inNumBytes)
|
||
|
{ fBytesInList += inNumBytes; fIsRetransmitting = false; }
|
||
|
|
||
|
//
|
||
|
// When data is acked, let the tracker know how much
|
||
|
// data was acked so it can adjust the window
|
||
|
void EmptyWindow(UInt32 inNumBytes, Bool16 updateBytesInList = true);
|
||
|
|
||
|
//
|
||
|
// When retransmitting a packet, call this function so
|
||
|
// the tracker can adjust the window sizes and back off.
|
||
|
void AdjustWindowForRetransmit();
|
||
|
|
||
|
//
|
||
|
// ACCESSORS
|
||
|
const Bool16 ReadyForAckProcessing() { return (fClientWindow > 0 && fCongestionWindow > 0); } // see RTPBandwidthTracker::EmptyWindow for requirements
|
||
|
const Bool16 IsFlowControlled() { return ( (SInt32)fBytesInList >= fCongestionWindow ); }
|
||
|
const SInt32 ClientWindowSize() { return fClientWindow; }
|
||
|
const UInt32 BytesInList() { return fBytesInList; }
|
||
|
const SInt32 CongestionWindow() { return fCongestionWindow; }
|
||
|
const SInt32 SlowStartThreshold() { return fSlowStartThreshold; }
|
||
|
const SInt32 RunningAverageMSecs() { return fRunningAverageMSecs / 8; } // fRunningAverageMSecs is stored scaled up 8x
|
||
|
const SInt32 RunningMeanDevationMSecs() { return fRunningMeanDevationMSecs/ 4; } // fRunningMeanDevationMSecs is stored scaled up 4x
|
||
|
const SInt32 CurRetransmitTimeout() { return fCurRetransmitTimeout; }
|
||
|
const SInt32 GetCurrentBandwidthInBps()
|
||
|
{ return (fUnadjustedRTO > 0) ? (fCongestionWindow * 1000) / fUnadjustedRTO : 0; }
|
||
|
inline const UInt32 RecommendedClientAckTimeout() { return fAckTimeout; }
|
||
|
void UpdateAckTimeout(UInt32 bitsSentInInterval, SInt64 intervalLengthInMsec);
|
||
|
void UpdateStats();
|
||
|
|
||
|
//
|
||
|
// Stats
|
||
|
SInt32 GetMaxCongestionWindowSize() { return fMaxCongestionWindowSize; }
|
||
|
SInt32 GetMinCongestionWindowSize() { return fMinCongestionWindowSize; }
|
||
|
SInt32 GetAvgCongestionWindowSize() { return (SInt32)(fTotalCongestionWindowSize / (SInt64)fNumStatsSamples); }
|
||
|
SInt32 GetMaxRTO() { return fMaxRTO; }
|
||
|
SInt32 GetMinRTO() { return fMinRTO; }
|
||
|
SInt32 GetAvgRTO() { return (SInt32)(fTotalRTO / (SInt64)fNumStatsSamples); }
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
kMaximumSegmentSize = 1466, // enet - just a guess!
|
||
|
|
||
|
//
|
||
|
// Our algorithm for telling the client what the ack timeout
|
||
|
// is currently not too sophisticated. This could probably be made
|
||
|
// better. During slow start, we just use 20, and afterwards, just use 100
|
||
|
kMinAckTimeout = 20,
|
||
|
kMaxAckTimeout = 100
|
||
|
};
|
||
|
|
||
|
private:
|
||
|
|
||
|
//
|
||
|
// For computing the round-trip estimate using Karn's algorithm
|
||
|
SInt32 fRunningAverageMSecs;
|
||
|
SInt32 fRunningMeanDevationMSecs;
|
||
|
SInt32 fCurRetransmitTimeout;
|
||
|
SInt32 fUnadjustedRTO;
|
||
|
|
||
|
//
|
||
|
// Tracking our window sizes
|
||
|
SInt64 fLastCongestionAdjust;
|
||
|
SInt32 fCongestionWindow; // implentation of VJ congestion avoidance
|
||
|
SInt32 fSlowStartThreshold; // point at which we stop adding to the window for each ack, and add to the window for each window full of acks
|
||
|
SInt32 fSlowStartByteCount; // counts window a full of acks when past ss thresh
|
||
|
SInt32 fClientWindow; // max window size based on client UDP buffer
|
||
|
UInt32 fBytesInList; // how many unacked bytes on this stream
|
||
|
UInt32 fAckTimeout;
|
||
|
|
||
|
Bool16 fUseSlowStart;
|
||
|
Bool16 fIsRetransmitting; // are we in the re-transmit 'state' ( started resending, but have yet to send 'new' data
|
||
|
|
||
|
//
|
||
|
// Stats
|
||
|
SInt32 fMaxCongestionWindowSize;
|
||
|
SInt32 fMinCongestionWindowSize;
|
||
|
SInt32 fMaxRTO;
|
||
|
SInt32 fMinRTO;
|
||
|
SInt64 fTotalCongestionWindowSize;
|
||
|
SInt64 fTotalRTO;
|
||
|
SInt32 fNumStatsSamples;
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
kMinRetransmitIntervalMSecs = 600,
|
||
|
kMaxRetransmitIntervalMSecs = 24000
|
||
|
};
|
||
|
};
|
||
|
|
||
|
#endif // __RTP_BANDWIDTH_TRACKER_H__
|