2
0
mirror of https://github.com/rehlds/revoice.git synced 2025-03-03 17:15:25 +03:00

Implement simple voice playback for codecs testing purposes

This commit is contained in:
s1lent 2017-12-06 19:53:55 +07:00 committed by s1lentq
parent 15780dfcaf
commit f0b5d960b3
20 changed files with 1321 additions and 216 deletions

View File

@ -1,27 +1,27 @@
/*********************************************************************** /***********************************************************************
Copyright (c) 2006-2012, Skype Limited. All rights reserved. Copyright (c) 2006-2012, Skype Limited. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, (subject to the limitations in the disclaimer below) modification, (subject to the limitations in the disclaimer below)
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, - Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer. this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright - Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution. documentation and/or other materials provided with the distribution.
- Neither the name of Skype Limited, nor the names of specific - Neither the name of Skype Limited, nor the names of specific
contributors, may be used to endorse or promote products derived from contributors, may be used to endorse or promote products derived from
this software without specific prior written permission. this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED 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 BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 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) # define SKP_STR_CASEINSENSITIVE_COMPARE(x, y) _stricmp(x, y)
#else #else
# define SKP_STR_CASEINSENSITIVE_COMPARE(x, y) strcasecmp(x, y) # 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_MAX ((SKP_int64)0x7FFFFFFFFFFFFFFFLL) /* 2^63 - 1 */
#define SKP_int64_MIN ((SKP_int64)0x8000000000000000LL) /* -2^63 */ #define SKP_int64_MIN ((SKP_int64)0x8000000000000000LL) /* -2^63 */

View File

@ -1,27 +1,27 @@
/*********************************************************************** /***********************************************************************
Copyright (c) 2006-2012, Skype Limited. All rights reserved. Copyright (c) 2006-2012, Skype Limited. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, (subject to the limitations in the disclaimer below) modification, (subject to the limitations in the disclaimer below)
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, - Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer. this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright - Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution. documentation and/or other materials provided with the distribution.
- Neither the name of Skype Limited, nor the names of specific - Neither the name of Skype Limited, nor the names of specific
contributors, may be used to endorse or promote products derived from contributors, may be used to endorse or promote products derived from
this software without specific prior written permission. this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED 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 BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 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 SKP_Silk_SDK_Get_Encoder_Size( SKP_int32 *encSizeBytes )
{ {
SKP_int ret = 0; SKP_int ret = 0;
*encSizeBytes = sizeof( SKP_Silk_encoder_state_FLP ); *encSizeBytes = sizeof( SKP_Silk_encoder_state_FLP );
return ret; return ret;
} }
@ -83,7 +83,7 @@ SKP_int SKP_Silk_SDK_InitEncoder(
SKP_Silk_encoder_state_FLP *psEnc; SKP_Silk_encoder_state_FLP *psEnc;
SKP_int ret = 0; SKP_int ret = 0;
psEnc = ( SKP_Silk_encoder_state_FLP* )encState; psEnc = ( SKP_Silk_encoder_state_FLP* )encState;
/* Reset Encoder */ /* Reset Encoder */
@ -103,7 +103,7 @@ SKP_int SKP_Silk_SDK_InitEncoder(
/**************************/ /**************************/
/* Encode frame with Silk */ /* Encode frame with Silk */
/**************************/ /**************************/
SKP_int SKP_Silk_SDK_Encode( SKP_int SKP_Silk_SDK_Encode(
void *encState, /* I/O: State */ void *encState, /* I/O: State */
const SKP_Silk_EncodeControlStruct *encControl, /* I: Control structure */ const SKP_Silk_EncodeControlStruct *encControl, /* I: Control structure */
const SKP_int16 *samplesIn, /* I: Speech sample input vector */ const SKP_int16 *samplesIn, /* I: Speech sample input vector */
@ -124,7 +124,7 @@ SKP_int SKP_Silk_SDK_Encode(
if( ( ( encControl->API_sampleRate != 8000 ) && if( ( ( encControl->API_sampleRate != 8000 ) &&
( encControl->API_sampleRate != 12000 ) && ( encControl->API_sampleRate != 12000 ) &&
( encControl->API_sampleRate != 16000 ) && ( encControl->API_sampleRate != 16000 ) &&
( encControl->API_sampleRate != 24000 ) && ( encControl->API_sampleRate != 24000 ) &&
( encControl->API_sampleRate != 32000 ) && ( encControl->API_sampleRate != 32000 ) &&
( encControl->API_sampleRate != 44100 ) && ( encControl->API_sampleRate != 44100 ) &&
( encControl->API_sampleRate != 48000 ) ) || ( 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 ); 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 ) { PacketLoss_perc, UseDTX, Complexity) ) != 0 ) {
SKP_assert( 0 ); SKP_assert( 0 );
return( ret ); return( ret );
@ -176,8 +176,8 @@ SKP_int SKP_Silk_SDK_Encode(
#if MAX_FS_KHZ > 16 #if MAX_FS_KHZ > 16
/* Detect energy above 8 kHz */ /* Detect energy above 8 kHz */
if( SKP_min( API_fs_Hz, 1000 * max_internal_fs_kHz ) == 24000 && if( SKP_min( API_fs_Hz, 1000 * max_internal_fs_kHz ) == 24000 &&
psEnc->sCmn.sSWBdetect.SWB_detected == 0 && psEnc->sCmn.sSWBdetect.SWB_detected == 0 &&
psEnc->sCmn.sSWBdetect.WB_detected == 0 ) { psEnc->sCmn.sSWBdetect.WB_detected == 0 ) {
SKP_Silk_detect_SWB_input( &psEnc->sCmn.sSWBdetect, samplesIn, ( SKP_int )nSamplesIn ); 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 */ MaxBytesOut = 0; /* return 0 output bytes if no encoder called */
while( 1 ) { while( 1 ) {
nSamplesToBuffer = psEnc->sCmn.frame_length - psEnc->sCmn.inputBufIx; 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 ); nSamplesToBuffer = SKP_min_int( nSamplesToBuffer, nSamplesIn );
nSamplesFromInput = nSamplesToBuffer; nSamplesFromInput = nSamplesToBuffer;
/* Copy to buffer */ /* Copy to buffer */
SKP_memcpy( &psEnc->sCmn.inputBuf[ psEnc->sCmn.inputBufIx ], samplesIn, nSamplesFromInput * sizeof( SKP_int16 ) ); 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 ); nSamplesToBuffer = SKP_min( nSamplesToBuffer, 10 * input_10ms * psEnc->sCmn.fs_kHz );
nSamplesFromInput = SKP_DIV32_16( nSamplesToBuffer * API_fs_Hz, psEnc->sCmn.fs_kHz * 1000 ); nSamplesFromInput = SKP_DIV32_16( nSamplesToBuffer * API_fs_Hz, psEnc->sCmn.fs_kHz * 1000 );
/* Resample and write to buffer */ /* 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 ); &psEnc->sCmn.inputBuf[ psEnc->sCmn.inputBufIx ], samplesIn, nSamplesFromInput );
} }
samplesIn += nSamplesFromInput; samplesIn += nSamplesFromInput;
nSamplesIn -= nSamplesFromInput; nSamplesIn -= nSamplesFromInput;
psEnc->sCmn.inputBufIx += nSamplesToBuffer; psEnc->sCmn.inputBufIx += nSamplesToBuffer;

View File

@ -1,27 +1,27 @@
/*********************************************************************** /***********************************************************************
Copyright (c) 2006-2012, Skype Limited. All rights reserved. Copyright (c) 2006-2012, Skype Limited. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, (subject to the limitations in the disclaimer below) modification, (subject to the limitations in the disclaimer below)
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, - Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer. this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright - Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution. documentation and/or other materials provided with the distribution.
- Neither the name of Skype Limited, nor the names of specific - Neither the name of Skype Limited, nor the names of specific
contributors, may be used to endorse or promote products derived from contributors, may be used to endorse or promote products derived from
this software without specific prior written permission. this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED 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 BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 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 */ /* Struct for Low BitRate Redundant (LBRR) information */
typedef struct { typedef struct {
SKP_uint8 payload[ MAX_ARITHM_BYTES ]; SKP_uint8 payload[ MAX_ARITHM_BYTES ];
SKP_int nBytes; /* Number of bytes in payload */ SKP_int nBytes; /* Number of bytes in payload */
SKP_int usage; /* Tells how the payload should be used as FEC */ SKP_int usage; /* Tells how the payload should be used as FEC */
} SKP_SILK_LBRR_struct; } 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 */ 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_SILK_LBRR_struct LBRR_buffer[ MAX_LBRR_DELAY ];
SKP_int oldest_LBRR_idx; SKP_int oldest_LBRR_idx;
SKP_int useInBandFEC; /* Saves the API setting for query */ SKP_int useInBandFEC; /* Saves the API setting for query */
@ -310,7 +310,7 @@ typedef struct {
/* Parameters used to investigate if inband FEC is used */ /* Parameters used to investigate if inband FEC is used */
SKP_int vadFlag; SKP_int vadFlag;
SKP_int no_FEC_counter; /* Counts number of frames wo inband FEC */ 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 */ /* CNG state */
SKP_Silk_CNG_struct sCNG; SKP_Silk_CNG_struct sCNG;

View File

@ -1,27 +1,27 @@
/*********************************************************************** /***********************************************************************
Copyright (c) 2006-2012, Skype Limited. All rights reserved. Copyright (c) 2006-2012, Skype Limited. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, (subject to the limitations in the disclaimer below) modification, (subject to the limitations in the disclaimer below)
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, - Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer. this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright - Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution. documentation and/or other materials provided with the distribution.
- Neither the name of Skype Limited, nor the names of specific - Neither the name of Skype Limited, nor the names of specific
contributors, may be used to endorse or promote products derived from contributors, may be used to endorse or promote products derived from
this software without specific prior written permission. this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED 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 BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
***********************************************************************/ ***********************************************************************/

BIN
revoice/dist/c2a2_ba_launch.wav vendored Normal file

Binary file not shown.

BIN
revoice/dist/cslig_nuages.wav vendored Normal file

Binary file not shown.

BIN
revoice/dist/dance.wav vendored Normal file

Binary file not shown.

BIN
revoice/dist/kolshik.wav vendored Normal file

Binary file not shown.

BIN
revoice/dist/pchela.wav vendored Normal file

Binary file not shown.

View File

@ -145,7 +145,7 @@
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<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/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <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)</AdditionalIncludeDirectories>
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
</ClCompile> </ClCompile>
<Link> <Link>

View File

@ -12,6 +12,7 @@ public:
// Initialize the object. The uncompressed format is always 8-bit signed mono. // Initialize the object. The uncompressed format is always 8-bit signed mono.
virtual bool Init(int quality) = 0; virtual bool Init(int quality) = 0;
virtual void Release() = 0; virtual void Release() = 0;
virtual int GetSamplesPerFrame() { return 0; }
// Compress the voice data. // Compress the voice data.
// pUncompressed - 16-bit signed mono voice data. // pUncompressed - 16-bit signed mono voice data.

188
revoice/public/counter.h Normal file
View File

@ -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 <windows.h>
#include <io.h>
#include <direct.h>
#else
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef OSX
#include <limits.h>
#else
#include <linux/limits.h>
#endif
#include <sys/time.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <math.h>
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
}

View File

@ -90,10 +90,10 @@ int CSteamP2PCodec::StreamEncode(const char *pUncompressedBytes, int nSamples, c
} }
*(writePos++) = PLT_SamplingRate; // Set sampling rate *(writePos++) = PLT_SamplingRate; // Set sampling rate
*(uint16 *)writePos = 16000; *(uint16 *)writePos = 8000;
writePos += 2; 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); int compressRes = m_BackendCodec->Compress(pUncompressedBytes, nSamples, writePos + 2, maxCompressedBytes - (1 + 2 + 1 + 2), bFinal);
if (compressRes == 0) { if (compressRes == 0) {
@ -123,18 +123,37 @@ int CSteamP2PCodec::Decompress(const char *pCompressed, int compressedBytes, cha
return StreamDecode(pCompressed + 8, compressedBytes - 12, pUncompressed, maxUncompressedBytes); 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) int CSteamP2PCodec::Compress(const char *pUncompressedBytes, int nSamples, char *pCompressed, int maxCompressedBytes, bool bFinal)
{ {
if (maxCompressedBytes < 12) { // no room if (maxCompressedBytes < 12) { // no room
return 0; return 0;
} }
/*union CSteamID
{
uint64 allbits64;
struct
{
uint32 lo;
uint32 hi;
};
};
CSteamID steamid;
steamid.allbits64 = 76561198051972183;
char *writePos = pCompressed; char *writePos = pCompressed;
*(uint32 *)writePos = 0x00000011; // steamid (low part) *(uint32 *)writePos = steamid.lo; // steamid (low part)
writePos += 4; writePos += 4;
*(uint32 *)writePos = 0x01100001; // steamid (high part) *(uint32 *)writePos = steamid.hi; // steamid (high part)
writePos += 4; writePos += 4;*/
char *writePos = pCompressed;
*(uint64 *)writePos = g_ulSteamIdCurrent;//76561198051972183;
writePos += 8;
int encodeRes = StreamEncode(pUncompressedBytes, nSamples, writePos, maxCompressedBytes - 12, bFinal); int encodeRes = StreamEncode(pUncompressedBytes, nSamples, writePos, maxCompressedBytes - 12, bFinal);
if (encodeRes <= 0) { if (encodeRes <= 0) {

View File

@ -59,82 +59,88 @@ bool VoiceEncoder_Silk::ResetState()
int VoiceEncoder_Silk::Compress(const char *pUncompressedIn, int nSamplesIn, char *pCompressed, int maxCompressedBytes, bool bFinal) 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 inSampleRate = 8000;
const int nSampleDataMinMS = 100; const int nSampleDataMinMS = 20;
const int nSamplesMin = inSampleRate * nSampleDataMinMS / 1000; const int nSamplesMin = (nSampleDataMinMS * inSampleRate) / 1000;
/* if (nSamplesIn + GetNumQueuedEncodingSamples() < nSamplesMin && !bFinal)
if ((nSamplesIn + m_bufOverflowBytes.TellPut() / 2) < nSamplesMin && !bFinal) { {
m_bufOverflowBytes.Put(pUncompressedIn, 2 * nSamplesIn); m_bufOverflowBytes.Put(pUncompressedIn, nSamplesIn * BYTES_PER_SAMPLE);
return 0; return 0;
} }
*/
if (m_bufOverflowBytes.TellPut()) { const int16_t *psRead = (const int16_t *)pUncompressedIn;
m_bufOverflowBytes.Put(pUncompressedIn, 2 * nSamplesIn);
psRead = (const __int16 *)m_bufOverflowBytes.Base(); int nSamplesToUse = nSamplesIn;
nSamplesToUse = m_bufOverflowBytes.TellPut() / 2; int nSamplesPerFrame = nSamplesMin;
} else { int nSamplesRemaining = nSamplesIn % nSamplesMin;
psRead = (const __int16 *)pUncompressedIn;
nSamplesToUse = nSamplesIn; 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; char *pWritePos = pCompressed;
nSamplesRemaining = nSamplesToUse % nSamplesPerFrame; const char *pWritePosMax = &pCompressed[maxCompressedBytes];
pWritePosMax = pCompressed + maxCompressedBytes;
nSamples = nSamplesToUse - nSamplesRemaining;
pWritePos = pCompressed;
int nSamples = nSamplesToUse - nSamplesRemaining;
while (nSamples > 0) while (nSamples > 0)
{ {
int16 *pWritePayloadSize = (int16 *)pWritePos; int16_t *pWritePayloadSize = (int16_t *)pWritePos;
pWritePos += sizeof(int16); //leave 2 bytes for the frame size (will be written after encoding) pWritePos += sizeof(int16_t);
int originalNBytes = (pWritePosMax - pWritePos > 0xFFFF) ? -1 : (pWritePosMax - pWritePos); m_encControl.maxInternalSampleRate = 24000;
nSamplesToEncode = (nSamples < nSamplesPerFrame) ? nSamples : nSamplesPerFrame; 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; int nSamplesToEncode = min(nSamples, nSamplesPerFrame);
this->m_encControl.maxInternalSampleRate = 16000;
this->m_encControl.useInBandFEC = 0; int nBytes = ((pWritePosMax - pWritePos) < 0x7FFF) ? (pWritePosMax - pWritePos) : 0x7FFF;
this->m_encControl.API_sampleRate = inSampleRate; int ret = SKP_Silk_SDK_Encode(m_pEncoder, &m_encControl, psRead, nSamplesToEncode, (unsigned char *)pWritePos, (__int16 *)&nBytes);
this->m_encControl.complexity = 2; *pWritePayloadSize = nBytes; // write frame size
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;
nSamples -= nSamplesToEncode; 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; psRead += nSamplesToEncode;
pWritePos += nBytes;
} }
m_bufOverflowBytes.Clear(); m_bufOverflowBytes.Clear();
if (nSamplesRemaining <= nSamplesIn && nSamplesRemaining) { if (nSamplesRemaining && nSamplesRemaining <= nSamplesIn)
m_bufOverflowBytes.Put(&pUncompressedIn[2 * (nSamplesIn - nSamplesRemaining)], 2 * nSamplesRemaining); {
m_bufOverflowBytes.Put(pUncompressedIn + ((nSamplesIn - nSamplesRemaining) * sizeof(int16_t)), nSamplesRemaining * BYTES_PER_SAMPLE);
} }
if (bFinal) if (bFinal)
{ {
ResetState(); ResetState();
if (pWritePosMax > pWritePos + 2) { if (pWritePosMax > pWritePos + 2)
uint16 *pWriteEndFlag = (uint16*)pWritePos; {
pWritePos += sizeof(uint16); uint16_t *pWriteEndFlag = (uint16_t *)pWritePos;
pWritePos += sizeof(uint16_t);
*pWriteEndFlag = 0xFFFF; *pWriteEndFlag = 0xFFFF;
} }
} }

View File

@ -23,7 +23,7 @@ public:
virtual bool Init(int quality); virtual bool Init(int quality);
virtual void Release(); 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 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 int Decompress(const char *pCompressed, int compressedBytes, char *pUncompressed, int maxUncompressedBytes);

View File

@ -52,7 +52,7 @@ DLL_FUNCTIONS g_DLLFuncTable =
NULL, // pfnClientDisconnect NULL, // pfnClientDisconnect
NULL, // pfnClientKill NULL, // pfnClientKill
NULL, // pfnClientPutInServer NULL, // pfnClientPutInServer
NULL, // pfnClientCommand &ClientCommand, // pfnClientCommand
NULL, // pfnClientUserInfoChanged NULL, // pfnClientUserInfoChanged
NULL, // pfnServerActivate NULL, // pfnServerActivate
NULL, // pfnServerDeactivate NULL, // pfnServerDeactivate
@ -105,14 +105,14 @@ DLL_FUNCTIONS g_DLLFuncTable_Post =
NULL, // pfnClientConnect NULL, // pfnClientConnect
NULL, // pfnClientDisconnect NULL, // pfnClientDisconnect
NULL, // pfnClientKill NULL, // pfnClientKill
NULL, // pfnClientPutInServer &ClientPutInServer_PostHook, // pfnClientPutInServer
NULL, // pfnClientCommand NULL, // pfnClientCommand
NULL, // pfnClientUserInfoChanged NULL, // pfnClientUserInfoChanged
&ServerActivate_PostHook, // pfnServerActivate &ServerActivate_PostHook, // pfnServerActivate
NULL, // pfnServerDeactivate NULL, // pfnServerDeactivate
NULL, // pfnPlayerPreThink NULL, // pfnPlayerPreThink
NULL, // pfnPlayerPostThink NULL, // pfnPlayerPostThink
NULL, // pfnStartFrame &StartFrame_Post, // pfnStartFrame
NULL, // pfnParmsNewLevel NULL, // pfnParmsNewLevel
NULL, // pfnParmsChangeLevel NULL, // pfnParmsChangeLevel
NULL, // pfnGetGameDescription NULL, // pfnGetGameDescription

View File

@ -18,6 +18,9 @@ bool Revoice_Init_Config()
const char *pszGameDir = GET_GAME_INFO(PLID, GINFO_GAMEDIR); const char *pszGameDir = GET_GAME_INFO(PLID, GINFO_GAMEDIR);
const char *pszPluginDir = GET_PLUGIN_PATH(PLID); const char *pszPluginDir = GET_PLUGIN_PATH(PLID);
printf("> pszGameDir: (%s)\n", pszGameDir);
printf("> pszPluginDir: (%s)\n", pszPluginDir);
char szRelativePath[MAX_PATH]; char szRelativePath[MAX_PATH];
strncpy(szRelativePath, &pszPluginDir[strlen(pszGameDir) + 1], sizeof(szRelativePath) - 1); strncpy(szRelativePath, &pszPluginDir[strlen(pszGameDir) + 1], sizeof(szRelativePath) - 1);
szRelativePath[sizeof(szRelativePath) - 1] = '\0'; szRelativePath[sizeof(szRelativePath) - 1] = '\0';
@ -94,7 +97,7 @@ void Cmd_REV_Status()
for (int i = 0; i < g_RehldsSvs->GetMaxClients(); i++) { for (int i = 0; i < g_RehldsSvs->GetMaxClients(); i++) {
auto plr = &g_Players[i]; auto plr = &g_Players[i];
if (plr->IsConnected()) { 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++; nUsers++;
} }
} }

View File

@ -20,7 +20,7 @@ void CvarValue2_PreHook(const edict_t *pEnt, int requestID, const char *cvarName
if (lastSeparator) if (lastSeparator)
{ {
int buildNumber = atoi(lastSeparator + 1); int buildNumber = atoi(lastSeparator + 1);
if (buildNumber > 4554) { if (buildNumber > 4554 || buildNumber == 2017) {
plr->SetCodecType(vct_opus); plr->SetCodecType(vct_opus);
} }
} }
@ -75,52 +75,34 @@ void SV_ParseVoiceData_emu(IGameClient *cl)
} }
CRevoicePlayer *srcPlayer = GetPlayerByClientPtr(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); 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; uint32_t computedChecksum = crc32(compressedBuf, compressedSize - 4);
char *speexData = nullptr; uint32 wireChecksum = *(uint32 *)(compressedBuf + compressedSize - 4);
int silkDataLen = 0; FILE *fp = fopen("recorder.snd", "ab");
int speexDataLen = 0; if (fp)
switch (srcPlayer->GetCodecType())
{ {
case vct_silk: printf(" -> Write chunk: (%d), computedChecksum: (%u), wireChecksum: (%u)\n", compressedSize, computedChecksum, wireChecksum);
{ printf(" -> Write chunk: (%d), computedChecksum: (%u), wireChecksum: (%u)\n", compressedSize, computedChecksum, wireChecksum);
if (nDataLength > MAX_SILK_DATA_LEN || srcPlayer->GetVoiceRate() > MAX_SILK_VOICE_RATE) fwrite(compressedBuf, 1, compressedSize, fp);
return; fclose(fp);
}*/
silkData = chReceived; silkDataLen = nDataLength; //return;
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;
}
int maxclients = g_RehldsSvs->GetMaxClients(); int maxclients = g_RehldsSvs->GetMaxClients();
for (int i = 0; i < maxclients; i++) for (int i = 0; i < maxclients; i++)
@ -128,43 +110,21 @@ void SV_ParseVoiceData_emu(IGameClient *cl)
CRevoicePlayer *dstPlayer = &g_Players[i]; CRevoicePlayer *dstPlayer = &g_Players[i];
IGameClient *dstClient = dstPlayer->GetClient(); IGameClient *dstClient = dstPlayer->GetClient();
if (!((1 << i) & cl->GetVoiceStream(0)) && dstPlayer != srcPlayer) if (!((1 << i) & cl->GetVoiceStream(0)) && dstPlayer != srcPlayer) {
continue; 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; continue;
}
if (dstPlayer == srcPlayer && !dstClient->GetLoopback())
nSendLen = 0;
sizebuf_t *dstDatagram = dstClient->GetDatagram(); 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, svc_voicedata);
g_RehldsFuncs->MSG_WriteByte(dstDatagram, cl->GetId()); g_RehldsFuncs->MSG_WriteByte(dstDatagram, cl->GetId());
g_RehldsFuncs->MSG_WriteShort(dstDatagram, nSendLen); g_RehldsFuncs->MSG_WriteShort(dstDatagram, nDataLength);
g_RehldsFuncs->MSG_WriteBuf(dstDatagram, nSendLen, sendBuf); 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) void Rehlds_HandleNetCommand(IRehldsHook_HandleNetCommand *chain, IGameClient *cl, int8 opcode)
{ {
const int clc_voicedata = 8; const int clc_voicedata = 8;
if (opcode == clc_voicedata) { //if (opcode == clc_voicedata) {
SV_ParseVoiceData_emu(cl); // SV_ParseVoiceData_emu(cl);
return; // return;
} //}
chain->callNext(cl, opcode); 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); 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 [ <tracknumber> ]\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) void ServerActivate_PostHook(edict_t *pEdictList, int edictCount, int clientMax)
{ {
Revoice_Exec_Config(); Revoice_Exec_Config();

View File

@ -9,5 +9,7 @@ bool Revoice_Main_Init();
void CvarValue2_PreHook(const edict_t *pEnt, int requestID, const char *cvarName, const char *cvarValue); 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]); 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 ServerActivate_PostHook(edict_t *pEdictList, int edictCount, int clientMax);
void StartFrame_Post();
void ClientCommand(edict_t *pEdict);

View File

@ -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 [ <tracknumber> ]\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 <iostream>
#include <chrono>
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();
}