void* rakVoiceThread( void* arguments ) #endif { SpeexBits bits; char output[ 2000 ]; int outputLength; unsigned char typeID; PlayerID id; BitStream b; int availableChunks; int MTU; int numberOfChunksPerSend; int i; unsigned long lastSendTime; CoderStateWithPlayerIDMapStruct *cswpims; lastSendTime = RakNet::GetTime(); PlayerID target; RakVoice *rakVoice = ( RakVoice* ) arguments; numberOfChunksPerSend = rakVoice->blockSize / rakVoice->frame_size; speex_bits_init( &bits ); MTU = rakVoice->peer->GetMTUSize(); while ( rakVoice->init ) { if ( rakVoice->writeCursor >= rakVoice->readCursor ) availableChunks = rakVoice->writeCursor - rakVoice->readCursor; else availableChunks = RAK_VOICE_INPUT_LIST_BUFFER_SIZE - rakVoice->readCursor + rakVoice->writeCursor; while ( availableChunks >= numberOfChunksPerSend ) { // Get a bit of a buffer before we start sending so we don't "grind" the data and get popping as data continually arrives and runs out if ( RakNet::GetTime() - lastSendTime > 1000 && availableChunks < numberOfChunksPerSend * 3 ) break; // Grab data at the read cursor and encode it speex_bits_reset( &bits ); target = rakVoice->targetedSendRecipient[ rakVoice->readCursor ]; cswpims = rakVoice->GetCoderFromPlayerID( rakVoice->sampleRate, target, false ); for ( i = 0; i < numberOfChunksPerSend; i++ ) { // For each frame, call speex_encode speex_encode( cswpims->encoderState, rakVoice->inputList[ rakVoice->readCursor ], &bits ); rakVoice->readCursor = ( rakVoice->readCursor + 1 ) % RAK_VOICE_INPUT_LIST_BUFFER_SIZE; } availableChunks -= numberOfChunksPerSend; // Write the encoded bitstream outputLength = speex_bits_write( ( SpeexBits* ) ( &bits ), output, 2000 ); #ifdef _DEBUG static bool printOnce = true; if ( printOnce == true && outputLength > MTU ) { printf( "Warning - compressed data larger than MTU! This will result in split packets and poor speech.\nYou should use a lower blockSize in the call to Init.\n" ); printOnce = false; } else if ( printOnce == true && outputLength < MTU / 4 ) { printf( "Warning - compressed data smaller than 1/4 the MTU. This is not an efficient use of bandwidth.\nYou might want to use a larger blockSize in the call to Init.\n" ); printOnce = false; } #endif b.Reset(); typeID = ID_VOICE_PACKET; b.Write( typeID ); b.Write( ( char* ) & target, sizeof( target ) ); b.Write( rakVoice->bps ); // Write how many bits we are encoding the data with b.Write( rakVoice->sampleRate ); // Write the sampling rate id = rakVoice->peer->GetInternalID(); b.Write( ( char* ) & id, sizeof( id ) ); // Write who is sending this packet b.Write( cswpims->nextPacketNumber ); // Write what speech packet number this is, so we can compensate for lost packets cswpims->nextPacketNumber++; b.Write( output, outputLength ); /* // This is for showing memory usage printf("PCMQueue=%i PCMQueuePool=%i\ndecoderStateList=%i encoderStateList=%i\n", rakVoice->PCMQueue.size(), rakVoice->PCMQueuePool.size(), rakVoice->decoderStateList.size(), rakVoice->encoderStateList.size()); */ // THis was for testing as a feedback loop //if (target==rakVoice->peer->GetInternalID()) // rakVoice->DecodeAndQueueSoundPacket((char*)b.GetData(), b.GetNumberOfBytesUsed()); //else rakVoice->peer->Send( &b, HIGH_PRIORITY, RELIABLE_SEQUENCED, 0, target, false ); lastSendTime = RakNet::GetTime(); } // Send out a packet aggreggate roughly every x ms #ifdef _WIN32 Sleep( 30 ); #else usleep( 30 * 1000 ); #endif } speex_bits_destroy( &bits ); return 0; }