From: bruceperens Date: Fri, 25 Apr 2014 20:44:35 +0000 (+0000) Subject: Change start/stop functions for ALSA output to deal with an intermittent X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=37ebc0eee89003c3bf9a551bcd99c7fe4c53b72b;p=freetel-svn-tracking.git Change start/stop functions for ALSA output to deal with an intermittent "roughness" problem on the output. Always pre-load after underrun. Use snd_pcm_drop() to stop, and don't call snd_pcm_prepare() until we're about to write. git-svn-id: https://svn.code.sf.net/p/freetel/code@1564 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/freedv-server/source/platform/linux/audio_out_alsa.cpp b/freedv-server/source/platform/linux/audio_out_alsa.cpp index b8e50b14..3d7e3f95 100644 --- a/freedv-server/source/platform/linux/audio_out_alsa.cpp +++ b/freedv-server/source/platform/linux/audio_out_alsa.cpp @@ -133,7 +133,8 @@ namespace FreeDV { // a shared clock, and the more expensive equipment that supports it, // to avoid this problem. // - int16_t buf[AudioFrameSamples]; + snd_pcm_prepare(handle); + int16_t buf[AudioFrameSamples * 2]; memset(buf, 0, sizeof(buf)); snd_pcm_writei(handle, buf, sizeof(buf) / sizeof(*buf)); } @@ -180,56 +181,55 @@ namespace FreeDV { std::size_t AudioOutALSA::ready() { - snd_pcm_sframes_t available = 0; - snd_pcm_sframes_t delay = 0; - int error; - - if ( !started ) - return AudioFrameSamples; - - error = snd_pcm_avail_delay(handle, &available, &delay); - if ( delay > (AudioFrameSamples * 8) ) { - const double seconds = (double)delay / (double)SampleRate; - - std::cerr << "ALSA output \"" << parameters - << "\": overlong delay, dropped " - << seconds << " seconds of output." << std::endl; - snd_pcm_drop(handle); - snd_pcm_prepare(handle); - snd_pcm_pause(handle, 1); - started = false; - return AudioFrameSamples; - } - - if ( error == -EPIPE ) { - std::cerr << "ALSA output \"" << parameters << "\": ready underrun." << std::endl; - snd_pcm_recover(handle, error, 1); - snd_pcm_pause(handle, 1); - started = false; - - return AudioFrameSamples; + const unsigned int MaximumDelayFrames = 8; + + for ( unsigned int loop = 0; loop < 10; loop++ ) { + snd_pcm_sframes_t available = 0; + snd_pcm_sframes_t delay = 0; + + const int error = snd_pcm_avail_delay(handle, &available, &delay); + + // If we've not started, allow the first write to be large, but + // not as large as the MaximumDelayFrames + the preload frame size. + if ( !started ) + return AudioFrameSamples * MaximumDelayFrames - 3; + + if ( error ) { + if ( error == -EPIPE ) { + std::cerr << "ALSA output \"" << parameters << "\": ready underrun." << std::endl; + snd_pcm_drop(handle); + started = false; + } + else + do_throw(error, "Get Frames Available for Write"); + } + else if ( delay > (AudioFrameSamples * MaximumDelayFrames) ) { + const double seconds = (double)delay / (double)SampleRate; + + std::cerr << "ALSA output \"" << parameters + << "\": overlong delay, dropped " + << seconds << " seconds of output." << std::endl; + snd_pcm_drop(handle); + started = false; + continue; + } + else + return available; } - - if ( error == 0 ) - return available; - else - do_throw(error, "Get Frames Available for Write"); + do_throw(0, "Audio output stuck in ready()"); + return 0; // NOTREACHED. } void AudioOutALSA::start() { snd_pcm_drop(handle); - snd_pcm_prepare(handle); - snd_pcm_pause(handle, 1); } void AudioOutALSA::stop() { snd_pcm_drop(handle); - snd_pcm_prepare(handle); - snd_pcm_pause(handle, 1); started = false; }