source/Sources/AirPlayReceiverSessionScreen.c
static OSStatus
	_AirPlayReceiverSessionScreen_ProcessFrame(
		AirPlayReceiverSessionScreenRef		me,
		AirPlayScreenHeader *				inHeader, 
		uint8_t *							inFramePtr )
{
	OSStatus		err;
	uint64_t		displayTicks;
	uint64_t		nowTicks;
	size_t			tempSize;
	
	if( inHeader->opcode == kAirPlayScreenOpCode_VideoFrame )
	{
		// Processing timestamps.
		
		if( me->respectTimestamps )
		{
			displayTicks = me->timeSynchronizer.getUpTicksNearSynchronizedNTPTimeFunc(
				me->timeSynchronizer.context, inHeader->params[ 0 ].u64 );
		}
		else
		{
			displayTicks = UpTicks();
		}
		nowTicks = UpTicks();
		
		if( displayTicks >= nowTicks )
		{
			me->displayDeltaMs = UpTicksToMilliseconds( displayTicks - nowTicks );
		}
		else
		{
			me->displayDeltaMs = -(int64_t) UpTicksToMilliseconds( nowTicks - displayTicks );
			++me->negativeAheadFrames;
		}
		me->displayDeltaMs = me->videoLatencyMs - me->displayDeltaMs;
		if( me->displayDeltaMs >= ( 2 * me->videoLatencyMs ) )
		{
			++me->lateFrames;
			tempSize = ( inHeader->bodySize >= 16 ) ? 16 : inHeader->bodySize;
			apvs_frames_ulog( kLogLevelNotice, "Late frame (%lld ms, %u total late frames): %.3H ... %.3H\n", 
				me->displayDeltaMs, me->lateFrames, inHeader, 16, 16, 
				inFramePtr + ( inHeader->bodySize - tempSize ), (int) tempSize, (int) tempSize );
		}

		if( me->chachaCryptor.isValid )
		{
			if( inHeader->bodySize >= 16 )
			{
				size_t len;
				chacha20_poly1305_init_64x64( &me->chachaCryptor.state, me->chachaCryptor.key, me->chachaCryptor.nonce );
				chacha20_poly1305_add_aad( &me->chachaCryptor.state, inHeader, sizeof( AirPlayScreenHeader ) );
				len = chacha20_poly1305_decrypt( &me->chachaCryptor.state, inFramePtr, inHeader->bodySize - 16, inFramePtr );
				len += chacha20_poly1305_verify( &me->chachaCryptor.state, &inFramePtr[ len ], &inFramePtr[ inHeader->bodySize - 16 ], &err );
				require_noerr( err, exit );
				require_action( len == inHeader->bodySize - 16, exit, err = kInternalErr );
				inHeader->bodySize -= 16;
				LittleEndianIntegerIncrement( me->chachaCryptor.nonce, sizeof( me->chachaCryptor.nonce ) );
			}
		}
		else
		if( me->aesValid )
		{
			err = AES_CTR_Update( &me->aesContext, inFramePtr, inHeader->bodySize, inFramePtr );
			require_noerr( err, exit );
		}
		
		err = ScreenStreamProcessData( me->screenStream, inFramePtr, inHeader->bodySize, displayTicks, NULL, NULL, NULL );
		require_noerr( err, exit );
	}
	else if( inHeader->opcode == kAirPlayScreenOpCode_VideoConfig )
	{
		me->respectTimestamps = ( inHeader->smallParam[ 1 ] & kAirPlayScreenFlag_RespectTimestamps ) != 0;
		
		ScreenStreamSetWidthHeight( me->screenStream, inHeader->params[ 1 ].f32[ 0 ], inHeader->params[ 1 ].f32[ 1 ] );
		
		if( inHeader->bodySize > 0 )
		{
			err = ScreenStreamSetAVCC( me->screenStream, inFramePtr, inHeader->bodySize );
			require_noerr( err, exit );
		}
	}
	else if( inHeader->opcode == kAirPlayScreenOpCode_KeepAlive )
	{
		// This opcode is intended to be ignored.
	}
	else if( inHeader->opcode == kAirPlayScreenOpCode_KeepAliveWithBody )
	{
		// This opcode is intended to be ignored.
	}
	else if( inHeader->opcode == kAirPlayScreenOpCode_Ignore )
	{
		// This opcode is intended to be ignored. It's only for measuring bandwidth.
	}
	else
	{
		apvs_ulog( kLogLevelError, "### Unknown screen opcode: %u\n", inHeader->opcode );
		err = kUnsupportedErr;
		goto exit;
	}
	err = kNoErr;
	
exit:
	if( inFramePtr ) free( inFramePtr );
	if( err )
	{
		++me->frameErrors;
		apvs_frames_ulog( kLogLevelError, "### Process frame error (%u): %#m\n", me->frameErrors, err );
	}
	return( err );
}
//===========================================================================================================================
//	_AirPlayReceiverSessionScreen_ProcessFrame
//
//	Warning: Unconventionally, ensuring that inFramePtr is munmap'd is the responsibility of this function.
//===========================================================================================================================
_AirPlayReceiverSessionScreen_ProcessFrame
Warning: Unconventionally, ensuring that inFramePtr is munmap'd is the responsibility of this function.
_AirPlayReceiverSessionScreen_ProcessFrame Warning : Unconventionally ensuring that inFramePtr is munmap ' d is the responsibility of this function .
static OSStatus
	_AirPlayReceiverSessionScreen_ProcessFrame(
		AirPlayReceiverSessionScreenRef		me,
		AirPlayScreenHeader *				inHeader, 
		uint8_t *							inFramePtr )
{
	OSStatus		err;
	uint64_t		displayTicks;
	uint64_t		nowTicks;
	size_t			tempSize;
	if( inHeader->opcode == kAirPlayScreenOpCode_VideoFrame )
	{
		if( me->respectTimestamps )
		{
			displayTicks = me->timeSynchronizer.getUpTicksNearSynchronizedNTPTimeFunc(
				me->timeSynchronizer.context, inHeader->params[ 0 ].u64 );
		}
		else
		{
			displayTicks = UpTicks();
		}
		nowTicks = UpTicks();
		if( displayTicks >= nowTicks )
		{
			me->displayDeltaMs = UpTicksToMilliseconds( displayTicks - nowTicks );
		}
		else
		{
			me->displayDeltaMs = -(int64_t) UpTicksToMilliseconds( nowTicks - displayTicks );
			++me->negativeAheadFrames;
		}
		me->displayDeltaMs = me->videoLatencyMs - me->displayDeltaMs;
		if( me->displayDeltaMs >= ( 2 * me->videoLatencyMs ) )
		{
			++me->lateFrames;
			tempSize = ( inHeader->bodySize >= 16 ) ? 16 : inHeader->bodySize;
			apvs_frames_ulog( kLogLevelNotice, "Late frame (%lld ms, %u total late frames): %.3H ... %.3H\n", 
				me->displayDeltaMs, me->lateFrames, inHeader, 16, 16, 
				inFramePtr + ( inHeader->bodySize - tempSize ), (int) tempSize, (int) tempSize );
		}
		if( me->chachaCryptor.isValid )
		{
			if( inHeader->bodySize >= 16 )
			{
				size_t len;
				chacha20_poly1305_init_64x64( &me->chachaCryptor.state, me->chachaCryptor.key, me->chachaCryptor.nonce );
				chacha20_poly1305_add_aad( &me->chachaCryptor.state, inHeader, sizeof( AirPlayScreenHeader ) );
				len = chacha20_poly1305_decrypt( &me->chachaCryptor.state, inFramePtr, inHeader->bodySize - 16, inFramePtr );
				len += chacha20_poly1305_verify( &me->chachaCryptor.state, &inFramePtr[ len ], &inFramePtr[ inHeader->bodySize - 16 ], &err );
				require_noerr( err, exit );
				require_action( len == inHeader->bodySize - 16, exit, err = kInternalErr );
				inHeader->bodySize -= 16;
				LittleEndianIntegerIncrement( me->chachaCryptor.nonce, sizeof( me->chachaCryptor.nonce ) );
			}
		}
		else
		if( me->aesValid )
		{
			err = AES_CTR_Update( &me->aesContext, inFramePtr, inHeader->bodySize, inFramePtr );
			require_noerr( err, exit );
		}
		err = ScreenStreamProcessData( me->screenStream, inFramePtr, inHeader->bodySize, displayTicks, NULL, NULL, NULL );
		require_noerr( err, exit );
	}
	else if( inHeader->opcode == kAirPlayScreenOpCode_VideoConfig )
	{
		me->respectTimestamps = ( inHeader->smallParam[ 1 ] & kAirPlayScreenFlag_RespectTimestamps ) != 0;
		ScreenStreamSetWidthHeight( me->screenStream, inHeader->params[ 1 ].f32[ 0 ], inHeader->params[ 1 ].f32[ 1 ] );
		if( inHeader->bodySize > 0 )
		{
			err = ScreenStreamSetAVCC( me->screenStream, inFramePtr, inHeader->bodySize );
			require_noerr( err, exit );
		}
	}
	else if( inHeader->opcode == kAirPlayScreenOpCode_KeepAlive )
	{
	}
	else if( inHeader->opcode == kAirPlayScreenOpCode_KeepAliveWithBody )
	{
	}
	else if( inHeader->opcode == kAirPlayScreenOpCode_Ignore )
	{
		 It's only for measuring bandwidth.
	}
	else
	{
		apvs_ulog( kLogLevelError, "### Unknown screen opcode: %u\n", inHeader->opcode );
		err = kUnsupportedErr;
		goto exit;
	}
	err = kNoErr;
exit:
	if( inFramePtr ) free( inFramePtr );
	if( err )
	{
		++me->frameErrors;
		apvs_frames_ulog( kLogLevelError, "### Process frame error (%u): %#m\n", me->frameErrors, err );
	}
	return( err );
}
static OSStatus _AirPlayReceiverSessionScreen_ProcessFrame ( AirPlayReceiverSessionScreenRef me , AirPlayScreenHeader * inHeader , uint8_t * inFramePtr ) { OSStatus err ; uint64_t displayTicks ; uint64_t nowTicks ; size_t tempSize ; if ( inHeader -> opcode == kAirPlayScreenOpCode_VideoFrame ) { if ( me -> respectTimestamps ) { displayTicks = me -> timeSynchronizer . getUpTicksNearSynchronizedNTPTimeFunc ( me -> timeSynchronizer . context , inHeader -> params [ 0 ] . u64 ) ; } else { displayTicks = UpTicks ( ) ; } nowTicks = UpTicks ( ) ; if ( displayTicks >= nowTicks ) { me -> displayDeltaMs = UpTicksToMilliseconds ( displayTicks - nowTicks ) ; } else { me -> displayDeltaMs = - ( int64_t ) UpTicksToMilliseconds ( nowTicks - displayTicks ) ; ++ me -> negativeAheadFrames ; } me -> displayDeltaMs = me -> videoLatencyMs - me -> displayDeltaMs ; if ( me -> displayDeltaMs >= ( 2 * me -> videoLatencyMs ) ) { ++ me -> lateFrames ; tempSize = ( inHeader -> bodySize >= 16 ) ? 16 : inHeader -> bodySize ; apvs_frames_ulog ( kLogLevelNotice , " \n " , me -> displayDeltaMs , me -> lateFrames , inHeader , 16 , 16 , inFramePtr + ( inHeader -> bodySize - tempSize ) , ( int ) tempSize , ( int ) tempSize ) ; } if ( me -> chachaCryptor . isValid ) { if ( inHeader -> bodySize >= 16 ) { size_t len ; chacha20_poly1305_init_64x64 ( & me -> chachaCryptor . state , me -> chachaCryptor . key , me -> chachaCryptor . nonce ) ; chacha20_poly1305_add_aad ( & me -> chachaCryptor . state , inHeader , sizeof ( AirPlayScreenHeader ) ) ; len = chacha20_poly1305_decrypt ( & me -> chachaCryptor . state , inFramePtr , inHeader -> bodySize - 16 , inFramePtr ) ; len += chacha20_poly1305_verify ( & me -> chachaCryptor . state , & inFramePtr [ len ] , & inFramePtr [ inHeader -> bodySize - 16 ] , & err ) ; require_noerr ( err , exit ) ; require_action ( len == inHeader -> bodySize - 16 , exit , err = kInternalErr ) ; inHeader -> bodySize -= 16 ; LittleEndianIntegerIncrement ( me -> chachaCryptor . nonce , sizeof ( me -> chachaCryptor . nonce ) ) ; } } else if ( me -> aesValid ) { err = AES_CTR_Update ( & me -> aesContext , inFramePtr , inHeader -> bodySize , inFramePtr ) ; require_noerr ( err , exit ) ; } err = ScreenStreamProcessData ( me -> screenStream , inFramePtr , inHeader -> bodySize , displayTicks , NULL , NULL , NULL ) ; require_noerr ( err , exit ) ; } else if ( inHeader -> opcode == kAirPlayScreenOpCode_VideoConfig ) { me -> respectTimestamps = ( inHeader -> smallParam [ 1 ] & kAirPlayScreenFlag_RespectTimestamps ) != 0 ; ScreenStreamSetWidthHeight ( me -> screenStream , inHeader -> params [ 1 ] . f32 [ 0 ] , inHeader -> params [ 1 ] . f32 [ 1 ] ) ; if ( inHeader -> bodySize > 0 ) { err = ScreenStreamSetAVCC ( me -> screenStream , inFramePtr , inHeader -> bodySize ) ; require_noerr ( err , exit ) ; } } else if ( inHeader -> opcode == kAirPlayScreenOpCode_KeepAlive ) { } else if ( inHeader -> opcode == kAirPlayScreenOpCode_KeepAliveWithBody ) { } else if ( inHeader -> opcode == kAirPlayScreenOpCode_Ignore ) { } else { apvs_ulog ( kLogLevelError , " \n " , inHeader -> opcode ) ; err = kUnsupportedErr ; goto exit ; } err = kNoErr ; exit : if ( inFramePtr ) free ( inFramePtr ) ; if ( err ) { ++ me -> frameErrors ; apvs_frames_ulog ( kLogLevelError , " \n " , me -> frameErrors , err ) ; } return ( err ) ; }
_AirPlayReceiverSessionScreen_ProcessFrame
Warning: Unconventionally, ensuring that inFramePtr is munmap'd is the responsibility of this function.
_AirPlayReceiverSessionScreen_ProcessFrame Warning : Unconventionally ensuring that inFramePtr is munmap ' d is the responsibility of this function .
// Processing timestamps. // This opcode is intended to be ignored. // This opcode is intended to be ignored. // This opcode is intended to be ignored. It's only for measuring bandwidth.