sending multi packets for nosteamers. reducing torchlight to 24000 hertz and mono channel at 32k bitrate
This commit is contained in:
parent
718284e7dd
commit
ddad8421e7
328
extension.cpp
328
extension.cpp
@ -284,6 +284,7 @@ CVoice::CVoice()
|
||||
m_aClients[i].m_Socket = -1;
|
||||
|
||||
m_OpusEncoder = NULL;
|
||||
m_TorchlightSeqNum = 0;
|
||||
m_AvailableTime = 0.0;
|
||||
|
||||
m_VoiceDetour = NULL;
|
||||
@ -429,19 +430,18 @@ bool CVoice::SDK_OnLoad(char *error, size_t maxlength, bool late)
|
||||
|
||||
//opus edit
|
||||
int err;
|
||||
m_OpusEncoder = opus_encoder_create(48000, 2, OPUS_APPLICATION_AUDIO, &err);
|
||||
m_OpusEncoder = opus_encoder_create(24000, 1, OPUS_APPLICATION_AUDIO, &err);
|
||||
//m_OpusEncoder = opus_encoder_create(48000, 2, OPUS_APPLICATION_AUDIO, &err);
|
||||
if (err<0)
|
||||
{
|
||||
smutils->LogError(myself, "failed to create encode: %s", opus_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
opus_encoder_ctl(m_OpusEncoder, OPUS_SET_BITRATE(128000));
|
||||
opus_encoder_ctl(m_OpusEncoder, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
|
||||
//opus_encoder_ctl(m_OpusEncoder, OPUS_SET_BITRATE(128000));
|
||||
opus_encoder_ctl(m_OpusEncoder, OPUS_SET_BITRATE(32000));
|
||||
opus_encoder_ctl(m_OpusEncoder, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); //required for forcing hybrid mode to get TOC 0x68
|
||||
opus_encoder_ctl(m_OpusEncoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); //MDCT mode
|
||||
opus_encoder_ctl(m_OpusEncoder, OPUS_SET_LSB_DEPTH(16));
|
||||
opus_encoder_ctl(m_OpusEncoder, OPUS_SET_PACKET_LOSS_PERC(0));
|
||||
opus_encoder_ctl(m_OpusEncoder, OPUS_SET_FORCE_CHANNELS(2));
|
||||
|
||||
if (err<0)
|
||||
{
|
||||
@ -771,7 +771,7 @@ void CVoice::SDK_OnUnload()
|
||||
void CVoice::OnGameFrame(bool simulating)
|
||||
{
|
||||
HandleNetwork();
|
||||
HandleVoiceData(); //torchlight audio emitting
|
||||
HandleVoiceDataTorchlight(); //torchlight audio emitting
|
||||
HandleNoSteamVoiceData(); //send opus packets to steamers.
|
||||
|
||||
//send celt packets to nosteamers
|
||||
@ -784,7 +784,7 @@ void CVoice::OnGameFrame(bool simulating)
|
||||
// Keep draining 512-sample blocks until the buffer has less than one full frame remaining
|
||||
while (m_playerVoiceBuffer[i].TotalLength() >= m_CeltEncoderSettings.FrameSize)
|
||||
{
|
||||
HandlePlayerVoiceData(i);
|
||||
HandlePlayerVoiceData(i); //send celt packets to nosteamers
|
||||
}
|
||||
}
|
||||
|
||||
@ -971,130 +971,96 @@ void CVoice::OnDataReceived(CClient *pClient, int16_t *pData, size_t Samples)
|
||||
pClient->m_LastValidData = getTime();
|
||||
}
|
||||
|
||||
|
||||
void CVoice::HandleVoiceData()
|
||||
void CVoice::HandleVoiceDataTorchlight()
|
||||
{
|
||||
uint32_t sampleRate = 48000;
|
||||
const int SamplesPerChannel = 480;
|
||||
const int Channels = 2;
|
||||
int TotalSamplesPerFrame = SamplesPerChannel * Channels;
|
||||
const uint32_t sampleRate = 24000;
|
||||
const int SamplesPerFrame = 480;
|
||||
|
||||
int FramesAvailable = m_Buffer.TotalLength() / TotalSamplesPerFrame;
|
||||
if(!FramesAvailable)
|
||||
return;
|
||||
|
||||
//int FramesMax = 5;
|
||||
int FramesMax = 2; //used to be 5
|
||||
bool reset_state = false;
|
||||
if (FramesAvailable <= FramesMax)
|
||||
{
|
||||
reset_state = true;
|
||||
}
|
||||
FramesAvailable = min_ext(FramesAvailable, FramesMax);
|
||||
|
||||
// Allow less buffering after audio has started playing
|
||||
if (m_Buffer.TotalLength() < TotalSamplesPerFrame)
|
||||
if (m_Buffer.TotalLength() < SamplesPerFrame)
|
||||
return;
|
||||
|
||||
float TimeAvailable = (float)m_Buffer.TotalLength() / sampleRate;
|
||||
if (m_AvailableTime < getTime() && TimeAvailable < 0.2)
|
||||
return;
|
||||
|
||||
double maxBuffer = (m_AvailableTime < getTime()) ? 0.2 : 0.04;
|
||||
if (m_AvailableTime > getTime() + maxBuffer)
|
||||
if (m_AvailableTime > getTime() + 0.2)
|
||||
{
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
IClient *pClient = iserver->GetClient(0);
|
||||
if(!pClient)
|
||||
if (!pClient)
|
||||
return;
|
||||
|
||||
unsigned char aFinal[8192];
|
||||
size_t FinalSize = 0;
|
||||
|
||||
// 1. Steam Account ID (4 bytes)
|
||||
uint32_t steamID = 1;
|
||||
memcpy(&aFinal[FinalSize], &steamID, sizeof(uint32_t));
|
||||
FinalSize += sizeof(uint32_t);
|
||||
|
||||
// 2. Steam Community (4 bytes)
|
||||
uint32_t steamCommunity = 0x01100001;
|
||||
memcpy(&aFinal[FinalSize], &steamCommunity, sizeof(uint32_t));
|
||||
FinalSize += sizeof(uint32_t);
|
||||
|
||||
// 3. Payload Type 11 (1 byte)
|
||||
aFinal[FinalSize++] = 0x0B;
|
||||
|
||||
// 4. Sample Rate (2 bytes little-endian)
|
||||
memcpy(&aFinal[FinalSize], &sampleRate, sizeof(uint16_t));
|
||||
FinalSize += sizeof(uint16_t);
|
||||
aFinal[FinalSize++] = 0x06;
|
||||
|
||||
// 5. Payload Type 5 for Opus. 6 for opus plc (1 byte)
|
||||
aFinal[FinalSize++] = 0x05;
|
||||
|
||||
// 6. Reserve space for total data length (2 bytes little-endian)
|
||||
uint16_t *pTotalDataLength = (uint16_t*)&aFinal[FinalSize];
|
||||
size_t totalDataLengthOffset = FinalSize;
|
||||
FinalSize += sizeof(uint16_t);
|
||||
*pTotalDataLength = 0;
|
||||
|
||||
// 7. Encode frames
|
||||
for(int Frame = 0; Frame < FramesAvailable; Frame++)
|
||||
size_t subframeStart = FinalSize;
|
||||
int framesEmitted = 0;
|
||||
|
||||
while (m_Buffer.TotalLength() >= SamplesPerFrame && framesEmitted < 5)
|
||||
{
|
||||
int16_t aBuffer[TotalSamplesPerFrame];
|
||||
int16_t aBuffer[SamplesPerFrame];
|
||||
if (!m_Buffer.Pop(aBuffer, SamplesPerFrame))
|
||||
break;
|
||||
|
||||
size_t OldReadIdx = m_Buffer.m_ReadIndex;
|
||||
size_t OldCurLength = m_Buffer.CurrentLength();
|
||||
size_t OldTotalLength = m_Buffer.TotalLength();
|
||||
size_t headerOffset = FinalSize;
|
||||
size_t opusOffset = FinalSize + 4;
|
||||
|
||||
if(!m_Buffer.Pop(aBuffer, TotalSamplesPerFrame))
|
||||
int nbBytes = opus_encode(m_OpusEncoder,
|
||||
(const opus_int16*)aBuffer, SamplesPerFrame,
|
||||
&aFinal[opusOffset], sizeof(aFinal) - opusOffset - 4);
|
||||
if (nbBytes <= 0)
|
||||
{
|
||||
smutils->LogError(myself, "Buffer pop failed!");
|
||||
return;
|
||||
smutils->LogError(myself, "HandleVoiceDataTorchlight: opus_encode failed: %s",
|
||||
opus_strerror(nbBytes));
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t *pFrameSize = (uint16_t*)&aFinal[FinalSize];
|
||||
FinalSize += sizeof(uint16_t);
|
||||
*pFrameSize = sizeof(aFinal) - sizeof(uint32_t) - FinalSize;
|
||||
BroadcastVoiceDataTorchlightCelt(pClient, aBuffer, SamplesPerFrame);
|
||||
|
||||
// Encode with Opus
|
||||
//pcm <tt>opus_int16*</tt>: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16)
|
||||
int nbBytes = opus_encode(m_OpusEncoder, (const opus_int16*)aBuffer, SamplesPerChannel,
|
||||
&aFinal[FinalSize], *pFrameSize);
|
||||
if (nbBytes <= 1)
|
||||
{
|
||||
smutils->LogError(myself, "Opus encode failed: %s", opus_strerror(nbBytes));
|
||||
return;
|
||||
}
|
||||
BroadcastVoiceDataTorchlightCelt(pClient, aBuffer, SamplesPerChannel);
|
||||
aFinal[headerOffset + 0] = (uint8_t)nbBytes;
|
||||
aFinal[headerOffset + 1] = 0x00;
|
||||
aFinal[headerOffset + 2] = (uint8_t)(m_TorchlightSeqNum++ & 0xFF);
|
||||
aFinal[headerOffset + 3] = 0x00;
|
||||
|
||||
// Write frame size
|
||||
*pFrameSize = (uint16_t)nbBytes;
|
||||
*pTotalDataLength += sizeof(uint16_t) + nbBytes;
|
||||
FinalSize += nbBytes;
|
||||
|
||||
// Check for buffer underruns
|
||||
for(int Client = 0; Client < MAX_CLIENTS; Client++)
|
||||
{
|
||||
CClient *pClient = &m_aClients[Client];
|
||||
if(pClient->m_Socket == -1 || pClient->m_New == true)
|
||||
continue;
|
||||
|
||||
m_Buffer.SetWriteIndex(pClient->m_BufferWriteIndex);
|
||||
|
||||
if(m_Buffer.CurrentLength() > pClient->m_LastLength)
|
||||
{
|
||||
pClient->m_BufferWriteIndex = m_Buffer.GetReadIndex();
|
||||
m_Buffer.SetWriteIndex(pClient->m_BufferWriteIndex);
|
||||
pClient->m_LastLength = m_Buffer.CurrentLength();
|
||||
}
|
||||
}
|
||||
FinalSize = opusOffset + nbBytes;
|
||||
framesEmitted++;
|
||||
}
|
||||
|
||||
// 8. Add CRC32
|
||||
|
||||
if (framesEmitted == 0)
|
||||
return;
|
||||
|
||||
if (m_Buffer.TotalLength() < SamplesPerFrame)
|
||||
{
|
||||
opus_encoder_ctl(m_OpusEncoder, OPUS_RESET_STATE);
|
||||
}
|
||||
|
||||
uint16_t totalDataLength = (uint16_t)(FinalSize - subframeStart);
|
||||
memcpy(&aFinal[totalDataLengthOffset], &totalDataLength, sizeof(uint16_t));
|
||||
|
||||
uint32_t crc32_value = UTIL_CRC32(aFinal, FinalSize);
|
||||
memcpy(&aFinal[FinalSize], &crc32_value, sizeof(uint32_t));
|
||||
FinalSize += sizeof(uint32_t);
|
||||
|
||||
|
||||
int maxClients = iserver->GetClientCount();
|
||||
for (int i = 0; i < maxClients; i++)
|
||||
{
|
||||
@ -1104,28 +1070,19 @@ void CVoice::HandleVoiceData()
|
||||
if (g_bClientMuted[i + 1][pClient->GetPlayerSlot()])
|
||||
continue;
|
||||
if (!g_bIsNoSteam[i + 1])
|
||||
{
|
||||
//sending opus packets to steam users.
|
||||
SendVoiceDataMsg(pClient->GetPlayerSlot(), pToClient, aFinal, FinalSize, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_AvailableTime < getTime())
|
||||
m_AvailableTime = getTime();
|
||||
m_AvailableTime += (double)FramesAvailable * 0.01;
|
||||
|
||||
if (reset_state)
|
||||
{
|
||||
opus_encoder_ctl(m_OpusEncoder, OPUS_RESET_STATE);
|
||||
}
|
||||
m_AvailableTime += (double)framesEmitted * (480.0 / 24000.0);
|
||||
}
|
||||
|
||||
void CVoice::BroadcastVoiceDataTorchlightCelt(IClient *pClient, int16_t *pPCM, int nSamples)
|
||||
{
|
||||
// pPCM is stereo interleaved at 48000 Hz (SamplesPerChannel * 2 total samples)
|
||||
// Downsample to mono 22050 Hz and accumulate into m_torchMonoAccum
|
||||
const int STEP = m_CeltEncoderSettings.SampleRate_Hz; // 22050
|
||||
const int DIV = 48000;
|
||||
const int DIV = 24000;
|
||||
const int CELT_FRAME_SIZE = m_CeltEncoderSettings.FrameSize; // 512
|
||||
const int CELT_PACKET_SIZE = m_CeltEncoderSettings.PacketSize; // 64
|
||||
|
||||
@ -1137,7 +1094,7 @@ void CVoice::BroadcastVoiceDataTorchlightCelt(IClient *pClient, int16_t *pPCM, i
|
||||
if (m_torchMonoAccumLen >= 4096)
|
||||
break;
|
||||
|
||||
int32_t mono = ((int32_t)pPCM[i * 2] + (int32_t)pPCM[i * 2 + 1]) / 2;
|
||||
int32_t mono = pPCM[i];
|
||||
if (mono > 32767) mono = 32767;
|
||||
if (mono < -32768) mono = -32768;
|
||||
|
||||
@ -1464,18 +1421,60 @@ void CVoice::HandleNoSteamVoiceData()
|
||||
if (m_nosteamAvailableTime[playerSlot] > getTime() + 1.0)
|
||||
continue;
|
||||
|
||||
IClient *pNoSteamClient = iserver->GetClient(playerSlot);
|
||||
if (!pNoSteamClient)
|
||||
continue;
|
||||
|
||||
const char *networkID = pNoSteamClient->GetNetworkIDString();
|
||||
uint32_t accountID = 0;
|
||||
const char *numStart = strrchr(networkID, ':');
|
||||
if (numStart)
|
||||
accountID = (uint32_t)atoi(numStart + 1);
|
||||
|
||||
unsigned char aFinal[8192];
|
||||
size_t FinalSize = 0;
|
||||
|
||||
// Steam voice packet header (12 bytes fixed)
|
||||
uint32_t steamID = accountID;
|
||||
uint32_t steamCommunity = 0x01100001;
|
||||
memcpy(&aFinal[FinalSize], &steamID, sizeof(uint32_t));
|
||||
FinalSize += sizeof(uint32_t);
|
||||
memcpy(&aFinal[FinalSize], &steamCommunity, sizeof(uint32_t));
|
||||
FinalSize += sizeof(uint32_t);
|
||||
|
||||
aFinal[FinalSize++] = 0x0B; // payload type
|
||||
uint16_t sampleRate = 24000;
|
||||
memcpy(&aFinal[FinalSize], &sampleRate, sizeof(uint16_t));
|
||||
FinalSize += sizeof(uint16_t);
|
||||
aFinal[FinalSize++] = 0x06; // codec type Opus PLC
|
||||
|
||||
// Reserve totalDataLength field
|
||||
size_t totalDataLengthOffset = FinalSize;
|
||||
FinalSize += sizeof(uint16_t);
|
||||
|
||||
// Encode as many 480-sample frames as we can fit
|
||||
size_t subframeStart = FinalSize;
|
||||
int framesEmitted = 0;
|
||||
|
||||
while (m_nosteamOpusPCMBuffer[playerSlot].TotalLength() >= 480)
|
||||
{
|
||||
if (framesEmitted >= 1)
|
||||
break;
|
||||
|
||||
int16_t opusInput[480];
|
||||
if (!m_nosteamOpusPCMBuffer[playerSlot].Pop(opusInput, 480))
|
||||
break;
|
||||
|
||||
unsigned char opusBuf[512];
|
||||
int opusBytes = opus_encode(m_nosteamOpusEncoder[playerSlot], opusInput, 480, opusBuf, sizeof(opusBuf));
|
||||
// Encode directly into aFinal after the 4-byte subframe header
|
||||
size_t headerOffset = FinalSize;
|
||||
size_t opusOffset = FinalSize + 4;
|
||||
|
||||
if (opusOffset + 512 > sizeof(aFinal) - 4) // leave room for CRC
|
||||
break;
|
||||
|
||||
int opusBytes = opus_encode(
|
||||
m_nosteamOpusEncoder[playerSlot],
|
||||
opusInput, 480,
|
||||
&aFinal[opusOffset], 512
|
||||
);
|
||||
|
||||
if (opusBytes < 0)
|
||||
{
|
||||
smutils->LogError(myself, "HandleNoSteamVoiceData: opus_encode failed: %s",
|
||||
@ -1483,93 +1482,40 @@ void CVoice::HandleNoSteamVoiceData()
|
||||
break;
|
||||
}
|
||||
|
||||
IClient *pNoSteamClient = iserver->GetClient(playerSlot);
|
||||
if (!pNoSteamClient)
|
||||
// Write 4-byte subframe header
|
||||
// [frameSize(1)] [0x00] [seqNum(1)] [0x00]
|
||||
aFinal[headerOffset + 0] = (uint8_t)opusBytes;
|
||||
aFinal[headerOffset + 1] = 0x00;
|
||||
aFinal[headerOffset + 2] = (uint8_t)(m_nosteamSeqNum[playerSlot]++ & 0xFF);
|
||||
aFinal[headerOffset + 3] = 0x00;
|
||||
|
||||
FinalSize = opusOffset + opusBytes;
|
||||
framesEmitted++;
|
||||
}
|
||||
|
||||
if (framesEmitted == 0)
|
||||
continue;
|
||||
|
||||
// Fill in totalDataLength
|
||||
uint16_t totalDataLength = (uint16_t)(FinalSize - subframeStart);
|
||||
memcpy(&aFinal[totalDataLengthOffset], &totalDataLength, sizeof(uint16_t));
|
||||
|
||||
// Append CRC32
|
||||
uint32_t crc = UTIL_CRC32(aFinal, FinalSize);
|
||||
memcpy(&aFinal[FinalSize], &crc, sizeof(uint32_t));
|
||||
FinalSize += sizeof(uint32_t);
|
||||
|
||||
for (int i = 0; i < maxClients; i++)
|
||||
{
|
||||
IClient *pToClient = iserver->GetClient(i);
|
||||
if (!pToClient || !pToClient->IsConnected() || !pToClient->IsActive() || pToClient->IsFakeClient())
|
||||
continue;
|
||||
if (g_bIsNoSteam[i + 1])
|
||||
continue;
|
||||
if (g_bClientMuted[i + 1][playerSlot + 1])
|
||||
continue;
|
||||
|
||||
const char *networkID = pNoSteamClient->GetNetworkIDString();
|
||||
uint32_t accountID = 0;
|
||||
// Parse [U:1:XXXXXXXX] format
|
||||
const char *numStart = strrchr(networkID, ':');
|
||||
if (numStart)
|
||||
accountID = (uint32_t)atoi(numStart + 1);
|
||||
|
||||
// Build modern Steam voice packet with working routing blocks
|
||||
unsigned char aFinal[8192];
|
||||
size_t FinalSize = 0;
|
||||
|
||||
// Build Steam voice packet header
|
||||
uint32_t steamID = accountID;
|
||||
uint32_t steamCommunity = 0x01100001;
|
||||
memcpy(&aFinal[FinalSize], &steamID, sizeof(uint32_t));
|
||||
FinalSize += sizeof(uint32_t);
|
||||
memcpy(&aFinal[FinalSize], &steamCommunity, sizeof(uint32_t));
|
||||
FinalSize += sizeof(uint32_t);
|
||||
|
||||
// 2. Payload Type (1 byte)
|
||||
aFinal[FinalSize++] = 0x0B;
|
||||
|
||||
// 3. Sample Rate (2 bytes little-endian)
|
||||
uint16_t sampleRate = 24000;
|
||||
memcpy(&aFinal[FinalSize], &sampleRate, sizeof(uint16_t));
|
||||
FinalSize += sizeof(uint16_t);
|
||||
|
||||
// 4. Codec Type (1 byte) - 0x06 for Opus PLC
|
||||
aFinal[FinalSize++] = 0x06;
|
||||
|
||||
// 5. Track where Size 1 lives
|
||||
size_t totalDataLengthOffset = FinalSize;
|
||||
FinalSize += sizeof(uint16_t); // Reserve 2 bytes
|
||||
|
||||
// 6. Sub-Frame Header size (2 bytes) - MUST be exactly raw opusBytes count
|
||||
uint16_t frameSize = (uint16_t)opusBytes;
|
||||
memcpy(&aFinal[FinalSize], &frameSize, sizeof(uint16_t));
|
||||
FinalSize += sizeof(uint16_t);
|
||||
|
||||
// 7. Sequence Number (2 bytes)
|
||||
uint16_t seq = m_nosteamSeqNum[playerSlot]++;
|
||||
memcpy(&aFinal[FinalSize], &seq, sizeof(uint16_t));
|
||||
FinalSize += sizeof(uint16_t);
|
||||
|
||||
// 8. Raw Opus Audio Payload
|
||||
memcpy(&aFinal[FinalSize], opusBuf, opusBytes);
|
||||
FinalSize += opusBytes;
|
||||
|
||||
uint16_t totalRemainingBytes = (uint16_t)(sizeof(uint16_t) + sizeof(uint16_t) + opusBytes);
|
||||
memcpy(&aFinal[totalDataLengthOffset], &totalRemainingBytes, sizeof(uint16_t));
|
||||
|
||||
// 10. Compute and append CRC32 checksum over the complete array built so far
|
||||
uint32_t crc = UTIL_CRC32(aFinal, FinalSize);
|
||||
memcpy(&aFinal[FinalSize], &crc, sizeof(uint32_t));
|
||||
FinalSize += sizeof(uint32_t);
|
||||
|
||||
for (int i = 0; i < maxClients; i++)
|
||||
{
|
||||
IClient *pToClient = iserver->GetClient(i);
|
||||
if (!pToClient || !pToClient->IsConnected() || !pToClient->IsActive() || pToClient->IsFakeClient())
|
||||
continue;
|
||||
if (g_bIsNoSteam[i + 1])
|
||||
continue;
|
||||
if (g_bClientMuted[i + 1][playerSlot + 1])
|
||||
continue;
|
||||
// debugging voice packets
|
||||
/*
|
||||
int dumpLen = (int)FinalSize < 32 ? (int)FinalSize : 32;
|
||||
char hexBuf[32 * 3 + 1];
|
||||
int pos = 0;
|
||||
for (int i = 0; i < dumpLen; i++)
|
||||
{
|
||||
static const char hex[] = "0123456789ABCDEF";
|
||||
hexBuf[pos++] = hex[(aFinal[i] >> 4) & 0xF];
|
||||
hexBuf[pos++] = hex[aFinal[i] & 0xF];
|
||||
hexBuf[pos++] = ' ';
|
||||
}
|
||||
hexBuf[pos] = '\0';
|
||||
smutils->LogMessage(myself, "CVoice::HandleNoSteamVoiceData packet: FinalSize=%d first %d bytes: %s", (int)FinalSize, dumpLen, hexBuf);
|
||||
*/
|
||||
SendVoiceDataMsg(playerSlot, pToClient, aFinal, (int)FinalSize, 0);
|
||||
}
|
||||
framesEmitted++;
|
||||
SendVoiceDataMsg(playerSlot, pToClient, aFinal, (int)FinalSize, 0);
|
||||
}
|
||||
|
||||
if (framesEmitted > 0)
|
||||
|
||||
@ -211,9 +211,11 @@ private:
|
||||
|
||||
double m_nosteamAvailableTime[SM_MAXPLAYERS + 1];
|
||||
|
||||
int m_TorchlightSeqNum;
|
||||
|
||||
void HandleNetwork();
|
||||
void OnDataReceived(CClient *pClient, int16_t *pData, size_t Samples);
|
||||
void HandleVoiceData();
|
||||
void HandleVoiceDataTorchlight();
|
||||
void HandleNoSteamVoiceData();
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user