engine: voice: send disabled voice status when raw chan is exhausted, also send enabled status only when we have something to play

And other minor refactorings.
This commit is contained in:
Alibek Omarov
2025-09-03 04:20:17 +05:00
parent 9df2b8f1fb
commit c2e2686b6a
3 changed files with 37 additions and 61 deletions

View File

@@ -1212,10 +1212,15 @@ static void S_FreeIdleRawChannels( void )
if( ch->s_rawend >= paintedtime )
continue;
if ( ch->entnum > 0 )
if( ch->entnum > 0 )
{
SND_ForceCloseMouth( ch->entnum );
if( ch->entnum <= MAX_CLIENTS )
Voice_StopChannel( ch->entnum );
}
if(( paintedtime - ch->s_rawend ) / SOUND_DMA_SPEED >= S_RAW_SOUND_IDLE_SEC )
{
raw_channels[i] = NULL;
@@ -1801,7 +1806,7 @@ static void S_VoiceRecordStart_f( void )
{
if( cls.state != ca_active )
return;
Voice_RecordStart();
}
@@ -1814,7 +1819,7 @@ static void S_VoiceRecordStop_f( void )
{
if( cls.state != ca_active || !Voice_IsRecording() )
return;
CL_AddVoiceToDatagram();
Voice_RecordStop();
}

View File

@@ -24,13 +24,15 @@ GNU General Public License for more details.
voice_state_t voice = { 0 };
CVAR_DEFINE_AUTO( voice_enable, "1", FCVAR_PRIVILEGED | FCVAR_ARCHIVE, "enable voice chat" );
static CVAR_DEFINE_AUTO( voice_enable, "1", FCVAR_PRIVILEGED | FCVAR_ARCHIVE, "enable voice chat" );
CVAR_DEFINE_AUTO( voice_loopback, "0", FCVAR_PRIVILEGED, "loopback voice back to the speaker" );
CVAR_DEFINE_AUTO( voice_scale, "1.0", FCVAR_PRIVILEGED | FCVAR_ARCHIVE, "incoming voice volume scale" );
CVAR_DEFINE_AUTO( voice_transmit_scale, "1.0", FCVAR_PRIVILEGED | FCVAR_ARCHIVE, "outcoming voice volume scale" );
CVAR_DEFINE_AUTO( voice_avggain, "0.5", FCVAR_PRIVILEGED | FCVAR_ARCHIVE, "automatic voice gain control (average)" );
CVAR_DEFINE_AUTO( voice_maxgain, "5.0", FCVAR_PRIVILEGED | FCVAR_ARCHIVE, "automatic voice gain control (maximum)" );
CVAR_DEFINE_AUTO( voice_inputfromfile, "0", FCVAR_PRIVILEGED, "input voice from voice_input.wav" );
static CVAR_DEFINE_AUTO( voice_scale, "1.0", FCVAR_PRIVILEGED | FCVAR_ARCHIVE, "incoming voice volume scale" );
static CVAR_DEFINE_AUTO( voice_transmit_scale, "1.0", FCVAR_PRIVILEGED | FCVAR_ARCHIVE, "outcoming voice volume scale" );
static CVAR_DEFINE_AUTO( voice_avggain, "0.5", FCVAR_PRIVILEGED | FCVAR_ARCHIVE, "automatic voice gain control (average)" );
static CVAR_DEFINE_AUTO( voice_maxgain, "5.0", FCVAR_PRIVILEGED | FCVAR_ARCHIVE, "automatic voice gain control (maximum)" );
static CVAR_DEFINE_AUTO( voice_inputfromfile, "0", FCVAR_PRIVILEGED, "input voice from voice_input.wav" );
static void Voice_StartChannel( uint samples, byte *data, int entnum );
/*
===============================================================================
@@ -69,24 +71,6 @@ static qboolean Voice_IsOpusCustomMode( const char *codec )
return Q_strcmp( codec, VOICE_OPUS_CUSTOM_CODEC ) == 0;
}
/*
=========================
Voice_GetPlayerStatus
Does proper entity index range checking and helps to avoid mess with off-by-one errors
=========================
*/
static voice_status_t *Voice_GetPlayerStatus( int playerent )
{
if ( playerent < 1 || playerent > MAX_CLIENTS )
{
Con_Printf( S_ERROR "%s: detected out-of-range player entity index\n", __func__ );
return NULL;
}
return &voice.players_status[playerent - 1];
}
/*
=========================
Voice_GetBitrateForQuality
@@ -832,7 +816,7 @@ Sends notification to user dll and
zeroes timeouts for this client
=========================
*/
void Voice_StatusAck( voice_status_t *status, int playerIndex )
static void Voice_StatusAck( voice_status_t *status, int playerIndex )
{
if( !status->talking_ack )
Voice_Status( playerIndex, true );
@@ -938,14 +922,7 @@ void Voice_Disconnect( void )
}
for( i = 1; i <= MAX_CLIENTS; i++ )
{
voice_status_t *status = Voice_GetPlayerStatus( i );
if( status->talking_ack )
{
Voice_Status( i, false );
status->talking_ack = false;
}
}
Voice_Status( i, false );
VoiceCapture_Shutdown();
voice.device_opened = false;
@@ -961,12 +938,26 @@ Voice_StartChannel
Feed the decoded data to engine sound subsystem
=========================
*/
void Voice_StartChannel( uint samples, byte *data, int entnum )
static void Voice_StartChannel( uint samples, byte *data, int entnum )
{
SND_ForceInitMouth( entnum );
S_RawEntSamples( entnum, samples, voice.samplerate, voice.width, VOICE_PCM_CHANNELS, data, bound( 0, 255 * voice_scale.value, 255 ));
Voice_Status( entnum, true );
}
/*
=========================
Voice_StopChannel
Called by mixer when channel idles
=========================
*/
void Voice_StopChannel( int entnum )
{
Voice_Status( entnum, false );
}
/*
=========================
Voice_AddIncomingData
@@ -996,9 +987,6 @@ void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames )
if( !voice.initialized || !voice_enable.value )
return;
status = Voice_GetPlayerStatus( ent );
Voice_StatusAck( status, ent );
if( voice.goldsrc )
{
// Voice_ProcessGSData handles Voice_StartChannel internally
@@ -1126,11 +1114,7 @@ static void Voice_Shutdown( void )
Voice_Status( VOICE_LOOPBACK_INDEX, false );
for( i = 1; i <= MAX_CLIENTS; i++ )
{
voice_status_t *status = Voice_GetPlayerStatus( i );
if( status->talking_ack )
Voice_Status( i, false );
}
Voice_Status( i, false );
voice.initialized = false;
voice.is_recording = false;
@@ -1147,7 +1131,6 @@ static void Voice_Shutdown( void )
memset( voice.compress_buffer, 0, sizeof( voice.compress_buffer ));
memset( voice.decompress_buffer, 0, sizeof( voice.decompress_buffer ));
memset( &voice.local, 0, sizeof( voice.local ));
memset( voice.players_status, 0, sizeof( voice.players_status ));
memset( &voice.autogain, 0, sizeof( voice.autogain ));
}
@@ -1177,16 +1160,6 @@ void Voice_Idle( double frametime )
// update local player status first
Voice_StatusTimeout( &voice.local, VOICE_LOOPBACK_INDEX, frametime );
for( i = 1; i <= MAX_CLIENTS; i++ )
{
voice_status_t *status = Voice_GetPlayerStatus( i );
// TODO: replace timeout logic with mixer channels. If mixer started playing back this player's
// voice channel, we must call VoiceStatus( true ) here and when it's done playing back, call VoiceStatus( false )
// Also, when it's done remove StatusAck from Voice_AddIncomingData!
Voice_StatusTimeout( status, i, frametime );
}
}
/*

View File

@@ -89,7 +89,6 @@ typedef struct voice_state_s
double start_time;
voice_status_t local;
voice_status_t players_status[MAX_CLIENTS]; // do not access this directly, use Voice_GetPlayerStatus instead
// opus stuff
OpusCustomMode *custom_mode;
@@ -130,8 +129,7 @@ void Voice_RecordStop( void );
void Voice_RecordStart( void );
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 );
void Voice_StartChannel( uint samples, byte *data, int entnum );
void Voice_LoopbackAck( void ); // sends -2 to client, gets disabled on timeout
void Voice_StopChannel( int entnum );
void Voice_LoopbackAck( void ); // sends VOICE_LOOPBACK_INDEX to client, gets disabled on timeout
#endif // VOICE_H