commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] [gnuradio] 01/09: audio: osx audio fixes


From: git
Subject: [Commit-gnuradio] [gnuradio] 01/09: audio: osx audio fixes
Date: Fri, 25 Apr 2014 16:44:34 +0000 (UTC)

This is an automated email from the git hooks/post-receive script.

trondeau pushed a commit to branch maint
in repository gnuradio.

commit 521e707297f9a5441cca559370a07b03a73b2abe
Author: Michael Dickens <address@hidden>
Date:   Thu Apr 24 09:51:04 2014 -0400

    audio: osx audio fixes
    
    - fix dequeue to return 3 when the requested number of items to dequeue is 
not the same as the actual number of items. fix comments to reflect this change 
as well as the actual input and output info for this variable.
    
    - fix comments. fix debug printouts to be consistent.
    
    - fix the AU callback to not throw, since it is not handled robustly by the 
OS routines that to the call.  Add NOTE to this effect.  Return better error 
codes when an issue arises.
    
    - correctly convert d_buffer_sample_count to int before using it.
    
    - when stopping: if waiting in ::work, signal the thread to wake up, in the 
hopes that it will correctly return and terminate.  After stopping the AU, 
abort and reset buffers as well as clear our local knowledge about the amount 
of data in the queues.
---
 gr-audio/lib/osx/circular_buffer.h |  15 ++-
 gr-audio/lib/osx/osx_sink.cc       | 218 +++++++++++++++++++++++++++----------
 2 files changed, 173 insertions(+), 60 deletions(-)

diff --git a/gr-audio/lib/osx/circular_buffer.h 
b/gr-audio/lib/osx/circular_buffer.h
index fee9eea..7a5cde0 100644
--- a/gr-audio/lib/osx/circular_buffer.h
+++ b/gr-audio/lib/osx/circular_buffer.h
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2006,2009,2010 Free Software Foundation, Inc.
+ * Copyright 2006,2009,2010,2014 Free Software Foundation, Inc.
  *
  * This file is part of GNU Radio.
  *
@@ -218,13 +218,17 @@ public:
  * inputs:
  *     buf: a pointer to the buffer into which to copy the data
  *
- *     bufLen_I: pointer to the number of items to remove in items
- *         (of the instantiated type)
+ *     bufLen_I: pointer to the requested number of items to remove
+ *
+ * outputs:
+ *     bufLen_I: pointer to the actual number of items removed
  *
  * returns:
  *     0: if nothing to do (0 length buffer)
  *     1: if success
  *     2: in the process of aborting, do doing nothing
+ *     3: if the number of requested items to remove is not the same
+ *        as the actual number of items removed.
  *
  * will throw runtime errors if inputs are improper:
  *     buffer pointer is NULL
@@ -297,11 +301,14 @@ public:
       d_readNdx_I = n_start_I;
     } else
       d_readNdx_I += n_now_I;
+    int rv = 1;
+    if (*bufLen_I != l_bufLen_I)
+      rv = 3;
     *bufLen_I = l_bufLen_I;
     d_n_avail_read_I -= l_bufLen_I;
     d_n_avail_write_I += l_bufLen_I;
     d_writeBlock->notify_one ();
-    return (1);
+    return (rv);
   };
 
   void abort () {
diff --git a/gr-audio/lib/osx/osx_sink.cc b/gr-audio/lib/osx/osx_sink.cc
index f027e2e..2e1d32e 100644
--- a/gr-audio/lib/osx/osx_sink.cc
+++ b/gr-audio/lib/osx/osx_sink.cc
@@ -216,14 +216,15 @@ namespace gr {
       }
 
       // set the interim buffer size; to work with the GR scheduler,
-      // must be at least 16kB.  Pick 50 kB since that's plenty yet
+      // must be at least 16kB.  Pick 50 kS since that's plenty yet
       // not very much.
 
       d_buffer_sample_count = (d_input_sample_rate < 50000.0 ?
                               50000 : (UInt32)d_input_sample_rate);
 
 #if _OSX_AU_DEBUG_
-      std::cerr << "sink(): max # samples = "
+      std::cerr << ((void*)(pthread_self()))
+               << " : audio_osx_sink: max # samples = "
                << d_buffer_sample_count << std::endl;
 #endif
 
@@ -420,7 +421,8 @@ namespace gr {
 
 
 #if _OSX_AU_DEBUG_
-      std::cerr << "audio_osx_sink Parameters:" << std::endl
+      std::cerr << ((void*)(pthread_self()))
+               << " : audio_osx_sink Parameters:" << std::endl
                << "  Sample Rate is " << d_input_sample_rate << std::endl
                << "  Max # samples to store per channel is "
                << d_buffer_sample_count << std::endl;
@@ -429,6 +431,12 @@ namespace gr {
 
     void osx_sink::teardown()
     {
+#if _OSX_AU_DEBUG_
+      std::cerr << ((void*)(pthread_self()))
+               << " : audio_osx_sink::teardown: starting"
+               << std::endl;
+#endif
+
       OSStatus err = noErr;
 
       // stop the AudioUnit
@@ -491,6 +499,12 @@ namespace gr {
       d_using_default_device = false;
       d_output_au = 0;
       d_output_ad_id = 0;
+
+#if _OSX_AU_DEBUG_
+      std::cerr << ((void*)(pthread_self()))
+               << " : audio_osx_sink::teardown: finished"
+               << std::endl;
+#endif
     }
 
     bool
@@ -547,7 +561,9 @@ namespace gr {
       d_n_user_channels = ninputs;
 
 #if _OSX_AU_DEBUG_
-      std::cerr << "chk_topo: Actual # user input channels = "
+      std::cerr << ((void*)(pthread_self()))
+               << " : audio_osx_sink::check_topology: "
+               << "Actual # user input channels = "
                 << d_n_user_channels << std::endl;
 #endif
 
@@ -643,6 +659,12 @@ namespace gr {
     {
       if(!is_running() && d_output_au) {
 
+#if _OSX_AU_DEBUG_
+       std::cerr << ((void*)(pthread_self()))
+               << " : audio_osx_sink::start: starting Output AudioUnit."
+                 << std::endl;
+#endif
+
        // check channels, (re)allocate and reset buffers if/as necessary
 
        check_channels(true);
@@ -655,6 +677,14 @@ namespace gr {
           "audio_osx_sink::start");
       }
 
+#if _OSX_AU_DEBUG_
+      else {
+       std::cerr << ((void*)(pthread_self()))
+                 << " : audio_osx_sink::start: "
+                 << "already running." << std::endl;
+      }
+#endif
+
       return (true);
     }
 
@@ -663,6 +693,23 @@ namespace gr {
     {
       if(is_running()) {
 
+#if _OSX_AU_DEBUG_
+       std::cerr << ((void*)(pthread_self()))
+                 << " : audio_osx_sink::stop: "
+                 << "stopping Output AudioUnit."
+                 << std::endl;
+#endif
+
+       // if waiting in ::work, signal to wake up
+       if (d_waiting_for_data) {
+#if _OSX_AU_DEBUG_
+         std::cerr << ((void*)(pthread_self()))
+                   << " : audio_osx_sink::stop: "
+                   << "signaling waiting condition" << std::endl;
+#endif
+         d_cond_data.notify_one();
+       }
+
        // stop the audio unit (should never fail)
 
         OSStatus err = AudioOutputUnitStop(d_output_au);
@@ -670,12 +717,25 @@ namespace gr {
          (err, "AudioOutputUnitStop",
           "audio_osx_sink::stop");
 
-       // abort all buffers
+       // abort and reset all buffers
 
         for(UInt32 nn = 0; nn < d_n_user_channels; ++nn) {
           d_buffers[nn]->abort();
+          d_buffers[nn]->reset();
         }
+
+       // reset local knowledge of amount of data in queues
+
+       d_queue_sample_count = 0;
+
+      }
+#if _OSX_AU_DEBUG_
+      else {
+       std::cerr << ((void*)(pthread_self()))
+                 << " : audio_osx_sink::stop: "
+                 << "already stopped." << std::endl;
       }
+#endif
 
       return(true);
     }
@@ -686,8 +746,14 @@ namespace gr {
                    gr_vector_void_star &output_items)
     {
 #if _OSX_AU_DEBUG_RENDER_
-      std::cerr << ((void*)(pthread_self()))
-               << " : audio_osx_sink::work: Starting." << std::endl;
+      {
+       gr::thread::scoped_lock l(d_internal);
+       std::cerr << ((void*)(pthread_self()))
+                 << " : audio_osx_sink::work: "
+                 << "Starting: #OI = "
+                 << noutput_items << ", reset = "
+                 << (d_do_reset ? "true" : "false") << std::endl;
+      }
 #endif
       if (d_do_reset) {
        if (d_hardware_changed) {
@@ -719,8 +785,12 @@ namespace gr {
        else {
 
 #if _OSX_AU_DEBUG_RENDER_
-         std::cerr << "audio_osx_sink::work: doing reset."
-                   << std::endl;
+         {
+           gr::thread::scoped_lock l(d_internal);
+           std::cerr << ((void*)(pthread_self()))
+                     << " : audio_osx_sink::work: "
+                     << "doing reset." << std::endl;
+         }
 #endif
 
          GR_LOG_WARN(d_logger, boost::format
@@ -736,16 +806,13 @@ namespace gr {
 
          gr::thread::scoped_lock l(d_internal);
 
-#if _OSX_AU_DEBUG_RENDER_
-         std::cerr << "audio_osx_sink::work: mutex locked."
-                   << std::endl;
-#endif
-
          setup();
          start();
 
 #if _OSX_AU_DEBUG_RENDER_
-         std::cerr << "audio_osx_sink: returning after reset."
+         std::cerr << ((void*)(pthread_self()))
+                   << " : audio_osx_sink: "
+                   << "returning 0 after reset."
                    << std::endl;
 #endif
          return(0);
@@ -755,14 +822,16 @@ namespace gr {
       gr::thread::scoped_lock l(d_internal);
 
       // take the input data, copy it, and push it to the bottom of
-      // the queue mono input are pushed onto queue[0]; stereo input
-      // are pushed onto queue[1].  If the number of user/graph
+      // the queue.  mono input is pushed onto queue[0]; stereo input
+      // is pushed onto queue[1].  If the number of user/graph
       // channels is less than the number of device channels, copy the
       // data from the last / highest number channel to remaining
       // device channels.
 
+      // find the maximum amount of buffer space available right now
+
       UInt32 l_max_count;
-      int diff_count = d_buffer_sample_count - noutput_items;
+      int diff_count = ((int)d_buffer_sample_count) - noutput_items;
       if(diff_count < 0) {
         l_max_count = 0;
       }
@@ -770,35 +839,39 @@ namespace gr {
         l_max_count = (UInt32)diff_count;
       }
 
-#if 0
-      if(l_max_count < d_queueItemLength->back()) {
-        // allow 2 buffers at a time, regardless of length
-        l_max_count = d_queueItemLength->back();
-      }
-#endif
-
 #if _OSX_AU_DEBUG_RENDER_
-      std::cerr << "work1: qSC = " << d_queue_sample_count
+      std::cerr << ((void*)(pthread_self()))
+               << " : audio_osx_sink::work: "
+               << "qSC = " << d_queue_sample_count
                 << ", lMC = "<< l_max_count
-                << ", dmSC = " << d_buffer_sample_count
-                << ", nOI = " << noutput_items << std::endl;
+                << ", dBSC = " << d_buffer_sample_count
+                << ", #OI = " << noutput_items << std::endl;
 #endif
 
       if(d_queue_sample_count > l_max_count) {
-        // data coming in too fast; ok_to_block decides what to do
+
+        // data coming in too fast; ok_to_block decides what to do: if
+        // ok to block, then wait until the render callback makes
+        // enough space.  If not blocking, detect overflow via writing
+        // data to the circular buffer.
+
         if(d_ok_to_block == true) {
           // block until there is data to return, or on reset
           while(d_queue_sample_count > l_max_count) {
            // release control so-as to allow data to be retrieved;
            // block until there is data to return
 #if _OSX_AU_DEBUG_RENDER_
-           std::cerr << "audio_osx_sink::work: waiting." << std::endl;
+           std::cerr << ((void*)(pthread_self()))
+                     << " : audio_osx_sink::work: "
+                     << "waiting." << std::endl;
 #endif
            d_waiting_for_data = true;
            d_cond_data.wait(l);
            d_waiting_for_data = false;
 #if _OSX_AU_DEBUG_RENDER_
-           std::cerr << "audio_osx_sink::work: done waiting." << std::endl;
+           std::cerr << ((void*)(pthread_self()))
+                     << " : audio_osx_sink::work: "
+                     << "done waiting." << std::endl;
 #endif
            // the condition's 'notify' was called; acquire control to
            // keep thread safe
@@ -807,8 +880,9 @@ namespace gr {
            // up the next time this method is called.
            if (d_do_reset) {
 #if _OSX_AU_DEBUG_RENDER_
-             std::cerr << "audio_osx_sink::work: "
-               "returning for reset." << std::endl;
+             std::cerr << ((void*)(pthread_self()))
+                       << " : audio_osx_sink::work: "
+                       << "returning 0 for reset." << std::endl;
 #endif
              return(0);
            }
@@ -816,7 +890,8 @@ namespace gr {
        }
       }
 
-      // not blocking case and overflow is handled by the circular buffer
+      // not blocking and overflow is handled by the circular buffer,
+      // or enough data space is available
 
       // add the input frames to the buffers' queue, checking for overflow
 
@@ -839,23 +914,26 @@ namespace gr {
        }
       }
 
+      // did overflow occur?
+
       if(res == -1) {
-        // data coming in too fast
-        // drop oldest buffer
+        // yes: data coming in too fast; drop oldest data.
         fputs("aO", stderr);
         fflush(stderr);
         // set the local number of samples available to the max
         d_queue_sample_count = d_buffers[0]->buffer_length_items();
       }
       else {
-        // keep up the local sample count
+        // no: keep up the local sample count
         d_queue_sample_count += noutput_items;
       }
 
 #if _OSX_AU_DEBUG_RENDER_
-      std::cerr << "work2: #OI = "
-                << noutput_items << ", #Cnt = "
-                << d_queue_sample_count << ", mSC = "
+      std::cerr << ((void*)(pthread_self()))
+               << " : audio_osx_sink::work: "
+               << "returning: #OI = "
+                << noutput_items << ", qSC = "
+                << d_queue_sample_count << ", bSS = "
                 << d_buffer_sample_count << std::endl;
 #endif
 
@@ -871,50 +949,78 @@ namespace gr {
      UInt32 in_number_frames,
      AudioBufferList* io_data)
     {
+      // NOTE: This is a callback from the OS, so throwing here does
+      // not work; return an error instead when something does not go
+      // as planned.
+
       osx_sink* This = reinterpret_cast<osx_sink*>(in_ref_con);
       OSStatus err = noErr;
 
       gr::thread::scoped_lock l(This->d_internal);
 
 #if _OSX_AU_DEBUG_RENDER_
-      std::cerr << "cb_in: SC = " << This->d_queue_sample_count
-                << ", in#F = " << in_number_frames << std::endl;
+      std::cerr << ((void*)(pthread_self()))
+               << " : audio_osx_sink::au_output_callback: "
+               << "starting: qSC = "
+               << This->d_queue_sample_count
+                << ", in#F = " << in_number_frames
+               << ", in#C = " << This->d_n_user_channels << std::endl;
 #endif
 
       if(This->d_queue_sample_count < in_number_frames) {
-        // not enough data to fill request
-        err = -1;
+
+        // not enough data to fill request; probably happened on
+        // start-up, where this callback was called before ::work was.
+
+        fputs("aU", stderr);
+        fflush(stderr);
+        err = kAudioUnitErr_Initialized;
+
       }
       else {
         // enough data; remove data from our buffers into the AU's buffers
         int nn = This->d_n_user_channels;
-
         while(--nn >= 0) {
+
           size_t t_n_output_items = in_number_frames;
           float* out_buffer = (float*)(io_data->mBuffers[nn].mData);
-          This->d_buffers[nn]->dequeue(out_buffer, &t_n_output_items);
-          if(t_n_output_items != in_number_frames) {
-            throw std::runtime_error
-             ("audio_osx_sink::au_output_callback: "
-              "number of available items changing "
-              "unexpectedly (should never happen).");
+          int rv = This->d_buffers[nn]->dequeue
+            (out_buffer, &t_n_output_items);
+
+          if((rv != 1) || (t_n_output_items != in_number_frames)) {
+
+            std::cerr << "audio_osx_sink::au_output_callback: "
+                      << "number of available items changing "
+                      << "unexpectedly (should never happen): was "
+                      << in_number_frames << " now "
+                      << t_n_output_items<< std::endl;
+           err = kAudioUnitErr_TooManyFramesToProcess;
+
           }
         }
 
         This->d_queue_sample_count -= in_number_frames;
       }
 
-#if _OSX_AU_DEBUG_RENDER_
-      std::cerr << "cb_out: SC = "
-                << This->d_queue_sample_count << std::endl;
-#endif
-
       // signal that data is available, if appropraite
 
       if (This->d_waiting_for_data) {
+#if _OSX_AU_DEBUG_RENDER_
+       std::cerr << ((void*)(pthread_self()))
+                 << " : audio_osx_sink::au_output_callback: "
+                 << "signaling waiting condition" << std::endl;
+#endif
        This->d_cond_data.notify_one();
       }
 
+#if _OSX_AU_DEBUG_RENDER_
+      std::cerr << ((void*)(pthread_self()))
+               << " : audio_osx_sink::au_output_callback: "
+               << "returning: qSC = "
+                << This->d_queue_sample_count
+               << ", err = " << err << std::endl;
+#endif
+
       return (err);
     }
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]