Example #1
0
/*
=====================
CL_ParseVoip

A VoIP message has been received from the server
=====================
*/
static
void CL_ParseVoip( msg_t *msg )
{
	static short decoded[ 4096 ]; // !!! FIXME: don't hardcode.

	const int    sender = MSG_ReadShort( msg );
	const int    generation = MSG_ReadByte( msg );
	const int    sequence = MSG_ReadLong( msg );
	const int    frames = MSG_ReadByte( msg );
	const int    packetsize = MSG_ReadShort( msg );
	const int    flags = MSG_ReadBits( msg, VOIP_FLAGCNT );
	char         encoded[ 1024 ];
	int          seqdiff = sequence - clc.voipIncomingSequence[ sender ];
	int          written = 0;
	int          i;

	Com_DPrintf( "VoIP: %d-byte packet from client %d\n", packetsize, sender );

	if ( sender < 0 )
	{
		return; // short/invalid packet, bail.
	}
	else if ( generation < 0 )
	{
		return; // short/invalid packet, bail.
	}
	else if ( sequence < 0 )
	{
		return; // short/invalid packet, bail.
	}
	else if ( frames < 0 )
	{
		return; // short/invalid packet, bail.
	}
	else if ( packetsize < 0 )
	{
		return; // short/invalid packet, bail.
	}

	if ( packetsize > sizeof( encoded ) )  // overlarge packet?
	{
		int bytesleft = packetsize;

		while ( bytesleft )
		{
			int br = bytesleft;

			if ( br > sizeof( encoded ) )
			{
				br = sizeof( encoded );
			}

			MSG_ReadData( msg, encoded, br );
			bytesleft -= br;
		}

		return; // overlarge packet, bail.
	}

	if ( !clc.speexInitialized )
	{
		MSG_ReadData( msg, encoded, packetsize );  // skip payload.
		return; // can't handle VoIP without libspeex!
	}
	else if ( sender >= MAX_CLIENTS )
	{
		MSG_ReadData( msg, encoded, packetsize );  // skip payload.
		return; // bogus sender.
	}
	else if ( CL_ShouldIgnoreVoipSender( sender ) )
	{
		MSG_ReadData( msg, encoded, packetsize );  // skip payload.
		return; // Channel is muted, bail.
	}

	// !!! FIXME: make sure data is narrowband? Does decoder handle this?

	Com_DPrintf( "VoIP: packet accepted!\n" );

	// This is a new "generation" ... a new recording started, reset the bits.
	if ( generation != clc.voipIncomingGeneration[ sender ] )
	{
		Com_DPrintf( "VoIP: new generation %d!\n", generation );
		speex_bits_reset( &clc.speexDecoderBits[ sender ] );
		clc.voipIncomingGeneration[ sender ] = generation;
		seqdiff = 0;
	}
	else if ( seqdiff < 0 ) // we're ahead of the sequence?!
	{
		// This shouldn't happen unless the packet is corrupted or something.
		Com_DPrintf( "VoIP: misordered sequence! %d < %d!\n",
		             sequence, clc.voipIncomingSequence[ sender ] );
		// reset the bits just in case.
		speex_bits_reset( &clc.speexDecoderBits[ sender ] );
		seqdiff = 0;
	}
	else if ( seqdiff > 100 ) // more than 2 seconds of audio dropped?
	{
		// just start over.
		Com_DPrintf( "VoIP: Dropped way too many (%d) frames from client #%d\n",
		             seqdiff, sender );
		speex_bits_reset( &clc.speexDecoderBits[ sender ] );
		seqdiff = 0;
	}

	if ( seqdiff != 0 )
	{
		Com_DPrintf( "VoIP: Dropped %d frames from client #%d\n",
		             seqdiff, sender );

		// tell speex that we're missing frames...
		for ( i = 0; i < seqdiff; i++ )
		{
			assert( ( written + clc.speexFrameSize ) * 2 < sizeof( decoded ) );
			speex_decode_int( clc.speexDecoder[ sender ], NULL, decoded + written );
			written += clc.speexFrameSize;
		}
	}

	for ( i = 0; i < frames; i++ )
	{
		const int len = MSG_ReadByte( msg );

		if ( len < 0 )
		{
			Com_DPrintf( "VoIP: Short packet!\n" );
			break;
		}

		MSG_ReadData( msg, encoded, len );

		// shouldn't happen, but just in case...
		if ( ( written + clc.speexFrameSize ) * 2 > sizeof( decoded ) )
		{
			Com_DPrintf( "VoIP: playback %d bytes, %d samples, %d frames\n",
			             written * 2, written, i );

			CL_PlayVoip( sender, written, ( const byte * ) decoded, flags );
			written = 0;
		}

		speex_bits_read_from( &clc.speexDecoderBits[ sender ], encoded, len );
		speex_decode_int( clc.speexDecoder[ sender ],
		                  &clc.speexDecoderBits[ sender ], decoded + written );

#if 0
		static FILE *encio = NULL;

		if ( encio == NULL ) { encio = fopen( "voip-incoming-encoded.bin", "wb" ); }

		if ( encio != NULL ) { fwrite( encoded, len, 1, encio ); fflush( encio ); }

		static FILE *decio = NULL;

		if ( decio == NULL ) { decio = fopen( "voip-incoming-decoded.bin", "wb" ); }

		if ( decio != NULL ) { fwrite( decoded + written, clc.speexFrameSize * 2, 1, decio ); fflush( decio ); }

#endif

		written += clc.speexFrameSize;
	}

	Com_DPrintf( "VoIP: playback %d bytes, %d samples, %d frames\n",
	             written * 2, written, i );

	if ( written > 0 )
	{
		CL_PlayVoip( sender, written, ( const byte * ) decoded, flags );
	}

	clc.voipIncomingSequence[ sender ] = sequence + frames;
}
Example #2
0
/*
=====================
CL_ParseVoip

A VoIP message has been received from the server
=====================
*/
static
void CL_ParseVoip ( msg_t *msg, qboolean ignoreData ) {
	static short decoded[VOIP_MAX_PACKET_SAMPLES*4]; // !!! FIXME: don't hard code

	const int sender = MSG_ReadShort(msg);
	const int generation = MSG_ReadByte(msg);
	const int sequence = MSG_ReadLong(msg);
	const int frames = MSG_ReadByte(msg);
	const int packetsize = MSG_ReadShort(msg);
	const int flags = MSG_ReadBits(msg, VOIP_FLAGCNT);
	unsigned char encoded[4000];
	int	numSamples;
	int seqdiff;
	int written = 0;
	int i;

	Com_DPrintf("VoIP: %d-byte packet from client %d\n", packetsize, sender);

	if (sender < 0)
		return;   // short/invalid packet, bail.
	else if (generation < 0)
		return;   // short/invalid packet, bail.
	else if (sequence < 0)
		return;   // short/invalid packet, bail.
	else if (frames < 0)
		return;   // short/invalid packet, bail.
	else if (packetsize < 0)
		return;   // short/invalid packet, bail.

	if (packetsize > sizeof (encoded)) {  // overlarge packet?
		int bytesleft = packetsize;
		while (bytesleft) {
			int br = bytesleft;
			if (br > sizeof (encoded))
				br = sizeof (encoded);
			MSG_ReadData(msg, encoded, br);
			bytesleft -= br;
		}
		return;   // overlarge packet, bail.
	}

	MSG_ReadData(msg, encoded, packetsize);

	if (ignoreData) {
		return; // just ignore legacy speex voip data
	} else if (!clc.voipCodecInitialized) {
		return;   // can't handle VoIP without libopus!
	} else if (sender >= MAX_CLIENTS) {
		return;   // bogus sender.
	} else if (CL_ShouldIgnoreVoipSender(sender)) {
		return;   // Channel is muted, bail.
	}

	// !!! FIXME: make sure data is narrowband? Does decoder handle this?

	Com_DPrintf("VoIP: packet accepted!\n");

	seqdiff = sequence - clc.voipIncomingSequence[sender];

	// This is a new "generation" ... a new recording started, reset the bits.
	if (generation != clc.voipIncomingGeneration[sender]) {
		Com_DPrintf("VoIP: new generation %d!\n", generation);
		opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE);
		clc.voipIncomingGeneration[sender] = generation;
		seqdiff = 0;
	} else if (seqdiff < 0) {   // we're ahead of the sequence?!
		// This shouldn't happen unless the packet is corrupted or something.
		Com_DPrintf("VoIP: misordered sequence! %d < %d!\n",
		            sequence, clc.voipIncomingSequence[sender]);
		// reset the decoder just in case.
		opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE);
		seqdiff = 0;
	} else if (seqdiff * VOIP_MAX_PACKET_SAMPLES*2 >= sizeof (decoded)) { // dropped more than we can handle?
		// just start over.
		Com_DPrintf("VoIP: Dropped way too many (%d) frames from client #%d\n",
		            seqdiff, sender);
		opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE);
		seqdiff = 0;
	}

	if (seqdiff != 0) {
		Com_DPrintf("VoIP: Dropped %d frames from client #%d\n",
		            seqdiff, sender);
		// tell opus that we're missing frames...
		for (i = 0; i < seqdiff; i++) {
			assert((written + VOIP_MAX_PACKET_SAMPLES) * 2 < sizeof (decoded));
			numSamples = opus_decode(clc.opusDecoder[sender], NULL, 0, decoded + written, VOIP_MAX_PACKET_SAMPLES, 0);
			if ( numSamples <= 0 ) {
				Com_DPrintf("VoIP: Error decoding frame %d from client #%d\n", i, sender);
				continue;
			}
			written += numSamples;
		}
	}

	numSamples = opus_decode(clc.opusDecoder[sender], encoded, packetsize, decoded + written, ARRAY_LEN(decoded) - written, 0);

	if ( numSamples <= 0 ) {
		Com_DPrintf("VoIP: Error decoding voip data from client #%d\n", sender);
		numSamples = 0;
	}

	#if 0
	static FILE *encio = NULL;
	if (encio == NULL) encio = fopen("voip-incoming-encoded.bin", "wb");
	if (encio != NULL) { fwrite(encoded, len, 1, encio); fflush(encio); }
	static FILE *decio = NULL;
	if (decio == NULL) decio = fopen("voip-incoming-decoded.bin", "wb");
	if (decio != NULL) { fwrite(decoded+written, clc.speexFrameSize*2, 1, decio); fflush(decio); }
	#endif

	written += numSamples;

	Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
	            written * 2, written, frames);

	if(written > 0)
		CL_PlayVoip(sender, written, (const byte *) decoded, flags);

	clc.voipIncomingSequence[sender] = sequence + frames;
}