Better handling of write underruns.
authorbruceperens <bruceperens@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 25 Apr 2014 21:24:04 +0000 (21:24 +0000)
committerbruceperens <bruceperens@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 25 Apr 2014 21:24:04 +0000 (21:24 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@1567 01035d8c-6547-0410-b346-abe4f91aad63

freedv-server/source/platform/linux/audio_in_alsa.cpp
freedv-server/source/platform/linux/audio_out_alsa.cpp

index 6d95544a12b80406271778aa63a3b13b6ebf5784..0bd9174d13440cd55ede21a1bea061d82d3fd27a 100644 (file)
@@ -117,10 +117,10 @@ namespace FreeDV {
     int result = snd_pcm_readi(handle, array, length);
     started = true;
     if ( result == -EPIPE ) {
-      snd_pcm_recover(handle, result, 1);
+      snd_pcm_drop(handle);
       snd_pcm_start(handle);
       std::cerr << "ALSA input \"" << parameters << "\": read underrun." << std::endl;
-      return 0;
+      return length;
     }
     if ( result >= 0 ) {
       return result;
@@ -187,7 +187,7 @@ namespace FreeDV {
     }
 
     if ( error == -EPIPE ) {
-      snd_pcm_recover(handle, error, 1);
+      snd_pcm_drop(handle);
       snd_pcm_start(handle);
       std::cerr << "ALSA input \"" << parameters << "\": ready underrun." << std::endl;
       return 0;
@@ -212,8 +212,6 @@ namespace FreeDV {
   AudioInALSA::stop()
   {
     snd_pcm_drop(handle);
-    snd_pcm_prepare(handle);
-    snd_pcm_pause(handle, 1);
     started = false;
   }
 
index b00d59e1d9615ac5d8d680e1e1751ca8148106af..a89e7ce146df5994e80326c91fc505e8a914454b 100644 (file)
@@ -130,6 +130,8 @@ namespace FreeDV {
   std::size_t
   AudioOutALSA::write16(const std::int16_t * array, std::size_t length)
   {
+    int16_t    buf[AudioFrameSamples * FillFrames];
+
     if ( !started ) {
       // Preload the audio output queue with some silence.
       // This makes underruns less likely.
@@ -143,7 +145,6 @@ namespace FreeDV {
       // to avoid this problem.
       //
       snd_pcm_prepare(handle);
-      int16_t  buf[AudioFrameSamples * FillFrames];
       memset(buf, 0, sizeof(buf));
       snd_pcm_writei(handle, buf, sizeof(buf) / sizeof(*buf));
     }
@@ -152,12 +153,27 @@ namespace FreeDV {
     started = true;
     if ( error == -EPIPE ) {
       std::cerr << "ALSA output \"" << parameters << "\": write underrun." << std::endl;
-      snd_pcm_recover(handle, error, 1);
+      snd_pcm_drop(handle);
+      snd_pcm_prepare(handle);
+      memset(buf, 0, sizeof(buf));
+      snd_pcm_writei(handle, buf, sizeof(buf) / sizeof(*buf));
       error = snd_pcm_writei(handle, array, length);
     }
 
     if ( error >= 0 )
       return error;
+    else if ( error == -EPIPE ) {
+      // This is an unlikely condition, but should not be allowed to abort
+      // the program.
+      // About the only reason this might happen would be a failure of
+      // real-time schduling, for example a system management interrupt
+      // outside of the control of the operating system, or a problem with
+      // the sound hardware or driver. Punt and hope it gets better the next
+      // time.
+      std::cerr << "ALSA output \"" << parameters
+       << "\": double write underrun." << std::endl;
+      return 0;
+    }
     else
       do_throw(error, "Write");
   }