source/Sources/AirPlayReceiverSession.c
static void	_RetransmitsUpdate( AirPlayReceiverSessionRef inSession, AirTunesBufferNode *inNode, Boolean inIsRetransmit )
{
	AirTunesSource * const			ats = &inSession->source;
	uint16_t						pktSeq;
	AirTunesRetransmitNode **		next;
	AirTunesRetransmitNode *		curr;
	uint64_t						nowNanos;
	uint64_t						ageNanos;
	int64_t							rttNanos;
	int								credits;
	Boolean							outlier;
	
	nowNanos = UpNanoseconds();
	pktSeq   = inNode->rtp->header.seq;
	
	// Search for the completed retransmit.
	
	for( next = &ats->rtcpRTBusyList; ( ( curr = *next ) != NULL ) && ( curr->seq != pktSeq ); next = &curr->next ) {}
	if( curr )
	{
		if( inIsRetransmit )
		{
			ageNanos = nowNanos - curr->startNanos;
			if( ageNanos < ats->retransmitMinNanos ) ats->retransmitMinNanos = ageNanos;
			if( ageNanos > ats->retransmitMaxNanos ) ats->retransmitMaxNanos = ageNanos;
			if( ( ageNanos > ats->retransmitMinNanos ) && ( ageNanos < ats->retransmitMaxNanos ) )
			{
				ats->retransmitAvgNanos = ( ( ats->retransmitAvgNanos * 63 ) + ageNanos ) / 64;
			}
			// If multiple requests have gone out, this may be a response to an earlier request and not the most
			// recent one so following Karn's algorithm, only consider the RTT if we've only sent 1 request.
			
			if( curr->tries <= 1 )
			{
				outlier = false;
				rttNanos = nowNanos - curr->sentNanos;
				if( rttNanos < ats->rtcpRTMinRTTNanos ) { ats->rtcpRTMinRTTNanos = rttNanos; outlier = true; }
				if( rttNanos > ats->rtcpRTMaxRTTNanos ) { ats->rtcpRTMaxRTTNanos = rttNanos; outlier = true; }
				if( !outlier )
				{
					int64_t		errNanos;
					int64_t		absErrNanos;
					
					errNanos				= rttNanos - ats->rtcpRTAvgRTTNanos;
					absErrNanos				= ( errNanos < 0 ) ? -errNanos : errNanos;
					ats->rtcpRTAvgRTTNanos	= ats->rtcpRTAvgRTTNanos + ( errNanos / 8 );
					ats->rtcpRTDevRTTNanos	= ats->rtcpRTDevRTTNanos + ( ( absErrNanos - ats->rtcpRTDevRTTNanos ) / 4 );
					ats->rtcpRTTimeoutNanos	= ( 2 * ats->rtcpRTAvgRTTNanos ) + ( 4 * ats->rtcpRTDevRTTNanos );
					if( ats->rtcpRTTimeoutNanos > 100000000 ) // Cap at 100 ms
					{
						ats->rtcpRTTimeoutNanos = 100000000;
					}
				}
			}
		}
		
		*next = curr->next;
		curr->next = ats->rtcpRTFreeList;
		ats->rtcpRTFreeList = curr;
	}
	else if( inIsRetransmit )
	{
		atr_stats_ulog( kLogLevelInfo, "### Retransmit seq %u not found\n", pktSeq );
		++ats->retransmitNotFoundCount;
	}
	
	// Retry retransmits that have timed out.
	
	credits = 3;
	for( curr = ats->rtcpRTBusyList; curr; curr = curr->next )
	{
		if( nowNanos < curr->nextNanos ) continue;
		ageNanos = nowNanos - curr->startNanos;
		if( curr->tries++ > 0 )
		{
			if( ageNanos < ats->retransmitRetryMinNanos ) ats->retransmitRetryMinNanos = ageNanos;
			if( ageNanos > ats->retransmitRetryMaxNanos ) ats->retransmitRetryMaxNanos = ageNanos;
		}
		curr->sentNanos = nowNanos;
		curr->nextNanos = nowNanos + ats->rtcpRTTimeoutNanos;
		_RetransmitsSendRequest( inSession, curr->seq, 1 );
		if( --credits == 0 ) break;
	}
}
//===========================================================================================================================
//	_RetransmitsUpdate
//
//	Warning: Assumes the AirTunes lock is held.
//===========================================================================================================================
_RetransmitsUpdate
Warning: Assumes the AirTunes lock is held.
_RetransmitsUpdate Warning : Assumes the AirTunes lock is held .
static void	_RetransmitsUpdate( AirPlayReceiverSessionRef inSession, AirTunesBufferNode *inNode, Boolean inIsRetransmit )
{
	AirTunesSource * const			ats = &inSession->source;
	uint16_t						pktSeq;
	AirTunesRetransmitNode **		next;
	AirTunesRetransmitNode *		curr;
	uint64_t						nowNanos;
	uint64_t						ageNanos;
	int64_t							rttNanos;
	int								credits;
	Boolean							outlier;
	nowNanos = UpNanoseconds();
	pktSeq   = inNode->rtp->header.seq;
	for( next = &ats->rtcpRTBusyList; ( ( curr = *next ) != NULL ) && ( curr->seq != pktSeq ); next = &curr->next ) {}
	if( curr )
	{
		if( inIsRetransmit )
		{
			ageNanos = nowNanos - curr->startNanos;
			if( ageNanos < ats->retransmitMinNanos ) ats->retransmitMinNanos = ageNanos;
			if( ageNanos > ats->retransmitMaxNanos ) ats->retransmitMaxNanos = ageNanos;
			if( ( ageNanos > ats->retransmitMinNanos ) && ( ageNanos < ats->retransmitMaxNanos ) )
			{
				ats->retransmitAvgNanos = ( ( ats->retransmitAvgNanos * 63 ) + ageNanos ) / 64;
			}
			if( curr->tries <= 1 )
			{
				outlier = false;
				rttNanos = nowNanos - curr->sentNanos;
				if( rttNanos < ats->rtcpRTMinRTTNanos ) { ats->rtcpRTMinRTTNanos = rttNanos; outlier = true; }
				if( rttNanos > ats->rtcpRTMaxRTTNanos ) { ats->rtcpRTMaxRTTNanos = rttNanos; outlier = true; }
				if( !outlier )
				{
					int64_t		errNanos;
					int64_t		absErrNanos;
					errNanos				= rttNanos - ats->rtcpRTAvgRTTNanos;
					absErrNanos				= ( errNanos < 0 ) ? -errNanos : errNanos;
					ats->rtcpRTAvgRTTNanos	= ats->rtcpRTAvgRTTNanos + ( errNanos / 8 );
					ats->rtcpRTDevRTTNanos	= ats->rtcpRTDevRTTNanos + ( ( absErrNanos - ats->rtcpRTDevRTTNanos ) / 4 );
					ats->rtcpRTTimeoutNanos	= ( 2 * ats->rtcpRTAvgRTTNanos ) + ( 4 * ats->rtcpRTDevRTTNanos );
					if( ats->rtcpRTTimeoutNanos > 100000000 ) 
					{
						ats->rtcpRTTimeoutNanos = 100000000;
					}
				}
			}
		}
		*next = curr->next;
		curr->next = ats->rtcpRTFreeList;
		ats->rtcpRTFreeList = curr;
	}
	else if( inIsRetransmit )
	{
		atr_stats_ulog( kLogLevelInfo, "### Retransmit seq %u not found\n", pktSeq );
		++ats->retransmitNotFoundCount;
	}
	credits = 3;
	for( curr = ats->rtcpRTBusyList; curr; curr = curr->next )
	{
		if( nowNanos < curr->nextNanos ) continue;
		ageNanos = nowNanos - curr->startNanos;
		if( curr->tries++ > 0 )
		{
			if( ageNanos < ats->retransmitRetryMinNanos ) ats->retransmitRetryMinNanos = ageNanos;
			if( ageNanos > ats->retransmitRetryMaxNanos ) ats->retransmitRetryMaxNanos = ageNanos;
		}
		curr->sentNanos = nowNanos;
		curr->nextNanos = nowNanos + ats->rtcpRTTimeoutNanos;
		_RetransmitsSendRequest( inSession, curr->seq, 1 );
		if( --credits == 0 ) break;
	}
}
static void _RetransmitsUpdate ( AirPlayReceiverSessionRef inSession , AirTunesBufferNode * inNode , Boolean inIsRetransmit ) { AirTunesSource * const ats = & inSession -> source ; uint16_t pktSeq ; AirTunesRetransmitNode * * next ; AirTunesRetransmitNode * curr ; uint64_t nowNanos ; uint64_t ageNanos ; int64_t rttNanos ; int credits ; Boolean outlier ; nowNanos = UpNanoseconds ( ) ; pktSeq = inNode -> rtp -> header . seq ; for ( next = & ats -> rtcpRTBusyList ; ( ( curr = * next ) != NULL ) && ( curr -> seq != pktSeq ) ; next = & curr -> next ) { } if ( curr ) { if ( inIsRetransmit ) { ageNanos = nowNanos - curr -> startNanos ; if ( ageNanos < ats -> retransmitMinNanos ) ats -> retransmitMinNanos = ageNanos ; if ( ageNanos > ats -> retransmitMaxNanos ) ats -> retransmitMaxNanos = ageNanos ; if ( ( ageNanos > ats -> retransmitMinNanos ) && ( ageNanos < ats -> retransmitMaxNanos ) ) { ats -> retransmitAvgNanos = ( ( ats -> retransmitAvgNanos * 63 ) + ageNanos ) / 64 ; } if ( curr -> tries <= 1 ) { outlier = false ; rttNanos = nowNanos - curr -> sentNanos ; if ( rttNanos < ats -> rtcpRTMinRTTNanos ) { ats -> rtcpRTMinRTTNanos = rttNanos ; outlier = true ; } if ( rttNanos > ats -> rtcpRTMaxRTTNanos ) { ats -> rtcpRTMaxRTTNanos = rttNanos ; outlier = true ; } if ( ! outlier ) { int64_t errNanos ; int64_t absErrNanos ; errNanos = rttNanos - ats -> rtcpRTAvgRTTNanos ; absErrNanos = ( errNanos < 0 ) ? - errNanos : errNanos ; ats -> rtcpRTAvgRTTNanos = ats -> rtcpRTAvgRTTNanos + ( errNanos / 8 ) ; ats -> rtcpRTDevRTTNanos = ats -> rtcpRTDevRTTNanos + ( ( absErrNanos - ats -> rtcpRTDevRTTNanos ) / 4 ) ; ats -> rtcpRTTimeoutNanos = ( 2 * ats -> rtcpRTAvgRTTNanos ) + ( 4 * ats -> rtcpRTDevRTTNanos ) ; if ( ats -> rtcpRTTimeoutNanos > 100000000 ) { ats -> rtcpRTTimeoutNanos = 100000000 ; } } } } * next = curr -> next ; curr -> next = ats -> rtcpRTFreeList ; ats -> rtcpRTFreeList = curr ; } else if ( inIsRetransmit ) { atr_stats_ulog ( kLogLevelInfo , " \n " , pktSeq ) ; ++ ats -> retransmitNotFoundCount ; } credits = 3 ; for ( curr = ats -> rtcpRTBusyList ; curr ; curr = curr -> next ) { if ( nowNanos < curr -> nextNanos ) continue ; ageNanos = nowNanos - curr -> startNanos ; if ( curr -> tries ++ > 0 ) { if ( ageNanos < ats -> retransmitRetryMinNanos ) ats -> retransmitRetryMinNanos = ageNanos ; if ( ageNanos > ats -> retransmitRetryMaxNanos ) ats -> retransmitRetryMaxNanos = ageNanos ; } curr -> sentNanos = nowNanos ; curr -> nextNanos = nowNanos + ats -> rtcpRTTimeoutNanos ; _RetransmitsSendRequest ( inSession , curr -> seq , 1 ) ; if ( -- credits == 0 ) break ; } }
_RetransmitsUpdate
Warning: Assumes the AirTunes lock is held.
_RetransmitsUpdate Warning : Assumes the AirTunes lock is held .
// Search for the completed retransmit. // If multiple requests have gone out, this may be a response to an earlier request and not the most // recent one so following Karn's algorithm, only consider the RTT if we've only sent 1 request. // Cap at 100 ms // Retry retransmits that have timed out.