This commit is contained in:
2025-11-24 14:19:51 +05:30
commit f5c1412b28
6734 changed files with 1527575 additions and 0 deletions

View File

@ -0,0 +1,908 @@
/*
* Original work: Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
*
*
* Modified work: Copyright (c) 2017-2020, SLikeSoft UG (haftungsbeschränkt)
*
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
* license found in the license.txt file in the root directory of this source tree.
*/
#include "RakVoice.h"
#include "speex/speex.h"
#include "speex/speex_preprocess.h"
#include "slikenet/BitStream.h"
#include "slikenet/PacketPriority.h"
#include "slikenet/MessageIdentifiers.h"
#include "slikenet/BitStream.h"
#include "slikenet/peerinterface.h"
#include <stdlib.h>
#include "slikenet/GetTime.h"
#ifdef _DEBUG
#include <stdio.h>
#endif
using namespace SLNet;
//#define PRINT_DEBUG_INFO
#define SAMPLESIZE 2
#ifdef PRINT_DEBUG_INFO
#include <stdio.h>
#endif
int SLNet::VoiceChannelComp( const RakNetGUID &key, VoiceChannel * const &data )
{
if (key < data->guid)
return -1;
if (key == data->guid)
return 0;
return 1;
}
RakVoice::RakVoice()
{
bufferedOutput=0;
defaultEncoderComplexity=2;
defaultVADState=true;
defaultDENOISEState=false;
defaultVBRState=false;
loopbackMode=false;
}
RakVoice::~RakVoice()
{
Deinit();
}
// #med - change member variable - then revert argument to sampleRate/bufferSizeBytes
void RakVoice::Init(unsigned short speexSampleRate, unsigned newBufferSizeBytes)
{
// Record the parameters
RakAssert(speexSampleRate==8000 || speexSampleRate==16000 || speexSampleRate==32000);
sampleRate=speexSampleRate;
bufferSizeBytes=newBufferSizeBytes;
bufferedOutputCount=newBufferSizeBytes/SAMPLESIZE;
bufferedOutput = (float*) rakMalloc_Ex(sizeof(float)*bufferedOutputCount, _FILE_AND_LINE_);
unsigned i;
for (i=0; i < bufferedOutputCount; i++)
bufferedOutput[i]=0.0f;
zeroBufferedOutput=false;
}
void RakVoice::Deinit(void)
{
// check pointer before free
if (bufferedOutput)
{
rakFree_Ex(bufferedOutput, _FILE_AND_LINE_ );
bufferedOutput = 0;
CloseAllChannels();
}
}
void RakVoice::SetLoopbackMode(bool enabled)
{
if (enabled)
{
Packet p;
SLNet::BitStream out;
out.Write((unsigned char)ID_RAKVOICE_OPEN_CHANNEL_REQUEST);
out.Write((int32_t)sampleRate);
p.data=out.GetData();
p.systemAddress= SLNet::UNASSIGNED_SYSTEM_ADDRESS;
p.guid=UNASSIGNED_RAKNET_GUID;
p.length=out.GetNumberOfBytesUsed();
OpenChannel(&p);
}
else
{
FreeChannelMemory(UNASSIGNED_RAKNET_GUID);
}
loopbackMode=enabled;
}
bool RakVoice::IsLoopbackMode(void) const
{
return loopbackMode;
}
void RakVoice::RequestVoiceChannel(RakNetGUID recipient)
{
// Send a reliable ordered message to the other system to open a voice channel
SLNet::BitStream out;
out.Write((unsigned char)ID_RAKVOICE_OPEN_CHANNEL_REQUEST);
out.Write((int32_t)sampleRate);
SendUnified(&out, HIGH_PRIORITY, RELIABLE_ORDERED,0,recipient,false);
}
void RakVoice::CloseVoiceChannel(RakNetGUID recipient)
{
FreeChannelMemory(recipient);
// Send a message to the remote system telling them to close the channel
SLNet::BitStream out;
out.Write((unsigned char)ID_RAKVOICE_CLOSE_CHANNEL);
SendUnified(&out, HIGH_PRIORITY, RELIABLE_ORDERED,0,recipient,false);
}
void RakVoice::CloseAllChannels(void)
{
SLNet::BitStream out;
out.Write((unsigned char)ID_RAKVOICE_CLOSE_CHANNEL);
// Free the memory for all channels
unsigned index;
for (index=0; index < voiceChannels.Size(); index++)
{
SendUnified(&out, HIGH_PRIORITY, RELIABLE_ORDERED,0,voiceChannels[index]->guid,false);
FreeChannelMemory(index,false);
}
voiceChannels.Clear(false, _FILE_AND_LINE_);
}
bool RakVoice::SendFrame(RakNetGUID recipient, void *inputBuffer)
{
bool objectExists;
unsigned index;
VoiceChannel *channel;
index = voiceChannels.GetIndexFromKey(recipient, &objectExists);
if (objectExists)
{
unsigned totalBufferSize;
unsigned remainingBufferSize;
channel=voiceChannels[index];
totalBufferSize=bufferSizeBytes * FRAME_OUTGOING_BUFFER_COUNT;
if (channel->outgoingWriteIndex >= channel->outgoingReadIndex)
remainingBufferSize=totalBufferSize-(channel->outgoingWriteIndex-channel->outgoingReadIndex);
else
remainingBufferSize=channel->outgoingReadIndex-channel->outgoingWriteIndex;
#ifdef _DEBUG
RakAssert(remainingBufferSize>0 && remainingBufferSize <= totalBufferSize);
// printf("SendFrame: buff=%i writeIndex=%i readIndex=%i\n",remainingBufferSize, channel->outgoingWriteIndex, channel->outgoingReadIndex);
//printf("Writing %i bytes to write offset %i. %i %i.\n", bufferSizeBytes, channel->outgoingWriteIndex, *((char*)inputBuffer+channel->outgoingWriteIndex), *((char*)inputBuffer+channel->outgoingWriteIndex+bufferSizeBytes-1));
#endif
// Copy encoded sound to the outgoing buffer for that channel. This has to be fast, since this function is likely to be called from a locked buffer
// I allocated the buffer to be a size multiple of bufferSizeBytes so don't have to watch for overflow on this line
memcpy(channel->outgoingBuffer + channel->outgoingWriteIndex, inputBuffer, bufferSizeBytes );
#ifdef _DEBUG
RakAssert(channel->outgoingWriteIndex+bufferSizeBytes <= totalBufferSize);
#endif
// Increment the write index, wrapping if needed.
channel->outgoingWriteIndex+=bufferSizeBytes;
#ifdef _DEBUG
// Verify that the write is aligned to the size of outgoingBuffer
RakAssert(channel->outgoingWriteIndex <= totalBufferSize);
#endif
if (channel->outgoingWriteIndex==totalBufferSize)
channel->outgoingWriteIndex=0;
if (bufferSizeBytes >= remainingBufferSize) // Would go past the current read position
{
#ifdef _DEBUG
// This is actually a warning - it means that FRAME_OUTGOING_BUFFER_COUNT wasn't big enough and old data is being overwritten
RakAssert(0);
#endif
// Force the read index up one block
channel->outgoingReadIndex=(channel->outgoingReadIndex+channel->speexOutgoingFrameSampleCount * SAMPLESIZE)%totalBufferSize;
}
return true;
}
return false;
}
bool RakVoice::IsSendingVoiceDataTo(RakNetGUID recipient)
{
bool objectExists;
unsigned index;
index = voiceChannels.GetIndexFromKey(recipient, &objectExists);
// Free the memory for this channel
if (objectExists)
return voiceChannels[index]->isSendingVoiceData;
return false;
}
void RakVoice::ReceiveFrame(void *outputBuffer)
{
short *out = (short*)outputBuffer;
unsigned i;
// Convert the floats to final 16-bits output
for (i=0; i < bufferSizeBytes / SAMPLESIZE; i++)
{
if (bufferedOutput[i]>32767.0f)
out[i]=32767;
else if (bufferedOutput[i]<-32768.0f)
out[i]=-32768;
else
out[i]=(short)bufferedOutput[i];
}
// Done with this block. Zero all the values in Update
zeroBufferedOutput=true;
}
int RakVoice::GetSampleRate(void) const
{
return sampleRate;
}
int RakVoice::GetBufferSizeBytes(void) const
{
return bufferSizeBytes;
}
bool RakVoice::IsInitialized(void) const
{
// Use bufferedOutput to tell if the object was not initialized
return (bufferedOutput!=0);
}
RakPeerInterface* RakVoice::GetRakPeerInterface(void) const
{
return rakPeerInterface;
}
unsigned RakVoice::GetBufferedBytesToSend(RakNetGUID guid) const
{
bool objectExists;
VoiceChannel *channel;
unsigned totalBufferSize=bufferSizeBytes * FRAME_OUTGOING_BUFFER_COUNT;
if (guid!=UNASSIGNED_RAKNET_GUID)
{
unsigned index = voiceChannels.GetIndexFromKey(guid, &objectExists);
channel = voiceChannels[index];
if (objectExists)
{
if (channel->outgoingWriteIndex>=channel->outgoingReadIndex)
return channel->outgoingWriteIndex-channel->outgoingReadIndex;
else
return channel->outgoingWriteIndex + (totalBufferSize-channel->outgoingReadIndex);
}
}
else
{
unsigned total=0;
for (unsigned i=0; i < voiceChannels.Size(); i++)
{
channel=voiceChannels[i];
if (channel->outgoingWriteIndex>=channel->outgoingReadIndex)
total+=channel->outgoingWriteIndex-channel->outgoingReadIndex;
else
total+=channel->outgoingWriteIndex + (totalBufferSize-channel->outgoingReadIndex);
}
return total;
}
return 0;
}
unsigned RakVoice::GetBufferedBytesToReturn(RakNetGUID guid) const
{
bool objectExists;
VoiceChannel *channel;
unsigned totalBufferSize=bufferSizeBytes * FRAME_OUTGOING_BUFFER_COUNT;
if (guid!=UNASSIGNED_RAKNET_GUID)
{
unsigned index = voiceChannels.GetIndexFromKey(guid, &objectExists);
channel = voiceChannels[index];
if (objectExists)
{
if (channel->incomingReadIndex <= channel->incomingWriteIndex)
return channel->incomingWriteIndex-channel->incomingReadIndex;
else
return totalBufferSize-channel->incomingReadIndex+channel->incomingWriteIndex;
}
}
else
{
unsigned total=0;
for (unsigned i=0; i < voiceChannels.Size(); i++)
{
channel=voiceChannels[i];
if (channel->incomingReadIndex <= channel->incomingWriteIndex)
total+=channel->incomingWriteIndex-channel->incomingReadIndex;
else
total+=totalBufferSize-channel->incomingReadIndex+channel->incomingWriteIndex;
}
return total;
}
return 0;
}
void RakVoice::OnShutdown(void)
{
CloseAllChannels();
}
void RakVoice::Update(void)
{
unsigned i,j, bytesAvailable, speexFramesAvailable, speexBlockSize;
unsigned bytesWaitingToReturn;
int bytesWritten;
VoiceChannel *channel;
char *inputBuffer;
char tempOutput[2048];
// 1 byte for ID, and 2 bytes(short) for Message number
static const int headerSize=sizeof(unsigned char) + sizeof(unsigned short);
// First byte is ID for RakNet
tempOutput[0]=ID_RAKVOICE_DATA;
SLNet::TimeMS currentTime = SLNet::GetTimeMS();
// Size of VoiceChannel::incomingBuffer and VoiceChannel::outgoingBuffer arrays
unsigned totalBufferSize=bufferSizeBytes * FRAME_OUTGOING_BUFFER_COUNT;
// Allow all channels to write, and set the output to zero in preparation
if (zeroBufferedOutput)
{
for (i=0; i < bufferedOutputCount; i++)
bufferedOutput[i]=0.0f;
for (i=0; i < voiceChannels.Size(); i++)
voiceChannels[i]->copiedOutgoingBufferToBufferedOutput=false;
zeroBufferedOutput=false;
}
// For each channel
for (i=0; i < voiceChannels.Size(); i++)
{
channel=voiceChannels[i];
if (currentTime - channel->lastSend > 50) // Throttle to 20 sends a second
{
channel->isSendingVoiceData=false;
// Circular buffer so I have to do this to count how many bytes are available
if (channel->outgoingWriteIndex>=channel->outgoingReadIndex)
bytesAvailable=channel->outgoingWriteIndex-channel->outgoingReadIndex;
else
bytesAvailable=channel->outgoingWriteIndex + (totalBufferSize-channel->outgoingReadIndex);
// Speex returns how many frames it encodes per block. Each frame is of byte length sampleSize.
speexBlockSize = channel->speexOutgoingFrameSampleCount * SAMPLESIZE;
#ifdef PRINT_DEBUG_INFO
static int lastPrint=0;
if (i==0 && currentTime-lastPrint > 2000)
{
lastPrint=currentTime;
unsigned bytesWaitingToReturn;
if (channel->incomingReadIndex <= channel->incomingWriteIndex)
bytesWaitingToReturn=channel->incomingWriteIndex-channel->incomingReadIndex;
else
bytesWaitingToReturn=totalBufferSize-channel->incomingReadIndex+channel->incomingWriteIndex;
printf("%i bytes to send. incomingMessageNumber=%i. bytesWaitingToReturn=%i.\n", bytesAvailable, channel->incomingMessageNumber, bytesWaitingToReturn );
}
#endif
#ifdef _TEST_LOOPBACK
/*
if (bufferSizeBytes<bytesAvailable)
{
printf("Update: bytesAvailable=%i writeIndex=%i readIndex=%i\n",bytesAvailable, channel->outgoingWriteIndex, channel->outgoingReadIndex);
memcpy(channel->incomingBuffer + channel->incomingWriteIndex, channel->outgoingBuffer+channel->outgoingReadIndex, bufferSizeBytes);
channel->incomingWriteIndex=(channel->incomingWriteIndex+bufferSizeBytes) % totalBufferSize;
channel->outgoingReadIndex=(channel->outgoingReadIndex+bufferSizeBytes) % totalBufferSize;
}
return;
*/
#endif
// Find out how many frames we can read out of the buffer for speex to encode and send these out.
speexFramesAvailable = bytesAvailable / speexBlockSize;
// Encode all available frames and send them unreliable sequenced
if (speexFramesAvailable > 0)
{
SpeexBits speexBits;
speex_bits_init(&speexBits);
while (speexFramesAvailable-- > 0)
{
speex_bits_reset(&speexBits);
// If the input data would wrap around the buffer, copy it to another buffer first
if (channel->outgoingReadIndex + speexBlockSize >= totalBufferSize)
{
#ifdef _DEBUG
RakAssert(speexBlockSize < 2048-1);
#endif
unsigned t;
for (t=0; t < speexBlockSize; t++)
tempOutput[t+headerSize]=channel->outgoingBuffer[t%totalBufferSize];
inputBuffer=tempOutput+headerSize;
}
else
inputBuffer=channel->outgoingBuffer+channel->outgoingReadIndex;
#ifdef _DEBUG
/*
printf("In: ");
if (shortSampleType)
{
short *blah = (short*) inputBuffer;
for (int p=0; p < 5; p++)
{
printf("%.i ", blah[p]);
}
}
else
{
float *blah = (float*) inputBuffer;
for (int p=0; p < 5; p++)
{
printf("%.3f ", blah[p]);
}
}
printf("\n");
*/
#endif
int is_speech=1;
// Run preprocessor if required
if (defaultDENOISEState||defaultVADState){
is_speech=speex_preprocess((SpeexPreprocessState*)channel->pre_state,(spx_int16_t*) inputBuffer, nullptr);
}
if ((is_speech)||(!defaultVADState)){
is_speech = speex_encode_int(channel->enc_state, (spx_int16_t*) inputBuffer, &speexBits);
}
channel->outgoingReadIndex=(channel->outgoingReadIndex+speexBlockSize)%totalBufferSize;
// If no speech detected, don't send this frame
if ((!is_speech)&&(defaultVADState)){
continue;
}
channel->isSendingVoiceData=true;
#ifdef _DEBUG
// printf("Update: bytesAvailable=%i writeIndex=%i readIndex=%i\n",bytesAvailable, channel->outgoingWriteIndex, channel->outgoingReadIndex);
#endif
bytesWritten = speex_bits_write(&speexBits, tempOutput+headerSize, 2048-headerSize);
#ifdef _DEBUG
// If this assert hits then you need to increase the size of the temp buffer, but this is really a bug because
// voice packets should never be bigger than a few hundred bytes.
RakAssert(bytesWritten!=2048-headerSize);
#endif
// static int bytesSent=0;
// bytesSent+= bytesWritten+headerSize;
// printf("bytesSent=%i\n", bytesSent);
#ifdef PRINT_DEBUG_INFO
static int voicePacketsSent=0;
printf("%i ", voicePacketsSent++);
#endif
// at +1, because the first byte in the buffer has the ID for RakNet.
memcpy(tempOutput+1, &channel->outgoingMessageNumber, sizeof(unsigned short));
channel->outgoingMessageNumber++;
SLNet::BitStream tempOutputBs((unsigned char*) tempOutput,bytesWritten+headerSize,false);
SendUnified(&tempOutputBs, HIGH_PRIORITY, UNRELIABLE,0,channel->guid,false);
if (loopbackMode)
{
Packet p;
p.length=bytesWritten+1;
p.data=(unsigned char*)tempOutput;
p.guid=channel->guid;
p.systemAddress=rakPeerInterface->GetSystemAddressFromGuid(p.guid);
OnVoiceData(&p);
}
}
speex_bits_destroy(&speexBits);
channel->lastSend=currentTime;
}
}
// As sound buffer blocks fill up, I add their values to RakVoice::bufferedOutput . Then when the user calls ReceiveFrame they get that value, already
// processed. This is necessary because that function needs to run as fast as possible so I remove all processing there that I can. Otherwise the sound
// plays back distorted and popping
if (channel->copiedOutgoingBufferToBufferedOutput==false)
{
if (channel->incomingReadIndex <= channel->incomingWriteIndex)
bytesWaitingToReturn=channel->incomingWriteIndex-channel->incomingReadIndex;
else
bytesWaitingToReturn=totalBufferSize-channel->incomingReadIndex+channel->incomingWriteIndex;
if (bytesWaitingToReturn==0)
{
channel->bufferOutput=true;
}
else if (channel->bufferOutput==false || bytesWaitingToReturn > bufferSizeBytes*2)
{
// Block running this again until the user calls ReceiveFrame since every call to ReceiveFrame only gets zero or one output blocks from
// each channel
channel->copiedOutgoingBufferToBufferedOutput=true;
// Stop buffering output. We won't start buffering again until there isn't enough data to read.
channel->bufferOutput=false;
// Cap to the size of the output buffer. But we do write less if less is available, with the rest silence
if (bytesWaitingToReturn > bufferSizeBytes)
{
bytesWaitingToReturn=bufferSizeBytes;
}
else
{
// Align the write index so when we increment the partial block read (which is always aligned) it computes out to 0 bytes waiting
channel->incomingWriteIndex=channel->incomingReadIndex+bufferSizeBytes;
if (channel->incomingWriteIndex==totalBufferSize)
channel->incomingWriteIndex=0;
}
short *in = (short *) (channel->incomingBuffer+channel->incomingReadIndex);
for (j=0; j < bytesWaitingToReturn / SAMPLESIZE; j++)
{
// Write short to float so if the range goes over the range of a float we can still add and subtract the correct final value.
// It will be clamped at the end
bufferedOutput[j]+=in[j%(totalBufferSize/SAMPLESIZE)];
}
// Update the read index. Always update by bufferSizeBytes, not bytesWaitingToReturn.
// if bytesWaitingToReturn < bufferSizeBytes then the rest is silence since this means the buffer ran out or we stopped sending.
channel->incomingReadIndex+=bufferSizeBytes;
if (channel->incomingReadIndex==totalBufferSize)
channel->incomingReadIndex=0;
// printf("%f %f\n", channel->incomingReadIndex/(float)bufferSizeBytes, channel->incomingWriteIndex/(float)bufferSizeBytes);
}
}
}
}
PluginReceiveResult RakVoice::OnReceive(Packet *packet)
{
RakAssert(packet);
switch (packet->data[0])
{
case ID_RAKVOICE_OPEN_CHANNEL_REQUEST:
OnOpenChannelRequest(packet);
break;
case ID_RAKVOICE_OPEN_CHANNEL_REPLY:
OnOpenChannelReply(packet);
break;
case ID_RAKVOICE_CLOSE_CHANNEL:
FreeChannelMemory(packet->guid);
break;
case ID_RAKVOICE_DATA:
OnVoiceData(packet);
return RR_STOP_PROCESSING_AND_DEALLOCATE;
}
return RR_CONTINUE_PROCESSING;
}
void RakVoice::OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
{
(void)systemAddress;
if (lostConnectionReason==LCR_CLOSED_BY_USER)
CloseVoiceChannel(rakNetGUID);
else
FreeChannelMemory(rakNetGUID);
}
void RakVoice::OnOpenChannelRequest(Packet *packet)
{
if (voiceChannels.HasData(packet->guid))
return;
// If the system is not initialized, just return
if (bufferedOutput==0)
return;
OpenChannel(packet);
SLNet::BitStream out;
out.Write((unsigned char)ID_RAKVOICE_OPEN_CHANNEL_REPLY);
out.Write((int32_t)sampleRate);
SendUnified(&out, HIGH_PRIORITY, RELIABLE_ORDERED,0,packet->systemAddress,false);
}
void RakVoice::OnOpenChannelReply(Packet *packet)
{
if (voiceChannels.HasData(packet->guid))
return;
OpenChannel(packet);
}
void RakVoice::OpenChannel(Packet *packet)
{
SLNet::BitStream in(packet->data, packet->length, false);
in.IgnoreBits(8);
FreeChannelMemory(packet->guid);
VoiceChannel *channel= SLNet::OP_NEW<VoiceChannel>( _FILE_AND_LINE_ );
channel->guid=packet->guid;
channel->isSendingVoiceData=false;
int newSampleRate;
in.Read(newSampleRate);
channel->remoteSampleRate=newSampleRate;
if (channel->remoteSampleRate!=8000 && channel->remoteSampleRate!=16000 && channel->remoteSampleRate!=32000)
{
#ifdef _DEBUG
RakAssert(0);
#endif
SLNet::OP_DELETE(channel, _FILE_AND_LINE_);
return;
}
if (newSampleRate==8000)
channel->enc_state=speex_encoder_init(&speex_nb_mode);
else if (newSampleRate==16000)
channel->enc_state=speex_encoder_init(&speex_wb_mode);
else // 32000
channel->enc_state=speex_encoder_init(&speex_uwb_mode);
if (channel->remoteSampleRate==8000)
channel->dec_state=speex_decoder_init(&speex_nb_mode);
else if (channel->remoteSampleRate==16000)
channel->dec_state=speex_decoder_init(&speex_wb_mode);
else // 32000
channel->dec_state=speex_decoder_init(&speex_uwb_mode);
// make sure encoder and decoder are created
RakAssert((channel->enc_state)&&(channel->dec_state));
int ret;
ret=speex_encoder_ctl(channel->enc_state, SPEEX_GET_FRAME_SIZE, &channel->speexOutgoingFrameSampleCount);
RakAssert(ret==0);
channel->outgoingBuffer = (char*) rakMalloc_Ex(bufferSizeBytes * FRAME_OUTGOING_BUFFER_COUNT, _FILE_AND_LINE_);
channel->outgoingReadIndex=0;
channel->outgoingWriteIndex=0;
channel->bufferOutput=true;
channel->outgoingMessageNumber=0;
channel->copiedOutgoingBufferToBufferedOutput=false;
ret=speex_decoder_ctl(channel->dec_state, SPEEX_GET_FRAME_SIZE, &channel->speexIncomingFrameSampleCount);
RakAssert(ret==0);
channel->incomingBuffer = (char*) rakMalloc_Ex(bufferSizeBytes * FRAME_INCOMING_BUFFER_COUNT, _FILE_AND_LINE_);
channel->incomingReadIndex=0;
channel->incomingWriteIndex=0;
channel->lastSend=0;
channel->incomingMessageNumber=0;
// Initialize preprocessor
channel->pre_state = speex_preprocess_state_init(channel->speexOutgoingFrameSampleCount, newSampleRate);
RakAssert(channel->pre_state);
// Set encoder default parameters
SetEncoderParameter(channel->enc_state, SPEEX_SET_VBR, (defaultVBRState) ? 1 : 0 );
SetEncoderParameter(channel->enc_state, SPEEX_SET_COMPLEXITY, defaultEncoderComplexity);
// Set preprocessor default parameters
SetPreprocessorParameter(channel->pre_state, SPEEX_PREPROCESS_SET_DENOISE, (defaultDENOISEState) ? 1 : 2);
SetPreprocessorParameter(channel->pre_state, SPEEX_PREPROCESS_SET_VAD, (defaultVADState) ? 1 : 2);
voiceChannels.Insert(packet->guid, channel, true, _FILE_AND_LINE_);
}
void RakVoice::SetEncoderParameter(void* enc_state, int vartype, int val)
{
if (enc_state){
// Set parameter for just one encoder
SLNET_VERIFY(speex_encoder_ctl(enc_state, vartype, &val) == 0);
} else {
// Set parameter for all encoders
for (unsigned int index=0; index < voiceChannels.Size(); index++)
{
SLNET_VERIFY(speex_encoder_ctl(voiceChannels[index]->enc_state, vartype, &val) == 0);
}
}
}
void RakVoice::SetPreprocessorParameter(void* pre_state, int vartype, int val)
{
if (pre_state){
// Set parameter for just one preprocessor
SLNET_VERIFY(speex_preprocess_ctl((SpeexPreprocessState*)pre_state, vartype, &val) == 0);
} else {
// Set parameter for all decoders
for (unsigned int index=0; index < voiceChannels.Size(); index++)
{
SLNET_VERIFY(speex_preprocess_ctl((SpeexPreprocessState*)voiceChannels[index]->pre_state, vartype, &val) == 0);
}
}
}
void RakVoice::SetEncoderComplexity(int complexity)
{
RakAssert((complexity>=0)&&(complexity<=10));
SetEncoderParameter(nullptr, SPEEX_SET_COMPLEXITY, complexity);
defaultEncoderComplexity = complexity;
}
void RakVoice::SetVAD(bool enable)
{
SetPreprocessorParameter(nullptr, SPEEX_PREPROCESS_SET_VAD, (enable)? 1 : 2);
defaultVADState = enable;
}
void RakVoice::SetNoiseFilter(bool enable)
{
SetPreprocessorParameter(nullptr, SPEEX_PREPROCESS_SET_DENOISE, (enable) ? 1 : 2);
defaultDENOISEState = enable;
}
void RakVoice::SetVBR(bool enable)
{
SetEncoderParameter(nullptr, SPEEX_SET_VBR, (enable) ? 1 : 0);
defaultVBRState = enable;
}
int RakVoice::GetEncoderComplexity(void)
{
return defaultEncoderComplexity;
}
bool RakVoice::IsVADActive(void)
{
return defaultVADState;
}
bool RakVoice::IsNoiseFilterActive()
{
return defaultDENOISEState;
}
bool RakVoice::IsVBRActive()
{
return defaultVBRState;
}
void RakVoice::FreeChannelMemory(RakNetGUID recipient)
{
bool objectExists;
unsigned index;
index = voiceChannels.GetIndexFromKey(recipient, &objectExists);
// Free the memory for this channel
if (objectExists)
{
FreeChannelMemory(index, true);
}
}
void RakVoice::FreeChannelMemory(unsigned index, bool removeIndex)
{
VoiceChannel *channel;
channel=voiceChannels[index];
speex_encoder_destroy(channel->enc_state);
speex_decoder_destroy(channel->dec_state);
speex_preprocess_state_destroy((SpeexPreprocessState*)channel->pre_state);
rakFree_Ex(channel->incomingBuffer, _FILE_AND_LINE_ );
rakFree_Ex(channel->outgoingBuffer, _FILE_AND_LINE_ );
SLNet::OP_DELETE(channel, _FILE_AND_LINE_);
if (removeIndex)
voiceChannels.RemoveAtIndex(index);
}
void RakVoice::OnVoiceData(Packet *packet)
{
bool objectExists;
unsigned index;
unsigned short packetMessageNumber, messagesSkipped;
VoiceChannel *channel;
char tempOutput[2048];
unsigned int i;
// 1 byte for ID, 2 bytes(short) for message number
static const int headerSize=sizeof(unsigned char) + sizeof(unsigned short);
index = voiceChannels.GetIndexFromKey(packet->guid, &objectExists);
if (objectExists)
{
SpeexBits speexBits;
speex_bits_init(&speexBits);
channel=voiceChannels[index];
memcpy(&packetMessageNumber, packet->data+1, sizeof(unsigned short));
// Intentional overflow
messagesSkipped=packetMessageNumber-channel->incomingMessageNumber;
if (messagesSkipped > ((unsigned short)-1)/2)
{
#ifdef PRINT_DEBUG_INFO
printf("--- UNDERFLOW ---\n");
#endif
// Underflow, just ignore it
return;
}
#ifdef PRINT_DEBUG_INFO
if (messagesSkipped>0)
printf("%i messages skipped\n", messagesSkipped);
#endif
// Don't do more than 100 ms of messages skipped. Discard the rest.
int maxSkip = (int)(100.0f / (float) sampleRate);
for (i=0; i < (unsigned) messagesSkipped && i < (unsigned) maxSkip; i++)
{
speex_decode_int(channel->dec_state, 0, (spx_int16_t*)tempOutput);
// Write to buffer a 'message skipped' interpolation
WriteOutputToChannel(channel, tempOutput);
}
channel->incomingMessageNumber=packetMessageNumber+1;
// Write to incomingBuffer the decoded data
speex_bits_read_from(&speexBits, (char*)(packet->data+headerSize), packet->length-headerSize);
speex_decode_int(channel->dec_state, &speexBits, (spx_int16_t*)tempOutput);
#ifdef _DEBUG
{
/*
printf("Out: ");
if (channel->remoteIsShortSampleType)
{
short *blah = (short*) tempOutput;
for (int p=0; p < 5; p++)
{
printf("%.i ", blah[p]);
}
}
else
{
float *blah = (float*) tempOutput;
for (int p=0; p < 5; p++)
{
printf("%.3f ", blah[p]);
}
}
printf("\n");
*/
}
#endif
// Write to buffer
WriteOutputToChannel(channel, tempOutput);
speex_bits_destroy(&speexBits);
}
}
void RakVoice::WriteOutputToChannel(VoiceChannel *channel, char *dataToWrite)
{
unsigned totalBufferSize;
unsigned remainingBufferSize;
unsigned speexBlockSize;
totalBufferSize=bufferSizeBytes * FRAME_INCOMING_BUFFER_COUNT;
if (channel->incomingWriteIndex >= channel->incomingReadIndex)
remainingBufferSize=totalBufferSize-(channel->incomingWriteIndex-channel->incomingReadIndex);
else
remainingBufferSize=channel->incomingReadIndex-channel->incomingWriteIndex;
// Speex returns how many frames it encodes per block. Each frame is of byte length sampleSize.
speexBlockSize = channel->speexIncomingFrameSampleCount * SAMPLESIZE;
if (channel->incomingWriteIndex+speexBlockSize <= totalBufferSize)
{
memcpy(channel->incomingBuffer + channel->incomingWriteIndex, dataToWrite, speexBlockSize);
}
else
{
memcpy(channel->incomingBuffer + channel->incomingWriteIndex, dataToWrite, totalBufferSize-channel->incomingWriteIndex);
memcpy(channel->incomingBuffer, dataToWrite, speexBlockSize-(totalBufferSize-channel->incomingWriteIndex));
}
channel->incomingWriteIndex=(channel->incomingWriteIndex+speexBlockSize) % totalBufferSize;
#ifdef _DEBUG
//printf("WriteOutputToChannel: buff=%i writeIndex=%i readIndex=%i\n",remainingBufferSize, channel->incomingWriteIndex, channel->incomingReadIndex);
#endif
if (bufferSizeBytes >= remainingBufferSize) // Would go past the current read position
{
#ifdef _DEBUG
// This is actually a warning - it means that FRAME_INCOMING_BUFFER_COUNT wasn't big enough and old data is being overwritten
RakAssert(0);
#endif
// Force the read index up one block
channel->incomingReadIndex+=bufferSizeBytes;
if (channel->incomingReadIndex==totalBufferSize)
channel->incomingReadIndex=0;
}
}