source/Sources/AirPlayUtils.c
static void	_RTPJitterBufferDiscardExcess( RTPJitterBufferContext *ctx)
{
	uint32_t				desired;
	uint32_t				queueSize;
	uint32_t				prevSampleSize;
	uint32_t				highWatermarkMs;
	size_t					listNdx, listCount;
	RTPPacketNodeList *		listsToDiscardFrom[] = { &ctx->preparedList, &ctx->receivedList };
	RTPPacketNode *			nodeToDiscard;
	RTPPacketNode *			safeNode;
	
	require( ( ctx->bufferMs > 0 && ctx->inputFormat.mSampleRate > 0 ), exit );

	highWatermarkMs = ctx->bufferMs + 20;
	// 200ms is derived from the 50 nodes PCM samples @44.1KHz
	if( highWatermarkMs < 200 ) highWatermarkMs = 200;

	desired =  highWatermarkMs * ( (uint32_t) ctx->inputFormat.mSampleRate ) / 1000;
	
	queueSize = prevSampleSize = _RTPJitterBufferBufferedSamples( ctx, false );

	listCount = sizeof( listsToDiscardFrom ) / sizeof( listsToDiscardFrom[0] );
	for( listNdx = 0; listNdx < listCount; ++listNdx )
	{
		TAILQ_FOREACH_SAFE( nodeToDiscard, listsToDiscardFrom[ listNdx ], list, safeNode )
		{
			// Stop discarding when we've reached our desired size
			
			if ( ( queueSize = _RTPJitterBufferBufferedSamples( ctx, false ) ) <= desired )
				break;
			
			// Make sure the node isn't in use by the decode thread
			
			if( !nodeToDiscard->decodeLock || dispatch_semaphore_wait( nodeToDiscard->decodeLock, DISPATCH_TIME_NOW ) == 0 )
			{
				TAILQ_REMOVE( listsToDiscardFrom[ listNdx ], nodeToDiscard, list );
				TAILQ_INSERT_HEAD( &ctx->freeList, nodeToDiscard, list );
				ctx->nodesUsed -= 1;
				
				if( nodeToDiscard->decodeLock )
					dispatch_semaphore_signal( nodeToDiscard->decodeLock );
			}
		}
	}
	
	if( queueSize != prevSampleSize )
	{
		RTPJitterBufferLog( ctx, kLogLevelNotice | kLogLevelFlagDontRateLimit,
			"Jitter Buffer Discard Excess, prevSize=%d(%dms) newSize=%d(%dms)\n",
			prevSampleSize, RTPJitterBufferSamplesToMs( ctx, prevSampleSize ),
			queueSize, RTPJitterBufferSamplesToMs( ctx, queueSize ) );
	}
	
exit:
	return;
}
// Internal function that is accessed after taking the jitter buffer lock
Internal function that is accessed after taking the jitter buffer lock
Internal function that is accessed after taking the jitter buffer lock
static void	_RTPJitterBufferDiscardExcess( RTPJitterBufferContext *ctx)
{
	uint32_t				desired;
	uint32_t				queueSize;
	uint32_t				prevSampleSize;
	uint32_t				highWatermarkMs;
	size_t					listNdx, listCount;
	RTPPacketNodeList *		listsToDiscardFrom[] = { &ctx->preparedList, &ctx->receivedList };
	RTPPacketNode *			nodeToDiscard;
	RTPPacketNode *			safeNode;
	require( ( ctx->bufferMs > 0 && ctx->inputFormat.mSampleRate > 0 ), exit );
	highWatermarkMs = ctx->bufferMs + 20;
	if( highWatermarkMs < 200 ) highWatermarkMs = 200;
	desired =  highWatermarkMs * ( (uint32_t) ctx->inputFormat.mSampleRate ) / 1000;
	queueSize = prevSampleSize = _RTPJitterBufferBufferedSamples( ctx, false );
	listCount = sizeof( listsToDiscardFrom ) / sizeof( listsToDiscardFrom[0] );
	for( listNdx = 0; listNdx < listCount; ++listNdx )
	{
		TAILQ_FOREACH_SAFE( nodeToDiscard, listsToDiscardFrom[ listNdx ], list, safeNode )
		{
			if ( ( queueSize = _RTPJitterBufferBufferedSamples( ctx, false ) ) <= desired )
				break;
			if( !nodeToDiscard->decodeLock || dispatch_semaphore_wait( nodeToDiscard->decodeLock, DISPATCH_TIME_NOW ) == 0 )
			{
				TAILQ_REMOVE( listsToDiscardFrom[ listNdx ], nodeToDiscard, list );
				TAILQ_INSERT_HEAD( &ctx->freeList, nodeToDiscard, list );
				ctx->nodesUsed -= 1;
				if( nodeToDiscard->decodeLock )
					dispatch_semaphore_signal( nodeToDiscard->decodeLock );
			}
		}
	}
	if( queueSize != prevSampleSize )
	{
		RTPJitterBufferLog( ctx, kLogLevelNotice | kLogLevelFlagDontRateLimit,
			"Jitter Buffer Discard Excess, prevSize=%d(%dms) newSize=%d(%dms)\n",
			prevSampleSize, RTPJitterBufferSamplesToMs( ctx, prevSampleSize ),
			queueSize, RTPJitterBufferSamplesToMs( ctx, queueSize ) );
	}
exit:
	return;
}
static void _RTPJitterBufferDiscardExcess ( RTPJitterBufferContext * ctx ) { uint32_t desired ; uint32_t queueSize ; uint32_t prevSampleSize ; uint32_t highWatermarkMs ; size_t listNdx , listCount ; RTPPacketNodeList * listsToDiscardFrom [ ] = { & ctx -> preparedList , & ctx -> receivedList } ; RTPPacketNode * nodeToDiscard ; RTPPacketNode * safeNode ; require ( ( ctx -> bufferMs > 0 && ctx -> inputFormat . mSampleRate > 0 ) , exit ) ; highWatermarkMs = ctx -> bufferMs + 20 ; if ( highWatermarkMs < 200 ) highWatermarkMs = 200 ; desired = highWatermarkMs * ( ( uint32_t ) ctx -> inputFormat . mSampleRate ) / 1000 ; queueSize = prevSampleSize = _RTPJitterBufferBufferedSamples ( ctx , false ) ; listCount = sizeof ( listsToDiscardFrom ) / sizeof ( listsToDiscardFrom [ 0 ] ) ; for ( listNdx = 0 ; listNdx < listCount ; ++ listNdx ) { TAILQ_FOREACH_SAFE ( nodeToDiscard , listsToDiscardFrom [ listNdx ] , list , safeNode ) { if ( ( queueSize = _RTPJitterBufferBufferedSamples ( ctx , false ) ) <= desired ) break ; if ( ! nodeToDiscard -> decodeLock || dispatch_semaphore_wait ( nodeToDiscard -> decodeLock , DISPATCH_TIME_NOW ) == 0 ) { TAILQ_REMOVE ( listsToDiscardFrom [ listNdx ] , nodeToDiscard , list ) ; TAILQ_INSERT_HEAD ( & ctx -> freeList , nodeToDiscard , list ) ; ctx -> nodesUsed -= 1 ; if ( nodeToDiscard -> decodeLock ) dispatch_semaphore_signal ( nodeToDiscard -> decodeLock ) ; } } } if ( queueSize != prevSampleSize ) { RTPJitterBufferLog ( ctx , kLogLevelNotice | kLogLevelFlagDontRateLimit , " \n " , prevSampleSize , RTPJitterBufferSamplesToMs ( ctx , prevSampleSize ) , queueSize , RTPJitterBufferSamplesToMs ( ctx , queueSize ) ) ; } exit : return ; }
Internal function that is accessed after taking the jitter buffer lock
Internal function that is accessed after taking the jitter buffer lock
// 200ms is derived from the 50 nodes PCM samples @44.1KHz // Stop discarding when we've reached our desired size // Make sure the node isn't in use by the decode thread