engine: client: voice api

This commit is contained in:
TheEVolk
2026-04-09 22:02:36 +03:00
committed by a1batross
parent 055d646225
commit 9e8d248044
13 changed files with 57 additions and 10 deletions

View File

@@ -159,11 +159,22 @@ typedef struct snd_globals_s
qboolean have_ambient_sfx;
} snd_globals_t;
typedef struct voice_audio_info_s
{
uint width;
uint samplerate;
uint frame_size; // in samples
} voice_audio_info_t;
// API from engine to client (client calls these)
typedef struct sound_api_s
{
qboolean (*CL_GetEntitySpatialization)( channel_t *ch );
sfx_t* (*S_GetSfxByHandle)( sound_t handle );
qboolean (*CL_GetEntitySpatialization)( channel_t *ch );
sfx_t* (*S_GetSfxByHandle)( sound_t handle );
// Voice extensions
void (*pfnS_RawEntSamples)( int entnum, uint samples, uint rate, word width, word channels, const byte *data, int snd_vol, float attn );
void (*pfnSND_ForceInitMouth)( int entnum );
voice_audio_info_t (*pfnVoice_GetAudioInfo)( void );
} sound_api_t;
// Callbacks from client to engine (engine calls these when custom sound is active)

View File

@@ -82,6 +82,7 @@ typedef struct cldll_func_s
void (*pfnLookEvent)( float relyaw, float relpitch );
// Sound API
int (*pfnGetSoundInterface)( int version, const sound_api_t *api, sound_interface_t *callback );
int (*pfnVoice_StartChannel)( int samples, byte *data, int entnum );
} cldll_func_t;
#endif//CDLL_EXP_H

View File

@@ -105,7 +105,8 @@ static const dllfunc_t cdll_new_exports[] = // allowed only in SDK 2.3 and high
{ "IN_ClientTouchEvent", (void **)&clgame.dllFuncs.pfnTouchEvent}, // Xash3D FWGS ext
{ "IN_ClientMoveEvent", (void **)&clgame.dllFuncs.pfnMoveEvent}, // Xash3D FWGS ext
{ "IN_ClientLookEvent", (void **)&clgame.dllFuncs.pfnLookEvent}, // Xash3D FWGS ext
{ "HUD_GetSoundInterface", (void **)&clgame.dllFuncs.pfnGetSoundInterface }, // Xash3D ext
{ "HUD_GetSoundInterface", (void **)&clgame.dllFuncs.pfnGetSoundInterface }, // Xash3D FWGS ext
{ "Voice_StartChannel", (void **)&clgame.dllFuncs.pfnVoice_StartChannel }, // Xash3D FWGS ext
};
static void pfnSPR_DrawHoles( int frame, int x, int y, const wrect_t *prc );

View File

@@ -1287,7 +1287,7 @@ uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint ma
S_RawEntSamples
===================
*/
void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word channels, const byte *data, int snd_vol )
void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word channels, const byte *data, int snd_vol, float attn )
{
rawchan_t *ch;
@@ -1298,7 +1298,7 @@ void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word chan
return;
ch->master_vol = snd_vol;
ch->dist_mult = (ATTN_NONE / SND_CLIP_DISTANCE);
ch->dist_mult = (attn / SND_CLIP_DISTANCE);
ch->s_rawend = S_RawSamplesStereo( ch->rawsamples, ch->s_rawend, ch->max_samples, samples, rate, width, channels, data );
ch->leftvol = ch->rightvol = snd_vol;
}
@@ -1938,6 +1938,9 @@ static void S_VoiceRecordStop_f( void )
static const sound_api_t gSoundAPI = {
CL_GetEntitySpatialization,
S_GetSfxByHandle,
S_RawEntSamples,
SND_ForceInitMouth,
Voice_GetAudioInfo,
};
/*

View File

@@ -253,7 +253,7 @@ void S_StreamBackgroundTrack( void )
{
// add to raw buffer
int music_vol = (int)(255.0f * S_GetMusicVolume());
S_RawEntSamples( S_RAW_SOUND_BACKGROUNDTRACK, fileSamples, info->rate, info->width, info->channels, raw, music_vol );
S_RawEntSamples( S_RAW_SOUND_BACKGROUNDTRACK, fileSamples, info->rate, info->width, info->channels, raw, music_vol, ATTN_NONE );
}
else
{

View File

@@ -111,7 +111,7 @@ int S_GetCurrentDynamicSounds( soundlist_t *pout, int size );
sfx_t *S_GetSfxByHandle( sound_t handle );
rawchan_t *S_FindRawChannel( int entnum, qboolean create );
uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint max_samples, uint samples, uint rate, word width, word channels, const byte *data );
void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word channels, const byte *data, int snd_vol );
void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word channels, const byte *data, int snd_vol, float attn );
void S_StopSound( int entnum, int channel, const char *soundname );
void S_UpdateFrame( struct ref_viewpass_s *rvp );
void S_StopAllSounds( qboolean ambient );

View File

@@ -939,8 +939,14 @@ Feed the decoded data to engine sound subsystem
*/
static void Voice_StartChannel( uint samples, byte *data, int entnum )
{
if( clgame.dllFuncs.pfnVoice_StartChannel != NULL )
{
if( clgame.dllFuncs.pfnVoice_StartChannel( samples, data, entnum ))
return;
}
SND_ForceInitMouth( entnum );
S_RawEntSamples( entnum, samples, voice.samplerate, voice.width, VOICE_PCM_CHANNELS, data, bound( 0, 255 * voice_scale.value, 255 ));
S_RawEntSamples( entnum, samples, voice.samplerate, voice.width, VOICE_PCM_CHANNELS, data, bound( 0, 255 * voice_scale.value, 255 ), ATTN_NONE );
Voice_Status( entnum, true );
}
@@ -1194,3 +1200,13 @@ qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
voice.initialized = true;
return true;
}
voice_audio_info_t Voice_GetAudioInfo( void )
{
voice_audio_info_t info;
info.width = voice.width;
info.samplerate = voice.samplerate;
info.frame_size = voice.frame_size;
return info;
}

View File

@@ -131,5 +131,6 @@ void Voice_Disconnect( void );
void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames );
void Voice_StopChannel( int entnum );
void Voice_LoopbackAck( void ); // sends VOICE_LOOPBACK_INDEX to client, gets disabled on timeout
voice_audio_info_t Voice_GetAudioInfo( void );
#endif // VOICE_H

View File

@@ -168,6 +168,8 @@ typedef struct physics_interface_s
void *(*SV_HullForBsp)( edict_t *ent, const float *mins, const float *maxs, float *offset );
// handle player custom think function
int (*SV_PlayerThink)( edict_t *ent, float frametime, double time );
// voice data
qboolean (*pfnVoiceData)( int client, uint frames, uint size, qboolean loopback, const char *received );
} physics_interface_t;
#endif//PHYSINT_H

View File

@@ -406,6 +406,7 @@ extern convar_t sv_wateralpha;
extern convar_t sv_wateramp;
extern convar_t sv_voiceenable;
extern convar_t sv_voicequality;
extern convar_t sv_voice_singleplayer;
extern convar_t sv_maxvelocity;
extern convar_t sv_stepsize;
extern convar_t sv_skyname;

View File

@@ -3571,7 +3571,16 @@ static void SV_ParseVoiceData( sv_client_t *cl, sizebuf_t *msg )
MSG_ReadBytes( msg, received, size );
if( !sv_voiceenable.value || svs.maxclients <= 1 || cl->state != cs_spawned )
if( !sv_voiceenable.value || cl->state != cs_spawned )
return;
if( svgame.physFuncs.pfnVoiceData != NULL )
{
if( svgame.physFuncs.pfnVoiceData( client, frames, size, loopback, received ))
return;
}
if( svs.maxclients <= 1 && sv_voice_singleplayer.value == 0.0f )
return;
for( i = 0; i < svs.maxclients; i++ )

View File

@@ -463,7 +463,7 @@ static void SV_CreateBaseline( void )
int delta_type;
int entnum;
if( svs.maxclients > 1 )
if( svs.maxclients > 1 || sv_voice_singleplayer.value )
SV_WriteVoiceCodec( &sv.signon );
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))

View File

@@ -124,6 +124,7 @@ static CVAR_DEFINE_AUTO( violence_agibs, "1", 0, "show alien gib entities" );
// voice chat
CVAR_DEFINE_AUTO( sv_voiceenable, "1", FCVAR_ARCHIVE|FCVAR_SERVER, "enable voice support" );
CVAR_DEFINE_AUTO( sv_voicequality, "3", FCVAR_ARCHIVE, "voice chat quality level, from 0 to 5, higher is better" );
CVAR_DEFINE_AUTO( sv_voice_singleplayer, "0", FCVAR_ARCHIVE, "enable voice subsystem in singleplayer games (maxclients == 1)" );
// enttools
CVAR_DEFINE_AUTO( sv_enttools_enable, "0", FCVAR_ARCHIVE|FCVAR_PROTECTED, "enable powerful and dangerous entity tools" );
@@ -975,6 +976,7 @@ void SV_Init( void )
Cvar_RegisterVariable( &sv_voiceenable );
Cvar_RegisterVariable( &sv_voicequality );
Cvar_RegisterVariable( &sv_voice_singleplayer );
Cvar_RegisterVariable( &sv_trace_messages );
Cvar_RegisterVariable( &sv_enttools_enable );
Cvar_RegisterVariable( &sv_enttools_maxfire );