diff --git a/revoice/msvc/PostBuild.bat b/revoice/msvc/PostBuild.bat
new file mode 100644
index 0000000..aa8a294
--- /dev/null
+++ b/revoice/msvc/PostBuild.bat
@@ -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
\ No newline at end of file
diff --git a/revoice/msvc/PublishPath.txt b/revoice/msvc/PublishPath.txt
new file mode 100644
index 0000000..ae7cc7c
--- /dev/null
+++ b/revoice/msvc/PublishPath.txt
@@ -0,0 +1 @@
+d:\rehlds_hbtrace\cstrike\addons\revoice\
diff --git a/revoice/msvc/ReVoice.vcxproj b/revoice/msvc/ReVoice.vcxproj
index 36e956c..ccc4e9b 100644
--- a/revoice/msvc/ReVoice.vcxproj
+++ b/revoice/msvc/ReVoice.vcxproj
@@ -35,6 +35,7 @@
+
@@ -56,6 +57,7 @@
+
@@ -120,6 +122,12 @@
ws2_32.lib;%(AdditionalDependencies)
revoice.def
+
+ IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)")
+
+
+ Automatic deployment script
+
diff --git a/revoice/msvc/ReVoice.vcxproj.filters b/revoice/msvc/ReVoice.vcxproj.filters
index f9c453d..6d51482 100644
--- a/revoice/msvc/ReVoice.vcxproj.filters
+++ b/revoice/msvc/ReVoice.vcxproj.filters
@@ -93,6 +93,9 @@
src
+
+ src
+
@@ -143,5 +146,8 @@
src
+
+ src
+
\ No newline at end of file
diff --git a/revoice/src/SteamP2PCodec.cpp b/revoice/src/SteamP2PCodec.cpp
new file mode 100644
index 0000000..7b90feb
--- /dev/null
+++ b/revoice/src/SteamP2PCodec.cpp
@@ -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;
+}
diff --git a/revoice/src/SteamP2PCodec.h b/revoice/src/SteamP2PCodec.h
new file mode 100644
index 0000000..c7cf8b5
--- /dev/null
+++ b/revoice/src/SteamP2PCodec.h
@@ -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;
+};
\ No newline at end of file
diff --git a/revoice/src/VoiceEncoder_Silk.cpp b/revoice/src/VoiceEncoder_Silk.cpp
index 92179d4..2473186 100644
--- a/revoice/src/VoiceEncoder_Silk.cpp
+++ b/revoice/src/VoiceEncoder_Silk.cpp
@@ -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;
diff --git a/revoice/src/VoiceEncoder_Speex.cpp b/revoice/src/VoiceEncoder_Speex.cpp
index 3f70a0c..88c22bc 100644
--- a/revoice/src/VoiceEncoder_Speex.cpp
+++ b/revoice/src/VoiceEncoder_Speex.cpp
@@ -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);
diff --git a/revoice/src/precompiled.h b/revoice/src/precompiled.h
index 3e3974d..c7a842b 100644
--- a/revoice/src/precompiled.h
+++ b/revoice/src/precompiled.h
@@ -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"
diff --git a/revoice/src/revoice_main.cpp b/revoice/src/revoice_main.cpp
index 321978f..2d861b4 100644
--- a/revoice/src/revoice_main.cpp
+++ b/revoice/src/revoice_main.cpp
@@ -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;
diff --git a/revoice/src/revoice_player.cpp b/revoice/src/revoice_player.cpp
index 12cf584..8596907 100644
--- a/revoice/src/revoice_player.cpp
+++ b/revoice/src/revoice_player.cpp
@@ -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);
diff --git a/revoice/src/revoice_player.h b/revoice/src/revoice_player.h
index af4bdce..eeb9c39 100644
--- a/revoice/src/revoice_player.h
+++ b/revoice/src/revoice_player.h
@@ -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; }
};
diff --git a/revoice/src/revoice_shared.h b/revoice/src/revoice_shared.h
index 165ee5d..551bc2a 100644
--- a/revoice/src/revoice_shared.h
+++ b/revoice/src/revoice_shared.h
@@ -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();
diff --git a/revoice/src/revoice_utils.cpp b/revoice/src/revoice_utils.cpp
index 3bc4070..8e958a1 100644
--- a/revoice/src/revoice_utils.cpp
+++ b/revoice/src/revoice_utils.cpp
@@ -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, ...)
{