engine: client: GoldSrc voice chat support

- Added support for GoldSrc voice mode, including initialization and shutdown functions.
- Implemented data size verification for the GoldSrc voice package.
- Creation and processing of voice packets, CRC verification of data integrity.
- Added a Steam ID field to the client_static_t structure
- Automatic gain control has been introduced for voice samples.
- The voice status structure has been updated.
- Refactored voice data handling for better type consistency and maintainability.
- Fixed ISO C90 compliance issues for better portability.
- Fixed decoder index usage.
This commit is contained in:
Sergey Degtyar
2025-06-26 08:56:48 +03:00
parent f37bbec78e
commit 6bb7bcd378
5 changed files with 773 additions and 216 deletions

View File

@@ -1029,6 +1029,10 @@ static void CL_WriteSteamTicket( sizebuf_t *send )
crc = CRC32_Final( crc );
i = GenerateRevEmu2013( buf, s, crc );
MSG_WriteBytes( send, buf, i );
// RevEmu2013: pTicket[1] = revHash (low), pTicket[5] = 0x01100001 (high)
*(uint32_t*)cls.steamid = LittleLong( ((uint32_t*)buf)[1] );
*(uint32_t*)(cls.steamid + 4) = LittleLong( ((uint32_t*)buf)[5] );
}
/*

View File

@@ -2010,44 +2010,41 @@ CL_ParseVoiceData
*/
void CL_ParseVoiceData( sizebuf_t *msg, connprotocol_t proto )
{
int size, idx, frames;
int size, idx, frames = 0;
byte received[8192];
idx = MSG_ReadByte( msg ) + 1;
if( proto == PROTO_GOLDSRC )
{
size = MSG_ReadShort( msg );
MSG_SeekToBit( msg, size << 3, SEEK_CUR ); // skip the entire buf, not supported yet
#if 0 // shall we notify client.dll if nothing can be heard?
// must notify through as both local player and normal client
if( idx == cl.playernum + 1 )
Voice_StatusAck( &voice.local, VOICE_LOOPBACK_INDEX );
Voice_StatusAck( &voice.players_status[idx], idx );
#endif
return;
}
frames = MSG_ReadByte( msg );
size = MSG_ReadShort( msg );
size = Q_min( size, sizeof( received ));
MSG_ReadBytes( msg, received, size );
if ( idx <= 0 || idx > cl.maxclients )
return;
// must notify through as both local player and normal client
if( idx == cl.playernum + 1 )
Voice_StatusAck( &voice.local, VOICE_LOOPBACK_INDEX );
if( proto == PROTO_GOLDSRC )
{
size = MSG_ReadShort( msg );
if ( size > 4096 )
{
Con_Printf( S_ERROR "Voice data size is too large: %d bytes (max: %d)\n", size, VOICE_MAX_GS_DATA_SIZE );
return;
}
}
else
{
frames = MSG_ReadByte( msg );
size = MSG_ReadShort( msg );
if (size > 8192 )
{
Con_Printf( S_ERROR "Voice data size is too large: %d bytes (max: %d)\n", size, VOICE_MAX_DATA_SIZE );
return;
}
}
Voice_StatusAck( &voice.players_status[idx], idx );
size = Q_min( size, sizeof( received ));
if ( !size )
return;
MSG_ReadBytes( msg, received, size );
Voice_AddIncomingData( idx, received, size, frames );
}

View File

@@ -638,6 +638,7 @@ typedef struct
// server's build number (might be zero)
int build_num;
uint8_t steamid[8];
} client_static_t;
#ifdef __cplusplus

File diff suppressed because it is too large Load Diff

View File

@@ -24,11 +24,15 @@ GNU General Public License for more details.
typedef struct OpusCustomEncoder OpusCustomEncoder;
typedef struct OpusCustomDecoder OpusCustomDecoder;
typedef struct OpusCustomMode OpusCustomMode;
typedef struct OpusEncoder OpusEncoder;
typedef struct OpusDecoder OpusDecoder;
#define VOICE_LOOPBACK_INDEX (-2)
#define VOICE_LOCALCLIENT_INDEX (-1)
#define VOICE_PCM_CHANNELS 1 // always mono
#define VOICE_MAX_DATA_SIZE 8192
#define VOICE_MAX_GS_DATA_SIZE 4096
// never change these parameters when using opuscustom
#define VOICE_OPUS_CUSTOM_SAMPLERATE 44100
@@ -40,16 +44,42 @@ typedef struct OpusCustomMode OpusCustomMode;
// a1ba: do not change, we don't have any re-encoding support now
#define VOICE_DEFAULT_CODEC VOICE_OPUS_CUSTOM_CODEC
// GoldSrc voice configuration
#define GS_MAX_DECOMPRESSED_SAMPLES 32768
#define GS_DEFAULT_SAMPLE_RATE 24000
#define GS_DEFAULT_FRAME_SIZE 480
// VPC (Voice Packet Control) types
enum gs_vpc_type {
GS_VPC_VDATA_SILENCE = 0,
GS_VPC_VDATA_MILES = 1,
GS_VPC_VDATA_SPEEX = 2,
GS_VPC_VDATA_RAW = 3,
GS_VPC_VDATA_SILK = 4,
GS_VPC_VDATA_OPUS_PLC = 6,
GS_VPC_SETSAMPLERATE = 11,
GS_VPC_UNKNOWN = 10
};
typedef struct voice_status_s
{
qboolean talking_ack;
double talking_timeout;
} voice_status_t;
typedef struct voice_autogain_s
{
int block_size;
float current_gain;
float next_gain;
float gain_multiplier;
} voice_autogain_t;
typedef struct voice_state_s
{
string codec;
int quality;
qboolean goldsrc;
qboolean initialized;
qboolean is_recording;
@@ -64,6 +94,9 @@ typedef struct voice_state_s
OpusCustomEncoder *encoder;
OpusCustomDecoder *decoders[MAX_CLIENTS];
OpusEncoder *gs_encoder;
OpusDecoder *gs_decoders[MAX_CLIENTS];
// audio info
uint width;
uint samplerate;
@@ -79,19 +112,12 @@ typedef struct voice_state_s
wavdata_t *input_file;
fs_offset_t input_file_pos; // in bytes
// automatic gain control
struct {
int block_size;
float current_gain;
float next_gain;
float gain_multiplier;
} autogain;
voice_autogain_t autogain;
} voice_state_t;
extern voice_state_t voice;
void CL_AddVoiceToDatagram( void );
void Voice_RegisterCvars( void );
qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit );
void Voice_Idle( double frametime );
@@ -102,4 +128,8 @@ void Voice_Disconnect( void );
void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames );
void Voice_StatusAck( voice_status_t *status, int playerIndex );
qboolean Voice_IsGoldSrcMode( const char *codec );
qboolean Voice_IsOpusCustomMode( const char *codec );
int Voice_GetBitrateForQuality( int quality, qboolean goldsrc );
#endif // VOICE_H