Adding a "change in progress" check to alsa sink.
[debian/gnuradio] / gr-audio-alsa / src / audio_alsa_sink.cc
index d6b7f84cfb8745723179874e4fc2b25b394cdfc2..84bf49151af4d8f1a9ceb3ded9c6b64c8d544e35 100644 (file)
@@ -90,7 +90,8 @@ 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),
+    d_change_in_progress(false)
 {
   CHATTY_DEBUG = gr_prefs::singleton()->get_bool("audio_alsa", "verbose", false);
 
@@ -100,6 +101,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));
@@ -222,6 +225,11 @@ audio_alsa_sink::check_topology (int ninputs, int noutputs)
   // FIXME check_topology may be called more than once.
   // Ensure that the pcm is in a state where we can still mess with the hw_params
 
+  d_change_in_progress = true;
+  
+  if (snd_pcm_state (d_pcm_handle) == SND_PCM_STATE_RUNNING)
+    snd_pcm_drop (d_pcm_handle);
+  
   bool special_case = nchan == 1 && d_special_case_mono_to_stereo;
   if (special_case)
     nchan = 2;
@@ -230,6 +238,7 @@ audio_alsa_sink::check_topology (int ninputs, int noutputs)
 
   if (err < 0){
     output_error_msg ("set_channels failed", err);
+    d_change_in_progress = false;
     return false;
   }
 
@@ -237,6 +246,7 @@ audio_alsa_sink::check_topology (int ninputs, int noutputs)
   err = snd_pcm_hw_params(d_pcm_handle, d_hw_params);
   if (err < 0){
     output_error_msg ("snd_pcm_hw_params failed", err);
+    d_change_in_progress = false;
     return false;
   }
 
@@ -287,7 +297,7 @@ audio_alsa_sink::check_topology (int ninputs, int noutputs)
   default:
     assert (0);
   }
-
+  d_change_in_progress = false;
   return true;
 }
 
@@ -486,10 +496,22 @@ audio_alsa_sink::write_buffer (const void *vbuffer,
 {
   const unsigned char *buffer = (const unsigned char *) vbuffer;
 
+  int change_counter = 10;
+  while (d_change_in_progress == true && change_counter >= 0) {
+    change_counter--;
+    usleep(10000);
+  }
+  d_change_in_progress = false;
+       
   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++;