mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-01-27 00:46:19 +00:00
Adjust some voice chat parameters and behavior
1. If the sample queue is too long, frames will be skipped. This prevents bursting with a bunch of voice packets at once. 2. The Opus frame size is doubled to 20ms to reduce UDP overhead. 3. The Opus bitrate is reduced from its default to 10kbps, to prevent potential UDP MTU size overruns. 4. The server will ignore Opus frames past a certain limit per tic from each player, preventing excessive voice packet propagation 5. Push to talk no longer eats chat typing, and no longer responds while chat mode is on.
This commit is contained in:
parent
68d83f6870
commit
0db1b16061
7 changed files with 58 additions and 8 deletions
|
|
@ -200,9 +200,11 @@ tic_t firstconnectattempttime = 0;
|
|||
|
||||
static OpusDecoder *g_player_opus_decoders[MAXPLAYERS];
|
||||
static UINT64 g_player_opus_lastframe[MAXPLAYERS];
|
||||
static UINT32 g_player_voice_frames_this_tic[MAXPLAYERS];
|
||||
#define MAX_PLAYER_VOICE_FRAMES_PER_TIC 3
|
||||
static OpusEncoder *g_local_opus_encoder;
|
||||
static UINT64 g_local_opus_frame = 0;
|
||||
#define SRB2_VOICE_OPUS_FRAME_SIZE 480
|
||||
#define SRB2_VOICE_OPUS_FRAME_SIZE 960
|
||||
static float g_local_voice_buffer[SRB2_VOICE_OPUS_FRAME_SIZE];
|
||||
static INT32 g_local_voice_buffer_len = 0;
|
||||
static INT32 g_local_voice_threshold_time = 0;
|
||||
|
|
@ -3698,12 +3700,13 @@ static void InitializeLocalVoiceEncoder(void)
|
|||
}
|
||||
int error;
|
||||
encoder = opus_encoder_create(48000, 1, OPUS_APPLICATION_VOIP, &error);
|
||||
opus_encoder_ctl(encoder, OPUS_SET_VBR(0));
|
||||
if (error != OPUS_OK)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Failed to create Opus voice encoder: opus error %d\n", error);
|
||||
encoder = NULL;
|
||||
}
|
||||
opus_encoder_ctl(encoder, OPUS_SET_VBR(0));
|
||||
opus_encoder_ctl(encoder, OPUS_SET_BITRATE(10000));
|
||||
g_local_opus_encoder = encoder;
|
||||
g_local_opus_frame = 0;
|
||||
}
|
||||
|
|
@ -5373,6 +5376,12 @@ static void PT_HandleVoiceServer(SINT8 node)
|
|||
// ignore, they should not be able to broadcast voice
|
||||
return;
|
||||
}
|
||||
g_player_voice_frames_this_tic[playernum] += 1;
|
||||
if (g_player_voice_frames_this_tic[playernum] > MAX_PLAYER_VOICE_FRAMES_PER_TIC)
|
||||
{
|
||||
// ignore; they sent too many voice frames this tic
|
||||
return;
|
||||
}
|
||||
|
||||
// Preserve terminal bit, blank all other bits
|
||||
pl->flags &= VOICE_PAK_FLAGS_TERMINAL_BIT;
|
||||
|
|
@ -5401,6 +5410,7 @@ static void PT_HandleVoiceServer(SINT8 node)
|
|||
HSendPacket(pnode, false, 0, doomcom->datalength - BASEPACKETSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
PT_HandleVoiceClient(node, true);
|
||||
}
|
||||
|
||||
|
|
@ -6867,6 +6877,12 @@ boolean TryRunTics(tic_t realtics)
|
|||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Reset received voice frames per tic for all players
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
g_player_voice_frames_this_tic[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (F_IsDeferredContinueCredits())
|
||||
|
|
@ -7489,7 +7505,8 @@ void NetVoiceUpdate(void)
|
|||
{
|
||||
// We need to drain the input queue completely, so do this in a full loop
|
||||
|
||||
INT32 to_read = (SRB2_VOICE_OPUS_FRAME_SIZE - g_local_voice_buffer_len) * sizeof(float);
|
||||
UINT32 to_read = (SRB2_VOICE_OPUS_FRAME_SIZE - g_local_voice_buffer_len) * sizeof(float);
|
||||
|
||||
if (to_read > 0)
|
||||
{
|
||||
// Attempt to fill the voice frame buffer
|
||||
|
|
@ -7507,6 +7524,14 @@ void NetVoiceUpdate(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (S_SoundInputRemainingSamples() > 5 * SRB2_VOICE_OPUS_FRAME_SIZE)
|
||||
{
|
||||
// If there are too many frames worth of samples to dequeue (100ms), skip this frame instead of encoding.
|
||||
// This is so we drain the queue without sending too many packets that might queue up on the network driver.
|
||||
g_local_voice_buffer_len = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Amp of +10 dB is appromiately "twice as loud"
|
||||
float ampfactor = powf(10, (float) cv_voice_inputamp.value / 20.f);
|
||||
for (int i = 0; i < g_local_voice_buffer_len; i++)
|
||||
|
|
|
|||
|
|
@ -240,6 +240,11 @@ UINT32 I_SoundInputDequeueSamples(void *data, UINT32 len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
UINT32 I_SoundInputRemainingSamples(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void I_QueueVoiceFrameFromPlayer(INT32 playernum, void *data, UINT32 len, boolean terminal)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -710,7 +710,7 @@ static void Got_Saycmd(const UINT8 **p, INT32 playernum)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (LUA_HookPlayerMsg(playernum, target, flags, msg))
|
||||
return;
|
||||
|
||||
|
|
@ -1116,15 +1116,13 @@ boolean HU_Responder(event_t *ev)
|
|||
|| ev->data1 == gamecontrol[0][gc_voicepushtotalk][2]
|
||||
|| ev->data1 == gamecontrol[0][gc_voicepushtotalk][3])
|
||||
{
|
||||
if (ev->type == ev_keydown)
|
||||
if (ev->type == ev_keydown && !chat_on)
|
||||
{
|
||||
g_voicepushtotalk_on = true;
|
||||
return true;
|
||||
}
|
||||
else if (ev->type == ev_keyup)
|
||||
{
|
||||
g_voicepushtotalk_on = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -252,6 +252,7 @@ boolean I_FadeInPlaySong(UINT32 ms, boolean looping);
|
|||
boolean I_SoundInputIsEnabled(void);
|
||||
boolean I_SoundInputSetEnabled(boolean enabled);
|
||||
UINT32 I_SoundInputDequeueSamples(void *data, UINT32 len);
|
||||
UINT32 I_SoundInputRemainingSamples(void);
|
||||
|
||||
// VOICE CHAT
|
||||
|
||||
|
|
|
|||
|
|
@ -2872,6 +2872,11 @@ UINT32 S_SoundInputDequeueSamples(void *data, UINT32 len)
|
|||
return I_SoundInputDequeueSamples(data, len);
|
||||
}
|
||||
|
||||
UINT32 S_SoundInputRemainingSamples(void)
|
||||
{
|
||||
return I_SoundInputRemainingSamples();
|
||||
}
|
||||
|
||||
static INT32 g_playerlastvoiceactive[MAXPLAYERS];
|
||||
|
||||
void S_QueueVoiceFrameFromPlayer(INT32 playernum, void *data, UINT32 len, boolean terminal)
|
||||
|
|
|
|||
|
|
@ -295,6 +295,7 @@ void S_StopSoundByNum(sfxenum_t sfxnum);
|
|||
boolean S_SoundInputIsEnabled(void);
|
||||
boolean S_SoundInputSetEnabled(boolean enabled);
|
||||
UINT32 S_SoundInputDequeueSamples(void *data, UINT32 len);
|
||||
UINT32 S_SoundInputRemainingSamples(void);
|
||||
|
||||
void S_QueueVoiceFrameFromPlayer(INT32 playernum, void *data, UINT32 len, boolean terminal);
|
||||
void S_SetPlayerVoiceActive(INT32 playernum);
|
||||
|
|
|
|||
|
|
@ -1013,7 +1013,7 @@ boolean I_SoundInputSetEnabled(boolean enabled)
|
|||
SDL_AudioSpec input_desired {};
|
||||
input_desired.format = AUDIO_F32SYS;
|
||||
input_desired.channels = 1;
|
||||
input_desired.samples = 2048;
|
||||
input_desired.samples = 1024;
|
||||
input_desired.freq = 48000;
|
||||
SDL_AudioSpec input_obtained {};
|
||||
g_input_device_id = SDL_OpenAudioDevice(nullptr, SDL_TRUE, &input_desired, &input_obtained, 0);
|
||||
|
|
@ -1022,6 +1022,11 @@ boolean I_SoundInputSetEnabled(boolean enabled)
|
|||
CONS_Alert(CONS_WARNING, "Failed to open input audio device: %s\n", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
if (input_obtained.freq != 48000 || input_obtained.format != AUDIO_F32SYS || input_obtained.channels != 1)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Input audio device has unexpected unusable format: %s\n", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
SDL_PauseAudioDevice(g_input_device_id, SDL_FALSE);
|
||||
}
|
||||
else if (g_input_device_id != 0 && !enabled)
|
||||
|
|
@ -1051,6 +1056,16 @@ UINT32 I_SoundInputDequeueSamples(void *data, UINT32 len)
|
|||
return ret;
|
||||
}
|
||||
|
||||
UINT32 I_SoundInputRemainingSamples(void)
|
||||
{
|
||||
if (!g_input_device_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
UINT32 avail = SDL_GetQueuedAudioSize(g_input_device_id);
|
||||
return avail / sizeof(float);
|
||||
}
|
||||
|
||||
void I_QueueVoiceFrameFromPlayer(INT32 playernum, void *data, UINT32 len, boolean terminal)
|
||||
{
|
||||
if (!sound_started)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue