From 01dab9948065ec8b072e57bdbd42cbd4eac820b6 Mon Sep 17 00:00:00 2001 From: thecrock Date: Sun, 13 Dec 2015 18:55:11 +0400 Subject: [PATCH] Main logic --- dep/rehlsdk/engine/sys_shared.cpp | 5 +- revoice/src/VoiceEncoder_Silk.cpp | 29 +++--- revoice/src/VoiceEncoder_Silk.h | 2 +- revoice/src/meta_api.cpp | 5 + revoice/src/revoice_main.cpp | 148 ++++++++++++++++++++++++++++- revoice/src/revoice_player.cpp | 7 +- revoice/src/revoice_player.h | 7 +- revoice/src/revoice_rehlds_api.cpp | 2 + revoice/src/revoice_rehlds_api.h | 1 + 9 files changed, 183 insertions(+), 23 deletions(-) diff --git a/dep/rehlsdk/engine/sys_shared.cpp b/dep/rehlsdk/engine/sys_shared.cpp index 58981d6..67594e6 100644 --- a/dep/rehlsdk/engine/sys_shared.cpp +++ b/dep/rehlsdk/engine/sys_shared.cpp @@ -42,9 +42,7 @@ cpuinfo_t cpuinfo; void Sys_CheckCpuInstructionsSupport(void) { - int cpuid_data[4]; - - cpuid_ex(cpuid_data, 1, 0); + int cpuid_data[4] = { 0,0,0,0 }; cpuinfo.sse3 = (cpuid_data[2] & SSE3_FLAG) ? 1 : 0; // ecx cpuinfo.ssse3 = (cpuid_data[2] & SSSE3_FLAG) ? 1 : 0; @@ -52,7 +50,6 @@ void Sys_CheckCpuInstructionsSupport(void) cpuinfo.sse4_2 = (cpuid_data[2] & SSE4_2_FLAG) ? 1 : 0; cpuinfo.avx = (cpuid_data[2] & AVX_FLAG) ? 1 : 0; - cpuid_ex(cpuid_data, 7, 0); cpuinfo.avx2 = (cpuid_data[1] & AVX2_FLAG) ? 1 : 0; // ebx } \ No newline at end of file diff --git a/revoice/src/VoiceEncoder_Silk.cpp b/revoice/src/VoiceEncoder_Silk.cpp index cd3a449..92179d4 100644 --- a/revoice/src/VoiceEncoder_Silk.cpp +++ b/revoice/src/VoiceEncoder_Silk.cpp @@ -4,7 +4,6 @@ VoiceEncoder_Silk::VoiceEncoder_Silk() { m_pEncoder = NULL; m_pDecoder = NULL; - m_API_fs_Hz = 0; m_targetRate_bps = 25000; m_packetLoss_perc = 0; } @@ -22,7 +21,6 @@ VoiceEncoder_Silk::~VoiceEncoder_Silk() { } bool VoiceEncoder_Silk::Init(int quality) { - m_API_fs_Hz = 16000; m_targetRate_bps = 25000; m_packetLoss_perc = 0; @@ -64,8 +62,9 @@ int VoiceEncoder_Silk::Compress(const char *pUncompressedIn, int nSamplesIn, cha const char *pWritePosMax; // [sp+2Ch] [bp-40h]@5 int nSamplesRemaining; // [sp+38h] [bp-34h]@5 + const int inSampleRate = 8000; const int nSampleDataMinMS = 100; - const int nSamplesMin = m_API_fs_Hz * nSampleDataMinMS / 1000; + const int nSamplesMin = inSampleRate * nSampleDataMinMS / 1000; if ((nSamplesIn + m_bufOverflowBytes.TellPut() / 2) < nSamplesMin && !bFinal) { m_bufOverflowBytes.Put(pUncompressedIn, 2 * nSamplesIn); @@ -82,7 +81,7 @@ int VoiceEncoder_Silk::Compress(const char *pUncompressedIn, int nSamplesIn, cha nSamplesToUse = nSamplesIn; } - nSamplesPerFrame = m_API_fs_Hz / 50; + nSamplesPerFrame = inSampleRate / 50; nSamplesRemaining = nSamplesToUse % nSamplesPerFrame; pWritePosMax = pCompressed + maxCompressedBytes; nSamples = nSamplesToUse - nSamplesRemaining; @@ -99,9 +98,9 @@ int VoiceEncoder_Silk::Compress(const char *pUncompressedIn, int nSamplesIn, cha this->m_encControl.useDTX = 1; this->m_encControl.maxInternalSampleRate = 16000; this->m_encControl.useInBandFEC = 0; - this->m_encControl.API_sampleRate = m_API_fs_Hz; + this->m_encControl.API_sampleRate = inSampleRate; this->m_encControl.complexity = 2; - this->m_encControl.packetSize = 20 * (m_API_fs_Hz / 1000); + this->m_encControl.packetSize = 20 * (inSampleRate / 1000); this->m_encControl.packetLossPercentage = this->m_packetLoss_perc; this->m_encControl.bitRate = (m_targetRate_bps >= 0) ? m_targetRate_bps : 0; @@ -143,8 +142,10 @@ int VoiceEncoder_Silk::Decompress(const char *pCompressed, int compressedBytes, char *pWritePosMax; // [sp+28h] [bp-44h]@4 const char *pReadPosMax; // [sp+3Ch] [bp-30h]@1 - m_decControl.API_sampleRate = m_API_fs_Hz; - int nSamplesPerFrame = m_API_fs_Hz / 50; + const int outSampleRate = 8000; + + m_decControl.API_sampleRate = outSampleRate; + int nSamplesPerFrame = outSampleRate / 50; if (compressedBytes <= 0) { return 0; } @@ -157,7 +158,7 @@ int VoiceEncoder_Silk::Decompress(const char *pCompressed, int compressedBytes, while (pReadPos < pReadPosMax) { if (pReadPosMax - pReadPos < 2) { - return pWritePos - pUncompressed; + break; } nPayloadSize = *(uint16 *)pReadPos; @@ -165,7 +166,7 @@ int VoiceEncoder_Silk::Decompress(const char *pCompressed, int compressedBytes, if (nPayloadSize == 0xFFFF) { ResetState(); - return pWritePos - pUncompressed; + break; } if (nPayloadSize == 0) { @@ -173,7 +174,7 @@ int VoiceEncoder_Silk::Decompress(const char *pCompressed, int compressedBytes, int numEmptySamples = nSamplesPerFrame; short nSamples = (pWritePosMax - pWritePos) / 2; if (nSamples < numEmptySamples) { - return pWritePos - pUncompressed; + break; } memset(pWritePos, 0, numEmptySamples * 2); pWritePos += numEmptySamples * 2; @@ -181,19 +182,19 @@ int VoiceEncoder_Silk::Decompress(const char *pCompressed, int compressedBytes, } if ((pReadPos + nPayloadSize) > pReadPosMax) { - return pWritePos - pUncompressed; + break; } do { short nSamples = (pWritePosMax - pWritePos) / 2; int decodeRes = SKP_Silk_SDK_Decode(m_pDecoder, &m_decControl, 0, (const unsigned char*)pReadPos, nPayloadSize, (__int16 *)pWritePos, &nSamples); if (SKP_SILK_NO_ERROR != decodeRes) { - return pWritePos - pUncompressed; + return (pWritePos - pUncompressed) / 2; } pWritePos += nSamples * sizeof(int16); } while (m_decControl.moreInternalDecoderFrames); pReadPos += nPayloadSize; } - return pWritePos - pUncompressed; + return (pWritePos - pUncompressed) / 2; } \ No newline at end of file diff --git a/revoice/src/VoiceEncoder_Silk.h b/revoice/src/VoiceEncoder_Silk.h index 7ee234d..a961fe6 100644 --- a/revoice/src/VoiceEncoder_Silk.h +++ b/revoice/src/VoiceEncoder_Silk.h @@ -7,7 +7,7 @@ class VoiceEncoder_Silk : public IVoiceCodec { private: void * m_pEncoder; /* 4 4 */ - int m_API_fs_Hz; /* 8 4 */ + //int m_API_fs_Hz; /* 8 4 */ int m_targetRate_bps; /* 12 4 */ int m_packetLoss_perc; /* 16 4 */ SKP_SILK_SDK_EncControlStruct m_encControl; /* 20 32 */ diff --git a/revoice/src/meta_api.cpp b/revoice/src/meta_api.cpp index ba4c219..2e2a640 100644 --- a/revoice/src/meta_api.cpp +++ b/revoice/src/meta_api.cpp @@ -121,6 +121,11 @@ bool Revoice_Load() { return false; } + Revoice_Init_Players(); + if (!Revoice_Main_Init()) { + LCPrintf(true, "Initialization failed\n"); + return false; + } return true; } diff --git a/revoice/src/revoice_main.cpp b/revoice/src/revoice_main.cpp index ef1f177..321978f 100644 --- a/revoice/src/revoice_main.cpp +++ b/revoice/src/revoice_main.cpp @@ -2,6 +2,7 @@ #include "precompiled.h" int g_ClientBeingConnected_Protocol = 0; +cvar_t* pcv_sv_voiceenable = NULL; void SV_ConnectClient_hook(IRehldsHook_SV_ConnectClient* chain) { g_ClientBeingConnected_Protocol = atoi(g_engfuncs.pfnCmd_Argv(1)); @@ -15,14 +16,20 @@ void Rehlds_ClientConnected_Hook(IRehldsHook_ClientConnected* chain, IGameClient if (g_ClientBeingConnected_Protocol == 47) { plr->InitVoice(vct_speex); - } else { - g_engfuncs.pfnQueryClientCvarValue2(cl->GetEdict(), "sv_version", 0); } + + //for p48 we will query sv_version cvar value later in mm_ClientConnect } chain->callNext(cl); } +void SV_DropClient_hook(IRehldsHook_SV_DropClient* chain, IGameClient* cl, bool crash, const char* msg) { + CRevoicePlayer* plr = GetPlayerByClientPtr(cl); + plr->OnDisconected(); + chain->callNext(cl, crash, msg); +} + void mm_CvarValue2(const edict_t *pEnt, int requestID, const char *cvarName, const char *value) { if (!strcmp("sv_version", cvarName)) { // ] sv_version @@ -45,12 +52,149 @@ void mm_CvarValue2(const edict_t *pEnt, int requestID, const char *cvarName, con RETURN_META(MRES_IGNORED); } +int TranscodeVoice(const char* srcBuf, int srcBufLen, IVoiceCodec* srcCodec, IVoiceCodec* dstCodec, char* dstBuf, int dstBufSize) { + char decodedBuf[32768]; + int numDecodedSamples = srcCodec->Decompress(srcBuf, srcBufLen, decodedBuf, sizeof(decodedBuf)); + if (numDecodedSamples <= 0) { + return 0; + } + + return dstCodec->Compress(decodedBuf, numDecodedSamples, dstBuf, dstBufSize, false); +} + +void SV_ParseVoiceData_emu(IGameClient* cl) { + char chReceived[4096]; + unsigned int nDataLength = g_RehldsFuncs->MSG_ReadShort(); + + if (nDataLength > sizeof(chReceived)) + { + g_RehldsFuncs->DropClient(cl, FALSE, "Invalid voice data\n"); + return; + } + + g_RehldsFuncs->MSG_ReadBuf(nDataLength, chReceived); + //cl->m_lastvoicetime = g_RehldsSv->GetTime(); + + if (pcv_sv_voiceenable->value == 0.0f) + return; + + CRevoicePlayer* srcPlayer = GetPlayerByClientPtr(cl); + if (srcPlayer->GetCodecType() == vct_none) { + return; + } + + char transcodedBuf[4096]; + char* speexData; int speexDataLen; + char* silkData; int silkDataLen; + + switch (srcPlayer->GetCodecType()) { + case vct_silk: + silkData = chReceived; silkDataLen = nDataLength; + speexData = transcodedBuf; + speexDataLen = TranscodeVoice(silkData, silkDataLen, srcPlayer->GetSilkCodec(), srcPlayer->GetSpeexCodec(), transcodedBuf, sizeof(transcodedBuf)); + break; + + case vct_speex: + speexData = chReceived; speexDataLen = nDataLength; + silkData = transcodedBuf; + silkDataLen = TranscodeVoice(speexData, speexDataLen, srcPlayer->GetSpeexCodec(), srcPlayer->GetSilkCodec(), transcodedBuf, sizeof(transcodedBuf)); + break; + + default: + return; + } + + for (int i = 0; i < g_RehldsSvs->GetMaxClients(); i++) { + CRevoicePlayer* dstPlayer = &g_Players[i]; + IGameClient* dstClient = dstPlayer->GetClient(); + + if (!((1 << (i & 0x1F)) & cl->GetVoiceStreams(i >> 5)) && i != cl->GetId()) + continue; + + if (!dstClient->IsActive() && !dstClient->IsConnected() && i != cl->GetId()) + continue; + + char* sendBuf; int nSendLen; + + switch (dstPlayer->GetCodecType()) { + case vct_silk: + sendBuf = silkData; nSendLen = silkDataLen; + break; + + case vct_speex: + sendBuf = speexData; nSendLen = speexDataLen; + break; + + default: + sendBuf = NULL; nSendLen = 0; + break; + } + + if (sendBuf == NULL) { + continue; + } + + if (i == cl->GetId() && !dstClient->GetLoopback()) + nSendLen = 0; + + sizebuf_t* dstDatagram = dstClient->GetDatagram(); + if (dstDatagram->cursize + nSendLen + 6 < dstDatagram->maxsize) + { + g_RehldsFuncs->MSG_WriteByte(dstDatagram, 53); //svc_voicedata + g_RehldsFuncs->MSG_WriteByte(dstDatagram, cl->GetId()); + g_RehldsFuncs->MSG_WriteShort(dstDatagram, nSendLen); + g_RehldsFuncs->MSG_WriteBuf(dstDatagram, nSendLen, sendBuf); + } + } +} + +void Rehlds_HandleNetCommand(IRehldsHook_HandleNetCommand* chain, IGameClient* cl, int8 opcode) { + if (opcode == 8) { //clc_voicedata + SV_ParseVoiceData_emu(cl); + return; + } + + chain->callNext(cl, opcode); +} + qboolean mm_ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128]) { + CRevoicePlayer* plr = GetPlayerByEdict(pEntity); + if (plr->GetProtocol() == 48) { + g_engfuncs.pfnQueryClientCvarValue2(pEntity, "sv_version", 0); + } RETURN_META_VALUE(MRES_IGNORED, 1); } +void SV_WriteVoiceCodec_hooked(IRehldsHook_SV_WriteVoiceCodec* chain, sizebuf_t* sb) { + IGameClient* cl = g_RehldsFuncs->GetHostClient(); + CRevoicePlayer* plr = GetPlayerByClientPtr(cl); + + switch (plr->GetCodecType()) { + case vct_silk: + g_RehldsFuncs->MSG_WriteByte(sb, 52); //svc_voiceinit + g_RehldsFuncs->MSG_WriteString(sb, ""); //codec id + g_RehldsFuncs->MSG_WriteByte(sb, 0); //quality + break; + + case vct_speex: + g_RehldsFuncs->MSG_WriteByte(sb, 52); //svc_voiceinit + g_RehldsFuncs->MSG_WriteString(sb, "speex"); //codec id + g_RehldsFuncs->MSG_WriteByte(sb, 5); //quality + break; + + default: + LCPrintf(true, "SV_WriteVoiceCodec() called on client(%d) with unknown voice codec\n", cl->GetId()); + break; + } +} + bool Revoice_Main_Init() { g_RehldsHookchains->SV_ConnectClient()->registerHook(SV_ConnectClient_hook); g_RehldsHookchains->ClientConnected()->registerHook(Rehlds_ClientConnected_Hook); + g_RehldsHookchains->SV_DropClient()->registerHook(SV_DropClient_hook); + g_RehldsHookchains->HandleNetCommand()->registerHook(Rehlds_HandleNetCommand); + g_RehldsHookchains->SV_WriteVoiceCodec()->registerHook(SV_WriteVoiceCodec_hooked); + pcv_sv_voiceenable = g_engfuncs.pfnCVarGetPointer("sv_voiceenable"); + return true; } \ No newline at end of file diff --git a/revoice/src/revoice_player.cpp b/revoice/src/revoice_player.cpp index 74251ab..12cf584 100644 --- a/revoice/src/revoice_player.cpp +++ b/revoice/src/revoice_player.cpp @@ -28,7 +28,12 @@ void CRevoicePlayer::InitVoice(revoice_codec_type codecType) { void CRevoicePlayer::OnConnected(int protocol) { m_Protocol = protocol; m_CodecType = vct_none; -} +} + +void CRevoicePlayer::OnDisconected() { + m_Protocol = 0; + m_CodecType = vct_none; +} void Revoice_Init_Players() { int maxclients = g_RehldsSvs->GetMaxClients(); diff --git a/revoice/src/revoice_player.h b/revoice/src/revoice_player.h index 2400b96..af4bdce 100644 --- a/revoice/src/revoice_player.h +++ b/revoice/src/revoice_player.h @@ -17,9 +17,14 @@ public: CRevoicePlayer(); void Initialize(IGameClient* cl); void OnConnected(int protocol); + void OnDisconected(); void InitVoice(revoice_codec_type codecType); - + int GetProtocol() const { return m_Protocol; } + revoice_codec_type GetCodecType() const { return m_CodecType; } + VoiceEncoder_Silk* GetSilkCodec() const { return m_SilkCodec; } + VoiceCodec_Frame* GetSpeexCodec() const { return m_SpeexCodec; } + IGameClient* GetClient() const { return m_RehldsClient; } }; extern CRevoicePlayer g_Players[MAX_PLAYERS]; diff --git a/revoice/src/revoice_rehlds_api.cpp b/revoice/src/revoice_rehlds_api.cpp index 01a49a9..ba736fc 100644 --- a/revoice/src/revoice_rehlds_api.cpp +++ b/revoice/src/revoice_rehlds_api.cpp @@ -4,6 +4,7 @@ IRehldsApi* g_RehldsApi; const RehldsFuncs_t* g_RehldsFuncs; IRehldsHookchains* g_RehldsHookchains; IRehldsServerStatic* g_RehldsSvs; +IRehldsServerData* g_RehldsSv; bool Revoice_RehldsApi_TryInit(CSysModule* engineModule, char* failureReason) { @@ -41,6 +42,7 @@ bool Revoice_RehldsApi_TryInit(CSysModule* engineModule, char* failureReason) g_RehldsFuncs = g_RehldsApi->GetFuncs(); g_RehldsHookchains = g_RehldsApi->GetHookchains(); g_RehldsSvs = g_RehldsApi->GetServerStatic(); + g_RehldsSv = g_RehldsApi->GetServerData(); return true; } diff --git a/revoice/src/revoice_rehlds_api.h b/revoice/src/revoice_rehlds_api.h index bab494e..80bbf08 100644 --- a/revoice/src/revoice_rehlds_api.h +++ b/revoice/src/revoice_rehlds_api.h @@ -6,5 +6,6 @@ extern IRehldsApi* g_RehldsApi; extern const RehldsFuncs_t* g_RehldsFuncs; extern IRehldsHookchains* g_RehldsHookchains; extern IRehldsServerStatic* g_RehldsSvs; +extern IRehldsServerData* g_RehldsSv; extern bool Revoice_RehldsApi_Init();