diff --git a/dep/silk/include/SKP_Silk_typedef.h b/dep/silk/include/SKP_Silk_typedef.h
index 5e1d2e7..088d5ed 100644
--- a/dep/silk/include/SKP_Silk_typedef.h
+++ b/dep/silk/include/SKP_Silk_typedef.h
@@ -1,27 +1,27 @@
/***********************************************************************
-Copyright (c) 2006-2012, Skype Limited. All rights reserved.
-Redistribution and use in source and binary forms, with or without
-modification, (subject to the limitations in the disclaimer below)
+Copyright (c) 2006-2012, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, (subject to the limitations in the disclaimer below)
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
-- Redistributions in binary form must reproduce the above copyright
-notice, this list of conditions and the following disclaimer in the
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
-- Neither the name of Skype Limited, nor the names of specific
-contributors, may be used to endorse or promote products derived from
+- Neither the name of Skype Limited, nor the names of specific
+contributors, may be used to endorse or promote products derived from
this software without specific prior written permission.
-NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED
-BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED
+BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
-BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
***********************************************************************/
@@ -73,7 +73,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# define SKP_STR_CASEINSENSITIVE_COMPARE(x, y) _stricmp(x, y)
#else
# define SKP_STR_CASEINSENSITIVE_COMPARE(x, y) strcasecmp(x, y)
-#endif
+#endif
#define SKP_int64_MAX ((SKP_int64)0x7FFFFFFFFFFFFFFFLL) /* 2^63 - 1 */
#define SKP_int64_MIN ((SKP_int64)0x8000000000000000LL) /* -2^63 */
diff --git a/dep/silk/src/SKP_Silk_enc_API.c b/dep/silk/src/SKP_Silk_enc_API.c
index 4876958..a29dc54 100644
--- a/dep/silk/src/SKP_Silk_enc_API.c
+++ b/dep/silk/src/SKP_Silk_enc_API.c
@@ -1,27 +1,27 @@
/***********************************************************************
-Copyright (c) 2006-2012, Skype Limited. All rights reserved.
-Redistribution and use in source and binary forms, with or without
-modification, (subject to the limitations in the disclaimer below)
+Copyright (c) 2006-2012, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, (subject to the limitations in the disclaimer below)
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
-- Redistributions in binary form must reproduce the above copyright
-notice, this list of conditions and the following disclaimer in the
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
-- Neither the name of Skype Limited, nor the names of specific
-contributors, may be used to endorse or promote products derived from
+- Neither the name of Skype Limited, nor the names of specific
+contributors, may be used to endorse or promote products derived from
this software without specific prior written permission.
-NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED
-BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED
+BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
-BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
***********************************************************************/
@@ -41,9 +41,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
SKP_int SKP_Silk_SDK_Get_Encoder_Size( SKP_int32 *encSizeBytes )
{
SKP_int ret = 0;
-
+
*encSizeBytes = sizeof( SKP_Silk_encoder_state_FLP );
-
+
return ret;
}
@@ -83,7 +83,7 @@ SKP_int SKP_Silk_SDK_InitEncoder(
SKP_Silk_encoder_state_FLP *psEnc;
SKP_int ret = 0;
-
+
psEnc = ( SKP_Silk_encoder_state_FLP* )encState;
/* Reset Encoder */
@@ -103,7 +103,7 @@ SKP_int SKP_Silk_SDK_InitEncoder(
/**************************/
/* Encode frame with Silk */
/**************************/
-SKP_int SKP_Silk_SDK_Encode(
+SKP_int SKP_Silk_SDK_Encode(
void *encState, /* I/O: State */
const SKP_Silk_EncodeControlStruct *encControl, /* I: Control structure */
const SKP_int16 *samplesIn, /* I: Speech sample input vector */
@@ -124,7 +124,7 @@ SKP_int SKP_Silk_SDK_Encode(
if( ( ( encControl->API_sampleRate != 8000 ) &&
( encControl->API_sampleRate != 12000 ) &&
( encControl->API_sampleRate != 16000 ) &&
- ( encControl->API_sampleRate != 24000 ) &&
+ ( encControl->API_sampleRate != 24000 ) &&
( encControl->API_sampleRate != 32000 ) &&
( encControl->API_sampleRate != 44100 ) &&
( encControl->API_sampleRate != 48000 ) ) ||
@@ -161,7 +161,7 @@ SKP_int SKP_Silk_SDK_Encode(
}
TargetRate_bps = SKP_LIMIT( TargetRate_bps, MIN_TARGET_RATE_BPS, MAX_TARGET_RATE_BPS );
- if( ( ret = SKP_Silk_control_encoder_FLP( psEnc, PacketSize_ms, TargetRate_bps,
+ if( ( ret = SKP_Silk_control_encoder_FLP( psEnc, PacketSize_ms, TargetRate_bps,
PacketLoss_perc, UseDTX, Complexity) ) != 0 ) {
SKP_assert( 0 );
return( ret );
@@ -176,8 +176,8 @@ SKP_int SKP_Silk_SDK_Encode(
#if MAX_FS_KHZ > 16
/* Detect energy above 8 kHz */
- if( SKP_min( API_fs_Hz, 1000 * max_internal_fs_kHz ) == 24000 &&
- psEnc->sCmn.sSWBdetect.SWB_detected == 0 &&
+ if( SKP_min( API_fs_Hz, 1000 * max_internal_fs_kHz ) == 24000 &&
+ psEnc->sCmn.sSWBdetect.SWB_detected == 0 &&
psEnc->sCmn.sSWBdetect.WB_detected == 0 ) {
SKP_Silk_detect_SWB_input( &psEnc->sCmn.sSWBdetect, samplesIn, ( SKP_int )nSamplesIn );
}
@@ -187,18 +187,18 @@ SKP_int SKP_Silk_SDK_Encode(
MaxBytesOut = 0; /* return 0 output bytes if no encoder called */
while( 1 ) {
nSamplesToBuffer = psEnc->sCmn.frame_length - psEnc->sCmn.inputBufIx;
- if( API_fs_Hz == SKP_SMULBB( 1000, psEnc->sCmn.fs_kHz ) ) {
+ if( API_fs_Hz == SKP_SMULBB( 1000, psEnc->sCmn.fs_kHz ) ) {
nSamplesToBuffer = SKP_min_int( nSamplesToBuffer, nSamplesIn );
nSamplesFromInput = nSamplesToBuffer;
/* Copy to buffer */
SKP_memcpy( &psEnc->sCmn.inputBuf[ psEnc->sCmn.inputBufIx ], samplesIn, nSamplesFromInput * sizeof( SKP_int16 ) );
- } else {
+ } else {
nSamplesToBuffer = SKP_min( nSamplesToBuffer, 10 * input_10ms * psEnc->sCmn.fs_kHz );
nSamplesFromInput = SKP_DIV32_16( nSamplesToBuffer * API_fs_Hz, psEnc->sCmn.fs_kHz * 1000 );
/* Resample and write to buffer */
- ret += SKP_Silk_resampler( &psEnc->sCmn.resampler_state,
+ ret += SKP_Silk_resampler( &psEnc->sCmn.resampler_state,
&psEnc->sCmn.inputBuf[ psEnc->sCmn.inputBufIx ], samplesIn, nSamplesFromInput );
- }
+ }
samplesIn += nSamplesFromInput;
nSamplesIn -= nSamplesFromInput;
psEnc->sCmn.inputBufIx += nSamplesToBuffer;
diff --git a/dep/silk/src/SKP_Silk_structs.h b/dep/silk/src/SKP_Silk_structs.h
index 4cb1db5..c7a43c0 100644
--- a/dep/silk/src/SKP_Silk_structs.h
+++ b/dep/silk/src/SKP_Silk_structs.h
@@ -1,27 +1,27 @@
/***********************************************************************
-Copyright (c) 2006-2012, Skype Limited. All rights reserved.
-Redistribution and use in source and binary forms, with or without
-modification, (subject to the limitations in the disclaimer below)
+Copyright (c) 2006-2012, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, (subject to the limitations in the disclaimer below)
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
-- Redistributions in binary form must reproduce the above copyright
-notice, this list of conditions and the following disclaimer in the
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
-- Neither the name of Skype Limited, nor the names of specific
-contributors, may be used to endorse or promote products derived from
+- Neither the name of Skype Limited, nor the names of specific
+contributors, may be used to endorse or promote products derived from
this software without specific prior written permission.
-NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED
-BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED
+BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
-BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
***********************************************************************/
@@ -57,7 +57,7 @@ typedef struct {
/* Struct for Low BitRate Redundant (LBRR) information */
typedef struct {
- SKP_uint8 payload[ MAX_ARITHM_BYTES ];
+ SKP_uint8 payload[ MAX_ARITHM_BYTES ];
SKP_int nBytes; /* Number of bytes in payload */
SKP_int usage; /* Tells how the payload should be used as FEC */
} SKP_SILK_LBRR_struct;
@@ -190,7 +190,7 @@ typedef struct {
const SKP_Silk_NLSF_CB_struct *psNLSF_CB[ 2 ]; /* Pointers to voiced/unvoiced NLSF codebooks */
- /* Struct for Inband LBRR */
+ /* Struct for Inband LBRR */
SKP_SILK_LBRR_struct LBRR_buffer[ MAX_LBRR_DELAY ];
SKP_int oldest_LBRR_idx;
SKP_int useInBandFEC; /* Saves the API setting for query */
@@ -310,7 +310,7 @@ typedef struct {
/* Parameters used to investigate if inband FEC is used */
SKP_int vadFlag;
SKP_int no_FEC_counter; /* Counts number of frames wo inband FEC */
- SKP_int inband_FEC_offset; /* 0: no FEC, 1: FEC with 1 packet offset, 2: FEC w 2 packets offset */
+ SKP_int inband_FEC_offset; /* 0: no FEC, 1: FEC with 1 packet offset, 2: FEC w 2 packets offset */
/* CNG state */
SKP_Silk_CNG_struct sCNG;
diff --git a/dep/silk/src/SKP_Silk_structs_FLP.h b/dep/silk/src/SKP_Silk_structs_FLP.h
index 35dd7ae..4b68425 100644
--- a/dep/silk/src/SKP_Silk_structs_FLP.h
+++ b/dep/silk/src/SKP_Silk_structs_FLP.h
@@ -1,27 +1,27 @@
/***********************************************************************
-Copyright (c) 2006-2012, Skype Limited. All rights reserved.
-Redistribution and use in source and binary forms, with or without
-modification, (subject to the limitations in the disclaimer below)
+Copyright (c) 2006-2012, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, (subject to the limitations in the disclaimer below)
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
-- Redistributions in binary form must reproduce the above copyright
-notice, this list of conditions and the following disclaimer in the
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
-- Neither the name of Skype Limited, nor the names of specific
-contributors, may be used to endorse or promote products derived from
+- Neither the name of Skype Limited, nor the names of specific
+contributors, may be used to endorse or promote products derived from
this software without specific prior written permission.
-NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED
-BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED
+BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
-BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
***********************************************************************/
diff --git a/revoice/dist/c2a2_ba_launch.wav b/revoice/dist/c2a2_ba_launch.wav
new file mode 100644
index 0000000..b0206b9
Binary files /dev/null and b/revoice/dist/c2a2_ba_launch.wav differ
diff --git a/revoice/dist/cslig_nuages.wav b/revoice/dist/cslig_nuages.wav
new file mode 100644
index 0000000..56a32ce
Binary files /dev/null and b/revoice/dist/cslig_nuages.wav differ
diff --git a/revoice/dist/dance.wav b/revoice/dist/dance.wav
new file mode 100644
index 0000000..2c63d9d
Binary files /dev/null and b/revoice/dist/dance.wav differ
diff --git a/revoice/dist/kolshik.wav b/revoice/dist/kolshik.wav
new file mode 100644
index 0000000..c87c4ec
Binary files /dev/null and b/revoice/dist/kolshik.wav differ
diff --git a/revoice/dist/pchela.wav b/revoice/dist/pchela.wav
new file mode 100644
index 0000000..114294d
Binary files /dev/null and b/revoice/dist/pchela.wav differ
diff --git a/revoice/msvc/revoice.vcxproj b/revoice/msvc/revoice.vcxproj
index 01ec10a..3646ffe 100644
--- a/revoice/msvc/revoice.vcxproj
+++ b/revoice/msvc/revoice.vcxproj
@@ -145,7 +145,7 @@
Level3
Disabled
WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
- $(ProjectDir)../src/;$(ProjectDir)../public/;$(ProjectDir)../version/;$(ProjectDir)../include/;$(SolutionDir)../dep/rehlsdk/common/;$(SolutionDir)../dep/rehlsdk/dlls/;$(SolutionDir)../dep/rehlsdk/engine/;$(SolutionDir)../dep/rehlsdk/public/;$(SolutionDir)../dep/silk/include/;$(SolutionDir)../dep/opus/include/;$(SolutionDir)../dep/speex/include/;$(SolutionDir)../dep/metamod/;%(AdditionalIncludeDirectories)
+ $(ProjectDir)../src/;$(ProjectDir)../public/;$(ProjectDir)../version/;$(ProjectDir)../include/;$(SolutionDir)../dep/rehlsdk/common/;$(SolutionDir)../dep/rehlsdk/dlls/;$(SolutionDir)../dep/rehlsdk/engine/;$(SolutionDir)../dep/rehlsdk/public/;$(SolutionDir)../dep/silk/include/;$(SolutionDir)../dep/opus/include/;$(SolutionDir)../dep/speex/include/;$(SolutionDir)../dep/metamod/;$(SolutionDir)../dep/opus/silk/;%(AdditionalIncludeDirectories)
precompiled.h
diff --git a/revoice/public/IVoiceCodec.h b/revoice/public/IVoiceCodec.h
index 632c45b..79721f1 100644
--- a/revoice/public/IVoiceCodec.h
+++ b/revoice/public/IVoiceCodec.h
@@ -12,6 +12,7 @@ public:
// Initialize the object. The uncompressed format is always 8-bit signed mono.
virtual bool Init(int quality) = 0;
virtual void Release() = 0;
+ virtual int GetSamplesPerFrame() { return 0; }
// Compress the voice data.
// pUncompressed - 16-bit signed mono voice data.
diff --git a/revoice/public/counter.h b/revoice/public/counter.h
new file mode 100644
index 0000000..0b55e02
--- /dev/null
+++ b/revoice/public/counter.h
@@ -0,0 +1,188 @@
+/*
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2 of the License, or (at
+* your option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+* In addition, as a special exception, the author gives permission to
+* link the code of this program with the Half-Life Game Engine ("HL
+* Engine") and Modified Game Libraries ("MODs") developed by Valve,
+* L.L.C ("Valve"). You must obey the GNU General Public License in all
+* respects for all of the code used other than the HL Engine and MODs
+* from Valve. If you modify this file, you may extend this exception
+* to your version of the file, but you are not obligated to do so. If
+* you do not wish to do so, delete this exception statement from your
+* version.
+*
+*/
+
+#pragma once
+
+#ifdef _WIN32
+ #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+ #include
+ #include
+ #include
+#else
+ #include
+ #include
+ #include
+ #include
+ #ifdef OSX
+ #include
+ #else
+ #include
+ #endif
+ #include
+#endif
+
+#include
+#include
+#include
+#include
+#include
+
+class CCounter
+{
+public:
+ CCounter();
+
+ bool Init();
+ double GetCurTime();
+
+private:
+ int m_iLowShift;
+ double m_flPerfCounterFreq;
+ double m_flCurrentTime;
+ double m_flLastCurrentTime;
+};
+
+inline CCounter::CCounter() :
+ m_iLowShift(0),
+ m_flPerfCounterFreq(0),
+ m_flCurrentTime(0),
+ m_flLastCurrentTime(0)
+{
+ Init();
+}
+
+inline bool CCounter::Init()
+{
+#ifdef _WIN32
+
+ LARGE_INTEGER performanceFreq;
+ if (!QueryPerformanceFrequency(&performanceFreq))
+ return false;
+
+ // get 32 out of the 64 time bits such that we have around
+ // 1 microsecond resolution
+ unsigned int lowpart, highpart;
+ lowpart = (unsigned int)performanceFreq.LowPart;
+ highpart = (unsigned int)performanceFreq.HighPart;
+ m_iLowShift = 0;
+
+ while (highpart || (lowpart > 2000000.0))
+ {
+ m_iLowShift++;
+ lowpart >>= 1;
+ lowpart |= (highpart & 1) << 31;
+ highpart >>= 1;
+ }
+
+ m_flPerfCounterFreq = 1.0 / (double)lowpart;
+
+#endif // _WIN32
+
+ return true;
+}
+
+inline double CCounter::GetCurTime()
+{
+#ifdef _WIN32
+
+ static int sametimecount;
+ static unsigned int oldtime;
+ static int first = 1;
+ LARGE_INTEGER PerformanceCount;
+ unsigned int temp, t2;
+ double time;
+
+ QueryPerformanceCounter(&PerformanceCount);
+ if (m_iLowShift == 0)
+ {
+ temp = (unsigned int)PerformanceCount.LowPart;
+ }
+ else
+ {
+ temp = ((unsigned int)PerformanceCount.LowPart >> m_iLowShift) |
+ ((unsigned int)PerformanceCount.HighPart << (32 - m_iLowShift));
+ }
+
+ if (first)
+ {
+ oldtime = temp;
+ first = 0;
+ }
+ else
+ {
+ // check for turnover or backward time
+ if ((temp <= oldtime) && ((oldtime - temp) < 0x10000000))
+ {
+ // so we can't get stuck
+ oldtime = temp;
+ }
+ else
+ {
+ t2 = temp - oldtime;
+
+ time = (double)t2 * m_flPerfCounterFreq;
+ oldtime = temp;
+
+ m_flCurrentTime += time;
+
+ if (m_flCurrentTime == m_flLastCurrentTime)
+ {
+ if (++sametimecount > 100000)
+ {
+ m_flCurrentTime += 1.0;
+ sametimecount = 0;
+ }
+ }
+ else
+ {
+ sametimecount = 0;
+ }
+
+ m_flLastCurrentTime = m_flCurrentTime;
+ }
+ }
+
+ return m_flCurrentTime;
+
+#else // _WIN32
+
+ struct timeval tp;
+ static int secbase = 0;
+
+ gettimeofday(&tp, NULL);
+
+ if (!secbase)
+ {
+ secbase = tp.tv_sec;
+ return (tp.tv_usec / 1000000.0);
+ }
+
+ return ((tp.tv_sec - secbase) + tp.tv_usec / 1000000.0);
+
+#endif // _WIN32
+}
diff --git a/revoice/src/SteamP2PCodec.cpp b/revoice/src/SteamP2PCodec.cpp
index b1cc45f..9c5122a 100644
--- a/revoice/src/SteamP2PCodec.cpp
+++ b/revoice/src/SteamP2PCodec.cpp
@@ -90,10 +90,10 @@ int CSteamP2PCodec::StreamEncode(const char *pUncompressedBytes, int nSamples, c
}
*(writePos++) = PLT_SamplingRate; // Set sampling rate
- *(uint16 *)writePos = 16000;
+ *(uint16 *)writePos = 8000;
writePos += 2;
- *(writePos++) = PLT_Silk; // Voice payload
+ *(writePos++) = PLT_Silk;//PLT_Silk; // Voice payload
int compressRes = m_BackendCodec->Compress(pUncompressedBytes, nSamples, writePos + 2, maxCompressedBytes - (1 + 2 + 1 + 2), bFinal);
if (compressRes == 0) {
@@ -123,18 +123,37 @@ int CSteamP2PCodec::Decompress(const char *pCompressed, int compressedBytes, cha
return StreamDecode(pCompressed + 8, compressedBytes - 12, pUncompressed, maxUncompressedBytes);
}
+extern uint64_t g_ulSteamIdCurrent;
+
int CSteamP2PCodec::Compress(const char *pUncompressedBytes, int nSamples, char *pCompressed, int maxCompressedBytes, bool bFinal)
{
if (maxCompressedBytes < 12) { // no room
return 0;
}
+ /*union CSteamID
+ {
+ uint64 allbits64;
+ struct
+ {
+ uint32 lo;
+ uint32 hi;
+ };
+ };
+
+ CSteamID steamid;
+ steamid.allbits64 = 76561198051972183;
+
char *writePos = pCompressed;
- *(uint32 *)writePos = 0x00000011; // steamid (low part)
+ *(uint32 *)writePos = steamid.lo; // steamid (low part)
writePos += 4;
- *(uint32 *)writePos = 0x01100001; // steamid (high part)
- writePos += 4;
+ *(uint32 *)writePos = steamid.hi; // steamid (high part)
+ writePos += 4;*/
+
+ char *writePos = pCompressed;
+ *(uint64 *)writePos = g_ulSteamIdCurrent;//76561198051972183;
+ writePos += 8;
int encodeRes = StreamEncode(pUncompressedBytes, nSamples, writePos, maxCompressedBytes - 12, bFinal);
if (encodeRes <= 0) {
diff --git a/revoice/src/VoiceEncoder_Silk.cpp b/revoice/src/VoiceEncoder_Silk.cpp
index 6a61820..6ec5698 100644
--- a/revoice/src/VoiceEncoder_Silk.cpp
+++ b/revoice/src/VoiceEncoder_Silk.cpp
@@ -59,82 +59,88 @@ bool VoiceEncoder_Silk::ResetState()
int VoiceEncoder_Silk::Compress(const char *pUncompressedIn, int nSamplesIn, char *pCompressed, int maxCompressedBytes, bool bFinal)
{
- signed int nSamplesToUse; // edi@4
- const __int16 *psRead; // ecx@4
- int nSamples; // edi@5
- int nSamplesToEncode; // esi@6
- char *pWritePos; // ebp@6
- int nSamplesPerFrame; // [sp+28h] [bp-44h]@5
- 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 = inSampleRate * nSampleDataMinMS / 1000;
+ const int nSampleDataMinMS = 20;
+ const int nSamplesMin = (nSampleDataMinMS * inSampleRate) / 1000;
- /*
- if ((nSamplesIn + m_bufOverflowBytes.TellPut() / 2) < nSamplesMin && !bFinal) {
- m_bufOverflowBytes.Put(pUncompressedIn, 2 * nSamplesIn);
+ if (nSamplesIn + GetNumQueuedEncodingSamples() < nSamplesMin && !bFinal)
+ {
+ m_bufOverflowBytes.Put(pUncompressedIn, nSamplesIn * BYTES_PER_SAMPLE);
return 0;
}
- */
- if (m_bufOverflowBytes.TellPut()) {
- m_bufOverflowBytes.Put(pUncompressedIn, 2 * nSamplesIn);
+ const int16_t *psRead = (const int16_t *)pUncompressedIn;
- psRead = (const __int16 *)m_bufOverflowBytes.Base();
- nSamplesToUse = m_bufOverflowBytes.TellPut() / 2;
- } else {
- psRead = (const __int16 *)pUncompressedIn;
- nSamplesToUse = nSamplesIn;
+ int nSamplesToUse = nSamplesIn;
+ int nSamplesPerFrame = nSamplesMin;
+ int nSamplesRemaining = nSamplesIn % nSamplesMin;
+
+ if (m_bufOverflowBytes.TellPut() || nSamplesRemaining && bFinal)
+ {
+ m_bufOverflowBytes.Put(pUncompressedIn, nSamplesIn * BYTES_PER_SAMPLE);
+ nSamplesToUse = GetNumQueuedEncodingSamples();
+ nSamplesRemaining = nSamplesToUse % nSamplesPerFrame;
+
+ if (bFinal && nSamplesRemaining)
+ {
+ // fill samples of silence at the remaining bytes
+ for (int i = nSamplesPerFrame - nSamplesRemaining; i > 0; i--)
+ {
+ m_bufOverflowBytes.PutShort(0);
+ }
+
+ nSamplesToUse = GetNumQueuedEncodingSamples();
+ nSamplesRemaining = nSamplesToUse % nSamplesPerFrame;
+ }
+
+ psRead = (const int16_t *)m_bufOverflowBytes.Base();
+ Assert(!bFinal || nSamplesRemaining == 0);
}
- nSamplesPerFrame = inSampleRate / 50;
- nSamplesRemaining = nSamplesToUse % nSamplesPerFrame;
- pWritePosMax = pCompressed + maxCompressedBytes;
- nSamples = nSamplesToUse - nSamplesRemaining;
- pWritePos = pCompressed;
+ char *pWritePos = pCompressed;
+ const char *pWritePosMax = &pCompressed[maxCompressedBytes];
+ int nSamples = nSamplesToUse - nSamplesRemaining;
while (nSamples > 0)
{
- int16 *pWritePayloadSize = (int16 *)pWritePos;
- pWritePos += sizeof(int16); //leave 2 bytes for the frame size (will be written after encoding)
+ int16_t *pWritePayloadSize = (int16_t *)pWritePos;
+ pWritePos += sizeof(int16_t);
- int originalNBytes = (pWritePosMax - pWritePos > 0xFFFF) ? -1 : (pWritePosMax - pWritePos);
- nSamplesToEncode = (nSamples < nSamplesPerFrame) ? nSamples : nSamplesPerFrame;
+ m_encControl.maxInternalSampleRate = 24000;
+ m_encControl.useInBandFEC = 0;
+ m_encControl.useDTX = 1;
+ m_encControl.complexity = 2;
+ m_encControl.API_sampleRate = inSampleRate;
+ m_encControl.packetSize = 20 * (inSampleRate / 1000);
+ m_encControl.packetLossPercentage = m_packetLoss_perc;
+ m_encControl.bitRate = 30000;//(m_targetRate_bps >= 0) ? m_targetRate_bps : 0;//clamp(voice_silk_bitrate.GetInt(), 10000, 40000);
- this->m_encControl.useDTX = 0;
- this->m_encControl.maxInternalSampleRate = 16000;
- this->m_encControl.useInBandFEC = 0;
- this->m_encControl.API_sampleRate = inSampleRate;
- this->m_encControl.complexity = 2;
- 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;
+ int nSamplesToEncode = min(nSamples, nSamplesPerFrame);
+
+ int nBytes = ((pWritePosMax - pWritePos) < 0x7FFF) ? (pWritePosMax - pWritePos) : 0x7FFF;
+ int ret = SKP_Silk_SDK_Encode(m_pEncoder, &m_encControl, psRead, nSamplesToEncode, (unsigned char *)pWritePos, (__int16 *)&nBytes);
+ *pWritePayloadSize = nBytes; // write frame size
nSamples -= nSamplesToEncode;
-
- int16 nBytes = originalNBytes;
- int res = SKP_Silk_SDK_Encode(this->m_pEncoder, &this->m_encControl, psRead, nSamplesToEncode, (unsigned char *)pWritePos, &nBytes);
- *pWritePayloadSize = nBytes; //write frame size
-
- pWritePos += nBytes;
psRead += nSamplesToEncode;
+ pWritePos += nBytes;
}
m_bufOverflowBytes.Clear();
- if (nSamplesRemaining <= nSamplesIn && nSamplesRemaining) {
- m_bufOverflowBytes.Put(&pUncompressedIn[2 * (nSamplesIn - nSamplesRemaining)], 2 * nSamplesRemaining);
+ if (nSamplesRemaining && nSamplesRemaining <= nSamplesIn)
+ {
+ m_bufOverflowBytes.Put(pUncompressedIn + ((nSamplesIn - nSamplesRemaining) * sizeof(int16_t)), nSamplesRemaining * BYTES_PER_SAMPLE);
}
if (bFinal)
{
ResetState();
- if (pWritePosMax > pWritePos + 2) {
- uint16 *pWriteEndFlag = (uint16*)pWritePos;
- pWritePos += sizeof(uint16);
+ if (pWritePosMax > pWritePos + 2)
+ {
+ uint16_t *pWriteEndFlag = (uint16_t *)pWritePos;
+ pWritePos += sizeof(uint16_t);
*pWriteEndFlag = 0xFFFF;
}
}
diff --git a/revoice/src/VoiceEncoder_Silk.h b/revoice/src/VoiceEncoder_Silk.h
index c3c0d35..420667b 100644
--- a/revoice/src/VoiceEncoder_Silk.h
+++ b/revoice/src/VoiceEncoder_Silk.h
@@ -23,7 +23,7 @@ public:
virtual bool Init(int quality);
virtual void Release();
- virtual bool ResetState();
+ virtual bool ResetState();
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);
diff --git a/revoice/src/dllapi.cpp b/revoice/src/dllapi.cpp
index 8b5e149..8b86924 100644
--- a/revoice/src/dllapi.cpp
+++ b/revoice/src/dllapi.cpp
@@ -52,7 +52,7 @@ DLL_FUNCTIONS g_DLLFuncTable =
NULL, // pfnClientDisconnect
NULL, // pfnClientKill
NULL, // pfnClientPutInServer
- NULL, // pfnClientCommand
+ &ClientCommand, // pfnClientCommand
NULL, // pfnClientUserInfoChanged
NULL, // pfnServerActivate
NULL, // pfnServerDeactivate
@@ -105,14 +105,14 @@ DLL_FUNCTIONS g_DLLFuncTable_Post =
NULL, // pfnClientConnect
NULL, // pfnClientDisconnect
NULL, // pfnClientKill
- NULL, // pfnClientPutInServer
+ &ClientPutInServer_PostHook, // pfnClientPutInServer
NULL, // pfnClientCommand
NULL, // pfnClientUserInfoChanged
&ServerActivate_PostHook, // pfnServerActivate
NULL, // pfnServerDeactivate
NULL, // pfnPlayerPreThink
NULL, // pfnPlayerPostThink
- NULL, // pfnStartFrame
+ &StartFrame_Post, // pfnStartFrame
NULL, // pfnParmsNewLevel
NULL, // pfnParmsChangeLevel
NULL, // pfnGetGameDescription
diff --git a/revoice/src/revoice_cfg.cpp b/revoice/src/revoice_cfg.cpp
index 12d8286..e84734d 100644
--- a/revoice/src/revoice_cfg.cpp
+++ b/revoice/src/revoice_cfg.cpp
@@ -18,6 +18,9 @@ bool Revoice_Init_Config()
const char *pszGameDir = GET_GAME_INFO(PLID, GINFO_GAMEDIR);
const char *pszPluginDir = GET_PLUGIN_PATH(PLID);
+ printf("> pszGameDir: (%s)\n", pszGameDir);
+ printf("> pszPluginDir: (%s)\n", pszPluginDir);
+
char szRelativePath[MAX_PATH];
strncpy(szRelativePath, &pszPluginDir[strlen(pszGameDir) + 1], sizeof(szRelativePath) - 1);
szRelativePath[sizeof(szRelativePath) - 1] = '\0';
@@ -94,7 +97,7 @@ void Cmd_REV_Status()
for (int i = 0; i < g_RehldsSvs->GetMaxClients(); i++) {
auto plr = &g_Players[i];
if (plr->IsConnected()) {
- printf("#%-4i %-32s %-6s %-4i %-2i %-3s", i + 1, UTIL_VarArgs("\"%s\"", plr->GetClient()->GetName()), plr->GetCodecTypeToString(), plr->GetVoiceRate(), plr->GetProtocol(), plr->IsHLTV() ? " (HLTV)" : "");
+ UTIL_ServerPrintf("#%-4i %-32s %-6s %-4i %-2i %-3s", i + 1, UTIL_VarArgs("\"%s\"", plr->GetClient()->GetName()), plr->GetCodecTypeToString(), plr->GetVoiceRate(), plr->GetProtocol(), plr->IsHLTV() ? " (HLTV)" : "");
nUsers++;
}
}
diff --git a/revoice/src/revoice_main.cpp b/revoice/src/revoice_main.cpp
index c1530ba..a251299 100644
--- a/revoice/src/revoice_main.cpp
+++ b/revoice/src/revoice_main.cpp
@@ -20,7 +20,7 @@ void CvarValue2_PreHook(const edict_t *pEnt, int requestID, const char *cvarName
if (lastSeparator)
{
int buildNumber = atoi(lastSeparator + 1);
- if (buildNumber > 4554) {
+ if (buildNumber > 4554 || buildNumber == 2017) {
plr->SetCodecType(vct_opus);
}
}
@@ -75,52 +75,34 @@ void SV_ParseVoiceData_emu(IGameClient *cl)
}
CRevoicePlayer *srcPlayer = GetPlayerByClientPtr(cl);
- srcPlayer->SetLastVoiceTime(g_RehldsSv->GetTime());
+
+ //FILE *fp = fopen("recorder.snd", "ab");
+ //if (fp)
+ //{
+ // printf(" -> Write chunk: (%d)\n", nDataLength);
+ // fwrite(chReceived, 1, nDataLength, fp);
+ // fclose(fp);
+ //}
+
+ /*srcPlayer->SetLastVoiceTime(g_RehldsSv->GetTime());
srcPlayer->IncreaseVoiceRate(nDataLength);
- char transcodedBuf[4096];
+ char compressedBuf[16384];
+ int compressedSize = TranscodeVoice(srcPlayer, chReceived, nDataLength, srcPlayer->GetOpusCodec(), srcPlayer->GetSilkCodec(), compressedBuf, sizeof(compressedBuf));
- char *silkData = nullptr;
- char *speexData = nullptr;
+ uint32_t computedChecksum = crc32(compressedBuf, compressedSize - 4);
+ uint32 wireChecksum = *(uint32 *)(compressedBuf + compressedSize - 4);
- int silkDataLen = 0;
- int speexDataLen = 0;
-
- switch (srcPlayer->GetCodecType())
+ FILE *fp = fopen("recorder.snd", "ab");
+ if (fp)
{
- case vct_silk:
- {
- if (nDataLength > MAX_SILK_DATA_LEN || srcPlayer->GetVoiceRate() > MAX_SILK_VOICE_RATE)
- return;
+ printf(" -> Write chunk: (%d), computedChecksum: (%u), wireChecksum: (%u)\n", compressedSize, computedChecksum, wireChecksum);
+ printf(" -> Write chunk: (%d), computedChecksum: (%u), wireChecksum: (%u)\n", compressedSize, computedChecksum, wireChecksum);
+ fwrite(compressedBuf, 1, compressedSize, fp);
+ fclose(fp);
+ }*/
- silkData = chReceived; silkDataLen = nDataLength;
- speexData = transcodedBuf;
- speexDataLen = TranscodeVoice(srcPlayer, silkData, silkDataLen, srcPlayer->GetSilkCodec(), srcPlayer->GetSpeexCodec(), transcodedBuf, sizeof(transcodedBuf));
- break;
- }
- case vct_opus:
- {
- if (nDataLength > MAX_OPUS_DATA_LEN || srcPlayer->GetVoiceRate() > MAX_OPUS_VOICE_RATE)
- return;
-
- silkData = chReceived; silkDataLen = nDataLength;
- speexData = transcodedBuf;
- speexDataLen = TranscodeVoice(srcPlayer, silkData, silkDataLen, srcPlayer->GetOpusCodec(), 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(srcPlayer, speexData, speexDataLen, srcPlayer->GetSpeexCodec(), srcPlayer->GetSilkCodec(), transcodedBuf, sizeof(transcodedBuf));
- break;
- }
- default:
- return;
- }
+ //return;
int maxclients = g_RehldsSvs->GetMaxClients();
for (int i = 0; i < maxclients; i++)
@@ -128,43 +110,21 @@ void SV_ParseVoiceData_emu(IGameClient *cl)
CRevoicePlayer *dstPlayer = &g_Players[i];
IGameClient *dstClient = dstPlayer->GetClient();
- if (!((1 << i) & cl->GetVoiceStream(0)) && dstPlayer != srcPlayer)
+ 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:
- case vct_opus:
- sendBuf = silkData;
- nSendLen = silkDataLen;
- break;
- case vct_speex:
- sendBuf = speexData;
- nSendLen = speexDataLen;
- break;
- default:
- sendBuf = nullptr;
- nSendLen = 0;
- break;
}
- if (sendBuf == nullptr || nSendLen == 0)
+ if (!dstClient->IsActive() && !dstClient->IsConnected() && dstPlayer != srcPlayer) {
continue;
-
- if (dstPlayer == srcPlayer && !dstClient->GetLoopback())
- nSendLen = 0;
+ }
sizebuf_t *dstDatagram = dstClient->GetDatagram();
- if (dstDatagram->cursize + nSendLen + 6 < dstDatagram->maxsize) {
+ if (dstDatagram->cursize + nDataLength + 6 < dstDatagram->maxsize)
+ {
g_RehldsFuncs->MSG_WriteByte(dstDatagram, svc_voicedata);
g_RehldsFuncs->MSG_WriteByte(dstDatagram, cl->GetId());
- g_RehldsFuncs->MSG_WriteShort(dstDatagram, nSendLen);
- g_RehldsFuncs->MSG_WriteBuf(dstDatagram, nSendLen, sendBuf);
+ g_RehldsFuncs->MSG_WriteShort(dstDatagram, nDataLength);
+ g_RehldsFuncs->MSG_WriteBuf(dstDatagram, nDataLength, chReceived);
}
}
}
@@ -172,10 +132,10 @@ void SV_ParseVoiceData_emu(IGameClient *cl)
void Rehlds_HandleNetCommand(IRehldsHook_HandleNetCommand *chain, IGameClient *cl, int8 opcode)
{
const int clc_voicedata = 8;
- if (opcode == clc_voicedata) {
- SV_ParseVoiceData_emu(cl);
- return;
- }
+ //if (opcode == clc_voicedata) {
+ // SV_ParseVoiceData_emu(cl);
+ // return;
+ //}
chain->callNext(cl, opcode);
}
@@ -188,6 +148,438 @@ qboolean ClientConnect_PreHook(edict_t *pEntity, const char *pszName, const char
RETURN_META_VALUE(MRES_IGNORED, TRUE);
}
+enum VoiceCodec_e
+{
+ VC_SPEEX = 0,
+ VC_SILK,
+ VC_MAX
+};
+
+struct SpeexContext_t
+{
+ VoiceCodec_e type;
+ const char *filename;
+ char *data;
+ int nDataBytes;
+ int wBitsPerSample;
+ int frame;
+ bool play;
+ bool load;
+ bool failed;
+ bool send_order;
+ double time;
+ double nextsend;
+ float framerate;
+ int index;
+ int startindex;
+ uint64_t steamid;
+ IVoiceCodec *encoder;
+};
+
+int g_tracks_silk = 0;
+int g_tracks_speex = 0;
+int g_tracksNumbers[VC_MAX][16] = {0};
+uint64_t g_ulSteamIdCurrent = 0ULL;
+
+SpeexContext_t g_SoundLists[] =
+{
+ { VC_SPEEX, "kolshik.wav", nullptr, 0, 0, 0, false, false, false, false, 0, 0, 8000, 2, 0, 76561198051972183ULL, nullptr },
+ { VC_SPEEX, "pchela.wav", nullptr, 0, 0, 0, false, false, false, false, 0, 0, 11025, 3, 0, 76561198051972185ULL, nullptr },
+ { VC_SILK, "c2a2_ba_launch.wav", nullptr, 0, 0, 0, false, false, false, false, 0, 0, 8000, 7, 0, 76561198051972186ULL, nullptr },
+ { VC_SILK, "cslig_nuages.wav", nullptr, 0, 0, 0, false, false, false, false, 0, 0, 8000, 7, 0, 76561198051972182ULL, nullptr },
+ { VC_SILK, "kolshik.wav", nullptr, 0, 0, 0, false, false, false, false, 0, 0, 8000, 4, 0, 76561198051972187ULL, nullptr },
+ { VC_SILK, "dance.wav", nullptr, 0, 0, 0, false, false, false, false, 0, 0, 8000, 5, 102832, 76561198051972188ULL, nullptr },
+};
+
+void ClientCommand(edict_t *pEdict)
+{
+ const char *argv1 = CMD_ARGV(0);
+ if (_stricmp(argv1, "speexmulti") == 0 || _stricmp(argv1, "silkmulti") == 0)
+ {
+ VoiceCodec_e type = _stricmp(argv1, "speexmulti") == 0 ? VC_SPEEX : VC_SILK;
+
+ if (type == VC_SILK)
+ {
+ g_SoundLists[2].play ^= true;
+ g_SoundLists[3].play ^= true;
+ g_SoundLists[4].play ^= true;
+ g_SoundLists[5].play ^= true;
+
+ if (g_SoundLists[2].play)
+ g_SoundLists[2].time = gpGlobals->time;
+
+ if (g_SoundLists[3].play)
+ g_SoundLists[3].time = gpGlobals->time;
+
+ if (g_SoundLists[4].play)
+ g_SoundLists[4].time = gpGlobals->time;
+
+ if (g_SoundLists[5].play)
+ g_SoundLists[5].time = gpGlobals->time;
+
+ g_SoundLists[2].frame = g_SoundLists[2].startindex;
+ g_SoundLists[3].frame = g_SoundLists[3].startindex;
+ g_SoundLists[4].frame = g_SoundLists[4].startindex;
+ g_SoundLists[5].frame = g_SoundLists[5].startindex;
+ }
+ else
+ {
+/*
+ g_SoundLists[0].play ^= true;
+ g_SoundLists[1].play ^= true;
+
+ if (g_SoundLists[0].play)
+ {
+ g_SoundLists[0].time = gpGlobals->time;
+ }
+
+ if (g_SoundLists[1].play)
+ {
+ g_SoundLists[1].time = gpGlobals->time;
+ }
+
+ g_SoundLists[0].frame = 0;
+ g_SoundLists[1].frame = 0;
+*/
+ }
+
+ RETURN_META(MRES_SUPERCEDE);
+ }
+ else if (_stricmp(argv1, "speexplay") == 0 || _stricmp(argv1, "silkplay") == 0)
+ {
+ VoiceCodec_e type = _stricmp(argv1, "speexplay") == 0 ? VC_SPEEX : VC_SILK;
+
+ if (CMD_ARGC() < 2)
+ {
+ int nIndex = 0;
+
+ bool header_once = false;
+ for (auto &list : g_SoundLists)
+ {
+ if (list.type != type)
+ continue;
+
+ if (!header_once)
+ {
+ header_once = true;
+
+ CLIENT_PRINTF(pEdict, print_console, UTIL_VarArgs("\nusage: silkplay [ ]\n\n"));
+ CLIENT_PRINTF(pEdict, print_console, UTIL_VarArgs("%4s %-32s %-10s %-12s\n", "#", "[name]", "[chunk]", "[framerate]"));
+ }
+
+ CLIENT_PRINTF(pEdict, print_console, UTIL_VarArgs("%4d. %-32s %-10d %-12.2f\n", nIndex++, list.filename, list.nDataBytes, list.framerate));
+ }
+
+ CLIENT_PRINTF(pEdict, print_console, "\n");
+ RETURN_META(MRES_SUPERCEDE);
+ }
+
+ int trackNumber = atoi(CMD_ARGV(1));
+ if (trackNumber < 0 || trackNumber >= (type == VC_SPEEX ? g_tracks_speex : g_tracks_silk))
+ {
+ trackNumber = 0;
+ }
+
+ trackNumber = g_tracksNumbers[type][trackNumber];
+
+ g_SoundLists[trackNumber].play ^= true;
+
+ if (g_SoundLists[trackNumber].play)
+ {
+ g_SoundLists[trackNumber].time = gpGlobals->time;
+ }
+
+ g_SoundLists[trackNumber].frame = g_SoundLists[trackNumber].startindex;
+ g_SoundLists[trackNumber].type = type;
+
+ CLIENT_PRINTF(pEdict, print_console, UTIL_VarArgs(" -> send voice are %s, track: (%s)\n", g_SoundLists[trackNumber].play ? "RUNNING" : "STOPPED", g_SoundLists[trackNumber].filename));
+ RETURN_META(MRES_SUPERCEDE);
+ }
+
+ RETURN_META(MRES_IGNORED);
+}
+
+unsigned long ReadDWord(FILE *fp)
+{
+ unsigned long ret;
+ fread(&ret, 4, 1, fp);
+ return ret;
+}
+
+unsigned short ReadWord(FILE *fp)
+{
+ unsigned short ret;
+ fread(&ret, 2, 1, fp);
+ return ret;
+}
+
+bool ReadWaveFile(const char *pFilename, char *&pData, int &nDataBytes, int &wBitsPerSample, int &nChannels, int &nSamplesPerSec)
+{
+ FILE *fp = fopen(pFilename, "rb");
+ if(!fp)
+ return false;
+
+ fseek(fp, 22, SEEK_SET);
+
+ nChannels = ReadWord(fp);
+ nSamplesPerSec = ReadDWord(fp);
+
+ fseek(fp, 34, SEEK_SET);
+ wBitsPerSample = ReadWord(fp);
+
+ fseek(fp, 40, SEEK_SET);
+ nDataBytes = ReadDWord(fp);
+ ReadDWord(fp);
+ pData = new char[nDataBytes];
+ if(!pData)
+ {
+ fclose(fp);
+ return false;
+ }
+ fread(pData, nDataBytes, 1, fp);
+ fclose(fp);
+ return true;
+}
+
+int Voice_GetSpeexCompressed(SpeexContext_t &snd, char *pchDest, int nCount, bool bFinal)
+{
+ if (!snd.encoder)
+ {
+ snd.encoder = new VoiceCodec_Frame(new VoiceEncoder_Speex());
+ snd.encoder->Init(SPEEX_VOICE_QUALITY);
+ }
+
+ if (snd.encoder)
+ {
+ int gotten;
+ short tempData[8192];
+
+ // If they want to get the data from a file instead of the mic, use that.
+ if (snd.data)
+ {
+ double curtime = gpGlobals->time;
+ int nShouldGet = (curtime - snd.time) * 8000;
+ gotten = min((signed)sizeof(tempData) / 2, min(nShouldGet, (snd.nDataBytes - snd.frame) / 2));
+ memcpy(tempData, &snd.data[snd.frame], gotten * 2);
+ snd.frame += gotten * 2;
+ snd.time = curtime;
+
+ return snd.encoder->Compress((char *)tempData, gotten, pchDest, nCount, !!bFinal);
+ }
+ }
+
+ return 0;
+}
+
+char uncompressedBuf[12002];
+
+int Voice_GetSilkCompressed(SpeexContext_t &snd, char *pchDest, int nCount, bool bFinal)
+{
+ if (!snd.encoder)
+ {
+ snd.encoder = new CSteamP2PCodec(new VoiceEncoder_Silk());
+ snd.encoder->Init(SILK_VOICE_QUALITY);
+ }
+
+ if (snd.encoder)
+ {
+ int gotten;
+ short tempData[8192];
+
+ // If they want to get the data from a file instead of the mic, use that.
+ if (snd.data)
+ {
+ double curtime = gpGlobals->time;
+ int nShouldGet = (curtime - snd.time) * 8000;
+ gotten = min((signed)sizeof(tempData) / 2, min(nShouldGet, (snd.nDataBytes - snd.frame) / 2));
+ memcpy(tempData, &snd.data[snd.frame], gotten * 2);
+ snd.frame += gotten * 2;
+ snd.time = curtime;
+
+ g_ulSteamIdCurrent = snd.steamid;
+ int res = snd.encoder->Compress((char *)tempData, gotten, pchDest, nCount, !!bFinal);
+ g_ulSteamIdCurrent = 0ULL;
+ return res;
+ }
+ }
+
+ return 0;
+}
+
+int Voice_GetCompressedData(SpeexContext_t &snd, char *pchDest, int nCount, bool bFinal)
+{
+ switch (snd.type)
+ {
+ case VC_SPEEX:
+ return Voice_GetSpeexCompressed(snd, pchDest, nCount, bFinal);
+ case VC_SILK:
+ return Voice_GetSilkCompressed(snd, pchDest, nCount, bFinal);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+void StartFrame_Post()
+{
+ static bool all_sound_initializes = false;
+ if (!all_sound_initializes)
+ {
+ for (auto &list : g_SoundLists)
+ {
+ if (list.load || list.failed)
+ {
+ continue;
+ }
+
+ int nDataBytes, wBitsPerSample, nChannels, nSamplesPerSec;
+ list.load = ReadWaveFile(list.filename, list.data, nDataBytes, wBitsPerSample, nChannels, nSamplesPerSec);
+
+ list.frame = 0;
+ list.nDataBytes = nDataBytes;
+ list.wBitsPerSample = wBitsPerSample;
+ list.time = gpGlobals->time;
+
+ //if (list.type == VC_SILK)
+ //{
+ // if (wBitsPerSample != 16 || nChannels != 1 || nSamplesPerSec != 24000)
+ // {
+ // printf(" > %s Wave file mismatch was got %d bits, %d channels, "
+ // "%d sample rate was expecting %d bits, %d channels, %d sample rate\n",
+ // list.filename, wBitsPerSample, nChannels, nSamplesPerSec, 16, 1, 24000);
+ //
+ // delete [] list.data;
+ // list.load = false;
+ // list.failed = true;
+ // continue;
+ // }
+ //}
+
+ if (list.load)
+ {
+ g_tracksNumbers[list.type][list.type == VC_SPEEX ? g_tracks_speex++ : g_tracks_silk++] = &list - g_SoundLists;
+ printf(" '%s' trackid: (%d), Load: (%s), chunk: (%d), framerate: (%0.2f), wBitsPerSample: (%d), nDataBytes: (%d), nSamplesPerSec: (%d)\n",
+ list.type == VC_SPEEX ? "SPEEX" : "SILK", g_tracksNumbers[list.type][(list.type == VC_SPEEX ? g_tracks_speex++ : g_tracks_silk) - 1],
+ list.filename, list.nDataBytes, list.framerate, list.wBitsPerSample, nDataBytes, nSamplesPerSec);
+ }
+ }
+ }
+
+ all_sound_initializes = true;
+ for (auto &list : g_SoundLists)
+ {
+ if (!list.load)
+ {
+ all_sound_initializes = false;
+ break;
+ }
+ }
+
+ static float fltime = 0.0f;
+ if (fltime > gpGlobals->time)
+ {
+ RETURN_META(MRES_IGNORED);
+ }
+
+ fltime = gpGlobals->time + 0.02f;// - 0.000125;
+
+ for (int snd = 0; snd < ARRAYSIZE(g_SoundLists); snd++)
+ {
+ if (!g_SoundLists[snd].play)
+ continue;
+
+ char uchVoiceData[4096];
+ bool bFinal = false;
+ int nDataLength = Voice_GetCompressedData(g_SoundLists[snd], uchVoiceData, sizeof(uchVoiceData), bFinal);
+ if (nDataLength <= 0)
+ continue;
+
+ if (g_SoundLists[snd].frame >= g_SoundLists[snd].nDataBytes)// || nDataLength <= 0)
+ {
+ g_SoundLists[snd].play = false;
+ g_SoundLists[snd].frame = 0;
+
+ //printf("> HIT END\n");
+ continue;
+ }
+
+ int maxclients = g_RehldsSvs->GetMaxClients();
+ for (int i = 0; i < maxclients; i++)
+ {
+ CRevoicePlayer *dstPlayer = &g_Players[i];
+ IGameClient *dstClient = dstPlayer->GetClient();
+
+ if (!dstClient->IsActive() && !dstClient->IsConnected()) {
+ continue;
+ }
+
+ sizebuf_t *dstDatagram = dstClient->GetDatagram();
+ if (dstDatagram->cursize + nDataLength + 6 < dstDatagram->maxsize)
+ {
+ //CLIENT_PRINTF(dstPlayer->GetClient()->GetEdict(), print_console, UTIL_VarArgs(" -> chunk: %4d / %4d, chunksize: %4d, progress: %3.2f%%\n", g_SoundLists[snd].frame, g_SoundLists[snd].nDataBytes, nDataLength, ((double)g_SoundLists[snd].frame / (double)g_SoundLists[snd].nDataBytes) * 100.0));
+ printf(" -> chunk: %4d / %4d, chunksize: %4d, progress: %3.2f%%\n", g_SoundLists[snd].frame, g_SoundLists[snd].nDataBytes, nDataLength, ((double)g_SoundLists[snd].frame / (double)g_SoundLists[snd].nDataBytes) * 100.0);
+
+ g_RehldsFuncs->MSG_WriteByte(dstDatagram, svc_voicedata);
+ g_RehldsFuncs->MSG_WriteByte(dstDatagram, g_SoundLists[snd].index);
+ g_RehldsFuncs->MSG_WriteShort(dstDatagram, nDataLength);
+ g_RehldsFuncs->MSG_WriteBuf(dstDatagram, nDataLength, uchVoiceData);
+ }
+ }
+ }
+
+ RETURN_META(MRES_IGNORED);
+}
+
+static const char *steamids[]
+{
+ "76561198051972183",
+ "76561198051972184",
+ "76561198051972185",
+ "76561198051972186",
+ "76561198051972187",
+ "76561198051972188",
+ "76561198051972189",
+ "76561198051972190",
+ "76561198051972191",
+ "76561198051972192",
+ "76561198051972193",
+ "76561198051972194",
+ "76561198051972195",
+ "76561198051972196",
+ "76561198051972197",
+};
+
+void ClientPutInServer_PostHook(edict_t *pEntity)
+{
+ IGameClient* client = g_RehldsSvs->GetClient(ENTINDEX(pEntity) - 1);
+ sizebuf_t *buf = client->GetNetChan()->GetMessageBuf();
+
+ unsigned char digest[] =
+ {
+ 0xcd, 0xff, 0xcc, 0x70, 0xda, 0x4a, 0x79, 0x1c, 0xea, 0x66, 0xba, 0xaa, 0xad, 0x2b, 0x40, 0x01
+ };
+
+ //memset(digest, 0, sizeof(digest));
+
+ for (int i = 1; i < 8; i++)
+ {
+ char name[64];
+ _snprintf(name, sizeof(name), "play-voice-%i", i);
+
+ char userinfo[256];
+ _snprintf(userinfo, sizeof(userinfo), "\\bottomcolor\\0\\topcolor\\0\\name\\%s\\model\\urban\\*sid\\%s", name, steamids[i]);
+
+ g_RehldsFuncs->MSG_WriteByte(buf, 13); // svc_updateuserinfo
+ g_RehldsFuncs->MSG_WriteByte(buf, i);
+ g_RehldsFuncs->MSG_WriteLong(buf, i - 1);
+ g_RehldsFuncs->MSG_WriteString(buf, userinfo);
+ g_RehldsFuncs->MSG_WriteBuf(buf, sizeof(digest), digest);
+ }
+
+ SET_META_RESULT(MRES_IGNORED);
+}
+
void ServerActivate_PostHook(edict_t *pEdictList, int edictCount, int clientMax)
{
Revoice_Exec_Config();
diff --git a/revoice/src/revoice_main.h b/revoice/src/revoice_main.h
index b920130..9d7d071 100644
--- a/revoice/src/revoice_main.h
+++ b/revoice/src/revoice_main.h
@@ -9,5 +9,7 @@ bool Revoice_Main_Init();
void CvarValue2_PreHook(const edict_t *pEnt, int requestID, const char *cvarName, const char *cvarValue);
qboolean ClientConnect_PreHook(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128]);
+void ClientPutInServer_PostHook(edict_t *pEntity);
void ServerActivate_PostHook(edict_t *pEdictList, int edictCount, int clientMax);
-
+void StartFrame_Post();
+void ClientCommand(edict_t *pEdict);
diff --git a/revoice/src/revoice_main_.cpp b/revoice/src/revoice_main_.cpp
new file mode 100644
index 0000000..6f7dcde
--- /dev/null
+++ b/revoice/src/revoice_main_.cpp
@@ -0,0 +1,494 @@
+#include "precompiled.h"
+
+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 CvarValue2_PreHook(const edict_t *pEnt, int requestID, const char *cvarName, const char *cvarValue)
+{
+ CRevoicePlayer *plr = GetPlayerByEdict(pEnt);
+ if (plr->GetRequestId() != requestID) {
+ RETURN_META(MRES_IGNORED);
+ }
+
+ const char *lastSeparator = strrchr(cvarValue, ',');
+ if (lastSeparator)
+ {
+ int buildNumber = atoi(lastSeparator + 1);
+ if (buildNumber > 4554 || buildNumber == 2017) {
+ plr->SetCodecType(vct_opus);
+ }
+ }
+
+ RETURN_META(MRES_IGNORED);
+}
+
+int TranscodeVoice(CRevoicePlayer *srcPlayer, 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)
+{
+ 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);
+
+ if (g_pcv_sv_voiceenable->value == 0.0f) {
+ return;
+ }
+
+ CRevoicePlayer *srcPlayer = GetPlayerByClientPtr(cl);
+
+
+
+ //FILE *fp = fopen("recorder.snd", "ab");
+ //if (fp)
+ //{
+ // printf(" -> Write chunk: (%d)\n", nDataLength);
+ // fwrite(chReceived, 1, nDataLength, fp);
+ // fclose(fp);
+ //}
+
+
+
+
+
+
+ /*srcPlayer->SetLastVoiceTime(g_RehldsSv->GetTime());
+ srcPlayer->IncreaseVoiceRate(nDataLength);
+
+ char compressedBuf[16384];
+ int compressedSize = TranscodeVoice(srcPlayer, chReceived, nDataLength, srcPlayer->GetOpusCodec(), srcPlayer->GetSilkCodec(), compressedBuf, sizeof(compressedBuf));
+
+ uint32_t computedChecksum = crc32(compressedBuf, compressedSize - 4);
+ uint32 wireChecksum = *(uint32 *)(compressedBuf + compressedSize - 4);
+
+ FILE *fp = fopen("recorder.snd", "ab");
+ if (fp)
+ {
+ printf(" -> Write chunk: (%d), computedChecksum: (%u), wireChecksum: (%u)\n", compressedSize, computedChecksum, wireChecksum);
+ printf(" -> Write chunk: (%d), computedChecksum: (%u), wireChecksum: (%u)\n", compressedSize, computedChecksum, wireChecksum);
+ fwrite(compressedBuf, 1, compressedSize, fp);
+ fclose(fp);
+ }*/
+
+ //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) {
+ //printf("-> #0\n");
+ continue;
+ }
+
+ if (!dstClient->IsActive() && !dstClient->IsConnected() && dstPlayer != srcPlayer) {
+ //printf("-> #1\n");
+ continue;
+ }
+
+ sizebuf_t *dstDatagram = dstClient->GetDatagram();
+ if (dstDatagram->cursize + nDataLength + 6 < dstDatagram->maxsize)
+ {
+ //uint32_t computedChecksum = crc32(compressedBuf, compressedSize - 4);
+ //uint32 wireChecksum = *(uint32 *)(compressedBuf + compressedSize - 4);
+
+ //FILE *fp = fopen("silk_chunk.snd", "ab");
+ //if (fp)
+ //{
+ // printf(" -> Write chunk: (%d), computedChecksum: (%u), wireChecksum: (%u)\n", compressedSize, computedChecksum, wireChecksum);
+ // fwrite(compressedBuf, 1, compressedSize, fp);
+ // fclose(fp);
+ //}
+
+ g_RehldsFuncs->MSG_WriteByte(dstDatagram, svc_voicedata);
+ g_RehldsFuncs->MSG_WriteByte(dstDatagram, cl->GetId());
+ g_RehldsFuncs->MSG_WriteShort(dstDatagram, nDataLength);
+ g_RehldsFuncs->MSG_WriteBuf(dstDatagram, nDataLength, chReceived);
+ }
+ }
+}
+
+void Rehlds_HandleNetCommand(IRehldsHook_HandleNetCommand *chain, IGameClient *cl, int8 opcode)
+{
+ const int clc_voicedata = 8;
+ //if (opcode == clc_voicedata) {
+ // SV_ParseVoiceData_emu(cl);
+ // return;
+ //}
+
+ chain->callNext(cl, opcode);
+}
+
+qboolean ClientConnect_PreHook(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128])
+{
+ CRevoicePlayer *plr = GetPlayerByEdict(pEntity);
+ plr->OnConnected();
+
+ RETURN_META_VALUE(MRES_IGNORED, TRUE);
+}
+
+struct SpeexContext_t
+{
+ const char *filename;
+ char *data;
+ int chunk;
+ int frame;
+ bool play;
+ bool load;
+ bool send_order;
+ double time;
+ double nextsend;
+ float framerate;
+ int index;
+ IVoiceCodec *encoder;
+};
+
+int g_NumFullSended = 0;
+SpeexContext_t g_SoundLists[] =
+{
+ { "akol.wav", nullptr, 0, 0, false, false, false, 0, 0, 8000, 4, nullptr },
+ //{ "akol2.wav", nullptr, 0, 0, false, false, false, 0, 0, 8000, 5, nullptr },
+ { "apchela.wav", nullptr, 0, 0, false, false, false, 0, 0, 11025, 6, nullptr },
+};
+
+void ClientCommand(edict_t *pEdict)
+{
+ const char *argv1 = CMD_ARGV(0);
+ if (_stricmp(argv1, "speexmulti") == 0)
+ {
+ g_SoundLists[0].play ^= true;
+ g_SoundLists[1].play ^= true;
+
+ if (g_SoundLists[0].play)
+ {
+ g_SoundLists[0].time = gpGlobals->time;
+ }
+
+ if (g_SoundLists[1].play)
+ {
+ g_SoundLists[1].time = gpGlobals->time;
+ }
+
+ g_SoundLists[0].frame = 0;
+ g_SoundLists[1].frame = 0;
+
+ RETURN_META(MRES_SUPERCEDE);
+ }
+ else if (_stricmp(argv1, "speexplay") == 0)
+ {
+ if (CMD_ARGC() < 2)
+ {
+ CLIENT_PRINTF(pEdict, print_console, UTIL_VarArgs("\nusage: speexplay [ ]\n\n"));
+ CLIENT_PRINTF(pEdict, print_console, UTIL_VarArgs("%4s %-32s %-10s %-12s\n", "#", "[name]", "[chunk]", "[framerate]"));
+
+ int nIndex = 0;
+ for (auto &list : g_SoundLists)
+ {
+ CLIENT_PRINTF(pEdict, print_console, UTIL_VarArgs("%4d. %-32s %-10d %-12.2f\n", nIndex++, list.filename, list.chunk, list.framerate));
+ }
+
+ CLIENT_PRINTF(pEdict, print_console, "\n");
+ RETURN_META(MRES_SUPERCEDE);
+ }
+
+ int trackNumber = atoi(CMD_ARGV(1));
+ if (trackNumber < 0 || trackNumber >= ARRAYSIZE(g_SoundLists))
+ {
+ trackNumber = 0;
+ }
+
+ g_SoundLists[trackNumber].play ^= true;
+
+ if (g_SoundLists[trackNumber].play)
+ {
+ g_SoundLists[trackNumber].time = gpGlobals->time;
+ }
+
+ g_SoundLists[trackNumber].frame = 0;
+
+ CLIENT_PRINTF(pEdict, print_console, UTIL_VarArgs(" -> send voice are %s, track: (%s)\n", g_SoundLists[trackNumber].play ? "RUNNING" : "STOPPED", g_SoundLists[trackNumber].filename));
+ RETURN_META(MRES_SUPERCEDE);
+ }
+
+ RETURN_META(MRES_IGNORED);
+}
+
+bool ReadWaveFile(const char *pFilename, char **pData, int &nDataBytes, int &nBitsPerSample, int &nChannels, int &nSamplesPerSec)
+{
+ FILE *fp = fopen(pFilename, "rb");
+ if (!fp) {
+ return false;
+ }
+
+ int pOutput;
+ fseek(fp, 22, SEEK_SET);
+ fread(&pOutput, sizeof(uint16), 1, fp);
+ nChannels = (uint16)pOutput;
+
+ fread(&pOutput, sizeof(int), 1, fp);
+ nSamplesPerSec = pOutput;
+
+ fseek(fp, 34, SEEK_SET);
+ fread(&pOutput, sizeof(uint16), 1, fp);
+ nBitsPerSample = (uint16)pOutput;
+
+ fseek(fp, 40, SEEK_SET);
+ fread(&pOutput, sizeof(int), 1, fp);
+ nDataBytes = pOutput;
+
+ fread(&pOutput, sizeof(int), 1, fp);
+
+ *pData = new char[ nDataBytes ];
+
+ if (*pData)
+ {
+ fread(*pData, nDataBytes, 1, fp);
+ fclose(fp);
+ return true;
+ }
+
+ fclose(fp);
+ return false;
+}
+
+int Voice_GetCompressedData(SpeexContext_t &snd, char *pchDest, int nCount, bool bFinal)
+{
+ if (!snd.encoder)
+ {
+ snd.encoder = new VoiceCodec_Frame(new VoiceEncoder_Speex());
+ snd.encoder->Init(SPEEX_VOICE_QUALITY);
+ }
+
+ if (snd.encoder)
+ {
+ int gotten;
+ short tempData[8192];
+
+ // If they want to get the data from a file instead of the mic, use that.
+ if (snd.data)
+ {
+ double curtime = gpGlobals->time;
+ int nShouldGet = (curtime - snd.time) * 8000;
+ gotten = min((signed)sizeof(tempData) / 2, min(nShouldGet, (snd.chunk - snd.frame) / 2));
+ memcpy(tempData, &snd.data[snd.frame], gotten * 2);
+ snd.frame += gotten * 2;
+ snd.time = curtime;
+
+ return snd.encoder->Compress((char *)tempData, gotten, pchDest, nCount, !!bFinal);
+ }
+ }
+
+ return 0;
+}
+
+#include "counter.h"
+CCounter g_Timer;
+
+#include
+#include
+
+void StartFrame_Post()
+{
+ static bool all_sound_initializes = false;
+ if (!all_sound_initializes)
+ {
+ g_Timer.Init();
+
+ for (auto &list : g_SoundLists)
+ {
+ if (list.load)
+ {
+ continue;
+ }
+
+ int a, b, c;
+ list.load = ReadWaveFile(list.filename, &list.data, list.chunk, a, b, c);
+ list.frame = 0;
+ list.time = gpGlobals->time;
+
+ if (list.load)
+ {
+ printf(" Load: (%s), chunk: (%d), framerate: (%0.2f)\n", list.filename, list.chunk, list.framerate);
+ }
+ }
+ }
+
+ all_sound_initializes = true;
+ for (auto &list : g_SoundLists)
+ {
+ if (!list.load)
+ {
+ all_sound_initializes = false;
+ break;
+ }
+ }
+
+ static float fltime = 0.0f;
+ if (fltime > gpGlobals->time)
+ {
+ RETURN_META(MRES_IGNORED);
+ }
+
+ fltime = gpGlobals->time + 0.02f - 0.000125;
+
+ for (int snd = 0; snd < ARRAYSIZE(g_SoundLists); snd++)
+ {
+ if (!g_SoundLists[snd].play)
+ continue;
+
+ char uchVoiceData[4096];
+ bool bFinal = false;
+ int nDataLength = Voice_GetCompressedData(g_SoundLists[snd], uchVoiceData, sizeof(uchVoiceData), bFinal);
+
+ if (g_SoundLists[snd].frame >= g_SoundLists[snd].chunk)// || nDataLength <= 0)
+ {
+ g_SoundLists[snd].play = false;
+ g_SoundLists[snd].frame = 0;
+
+ //printf("> HIT END\n");
+ continue;
+ }
+
+ int maxclients = g_RehldsSvs->GetMaxClients();
+ for (int i = 0; i < maxclients; i++)
+ {
+ CRevoicePlayer *dstPlayer = &g_Players[i];
+ IGameClient *dstClient = dstPlayer->GetClient();
+
+ if (!dstClient->IsActive() && !dstClient->IsConnected()) {
+ continue;
+ }
+
+ sizebuf_t *dstDatagram = dstClient->GetDatagram();
+ if (dstDatagram->cursize + nDataLength + 6 < dstDatagram->maxsize)
+ {
+ //CLIENT_PRINTF(dstPlayer->GetClient()->GetEdict(), print_console, UTIL_VarArgs(" -> chunk: %4d / %4d, chunksize: %4d, progress: %3.2f%%\n", g_SoundLists[snd].frame, g_SoundLists[snd].chunk, nDataLength, ((double)g_SoundLists[snd].frame / (double)g_SoundLists[snd].chunk) * 100.0));
+ printf(" -> chunk: %4d / %4d, chunksize: %4d, progress: %3.2f%%\n", g_SoundLists[snd].frame, g_SoundLists[snd].chunk, nDataLength, ((double)g_SoundLists[snd].frame / (double)g_SoundLists[snd].chunk) * 100.0);
+
+ g_RehldsFuncs->MSG_WriteByte(dstDatagram, svc_voicedata);
+ g_RehldsFuncs->MSG_WriteByte(dstDatagram, g_SoundLists[snd].index);
+ g_RehldsFuncs->MSG_WriteShort(dstDatagram, nDataLength);
+ g_RehldsFuncs->MSG_WriteBuf(dstDatagram, nDataLength, uchVoiceData);
+ }
+ }
+ }
+
+ RETURN_META(MRES_IGNORED);
+}
+
+void ServerActivate_PostHook(edict_t *pEdictList, int edictCount, int clientMax)
+{
+ Revoice_Exec_Config();
+ SET_META_RESULT(MRES_IGNORED);
+}
+
+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:
+ case vct_opus:
+ case vct_speex:
+ {
+ g_RehldsFuncs->MSG_WriteByte(sb, 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_Load()
+{
+ if (!Revoice_Utils_Init())
+ return false;
+
+ if (!Revoice_RehldsApi_Init()) {
+ LCPrintf(true, "Failed to locate REHLDS API\n");
+ return false;
+ }
+
+ if (!Revoice_ReunionApi_Init())
+ return false;
+
+ Revoice_Init_Cvars();
+ Revoice_Init_Config();
+ Revoice_Init_Players();
+
+ if (!Revoice_Main_Init()) {
+ LCPrintf(true, "Initialization failed\n");
+ return false;
+ }
+
+ return true;
+}
+
+bool Revoice_Main_Init()
+{
+ g_RehldsHookchains->SV_DropClient()->registerHook(&SV_DropClient_hook, HC_PRIORITY_DEFAULT + 1);
+ g_RehldsHookchains->HandleNetCommand()->registerHook(&Rehlds_HandleNetCommand, HC_PRIORITY_DEFAULT + 1);
+ g_RehldsHookchains->SV_WriteVoiceCodec()->registerHook(&SV_WriteVoiceCodec_hooked, HC_PRIORITY_DEFAULT + 1);
+
+ return true;
+}
+
+void Revoice_Main_DeInit()
+{
+ g_RehldsHookchains->SV_DropClient()->unregisterHook(&SV_DropClient_hook);
+ g_RehldsHookchains->HandleNetCommand()->unregisterHook(&Rehlds_HandleNetCommand);
+ g_RehldsHookchains->SV_WriteVoiceCodec()->unregisterHook(&SV_WriteVoiceCodec_hooked);
+
+ Revoice_DeInit_Cvars();
+}