Root Causes of Voice Chat System Issues
Reconnection bug (sound does not return upon entering range)
3 combined root causes:
playback.h — `neededMoreSamples` was not initialized. When creating a speaker buffer, the boolean had a garbage value → the jitter buffer did not insert silence correctly → audio never started.
Fix: bool neededMoreSamples = true;
VoiceChat.cpp — smallestSplValue and inactiveBypassLeft were static. They persisted across sessions. Upon reconnecting, the voice detection threshold remained calibrated with old values → new voice was rejected as noise.
Fix: Moved to class members with reset in Initialize()/Destroy()
flac_decoder.h — After an error or end of stream, the decoder remained in an invalid state. initialize() did not reinitialize if it was not in UNINITIALIZED. New packets failed silently.
Fix: execute() detects error/end states and automatically calls finish() + initialize()
Packet corruption
2 root causes:
packet.h (server + client) — TVoiceChatPacket without #pragma pack(1). The#pragmated padding between the uint8_t header and uint16_t size. Server and client could have different sizes → different sizeof(TVoiceChatPacket) → validation pack.dataSize != pack.size - sizeof(TVoiceChatPacket) failed or passed incorrectly.
Fix: #pragma pack(push, 1) / #pragmap) on bot#pragma
input_main.cpp (server) — *(TVoiceChatPacket*)c_pData without verifying that uiBytes >= sizeof(TVoiceChatPacket) → buffer over-read. Invalid packet read memory
Fix: Bounds check first, then safe memcpy instead of pointer cast
Race conditions (crackling, crashes)
2 root causes:
playback.h — setSpeakerVolume() modified m_SpeakerBuffers without a mutex, while the audio thread was reading it in dataCallback.
Fix: std::lock_guard<std::mutex> added
playback.h — mixedSamples was static inside getSamples(), called from the audio thread. Static in a function = shared across invocations, not thread-safe if re-entry occurred.
Fix: Moved to member m_MixBuffer
Incorrect sample calculation
playback.h — samplesPerMillisecond() used m_Device.capture.channels but the class is Playback (it has no capture). The correct field is m_Device.playback.channels.
Oversized receive buffer
PythonNetworkStreamPhaseGame.cpp — Allocated sampleRate * 8 channels * sizeof(int16_t) = ~768KB per packet, when the actual data is ~6KB. Used std::max<uint8_t>(8, channelCount), which always returns at least 8.
Fix: Buffer sized to actual packet.dataSize
Static vector in hot path
VoiceChat.cpp — samplesVec was static, causing the vector to retain old state between calls and be reused without being properly cleaned up.
Fix: Normal local variable std::vector<int16_t> samplesVec(samples, samples + sampleCount)
Ekli dosyayı görüntüle 173298
V3.0 TEST AND WORK
Virüs Total
Game-level fixes
Sound wouldn't come back when you got close to someone
You'd leave the voice chat range → get close again → total silence. You had to reconnect for it to work again. Now the audio resumes automatically when you return to the range.
Voice chat would cut out during map changes / reconnections
When changing maps or reconnecting, voice chat would stop working. The microphone would detect your voice as “background noise” because it remembered the sound levels from the previous session. Now it recalibrates upon reconnecting.
Crackling / noise when changing a player’s volume
If you adjusted a speaker’s volume while they were speaking, it could cause crackling or glitches. Now volume changes are smooth without interrupting the audio.
Corrupted packets caused disconnections or silence
If a voice packet arrived malformed, it could corrupt subsequent packets and desynchronize the connection. In the worst case, the client would disconnect. Now the server validates correctly before processing.
Excessive memory usage when receiving voice
Each voice packet allocated ~768KB of memory when it only needed ~6KB. With multiple players speaking, RAM usage skyrocketed. Now it uses only what is necessary.
Reconnection bug (sound does not return upon entering range)3 combined root causes:
playback.h — `neededMoreSamples` was not initialized. When creating a speaker buffer, the boolean had a garbage value → the jitter buffer did not insert silence correctly → audio never started.
Fix: bool neededMoreSamples = true;
VoiceChat.cpp — smallestSplValue and inactiveBypassLeft were static. They persisted across sessions. Upon reconnecting, the voice detection threshold remained calibrated with old values → new voice was rejected as noise.
Fix: Moved to class members with reset in Initialize()/Destroy()
flac_decoder.h — After an error or end of stream, the decoder remained in an invalid state. initialize() did not reinitialize if it was not in UNINITIALIZED. New packets failed silently.
Fix: execute() detects error/end states and automatically calls finish() + initialize()
Packet corruption2 root causes:
packet.h (server + client) — TVoiceChatPacket without #pragma pack(1). The#pragmated padding between the uint8_t header and uint16_t size. Server and client could have different sizes → different sizeof(TVoiceChatPacket) → validation pack.dataSize != pack.size - sizeof(TVoiceChatPacket) failed or passed incorrectly.
Fix: #pragma pack(push, 1) / #pragmap) on bot#pragma
input_main.cpp (server) — *(TVoiceChatPacket*)c_pData without verifying that uiBytes >= sizeof(TVoiceChatPacket) → buffer over-read. Invalid packet read memory
Fix: Bounds check first, then safe memcpy instead of pointer cast
Race conditions (crackling, crashes)2 root causes:
playback.h — setSpeakerVolume() modified m_SpeakerBuffers without a mutex, while the audio thread was reading it in dataCallback.
Fix: std::lock_guard<std::mutex> added
playback.h — mixedSamples was static inside getSamples(), called from the audio thread. Static in a function = shared across invocations, not thread-safe if re-entry occurred.
Fix: Moved to member m_MixBuffer
Incorrect sample calculationplayback.h — samplesPerMillisecond() used m_Device.capture.channels but the class is Playback (it has no capture). The correct field is m_Device.playback.channels.
Oversized receive bufferPythonNetworkStreamPhaseGame.cpp — Allocated sampleRate * 8 channels * sizeof(int16_t) = ~768KB per packet, when the actual data is ~6KB. Used std::max<uint8_t>(8, channelCount), which always returns at least 8.
Fix: Buffer sized to actual packet.dataSize
Static vector in hot pathVoiceChat.cpp — samplesVec was static, causing the vector to retain old state between calls and be reused without being properly cleaned up.
Fix: Normal local variable std::vector<int16_t> samplesVec(samples, samples + sampleCount)
Ekli dosyayı görüntüle 173298
V3.0 TEST AND WORK
Download m2-voice-chat-main_v3.zip | LimeWire
Virüs Total
Game-level fixes
Sound wouldn't come back when you got close to someoneYou'd leave the voice chat range → get close again → total silence. You had to reconnect for it to work again. Now the audio resumes automatically when you return to the range.
Voice chat would cut out during map changes / reconnectionsWhen changing maps or reconnecting, voice chat would stop working. The microphone would detect your voice as “background noise” because it remembered the sound levels from the previous session. Now it recalibrates upon reconnecting.
Crackling / noise when changing a player’s volumeIf you adjusted a speaker’s volume while they were speaking, it could cause crackling or glitches. Now volume changes are smooth without interrupting the audio.
Corrupted packets caused disconnections or silenceIf a voice packet arrived malformed, it could corrupt subsequent packets and desynchronize the connection. In the worst case, the client would disconnect. Now the server validates correctly before processing.
Excessive memory usage when receiving voiceEach voice packet allocated ~768KB of memory when it only needed ~6KB. With multiple players speaking, RAM usage skyrocketed. Now it uses only what is necessary.