A new patch for fixing the alsa restart issue. Submitted by Volker Schroer.
[debian/gnuradio] / gr-audio-alsa / src / audio_alsa_sink.cc
index 9b509e45b755a86bb5077898e68309a4609d0b37..d44a93b3f37a44ccfb3635eeadf3419f6a8b9892 100644 (file)
@@ -1,12 +1,12 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2004 Free Software Foundation, Inc.
+ * Copyright 2004,2010 Free Software Foundation, Inc.
  * 
  * This file is part of GNU Radio
  * 
  * GNU Radio is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
+ * the Free Software Foundation; either version 3, or (at your option)
  * any later version.
  * 
  * GNU Radio is distributed in the hope that it will be useful,
@@ -70,7 +70,7 @@ audio_alsa_make_sink (int sampling_rate,
                      const std::string dev,
                      bool ok_to_block)
 {
-  return audio_alsa_sink_sptr (new audio_alsa_sink (sampling_rate, dev,
+  return gnuradio::get_initial_sptr(new audio_alsa_sink (sampling_rate, dev,
                                                    ok_to_block));
 }
 
@@ -90,7 +90,7 @@ audio_alsa_sink::audio_alsa_sink (int sampling_rate,
     d_period_size (0),
     d_buffer_size_bytes (0), d_buffer (0),
     d_worker (0), d_special_case_mono_to_stereo (false),
-    d_nunderuns (0), d_nsuspends (0)
+    d_nunderuns (0), d_nsuspends (0), d_ok_to_block(ok_to_block)
 {
   CHATTY_DEBUG = gr_prefs::singleton()->get_bool("audio_alsa", "verbose", false);
 
@@ -100,6 +100,8 @@ audio_alsa_sink::audio_alsa_sink (int sampling_rate,
   // open the device for playback
   error = snd_pcm_open(&d_pcm_handle, d_device_name.c_str (),
                       SND_PCM_STREAM_PLAYBACK, 0);
+  if (ok_to_block == false)
+    snd_pcm_nonblock(d_pcm_handle, !ok_to_block);
   if (error < 0){
     fprintf (stderr, "audio_alsa_sink[%s]: %s\n",
             d_device_name.c_str(), snd_strerror(error));
@@ -138,7 +140,8 @@ audio_alsa_sink::audio_alsa_sink (int sampling_rate,
   // Specify the access methods we implement
   // For now, we only handle RW_INTERLEAVED...
   snd_pcm_access_mask_t *access_mask;
-  snd_pcm_access_mask_alloca (&access_mask);
+  snd_pcm_access_mask_t **access_mask_ptr = &access_mask; // FIXME: workaround for compiler warning
+  snd_pcm_access_mask_alloca (access_mask_ptr);
   snd_pcm_access_mask_none (access_mask);
   snd_pcm_access_mask_set (access_mask, SND_PCM_ACCESS_RW_INTERLEAVED);
   // snd_pcm_access_mask_set (access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED);
@@ -218,9 +221,15 @@ audio_alsa_sink::check_topology (int ninputs, int noutputs)
   int nchan = ninputs;
   int err;
 
-  // FIXME check_topology may be called more than once.
+  // Check the state of the stream
   // Ensure that the pcm is in a state where we can still mess with the hw_params
-
+  snd_pcm_state_t state;
+  state=snd_pcm_state(d_pcm_handle);
+  if ( state== SND_PCM_STATE_RUNNING)
+    return true;  // If stream is running, don't change any parameters
+  else if(state == SND_PCM_STATE_XRUN )
+    snd_pcm_prepare ( d_pcm_handle ); // Prepare stream on underrun, and we can set parameters;
+  
   bool special_case = nchan == 1 && d_special_case_mono_to_stereo;
   if (special_case)
     nchan = 2;
@@ -286,7 +295,6 @@ audio_alsa_sink::check_topology (int ninputs, int noutputs)
   default:
     assert (0);
   }
-
   return true;
 }
 
@@ -488,7 +496,12 @@ audio_alsa_sink::write_buffer (const void *vbuffer,
   while (nframes > 0){
     int r = snd_pcm_writei (d_pcm_handle, buffer, nframes);
     if (r == -EAGAIN)
-      continue;                        // try again
+    {
+      if (d_ok_to_block == true)
+       continue;               // try again
+      
+      break;
+    }
 
     else if (r == -EPIPE){     // underrun
       d_nunderuns++;