Merge branch 'upstream' into dfsg-orig
[debian/gnuradio] / gr-audio-portaudio / src / audio_portaudio_sink.cc
index cfdc6302af4fdbd6e6e8eba8e06d18787894d21f..65a38f9119011f4dc96bd66bc1a6a71e7bb08023 100644 (file)
 #include <unistd.h>
 #include <stdexcept>
 #include <gri_portaudio.h>
-#include <gnuradio/omnithread.h>
 #include <string.h>
 
-#define        LOGGING   0             // define to 0 or 1
+//#define      LOGGING   0             // define to 0 or 1
 
 #define SAMPLE_FORMAT          paFloat32
 typedef float sample_t;
@@ -84,31 +83,33 @@ portaudio_sink_callback (const void *inputBuffer,
 
   int navail_samples = self->d_reader->items_available();
   
-  if (nreqd_samples <= navail_samples){  // We've got enough data...
-    if (LOGGING)
-      self->d_log->printf("PAsink cb: f/b = %4ld\n", framesPerBuffer);
-    // copy from ringbuffer into output buffer
-    memcpy(outputBuffer,
-          self->d_reader->read_pointer(),
-          nreqd_samples * sizeof(sample_t));
-    self->d_reader->update_read_pointer(nreqd_samples);
-        
+  if (nreqd_samples <= navail_samples) {  // We've got enough data...
+    {
+      gruel::scoped_lock guard(self->d_ringbuffer_mutex);
+
+      memcpy(outputBuffer,
+            self->d_reader->read_pointer(),
+            nreqd_samples * sizeof(sample_t));
+      self->d_reader->update_read_pointer(nreqd_samples);
+
+      self->d_ringbuffer_ready = true;
+    }
+
     // Tell the sink thread there is new room in the ringbuffer.
-    self->d_ringbuffer_ready.post();
+    self->d_ringbuffer_cond.notify_one();
     return paContinue;
   }
 
   else {                       // underrun
-    if (LOGGING)
-      self->d_log->printf("PAsink cb: f/b = %4ld UNDERRUN\n", framesPerBuffer);
-
     self->d_nunderuns++;
     ::write(2, "aU", 2);       // FIXME change to non-blocking call
 
     // FIXME we should transfer what we've got and pad the rest
     memset(outputBuffer, 0, nreqd_samples * sizeof(sample_t));
 
-    self->d_ringbuffer_ready.post();  // Tell the sink to get going!
+    self->d_ringbuffer_ready = true;
+    self->d_ringbuffer_cond.notify_one();  // Tell the sink to get going!
+
     return paContinue;
   }
 }
@@ -135,12 +136,14 @@ audio_portaudio_sink::audio_portaudio_sink(int sampling_rate,
     d_verbose(gr_prefs::singleton()->get_bool("audio_portaudio", "verbose", false)),
     d_portaudio_buffer_size_frames(0),
     d_stream(0),
-    d_ringbuffer_ready(1, 1),          // binary semaphore
+    d_ringbuffer_mutex(),
+    d_ringbuffer_cond(),
+    d_ringbuffer_ready(false),
     d_nunderuns(0)
 {
   memset(&d_output_parameters, 0, sizeof(d_output_parameters));
-  if (LOGGING)
-    d_log = gri_logger::singleton();
+  //if (LOGGING)
+  //  d_log = gri_logger::singleton();
 
   PaError            err;
   int                i, numDevices;
@@ -297,12 +300,17 @@ audio_portaudio_sink::work (int noutput_items,
   const unsigned nchan = d_output_parameters.channelCount; // # of channels == samples/frame
 
   int k;
-  for (k = 0; k < noutput_items; ){
 
+  for (k = 0; k < noutput_items; ){
     int nframes = d_writer->space_available() / nchan; // How much space in ringbuffer
     if (nframes == 0){                 // no room...
       if (d_ok_to_block){
-       d_ringbuffer_ready.wait();      // block here, then try again
+       {
+         gruel::scoped_lock guard(d_ringbuffer_mutex);
+         while (!d_ringbuffer_ready)
+           d_ringbuffer_cond.wait(guard);
+       }
+
        continue;
       }
       else {
@@ -316,16 +324,21 @@ audio_portaudio_sink::work (int noutput_items,
     }
 
     // We can write the smaller of the request and the room we've got
-    int nf = std::min(noutput_items - k, nframes);
-
-    float *p = (float *) d_writer->write_pointer();
-    for (int i = 0; i < nf; i++){
-      for (unsigned int c = 0; c < nchan; c++){
-       *p++ = in[c][k + i];
-      }
+    {
+      gruel::scoped_lock guard(d_ringbuffer_mutex);
+
+      int nf = std::min(noutput_items - k, nframes);
+      float *p = (float *) d_writer->write_pointer();
+      
+      for (int i = 0; i < nf; i++)
+       for (unsigned int c = 0; c < nchan; c++)
+         *p++ = in[c][k + i];
+      
+      d_writer->update_write_pointer(nf * nchan);
+      k += nf;
+
+      d_ringbuffer_ready = false;
     }
-    d_writer->update_write_pointer(nf * nchan);
-    k += nf;
   }
 
   return k;  // tell how many we actually did