Darwin-Streaming-Server/Server.tproj/RTPBandwidthTracker.cpp
Darren VanBuren 849723c9cf Add even more of the source
This should be about everything needed to build so far?
2017-03-07 17:14:16 -08:00

258 lines
9.1 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.cpp
Contains: Implementation of class decribed in .h file
*/
#include "RTPBandwidthTracker.h"
#include "MyAssert.h"
#include "OS.h"
void RTPBandwidthTracker::SetWindowSize( SInt32 clientWindowSize )
{
//
// Currently we only allow this info to be set once
if (fClientWindow > 0)
return;
// call SetWindowSize once the clients buffer size is known
// since this occurs before the stream starts to send
fClientWindow = clientWindowSize;
fLastCongestionAdjust = 0;
#if RTP_PACKET_RESENDER_DEBUGGING
//€ test to see what happens w/o slow start at beginning
//if ( initSlowStart )
// qtss_printf( "ack list initializing with slow start.\n" );
//else
// qtss_printf( "ack list initializing at full speed.\n" );
#endif
if ( fUseSlowStart )
{
fSlowStartThreshold = clientWindowSize * 3 / 4;
//
// This is a change to the standard TCP slow start algorithm. What
// we found was that on high bitrate high latency networks (a DSL connection, perhaps),
// it took just too long for the ACKs to come in and for the window size to
// grow enough. So we cheat a bit.
fCongestionWindow = clientWindowSize / 2;
//fCongestionWindow = kMaximumSegmentSize;
}
else
{
fSlowStartThreshold = clientWindowSize;
fCongestionWindow = clientWindowSize;
}
if ( fSlowStartThreshold < kMaximumSegmentSize )
fSlowStartThreshold = kMaximumSegmentSize;
}
void RTPBandwidthTracker::EmptyWindow( UInt32 bytesIncreased, Bool16 updateBytesInList )
{
if (bytesIncreased == 0)
return;
Assert(fClientWindow > 0 && fCongestionWindow > 0);
if(fBytesInList < bytesIncreased)
bytesIncreased = fBytesInList;
if (updateBytesInList)
fBytesInList -= bytesIncreased;
// this assert hits
Assert(fBytesInList < ((UInt32)fClientWindow + 2000)); //mainly just to catch fBytesInList wrapping below 0
// update the congestion window by the number of bytes just acknowledged.
if ( fCongestionWindow >= fSlowStartThreshold )
{
// when we hit the slow start threshold, only increase the
// window for each window full of acks.
fCongestionWindow += bytesIncreased * bytesIncreased / fCongestionWindow;
}
else
//
// This is a change to the standard TCP slow start algorithm. What
// we found was that on high bitrate high latency networks (a DSL connection, perhaps),
// it took just too long for the ACKs to come in and for the window size to
// grow enough. So we cheat a bit.
fCongestionWindow += bytesIncreased;
if ( fCongestionWindow > fClientWindow )
fCongestionWindow = fClientWindow;
// qtss_printf("Window = %d, %d left\n", fCongestionWindow, fCongestionWindow-fBytesInList);
}
void RTPBandwidthTracker::AdjustWindowForRetransmit()
{
// this assert hits
Assert(fBytesInList < ((UInt32)fClientWindow + 2000)); //mainly just to catch fBytesInList wrapping below 0
// slow start says that we should reduce the new ss threshold to 1/2
// of where started getting errors ( the current congestion window size )
// so, we get a burst of re-tx becuase our RTO was mis-estimated
// it doesn't seem like we should lower the threshold for each one.
// it seems like we should just lower it when we first enter
// the re-transmit "state"
// if ( !fIsRetransmitting )
// fSlowStartThreshold = fCongestionWindow/2;
// make sure that it is at least 1 packet
if ( fSlowStartThreshold < kMaximumSegmentSize )
fSlowStartThreshold = kMaximumSegmentSize;
// start the full window segemnt counter over again.
fSlowStartByteCount = 0;
// tcp resets to one (max segment size) mss, but i'm experimenting a bit
// with not being so brutal.
//curAckList->fCongestionWindow = kMaximumSegmentSize;
// fCongestionWindow = kMaximumSegmentSize;
// fCongestionWindow = fCongestionWindow / 2; // half the congestion window size
SInt64 theTime = OS::Milliseconds();
if (theTime - fLastCongestionAdjust > 250)
{
fSlowStartThreshold = fCongestionWindow * 3 / 4;
fCongestionWindow = fCongestionWindow / 2;
fLastCongestionAdjust = theTime;
}
/*
if ( fSlowStartThreshold < fCongestionWindow )
fCongestionWindow = fSlowStartThreshold/2;
else
fCongestionWindow = fCongestionWindow /2;
*/
if ( fCongestionWindow < kMaximumSegmentSize )
fCongestionWindow = kMaximumSegmentSize;
// qtss_printf("Congestion window now %d\n", fCongestionWindow);
fIsRetransmitting = true;
}
void RTPBandwidthTracker::AddToRTTEstimate( SInt32 rttSampleMSecs )
{
// qtss_printf("%d ", rttSampleMSecs);
// static int count = 0;
// if ((count++ % 10) == 0) qtss_printf("\n");
// this assert hits
Assert(fBytesInList < ((UInt32)fClientWindow + 2000)); //mainly just to catch fBytesInList wrapping below 0
if ( fRunningAverageMSecs == 0 )
fRunningAverageMSecs = rttSampleMSecs * 8; // init avg to cur sample, scaled by 2**3
SInt32 delta = rttSampleMSecs - fRunningAverageMSecs / 8; // scale average back to get cur delta from sample
// add 1/8 the delta back to the smooth running average
fRunningAverageMSecs = fRunningAverageMSecs + delta; // same as: rt avg = rt avg + delta / 8, but scaled
if ( delta < 0 )
delta = -1*delta; // absolute value
/*
fRunningMeanDevationMSecs is kept scaled by 4
so this is the same as
fRunningMeanDevationMSecs = fRunningMeanDevationMSecs + ( |delta| - fRunningMeanDevationMSecs ) /4;
*/
fRunningMeanDevationMSecs += delta - fRunningMeanDevationMSecs / 4;
fUnadjustedRTO = fCurRetransmitTimeout = fRunningAverageMSecs / 8 + fRunningMeanDevationMSecs;
// rto should not be too low..
if ( fCurRetransmitTimeout < kMinRetransmitIntervalMSecs )
fCurRetransmitTimeout = kMinRetransmitIntervalMSecs;
// or too high...
if ( fCurRetransmitTimeout > kMaxRetransmitIntervalMSecs )
fCurRetransmitTimeout = kMaxRetransmitIntervalMSecs;
// qtss_printf("CurTimeout == %d\n", fCurRetransmitTimeout);
}
void RTPBandwidthTracker::UpdateStats()
{
fNumStatsSamples++;
if (fMaxCongestionWindowSize < fCongestionWindow)
fMaxCongestionWindowSize = fCongestionWindow;
if (fMinCongestionWindowSize > fCongestionWindow)
fMinCongestionWindowSize = fCongestionWindow;
if (fMaxRTO < fUnadjustedRTO)
fMaxRTO = fUnadjustedRTO;
if (fMinRTO > fUnadjustedRTO)
fMinRTO = fUnadjustedRTO;
fTotalCongestionWindowSize += fCongestionWindow;
fTotalRTO += fUnadjustedRTO;
}
void RTPBandwidthTracker::UpdateAckTimeout(UInt32 bitsSentInInterval, SInt64 intervalLengthInMsec)
{
//
// First figure out how long it will take us to fill up our window, based on
// the movie's current bit rate
UInt32 unadjustedTimeout = 0;
if (bitsSentInInterval > 0)
unadjustedTimeout = (UInt32) ((intervalLengthInMsec * fCongestionWindow) / bitsSentInInterval);
//
// If we wait that long, that's too long because we need to actually wait for the ack to arrive.
// So, subtract 1/2 the rto - the last ack timeout
UInt32 rto = (UInt32)fUnadjustedRTO;
if (rto < fAckTimeout)
rto = fAckTimeout;
UInt32 adjustment = (rto - fAckTimeout) / 2;
//qtss_printf("UnadjustedTimeout = %"_U32BITARG_". rto: %"_S32BITARG_". Last ack timeout: %"_U32BITARG_". Adjustment = %"_U32BITARG_".", unadjustedTimeout, fUnadjustedRTO, fAckTimeout, adjustment);
if (adjustment > unadjustedTimeout)
adjustment = unadjustedTimeout;
fAckTimeout = unadjustedTimeout - adjustment;
//qtss_printf("AckTimeout: %"_U32BITARG_"\n",fAckTimeout);
if (fAckTimeout > kMaxAckTimeout)
fAckTimeout = kMaxAckTimeout;
else if (fAckTimeout < kMinAckTimeout)
fAckTimeout = kMinAckTimeout;
}