View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0004191 | The Dark Mod | Sound | public | 31.07.2015 01:01 | 14.08.2015 17:48 |
Reporter | NagaHuntress | Assigned To | SteveL | ||
Priority | normal | Severity | normal | Reproducibility | random |
Status | resolved | Resolution | fixed | ||
OS | Linux | ||||
Product Version | TDM 2.03 | ||||
Target Version | TDM 2.04 | Fixed in Version | TDM 2.04 | ||
Summary | 0004191: Popping/crackling sound when running on Linux | ||||
Description | When running the game, there's a sizable chance that the audio will start popping or crackling, as if the audio is being interrupt for a fraction of a second. This problem will manifest either immediately upon running the game, or a few seconds after. When this problem does occur the following can be seen printed repeatedly in the terminal window used to run the game: snd_pcm_writei 4096 frames failed: Broken pipe preparing audio device for output This problem has been experienced on the following distros: Ubuntu 12.04 (32 bit) Linux Mint 15 (64 bit) Linux Mint 17.2 (64 bit) | ||||
Tags | No tags attached. | ||||
Attached Files | tdm-linux-sound-fix.diff (2,526 bytes)
Index: sys/linux/sound_alsa.cpp =================================================================== --- sys/linux/sound_alsa.cpp (revision 6521) +++ sys/linux/sound_alsa.cpp (working copy) @@ -26,6 +26,11 @@ static idCVar s_alsa_pcm( "s_alsa_pcm", "default", CVAR_SYSTEM | CVAR_ARCHIVE, "which alsa pcm device to use. default, hwplug, hw.. see alsa docs" ); static idCVar s_alsa_lib( "s_alsa_lib", "libasound.so.2", CVAR_SYSTEM | CVAR_ARCHIVE, "alsa client sound library" ); +/** +This idCVar configures how many extra frames of audio data it sends when the alsa driver experiences an underrun. This is more of a work around then a fix, as the root cause of the issue is likely elsewhere. + */ +static idCVar s_alsa_underrun_extrafill( "s_alsa_underrun_extrafill", "1024", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT, "If an underrun error occurs while outputing ausio, it will retry and refill the audio stream with extra data to try and clear the underrun condition. This specifies the number of extra frames." ); + /* =============== idAudioHardwareALSA::DLOpen @@ -299,6 +304,20 @@ // write the max frames you can in one shot - we need to write it all out in Flush() calls before the next Write() happens int pos = (int)m_buffer + ( MIXBUFFER_SAMPLES - m_remainingFrames ) * m_channels * 2; snd_pcm_sframes_t frames = id_snd_pcm_writei( m_pcm_handle, (void*)pos, m_remainingFrames ); + /* + A kludge to handle buffer underruns (reported as broken pipes). + To the user this condition manifests as popping or crackling audio. + This will re-ready the sound out and send the pending data twice. + The root cause of this error is likely to lie else where in the audio pipeline, but this work around plugs the problem for now. + */ + if ( frames == -EPIPE ) { + snd_pcm_sframes_t nextframes = s_alsa_underrun_extrafill.GetInteger(); + nextframes = (m_remainingFrames > nextframes) ? nextframes : m_remainingFrames; + Sys_Printf( "snd_pcm_writei() reports broken pipe (underrun) while sending %d frames. Retrying but also sending %d duplicate frames first. Try increasing 's_alsa_underrun_extrafill' if this persists.\n", m_remainingFrames, nextframes); + id_snd_pcm_prepare( m_pcm_handle ); + frames = id_snd_pcm_writei( m_pcm_handle, (void*)pos, nextframes ); + frames = id_snd_pcm_writei( m_pcm_handle, (void*)pos, m_remainingFrames ); + } if ( frames < 0 ) { if ( frames != -EAGAIN ) { Sys_Printf( "snd_pcm_writei %d frames failed: %s\n", m_remainingFrames, id_snd_strerror( frames ) ); tdm-linux-sound-fix-v2.diff (2,764 bytes)
Index: sys/linux/sound_alsa.cpp =================================================================== --- sys/linux/sound_alsa.cpp (revision 6527) +++ sys/linux/sound_alsa.cpp (working copy) @@ -26,6 +26,11 @@ static idCVar s_alsa_pcm( "s_alsa_pcm", "default", CVAR_SYSTEM | CVAR_ARCHIVE, "which alsa pcm device to use. default, hwplug, hw.. see alsa docs" ); static idCVar s_alsa_lib( "s_alsa_lib", "libasound.so.2", CVAR_SYSTEM | CVAR_ARCHIVE, "alsa client sound library" ); +/** +This idCVar configures how many extra frames of audio data it sends when the alsa driver experiences an underrun. This is more of a work around then a fix, as the root cause of the issue is likely elsewhere. + */ +static idCVar s_alsa_underrun_extrafill( "s_alsa_underrun_extrafill", "1024", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT | CVAR_INTEGER, "If an underrun error occurs while outputing ausio, it will retry and refill the audio stream with extra data to try and clear the underrun condition. This specifies the number of extra frames.", 0, 8192 ); + /* =============== idAudioHardwareALSA::DLOpen @@ -297,8 +302,25 @@ return; } // write the max frames you can in one shot - we need to write it all out in Flush() calls before the next Write() happens - int pos = (int)m_buffer + ( MIXBUFFER_SAMPLES - m_remainingFrames ) * m_channels * 2; + size_t pos = (size_t)m_buffer + ( MIXBUFFER_SAMPLES - m_remainingFrames ) * m_channels * 2; snd_pcm_sframes_t frames = id_snd_pcm_writei( m_pcm_handle, (void*)pos, m_remainingFrames ); + /* + A kludge to handle buffer underruns (reported as broken pipes). + To the user this condition manifests as popping or crackling audio. + This will re-ready the sound out and send the pending data twice. + The root cause of this error is likely to lie else where in the audio pipeline, but this work around plugs the problem for now. + */ + if ( frames == -EPIPE ) { + snd_pcm_sframes_t nextframes = s_alsa_underrun_extrafill.GetInteger(); + nextframes = (nextframes < 0) ? 0 : nextframes; + nextframes = (m_remainingFrames > nextframes) ? nextframes : m_remainingFrames; + Sys_Printf( "snd_pcm_writei() reports broken pipe (underrun) while sending %u frames. Retrying but also sending %u duplicate frames first. Try increasing 's_alsa_underrun_extrafill' if this persists.\n", (unsigned int)m_remainingFrames, (unsigned int)nextframes); + id_snd_pcm_prepare( m_pcm_handle ); + if(nextframes) { + frames = id_snd_pcm_writei( m_pcm_handle, (void*)pos, nextframes ); + } + frames = id_snd_pcm_writei( m_pcm_handle, (void*)pos, m_remainingFrames ); + } if ( frames < 0 ) { if ( frames != -EAGAIN ) { Sys_Printf( "snd_pcm_writei %d frames failed: %s\n", m_remainingFrames, id_snd_strerror( frames ) ); | ||||
The attached diff file fixes the issue of buffer underrun (broken pipes) on the audio output by re-preparing the audio connection and sending extra audio data in the retry. The extra data in the retry pads the output buffer so that it won't run out of audio data too soon. This patch is probably more a work around rather than a fix that addresses the root cause of the issue. |
|
Made a second version of the patch which adds these changes: - Sets the CVAR to an integer and limits the range from 0 to 8192. - If it's set to 0, it will skip sending the extra block of data. |
|
At revision 6529 /trunk/sys/linux/sound_alsa.cpp |
|
Date Modified | Username | Field | Change |
---|---|---|---|
31.07.2015 01:01 | NagaHuntress | New Issue | |
31.07.2015 01:02 | NagaHuntress | File Added: tdm-linux-sound-fix.diff | |
31.07.2015 01:11 | NagaHuntress | Note Added: 0007679 | |
13.08.2015 18:51 | SteveL | Assigned To | => SteveL |
13.08.2015 18:51 | SteveL | Status | new => assigned |
13.08.2015 18:52 | SteveL | Product Version | => TDM 2.03 |
13.08.2015 18:52 | SteveL | Target Version | => TDM 2.04 |
14.08.2015 17:16 | NagaHuntress | File Added: tdm-linux-sound-fix-v2.diff | |
14.08.2015 17:20 | NagaHuntress | Note Added: 0007715 | |
14.08.2015 17:48 | SteveL | Note Added: 0007716 | |
14.08.2015 17:48 | SteveL | Status | assigned => resolved |
14.08.2015 17:48 | SteveL | Fixed in Version | => TDM 2.04 |
14.08.2015 17:48 | SteveL | Resolution | open => fixed |