2
0
mirror of https://github.com/rehlds/revoice.git synced 2025-03-03 09:05:29 +03:00

Implemented Steam P2P stream voice codec

This commit is contained in:
thecrock 2015-12-14 17:13:59 +04:00
parent 01dab99480
commit 46165f761f
14 changed files with 219 additions and 8 deletions

View File

@ -0,0 +1,39 @@
@echo OFF
::
:: Post-build auto-deploy script
:: Create and fill PublishPath.txt file with path to deployment folder
:: I.e. PublishPath.txt should contain one line with a folder path
:: Call it so:
:: IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)")
::
SET targetDir=%~1
SET targetName=%~2
SET targetExt=%~3
SET projectDir=%~4
SET destination=
IF NOT EXIST "%projectDir%\PublishPath.txt" (
ECHO No deployment path specified. Create PublishPath.txt near PostBuild.bat with paths on separate lines for auto deployment.
exit /B 0
)
FOR /f "tokens=* delims= usebackq" %%a IN ("%projectDir%\PublishPath.txt") DO (
ECHO Deploying to: %%a
IF NOT "%%a" == "" (
copy /Y "%targetDir%%targetName%%targetExt%" "%%a"
IF NOT ERRORLEVEL 1 (
IF EXIST "%targetDir%%targetName%.pdb" (
copy /Y "%targetDir%%targetName%.pdb" "%%a"
)
) ELSE (
ECHO PostBuild.bat ^(27^) : warning : Can't copy '%targetName%%targetExt%' to deploy path '%%a'
)
)
)
IF "%%a" == "" (
ECHO No deployment path specified.
)
exit /B 0

View File

@ -0,0 +1 @@
d:\rehlds_hbtrace\cstrike\addons\revoice\

View File

@ -35,6 +35,7 @@
<ClInclude Include="..\src\revoice_player.h" />
<ClInclude Include="..\src\revoice_rehlds_api.h" />
<ClInclude Include="..\src\revoice_shared.h" />
<ClInclude Include="..\src\SteamP2PCodec.h" />
<ClInclude Include="..\src\VoiceEncoder_Silk.h" />
<ClInclude Include="..\src\VoiceEncoder_Speex.h" />
<ClInclude Include="..\src\voice_codec_frame.h" />
@ -56,6 +57,7 @@
<ClCompile Include="..\src\revoice_rehlds_api.cpp" />
<ClCompile Include="..\src\revoice_utils.cpp" />
<ClCompile Include="..\src\sdk_util.cpp" />
<ClCompile Include="..\src\SteamP2PCodec.cpp" />
<ClCompile Include="..\src\VoiceEncoder_Silk.cpp" />
<ClCompile Include="..\src\VoiceEncoder_Speex.cpp" />
<ClCompile Include="..\src\voice_codec_frame.cpp" />
@ -120,6 +122,12 @@
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>revoice.def</ModuleDefinitionFile>
</Link>
<PostBuildEvent>
<Command>IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)")</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Automatic deployment script</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>

View File

@ -93,6 +93,9 @@
<ClInclude Include="..\src\revoice_main.h">
<Filter>src</Filter>
</ClInclude>
<ClInclude Include="..\src\SteamP2PCodec.h">
<Filter>src</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\dllapi.cpp">
@ -143,5 +146,8 @@
<ClCompile Include="..\src\revoice_main.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\src\SteamP2PCodec.cpp">
<Filter>src</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,120 @@
#include "precompiled.h"
CSteamP2PCodec::CSteamP2PCodec(IVoiceCodec* backend) {
m_BackendCodec = backend;
}
bool CSteamP2PCodec::Init(int quality) {
return m_BackendCodec->Init(quality);
}
void CSteamP2PCodec::Release() {
m_BackendCodec->Release();
delete this;
}
bool CSteamP2PCodec::ResetState() {
return m_BackendCodec->ResetState();
}
int CSteamP2PCodec::StreamDecode(const char *pCompressed, int compressedBytes, char *pUncompressed, int maxUncompressedBytes) const {
const char* maxReadPos = pCompressed + compressedBytes;
const char* readPos = pCompressed;
while (readPos < maxReadPos) {
uint8 opcode = *(uint8*)readPos;
readPos++;
switch (opcode) {
case 0xB: //Set sampling rate
if (readPos + 2 > maxReadPos) {
return 0;
}
readPos += 2;
break;
case 0x04: //Voice payoad
{
if (readPos + 2 > maxReadPos) {
return 0;
}
uint16 len = *(uint16*)readPos;
readPos += 2;
if (readPos + len > maxReadPos) {
return 0;
}
int decompressedLen = m_BackendCodec->Decompress(readPos, len, pUncompressed, maxUncompressedBytes);
return decompressedLen;
}
default: //Invalid or unknown opcode
return 0;
}
}
return 0; // no voice payload in the stream
}
int CSteamP2PCodec::StreamEncode(const char *pUncompressedBytes, int nSamples, char *pCompressed, int maxCompressedBytes, bool bFinal) const {
char* writePos = pCompressed;
if (maxCompressedBytes < 10) { // no room
return 0;
}
*(writePos++) = 0x0B; //set sampling rate
*(uint16*)writePos = 16000;
writePos += 2;
*(writePos++) = 0x04; //voice payload
int compressRes = m_BackendCodec->Compress(pUncompressedBytes, nSamples, writePos + 2, maxCompressedBytes - (1 + 2 + 1 + 2), bFinal);
if (compressRes == 0) {
return 0;
}
*(uint16*)writePos = compressRes;
writePos += 2;
writePos += compressRes;
return writePos - pCompressed;
}
int CSteamP2PCodec::Decompress(const char *pCompressed, int compressedBytes, char *pUncompressed, int maxUncompressedBytes) {
if (compressedBytes < 12) {
return 0;
}
uint32 computedChecksum = crc32(pCompressed, compressedBytes - 4);
uint32 wireChecksum = *(uint32*)(pCompressed + compressedBytes - 4);
if (computedChecksum != wireChecksum) {
return 0;
}
return StreamDecode(pCompressed + 8, compressedBytes - 12, pUncompressed, maxUncompressedBytes);
}
int CSteamP2PCodec::Compress(const char *pUncompressedBytes, int nSamples, char *pCompressed, int maxCompressedBytes, bool bFinal) {
if (maxCompressedBytes < 12) { //no room
return 0;
}
char* writePos = pCompressed;
*(uint32*)writePos = 0x00000011; //steamid (low part)
writePos += 4;
*(uint32*)writePos = 0x01100001; //steamid (high part)
writePos += 4;
int encodeRes = StreamEncode(pUncompressedBytes, nSamples, writePos, maxCompressedBytes - 12, bFinal);
if (encodeRes <= 0) {
return 0;
}
writePos += encodeRes;
uint32 cksum = crc32(pUncompressedBytes, writePos - pCompressed);
*(uint32*)writePos = cksum;
writePos += 4;
return writePos - pCompressed;
}

View File

@ -0,0 +1,20 @@
#pragma once
#include "revoice_shared.h"
#include "VoiceEncoder_Silk.h"
class CSteamP2PCodec : public IVoiceCodec {
public:
CSteamP2PCodec(IVoiceCodec* backend);
virtual bool Init(int quality);
virtual void Release();
virtual int Compress(const char *pUncompressedBytes, int nSamples, char *pCompressed, int maxCompressedBytes, bool bFinal);
virtual int Decompress(const char *pCompressed, int compressedBytes, char *pUncompressed, int maxUncompressedBytes);
virtual bool ResetState();
private:
int StreamDecode(const char *pCompressed, int compressedBytes, char *pUncompressed, int maxUncompressedBytes) const;
int StreamEncode(const char *pUncompressedBytes, int nSamples, char *pCompressed, int maxCompressedBytes, bool bFinal) const;
private:
IVoiceCodec* m_BackendCodec;
};

View File

@ -95,7 +95,7 @@ int VoiceEncoder_Silk::Compress(const char *pUncompressedIn, int nSamplesIn, cha
int originalNBytes = (pWritePosMax - pWritePos > 0xFFFF) ? -1 : (pWritePosMax - pWritePos);
nSamplesToEncode = (nSamples < nSamplesPerFrame) ? nSamples : nSamplesPerFrame;
this->m_encControl.useDTX = 1;
this->m_encControl.useDTX = 0;
this->m_encControl.maxInternalSampleRate = 16000;
this->m_encControl.useInBandFEC = 0;
this->m_encControl.API_sampleRate = inSampleRate;

View File

@ -55,7 +55,6 @@ bool VoiceEncoder_Speex::Init(int quality, int &rawFrameSize, int &encodedFrameS
encodedFrameSize = ENCODED_FRAME_SIZE[m_Quality];
speex_encoder_ctl(m_EncoderState, SPEEX_SET_QUALITY, &m_Quality);
speex_decoder_ctl(m_DecoderState, SPEEX_SET_QUALITY, &m_Quality);
postfilter = 1;
speex_decoder_ctl(m_DecoderState, SPEEX_SET_ENH, &postfilter);

View File

@ -21,6 +21,7 @@
#include "VoiceEncoder_Silk.h"
#include "VoiceEncoder_Speex.h"
#include "voice_codec_frame.h"
#include "SteamP2PCodec.h"
#include "revoice_player.h"
#include "revoice_main.h"

View File

@ -35,7 +35,7 @@ void mm_CvarValue2(const edict_t *pEnt, int requestID, const char *cvarName, con
// ] sv_version
// "sv_version" is "1.1.2.1/2.0.0.0,48,4554"
const char* lastSeparator = strrchr(cvarName, ',');
const char* lastSeparator = strrchr(value, ',');
int buildNumber = 0;
if (lastSeparator) {
buildNumber = atoi(lastSeparator + 1);
@ -89,10 +89,16 @@ void SV_ParseVoiceData_emu(IGameClient* cl) {
switch (srcPlayer->GetCodecType()) {
case vct_silk:
{
CRC32_t hCrc;
g_engfuncs.pfnCRC32_Init(&hCrc);
g_engfuncs.pfnCRC32_ProcessBuffer(&hCrc, chReceived, nDataLength - 4);
hCrc = g_engfuncs.pfnCRC32_Final(hCrc);
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;
@ -130,7 +136,7 @@ void SV_ParseVoiceData_emu(IGameClient* cl) {
break;
}
if (sendBuf == NULL) {
if (sendBuf == NULL || nSendLen == 0) {
continue;
}
@ -178,7 +184,7 @@ void SV_WriteVoiceCodec_hooked(IRehldsHook_SV_WriteVoiceCodec* chain, sizebuf_t*
case vct_speex:
g_RehldsFuncs->MSG_WriteByte(sb, 52); //svc_voiceinit
g_RehldsFuncs->MSG_WriteString(sb, "speex"); //codec id
g_RehldsFuncs->MSG_WriteString(sb, "voice_speex"); //codec id
g_RehldsFuncs->MSG_WriteByte(sb, 5); //quality
break;

View File

@ -6,7 +6,7 @@ CRevoicePlayer g_Players[MAX_PLAYERS];
CRevoicePlayer::CRevoicePlayer() {
m_CodecType = vct_none;
m_SpeexCodec = new VoiceCodec_Frame(new VoiceEncoder_Speex());
m_SilkCodec = new VoiceEncoder_Silk();
m_SilkCodec = new CSteamP2PCodec(new VoiceEncoder_Silk());
m_SpeexCodec->Init(5);
m_SilkCodec->Init(5);

View File

@ -2,14 +2,16 @@
#include "revoice_shared.h"
#include "VoiceEncoder_Silk.h"
#include "SteamP2PCodec.h"
#include "VoiceEncoder_Speex.h"
#include "voice_codec_frame.h"
class CRevoicePlayer {
private:
IGameClient* m_RehldsClient;
revoice_codec_type m_CodecType;
VoiceEncoder_Silk* m_SilkCodec;
CSteamP2PCodec* m_SilkCodec;
VoiceCodec_Frame* m_SpeexCodec;
int m_Protocol;
@ -22,7 +24,7 @@ public:
int GetProtocol() const { return m_Protocol; }
revoice_codec_type GetCodecType() const { return m_CodecType; }
VoiceEncoder_Silk* GetSilkCodec() const { return m_SilkCodec; }
CSteamP2PCodec* GetSilkCodec() const { return m_SilkCodec; }
VoiceCodec_Frame* GetSpeexCodec() const { return m_SpeexCodec; }
IGameClient* GetClient() const { return m_RehldsClient; }
};

View File

@ -40,6 +40,7 @@ T clamp(T a, T min, T max) {
extern char* trimbuf(char *str);
extern void LCPrintf(bool critical, const char *fmt, ...);
extern uint32 crc32(const void* buf, unsigned int bufLen);
extern bool Revoice_Load();
extern bool Revoice_Utils_Init();

View File

@ -61,6 +61,14 @@ char* trimbuf(char *str) {
return str;
}
uint32 crc32(const void* buf, unsigned int bufLen) {
CRC32_t hCrc;
g_engfuncs.pfnCRC32_Init(&hCrc);
g_engfuncs.pfnCRC32_ProcessBuffer(&hCrc, (void*)buf, bufLen);
hCrc = g_engfuncs.pfnCRC32_Final(hCrc);
return hCrc;
}
void util_syserror(const char* fmt, ...)
{