2
0
mirror of https://github.com/rehlds/revoice.git synced 2025-03-15 23:10:16 +03:00
revoice/revoice/src/revoice_main.cpp

217 lines
6.4 KiB
C++

#include "precompiled.h"
cvar_t* pcv_sv_voiceenable = NULL;
void Rehlds_ClientConnected_Hook(IRehldsHook_ClientConnected* chain, IGameClient* cl) {
int protocol = g_ReunionApi->GetClientProtocol(cl->GetId());
if (protocol == 47 || protocol == 48) {
CRevoicePlayer* plr = GetPlayerByClientPtr(cl);
plr->OnConnected(protocol);
// default codec
plr->InitVoice(vct_speex);
//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->OnDisconnected();
chain->callNext(cl, crash, msg);
}
void mm_CvarValue2(const edict_t *pEnt, int requestID, const char *cvarName, const char *cvarValue) {
if (!strcmp("sv_version", cvarName)) {
// ] sv_version
// "sv_version" is "1.1.2.1/2.0.0.0,48,4554"
const char* lastSeparator = strrchr(cvarValue, ',');
int buildNumber = 0;
if (lastSeparator) {
buildNumber = atoi(lastSeparator + 1);
}
CRevoicePlayer* plr = GetPlayerByEdict(pEnt);
if (buildNumber > 4554) {
plr->InitVoice(vct_silk);
} else {
plr->InitVoice(vct_speex);
}
}
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;
}
int compressedSize = dstCodec->Compress(decodedBuf, numDecodedSamples, dstBuf, dstBufSize, false);
if (compressedSize <= 0) {
return 0;
}
/*
int numDecodedSamples2 = dstCodec->Decompress(dstBuf, compressedSize, decodedBuf, sizeof(decodedBuf));
if (numDecodedSamples2 <= 0) {
return compressedSize;
}
FILE* rawSndFile = fopen("d:\\revoice_raw.snd", "ab");
if (rawSndFile) {
fwrite(decodedBuf, 2, numDecodedSamples2, rawSndFile);
fclose(rawSndFile);
}
*/
return compressedSize;
}
void SV_ParseVoiceData_emu(IGameClient* cl) {
if (pcv_sv_voiceenable->value == 0.0f) {
return;
}
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);
CRevoicePlayer* srcPlayer = GetPlayerByClientPtr(cl);
srcPlayer->SetLastVoiceTime(g_RehldsSv->GetTime());
srcPlayer->IncreaseVoiceRate(nDataLength);
char transcodedBuf[4096];
char* speexData; int speexDataLen;
char* silkData; int silkDataLen;
switch (srcPlayer->GetCodecType()) {
case vct_silk:
{
if (nDataLength > MAX_SILK_DATA_LEN || srcPlayer->GetVoiceRate() > MAX_SILK_VOICE_RATE)
return;
silkData = chReceived; silkDataLen = nDataLength;
speexData = transcodedBuf;
speexDataLen = TranscodeVoice(silkData, silkDataLen, srcPlayer->GetSilkCodec(), srcPlayer->GetSpeexCodec(), transcodedBuf, sizeof(transcodedBuf));
break;
}
case vct_speex:
if (nDataLength > MAX_SPEEX_DATA_LEN || srcPlayer->GetVoiceRate() > MAX_SPEEX_VOICE_RATE)
return;
speexData = chReceived; speexDataLen = nDataLength;
silkData = transcodedBuf;
silkDataLen = TranscodeVoice(speexData, speexDataLen, srcPlayer->GetSpeexCodec(), srcPlayer->GetSilkCodec(), transcodedBuf, sizeof(transcodedBuf));
break;
default:
return;
}
int maxclients = g_RehldsSvs->GetMaxClients();
for (int i = 0; i < maxclients; i++) {
CRevoicePlayer* dstPlayer = &g_Players[i];
IGameClient* dstClient = dstPlayer->GetClient();
if (!((1 << i) & cl->GetVoiceStream(0)) && dstPlayer != srcPlayer)
continue;
if (!dstClient->IsActive() && !dstClient->IsConnected() && dstPlayer != srcPlayer)
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 || nSendLen == 0)
continue;
if (dstPlayer == srcPlayer && !dstClient->GetLoopback())
nSendLen = 0;
sizebuf_t* dstDatagram = dstClient->GetDatagram();
if (dstDatagram->cursize + nSendLen + 6 < dstDatagram->maxsize) {
g_RehldsFuncs->MSG_WriteByte(dstDatagram, svc_voicedata); //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, TRUE);
}
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, svc_voiceinit); //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, svc_voiceinit); //svc_voiceinit
g_RehldsFuncs->MSG_WriteString(sb, "voice_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->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;
}