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:
parent
15780dfcaf
commit
f0b5d960b3
@ -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 */
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
BIN
revoice/dist/c2a2_ba_launch.wav
vendored
Normal file
Binary file not shown.
BIN
revoice/dist/cslig_nuages.wav
vendored
Normal file
BIN
revoice/dist/cslig_nuages.wav
vendored
Normal file
Binary file not shown.
BIN
revoice/dist/dance.wav
vendored
Normal file
BIN
revoice/dist/dance.wav
vendored
Normal file
Binary file not shown.
BIN
revoice/dist/kolshik.wav
vendored
Normal file
BIN
revoice/dist/kolshik.wav
vendored
Normal file
Binary file not shown.
BIN
revoice/dist/pchela.wav
vendored
Normal file
BIN
revoice/dist/pchela.wav
vendored
Normal file
Binary file not shown.
@ -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>
|
||||||
|
@ -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
188
revoice/public/counter.h
Normal 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
|
||||||
|
}
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
494
revoice/src/revoice_main_.cpp
Normal file
494
revoice/src/revoice_main_.cpp
Normal 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();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user