/* ===================== 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; }
/* ===================== 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; }