From 6e0895cb3cbc355060eab037ef74b8e237dcf133 Mon Sep 17 00:00:00 2001
From: Michael Dickens <mlk@alum.mit.edu>
Date: Fri, 7 Mar 2014 11:10:07 -0500
Subject: fix gr-audio osx: + use GNU Radio preferences file to set default
 input and output audio device, if provided; + use gr::logger for all
 non-debug messages; + case-insensitive string find with desired audio device
 name; + fixes buffer allocation bug with low sample rates; + allows using a
 specific (named) audio device, or the default; + handles the case when the
 selected audio device becomes unavailable (e.g., a USB stick is removed while
 in use); + if no audio device name is provided, uses the default audio device
 as found in System Preferences::Sound; + handles the case when the default
 audio device is in use, and the user changes that audio device in System
 Preferences::Sound, by internally resetting to use the newly selected audio
 device; + all non-Apple names are now lower_case, not CamelCase; + move
 osx_impl functions to gr::audio::osx, and use them correctly; + install
 osx_impl.h to expose gr::audio::osx functions, but iff OSX audio is enabled.

---
 gr-audio/lib/osx/osx_source.cc | 1881 +++++++++++++++++++++++++---------------
 1 file changed, 1163 insertions(+), 718 deletions(-)

(limited to 'gr-audio/lib/osx/osx_source.cc')

diff --git a/gr-audio/lib/osx/osx_source.cc b/gr-audio/lib/osx/osx_source.cc
index 3e2dcef4fe..93d857e4be 100644
--- a/gr-audio/lib/osx/osx_source.cc
+++ b/gr-audio/lib/osx/osx_source.cc
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2006-2011,2013 Free Software Foundation, Inc.
+ * Copyright 2006-2011,2013-2014 Free Software Foundation, Inc.
  *
  * This file is part of GNU Radio.
  *
@@ -25,370 +25,484 @@
 #endif
 
 #include "audio_registry.h"
-#include <osx_source.h>
-#include <osx_impl.h>
+#include "osx_source.h"
+
 #include <gnuradio/io_signature.h>
+#include <gnuradio/prefs.h>
 #include <stdexcept>
 
 namespace gr {
   namespace audio {
 
-#define _OSX_AU_DEBUG_ 0
-#define _OSX_DO_LISTENERS_ 0
-
-    AUDIO_REGISTER_SOURCE(REG_PRIO_HIGH, osx)(int sampling_rate,
-                                              const std::string &device_name,
-                                              bool ok_to_block)
+    AUDIO_REGISTER_SOURCE(REG_PRIO_HIGH, osx)
+      (int sampling_rate,
+       const std::string& device_name,
+       bool ok_to_block)
     {
       return source::sptr
         (new osx_source(sampling_rate, device_name, ok_to_block));
     }
 
-    void
-    PrintStreamDesc(AudioStreamBasicDescription *inDesc)
+    static std::string
+    default_device_name()
     {
-      if(inDesc == NULL) {
-        std::cerr << "PrintStreamDesc: Can't print a NULL desc!" << std::endl;
-        return;
-      }
-
-      std::cerr << "  Sample Rate        : " << inDesc->mSampleRate << std::endl;
-      char format_id[4];
-      strncpy(format_id, (char*)(&inDesc->mFormatID), 4);
-      std::cerr << "  Format ID          : " << format_id << std::endl;
-      std::cerr << "  Format Flags       : " << inDesc->mFormatFlags << std::endl;
-      std::cerr << "  Bytes per Packet   : " << inDesc->mBytesPerPacket << std::endl;
-      std::cerr << "  Frames per Packet  : " << inDesc->mFramesPerPacket << std::endl;
-      std::cerr << "  Bytes per Frame    : " << inDesc->mBytesPerFrame << std::endl;
-      std::cerr << "  Channels per Frame : " << inDesc->mChannelsPerFrame << std::endl;
-      std::cerr << "  Bits per Channel   : " << inDesc->mBitsPerChannel << std::endl;
+      return prefs::singleton()->get_string
+        ("audio_osx", "default_input_device", "built-in");
     }
 
-    // FIXME these should query some kind of user preference
-
-    osx_source::osx_source(int sample_rate,
-                           const std::string device_name,
-                           bool do_block,
-                           int channel_config,
-                           int max_sample_count)
+    osx_source::osx_source
+    (int sample_rate,
+     const std::string& device_name,
+     bool ok_to_block)
       : sync_block("audio_osx_source",
-                      io_signature::make(0, 0, 0),
-                      io_signature::make(0, 0, 0)),
-        d_deviceSampleRate(0.0), d_outputSampleRate(0.0),
-	d_channel_config(0),
-	d_inputBufferSizeFrames(0), d_inputBufferSizeBytes(0),
-	d_outputBufferSizeFrames(0), d_outputBufferSizeBytes(0),
-	d_deviceBufferSizeFrames(0), d_deviceBufferSizeBytes(0),
-	d_leadSizeFrames(0), d_leadSizeBytes(0),
-	d_trailSizeFrames(0), d_trailSizeBytes(0),
-	d_extraBufferSizeFrames(0), d_extraBufferSizeBytes(0),
-	d_queueSampleCount(0), d_max_sample_count(0),
-	d_n_AvailableInputFrames(0), d_n_ActualInputFrames(0),
-	d_n_user_channels(0), d_n_max_channels(0), d_n_deviceChannels(0),
-	d_do_block(do_block), d_passThrough(false),
-	d_internal(0), d_cond_data(0),
-	d_buffers(0),
-	d_InputAU(0), d_InputBuffer(0), d_OutputBuffer(0),
-	d_AudioConverter(0)
+		   io_signature::make(0, 0, 0),
+		   io_signature::make(0, 0, 0)),
+        d_device_sample_rate(0.0), d_output_sample_rate(0.0),
+	d_input_buffer_size_frames(0), d_input_buffer_size_bytes(0),
+	d_output_buffer_size_frames(0), d_output_buffer_size_bytes(0),
+	d_device_buffer_size_frames(0), d_device_buffer_size_bytes(0),
+	d_lead_size_frames(0), d_lead_size_bytes(0),
+	d_trail_size_frames(0), d_trail_size_bytes(0),
+	d_extra_buffer_size_frames(0), d_extra_buffer_size_bytes(0),
+	d_queue_sample_count(0), d_buffer_sample_count(0),
+	d_n_available_input_frames(0), d_n_actual_input_frames(0),
+	d_n_user_channels(0), d_n_dev_channels(0),
+	d_ok_to_block(ok_to_block), d_pass_through(false),
+	d_waiting_for_data(false), d_do_reset(false),
+	d_hardware_changed(false), d_using_default_device(false),
+	d_desired_name(device_name.empty() ? default_device_name()
+		       : device_name),
+	d_input_ad_id(0), d_input_au(0), d_input_buffer(0),
+	d_output_buffer(0), d_audio_converter(0)
     {
+      // set the desired output sample rate
+
       if(sample_rate <= 0) {
-        std::cerr << "Invalid Sample Rate: " << sample_rate << std::endl;
-        throw std::invalid_argument("audio_osx_source::audio_osx_source");
+	GR_LOG_ERROR(d_logger, boost::format
+		     ("Invalid Sample Rate: %d")
+		     % sample_rate);
+        throw std::invalid_argument("audio_osx_source");
       }
-      else
-        d_outputSampleRate = (Float64)sample_rate;
+      else {
+        d_output_sample_rate = (Float64)sample_rate;
+      }
+
+      // set up for audio input using the stored desired parameters
+
+      setup();
+    }
+
+    void osx_source::setup()
+    {
+      OSStatus err = noErr;
+
+      // set the default input audio device id to "unknown"
+
+      d_input_ad_id = kAudioDeviceUnknown;
+
+      // try to find the input audio device, if specified
+
+      std::vector < AudioDeviceID > all_ad_ids;
+      std::vector < std::string > all_names;
 
-      if(channel_config <= 0 & channel_config != -1) {
-        std::cerr << "Invalid Channel Config: " << channel_config << std::endl;
-        throw std::invalid_argument("audio_osx_source::audio_osx_source");
+      osx::find_audio_devices
+	(d_desired_name, true,
+	 &all_ad_ids, &all_names);
+
+      // check number of device(s) returned
+
+      if (d_desired_name.length() != 0) {
+	if (all_ad_ids.size() == 1) {
+
+	  // exactly 1 match was found; see if it was partial
+
+	  if (all_names[0].compare(d_desired_name) != 0) {
+
+	    // yes: log the full device name
+	    GR_LOG_INFO(d_logger, boost::format
+			("Using input audio device '%s'.")
+			% all_names[0]);
+
+	  }
+
+	  // store info on this device
+
+	  d_input_ad_id = all_ad_ids[0];
+	  d_selected_name = all_names[0];
+
+	} else {
+
+	  // either 0 or more than 1 device was found; get all input
+	  // device names, print those, and error out.
+
+	  osx::find_audio_devices("", true, NULL, &all_names);
+
+	  std::string err_str("\n\nA unique input audio device name "
+			      "matching the string '");
+	  err_str += d_desired_name;
+	  err_str += "' was not found.\n\n";
+	  err_str += "The current known input audio device name";
+	  err_str += ((all_names.size() > 1) ? "s are" : " is");
+	  err_str += ":\n";
+	  for (UInt32 nn = 0; nn < all_names.size(); ++nn) {
+	    err_str += "    " + all_names[nn] + "\n";
+	  }
+	  GR_LOG_ERROR(d_logger, boost::format(err_str));
+	  throw std::runtime_error("audio_osx_source::setup");
+
+	}
       }
-      else if (channel_config == -1) {
-        // no user input; try "device name" instead
-        int l_n_channels = (int)strtol(device_name.data(), (char **)NULL, 10);
-        if((l_n_channels == 0) & errno) {
-          std::cerr << "Error Converting Device Name: " << errno << std::endl;
-          throw std::invalid_argument("audio_osx_source::audio_osx_source");
-        }
-        if(l_n_channels <= 0)
-          channel_config = 2;
-        else
-          channel_config = l_n_channels;
+
+      // if no input audio device id was found or no specific device
+      // name was provided, use the default input audio device id as
+      // set in System Preferences.
+
+      if (d_input_ad_id == kAudioDeviceUnknown) {
+
+        UInt32 prop_size = (UInt32)sizeof(AudioDeviceID);
+        AudioObjectPropertyAddress ao_address = {
+	  kAudioHardwarePropertyDefaultInputDevice,
+	  kAudioObjectPropertyScopeGlobal,
+	  kAudioObjectPropertyElementMaster
+        };
+
+        err = AudioObjectGetPropertyData
+	  (kAudioObjectSystemObject, &ao_address,
+	   0, NULL, &prop_size, &d_input_ad_id);
+	check_error_and_throw
+	  (err, "Getting the default input audio device ID failed",
+	   "audio_osx_source::setup");
+
+	{
+	  // retrieve the device name; max name length is 64 characters.
+
+	  UInt32 prop_size = 65;
+	  char c_name_buf[prop_size];
+	  memset((void*)c_name_buf, 0, (size_t)prop_size);
+	  --prop_size;
+
+	  AudioObjectPropertyAddress ao_address = {
+	    kAudioDevicePropertyDeviceName,
+	    kAudioDevicePropertyScopeInput, 0
+	  };
+
+	  if ((err = AudioObjectGetPropertyData
+	       (d_input_ad_id, &ao_address, 0, NULL,
+		&prop_size, (void*)c_name_buf)) != noErr) {
+
+	    check_error(err, "Unable to retrieve input audio device name");
+
+	  } else {
+
+	    GR_LOG_INFO(d_logger, boost::format
+			 ("\n\nUsing input audio device '%s'.\n  ... "
+			  "which is the current default input audio"
+			  " device.\n  Changing the default input"
+			  " audio device in the System Preferences"
+			  " will \n  result in changing it here, too "
+			  "(with an internal reconfiguration).\n") %
+			std::string(c_name_buf));
+
+	  }
+
+	  d_selected_name = c_name_buf;
+
+	}
+
+	d_using_default_device = true;
+
       }
 
-      d_channel_config = channel_config;
+      // retrieve the total number of channels for the selected input
+      // audio device
+
+      osx::get_num_channels_for_audio_device_id
+	(d_input_ad_id, &d_n_dev_channels, NULL);
 
-      // check that the max # of samples to store is valid
+      // set the block output signature, if not already set
+      // (d_n_user_channels is set in check_topology, which is called
+      // before the flow-graph is running)
 
-      if(max_sample_count == -1)
-        max_sample_count = sample_rate;
-      else if(max_sample_count <= 0) {
-        std::cerr << "Invalid Max Sample Count: " << max_sample_count << std::endl;
-        throw std::invalid_argument("audio_osx_source::audio_osx_source");
+      if (d_n_user_channels == 0) {
+	set_output_signature(io_signature::make
+			     (1, d_n_dev_channels, sizeof(float)));
       }
 
-      d_max_sample_count = max_sample_count;
+      // set the interim buffer size; to work with the GR scheduler,
+      // must be at least 16kB.  Pick 50 kB since that's plenty yet
+      // not very much.
+
+      d_buffer_sample_count = (d_output_sample_rate < 50000.0 ?
+			       50000 : (UInt32)d_output_sample_rate);
 
 #if _OSX_AU_DEBUG_
-      std::cerr << "source(): max # samples = " << d_max_sample_count << std::endl;
+      std::cerr << "source(): max # samples = "
+		<< d_buffer_sample_count << std::endl;
 #endif
 
-      OSStatus err = noErr;
-
       // create the default AudioUnit for input
 
       // Open the default input unit
+
 #ifndef GR_USE_OLD_AUDIO_UNIT
-      AudioComponentDescription InputDesc;
+      AudioComponentDescription desc;
 #else
-      ComponentDescription InputDesc;
+      ComponentDescription desc;
 #endif
 
-      InputDesc.componentType = kAudioUnitType_Output;
-      InputDesc.componentSubType = kAudioUnitSubType_HALOutput;
-      InputDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
-      InputDesc.componentFlags = 0;
-      InputDesc.componentFlagsMask = 0;
+      desc.componentType = kAudioUnitType_Output;
+      desc.componentSubType = kAudioUnitSubType_HALOutput;
+      desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+      desc.componentFlags = 0;
+      desc.componentFlagsMask = 0;
 
 #ifndef GR_USE_OLD_AUDIO_UNIT
-      AudioComponent comp = AudioComponentFindNext(NULL, &InputDesc);
-#else
-      Component comp = FindNextComponent(NULL, &InputDesc);
-#endif
 
-      if(comp == NULL) {
-#ifndef GR_USE_OLD_AUDIO_UNIT
-        std::cerr << "AudioComponentFindNext Error" << std::endl;
-#else
-        std::cerr << "FindNextComponent Error" << std::endl;
-#endif
-        throw std::runtime_error("audio_osx_source::audio_osx_source");
-  }
+      AudioComponent comp = AudioComponentFindNext(NULL, &desc);
+      if(!comp) {
+        GR_LOG_FATAL(d_logger, boost::format
+		     ("AudioComponentFindNext Failed"));
+        throw std::runtime_error("audio_osx_source::setup");
+      }
+      err = AudioComponentInstanceNew(comp, &d_input_au);
+      check_error_and_throw(err, "AudioComponentInstanceNew Failed",
+			    "audio_osx_source::setup");
 
-#ifndef GR_USE_OLD_AUDIO_UNIT
-      err = AudioComponentInstanceNew(comp, &d_InputAU);
-      CheckErrorAndThrow(err, "AudioComponentInstanceNew",
-                         "audio_osx_source::audio_osx_source");
 #else
-      err = OpenAComponent(comp, &d_InputAU);
-      CheckErrorAndThrow(err, "OpenAComponent",
-                         "audio_osx_source::audio_osx_source");
-#endif
 
-      UInt32 enableIO;
+      Component comp = FindNextComponent(NULL, &desc);
+      if(!comp) {
+        GR_LOG_FATAL(d_logger, boost::format
+		     ("FindNextComponent Failed"));
+        throw std::runtime_error("audio_osx_source::setup");
+      }
+      err = OpenAComponent(comp, &d_input_au);
+      check_error_and_throw(err, "OpenAComponent Failed",
+                         "audio_osx_source::setup");
+
+#endif
 
       // must enable the AUHAL for input and disable output
       // before setting the AUHAL's current device
 
       // Enable input on the AUHAL
-      enableIO = 1;
-      err = AudioUnitSetProperty(d_InputAU,
-                                 kAudioOutputUnitProperty_EnableIO,
-                                 kAudioUnitScope_Input,
-                                 1, // input element
-                                 &enableIO,
-                                 sizeof(UInt32));
-      CheckErrorAndThrow(err, "AudioUnitSetProperty Input Enable",
-                         "audio_osx_source::audio_osx_source");
 
-      // Disable output on the AUHAL
-      enableIO = 0;
-      err = AudioUnitSetProperty(d_InputAU,
-                                 kAudioOutputUnitProperty_EnableIO,
-                                 kAudioUnitScope_Output,
-                                 0, // output element
-                                 &enableIO,
-                                 sizeof (UInt32));
-      CheckErrorAndThrow(err, "AudioUnitSetProperty Output Disable",
-                         "audio_osx_source::audio_osx_source");
-  
-      // set the default input device for our input AU
-
-      SetDefaultInputDeviceAsCurrent();
-
-#if _OSX_DO_LISTENERS_
-      // set up a listener if default hardware input device changes
+      UInt32 enable_io = 1;
+      err = AudioUnitSetProperty
+	(d_input_au,
+	 kAudioOutputUnitProperty_EnableIO,
+	 kAudioUnitScope_Input, 1, // input element
+	 &enable_io, sizeof(enable_io));
+      check_error_and_throw
+	(err, "AudioUnitSetProperty Input Enable",
+	 "audio_osx_source::setup");
 
-      err = AudioHardwareAddPropertyListener
-        (kAudioHardwarePropertyDefaultInputDevice,
-         (AudioHardwarePropertyListenerProc)HardwareListener,
-         this);
-
-      CheckErrorAndThrow(err, "AudioHardwareAddPropertyListener",
-                         "audio_osx_source::audio_osx_source");
-
-      // Add a listener for any changes in the input AU's output stream
-      // the function "UnitListener" will be called if the stream format
-      // changes for whatever reason
-
-      err = AudioUnitAddPropertyListener
-        (d_InputAU,
-         kAudioUnitProperty_StreamFormat,
-         (AudioUnitPropertyListenerProc)UnitListener,
-         this);
-      CheckErrorAndThrow(err, "Adding Unit Property Listener",
-                         "audio_osx_source::audio_osx_source");
-#endif
+      // Disable output on the AUHAL
 
-      // Now find out if it actually can do input.
-
-      UInt32 hasInput = 0;
-      UInt32 dataSize = sizeof(hasInput);
-      err = AudioUnitGetProperty(d_InputAU,
-                                 kAudioOutputUnitProperty_HasIO,
-                                 kAudioUnitScope_Input,
-                                 1,
-                                 &hasInput,
-                                 &dataSize);
-      CheckErrorAndThrow(err, "AudioUnitGetProperty HasIO",
-                         "audio_osx_source::audio_osx_source");
-      if(hasInput == 0) {
-        std::cerr << "Selected Audio Device does not support Input." << std::endl;
-        throw std::runtime_error("audio_osx_source::audio_osx_source");
-      }
+      enable_io = 0;
+      err = AudioUnitSetProperty
+	(d_input_au,
+	 kAudioOutputUnitProperty_EnableIO,
+	 kAudioUnitScope_Output, 0, // output element
+	 &enable_io, sizeof(enable_io));
+      check_error_and_throw
+	(err, "AudioUnitSetProperty Output Disable",
+	 "audio_osx_source::setup");
+
+      // set the selected device ID as the current input device
+
+      err = AudioUnitSetProperty
+	(d_input_au, kAudioOutputUnitProperty_CurrentDevice,
+	 kAudioUnitScope_Global, 0,
+	 &d_input_ad_id, sizeof(d_input_ad_id));
+      check_error_and_throw
+	(err, "Setting selected input device as current failed",
+	 "audio_osx_source::setup");
 
       // Set up a callback function to retrieve input from the Audio Device
 
-      AURenderCallbackStruct AUCallBack;
+      AURenderCallbackStruct au_callback = {
+        reinterpret_cast<AURenderCallback>
+	  (&osx_source::au_input_callback),
+	reinterpret_cast<void*>(this)
+      };
+      UInt32 prop_size = (UInt32)sizeof(au_callback);
+
+      err = AudioUnitSetProperty
+	(d_input_au,
+	 kAudioOutputUnitProperty_SetInputCallback,
+	 kAudioUnitScope_Global, 0,
+	 &au_callback, prop_size);
+      check_error_and_throw
+	(err, "Set Input Callback",
+	 "audio_osx_source::setup");
+
+      // Get the Stream Format (device side; cannot generally be changed)
+
+      prop_size = (UInt32)sizeof(d_asbd_device);
+      memset((void*)(&d_asbd_device), 0, (size_t)prop_size);
+      err = AudioUnitGetProperty
+	(d_input_au,
+	 kAudioUnitProperty_StreamFormat,
+	 kAudioUnitScope_Input, 1,
+	 &d_asbd_device, &prop_size);
+      check_error_and_throw
+	(err, "Get Device Input Stream Format (before) failed",
+	 "audio_osx_source::setup");
 
-      AUCallBack.inputProc = (AURenderCallback)(osx_source::AUInputCallback);
-      AUCallBack.inputProcRefCon = this;
+#if _OSX_AU_DEBUG_
+      std::cerr << std::endl << "---- Device Stream Format (before) ----"
+		<< std::endl << d_asbd_device << std::endl << std::endl;
+#endif
 
-      err = AudioUnitSetProperty(d_InputAU,
-                                 kAudioOutputUnitProperty_SetInputCallback,
-                                 kAudioUnitScope_Global,
-                                 0,
-                                 &AUCallBack,
-                                 sizeof (AURenderCallbackStruct));
-      CheckErrorAndThrow(err, "AudioUnitSetProperty Input Callback",
-                         "audio_osx_source::audio_osx_source");
+      // try to set the device (input) side of the audio device to the
+      // sample rate of this source.  This will likely fail, and
+      // that's OK; just ignore the error since we can accomplish
+      // audio input in other ways.
+
+      prop_size = (UInt32)sizeof(d_asbd_device);
+      d_asbd_device.mSampleRate = d_output_sample_rate;
+      err = AudioUnitSetProperty
+	(d_input_au,
+	 kAudioUnitProperty_StreamFormat,
+	 kAudioUnitScope_Input, 1,
+	 &d_asbd_device, prop_size);
+#if _OSX_AU_DEBUG_
+      check_error
+	(err, "Set Device Input Stream Format failed (expected)");
+#endif
 
-      UInt32 propertySize;
-      AudioStreamBasicDescription asbd_device, asbd_client, asbd_user;
+      memset((void*)(&d_asbd_device), 0, (size_t)prop_size);
+      err = AudioUnitGetProperty
+	(d_input_au,
+	 kAudioUnitProperty_StreamFormat,
+	 kAudioUnitScope_Input, 1,
+	 &d_asbd_device, &prop_size);
+      check_error_and_throw
+	(err, "Get Device Input Stream Format (after) failed",
+	 "audio_osx_source::setup");
 
-      // asbd_device: ASBD of the device that is creating the input data stream
-      // asbd_client: ASBD of the client size (output) of the hardware device
-      // asbd_user:   ASBD of the user's arguments
+#if _OSX_AU_DEBUG_
+      std::cerr << std::endl << "---- Device Stream Format (after) ----"
+		<< std::endl << d_asbd_device << std::endl << std::endl;
+#endif
 
-      // Get the Stream Format (device side)
+      d_device_sample_rate = d_asbd_device.mSampleRate;
 
-      propertySize = sizeof(asbd_device);
-      err = AudioUnitGetProperty(d_InputAU,
-                                 kAudioUnitProperty_StreamFormat,
-                                 kAudioUnitScope_Input,
-                                 1,
-                                 &asbd_device,
-                                 &propertySize);
-      CheckErrorAndThrow(err, "AudioUnitGetProperty Device Input Stream Format",
-                         "audio_osx_source::audio_osx_source");
+      // Get the Stream Format (client side; might be changeable)
+
+      prop_size = (UInt32)sizeof(d_asbd_client);
+      memset((void*)(&d_asbd_client), 0, (size_t)prop_size);
+      err = AudioUnitGetProperty
+	(d_input_au,
+	 kAudioUnitProperty_StreamFormat,
+	 kAudioUnitScope_Output, 1,
+	 &d_asbd_client, &prop_size);
+      check_error_and_throw
+	(err, "Get Device Output Stream Format (before) failed",
+	 "audio_osx_source::setup");
 
 #if _OSX_AU_DEBUG_
-      std::cerr << std::endl << "---- Device Stream Format ----" << std::endl;
-      PrintStreamDesc(&asbd_device);
+      std::cerr << "---- Client Stream Format (Before) ----"
+		<< std::endl << d_asbd_client << std::endl << std::endl;
 #endif
 
-      // Get the Stream Format (client side)
-      propertySize = sizeof(asbd_client);
-      err = AudioUnitGetProperty(d_InputAU,
-                                 kAudioUnitProperty_StreamFormat,
-                                 kAudioUnitScope_Output,
-                                 1,
-                                 &asbd_client,
-                                 &propertySize);
-      CheckErrorAndThrow(err, "AudioUnitGetProperty Device Ouput Stream Format",
-                         "audio_osx_source::audio_osx_source");
+      // Set the format of all the AUs to the
+      // input/output devices channel count
+
+      d_asbd_client.mFormatID = kAudioFormatLinearPCM;
+      d_asbd_client.mFormatFlags = (kAudioFormatFlagIsFloat |
+                                  kAudioFormatFlagIsPacked |
+                                  kAudioFormatFlagIsNonInterleaved);
+      if((d_asbd_client.mFormatID == kAudioFormatLinearPCM) &&
+         (d_n_dev_channels == 1)) {
+        d_asbd_client.mFormatFlags &= ~kLinearPCMFormatFlagIsNonInterleaved;
+      }
+      d_asbd_client.mBytesPerFrame = (UInt32)sizeof(float);
+      d_asbd_client.mFramesPerPacket = 1;
+      d_asbd_client.mBitsPerChannel = d_asbd_client.mBytesPerFrame * 8;
+      d_asbd_client.mChannelsPerFrame = d_n_dev_channels;
+      d_asbd_client.mBytesPerPacket = d_asbd_client.mBytesPerFrame;
+
+      // according to Apple docs [see, e.g., Apple Technical Note
+      // TN2091 "Device input using the HAL Output Audio Unit"], the
+      // device input and output sample rate must be the same; do
+      // sample rate conversion elsewhere.
+
+      d_asbd_client.mSampleRate = d_asbd_device.mSampleRate;
+      err = AudioUnitSetProperty
+	(d_input_au,
+	 kAudioUnitProperty_StreamFormat,
+	 kAudioUnitScope_Output, 1,
+	 &d_asbd_client, prop_size);
+      check_error_and_throw
+	(err, "Set Device Ouput Stream Format failed",
+	 "audio_osx_source::setup");
+
+      // Get the Stream Format (client side), again
+
+      prop_size = (UInt32)sizeof(d_asbd_client);
+      memset((void*)(&d_asbd_client), 0, (size_t)prop_size);
+      err = AudioUnitGetProperty
+	(d_input_au,
+	 kAudioUnitProperty_StreamFormat,
+	 kAudioUnitScope_Output, 1,
+	 &d_asbd_client, &prop_size);
+      check_error_and_throw
+	(err, "Get Device Output Stream Format (after) failed",
+	 "audio_osx_source::setup");
 
 #if _OSX_AU_DEBUG_
-      std::cerr << std::endl << "---- Client Stream Format ----" << std::endl;
-      PrintStreamDesc(&asbd_client);
+      std::cerr << "---- Client Stream Format (After) ----"
+		<< std::endl << d_asbd_client << std::endl << std::endl;
 #endif
 
-      // Set the format of all the AUs to the input/output devices channel count
+      d_pass_through = (d_asbd_client.mSampleRate == d_output_sample_rate);
 
-      // get the max number of input (& thus output) channels supported by
-      // this device
-      d_n_max_channels = asbd_device.mChannelsPerFrame;
+      if (d_pass_through) {
 
-      // create the output io signature;
-      // no input siganture to set (source is hardware)
-      set_output_signature(io_signature::make(1,
-                                                d_n_max_channels,
-                                                sizeof(float)));
+        // no need to do conversion if d_asbd_client matches user wants
+        d_lead_size_frames = d_trail_size_frames = 0L;
 
-      // allocate the output circular buffer(s), one per channel
-      d_buffers = (circular_buffer<float>**)new
-        circular_buffer<float>* [d_n_max_channels];
-      UInt32 n_alloc = (UInt32)ceil((double)d_max_sample_count);
-      for(UInt32 n = 0; n < d_n_max_channels; n++) {
-        d_buffers[n] = new circular_buffer<float>(n_alloc, false, false);
       }
+      else {
 
-      d_deviceSampleRate = asbd_device.mSampleRate;
-      d_n_deviceChannels = asbd_device.mChannelsPerFrame;
+	// create an ASBD for the user's wants
+
+	memset((void*)(&d_asbd_user), 0, sizeof(d_asbd_user));
+	d_asbd_user.mSampleRate = d_output_sample_rate;
+	d_asbd_user.mFormatID = kAudioFormatLinearPCM;
+	d_asbd_user.mFormatFlags = (kLinearPCMFormatFlagIsFloat |
+				    GR_PCM_ENDIANNESS |
+				    kLinearPCMFormatFlagIsPacked |
+				    kAudioFormatFlagIsNonInterleaved);
+	d_asbd_user.mBytesPerPacket = (UInt32)sizeof(float);
+	d_asbd_user.mFramesPerPacket = 1;
+	d_asbd_user.mBytesPerFrame = d_asbd_user.mBytesPerPacket;
+	d_asbd_user.mChannelsPerFrame = d_n_dev_channels;
+	d_asbd_user.mBitsPerChannel = d_asbd_user.mBytesPerPacket * 8;
 
-      asbd_client.mSampleRate = asbd_device.mSampleRate;
-      asbd_client.mFormatID = kAudioFormatLinearPCM;
-      asbd_client.mFormatFlags = (kAudioFormatFlagIsFloat |
-                                  kAudioFormatFlagIsPacked |
-                                  kAudioFormatFlagIsNonInterleaved);
-      if((asbd_client.mFormatID == kAudioFormatLinearPCM) &&
-         (d_n_deviceChannels == 1)) {
-        asbd_client.mFormatFlags &= ~kLinearPCMFormatFlagIsNonInterleaved;
-      }
-      asbd_client.mBytesPerFrame = sizeof(float);
-      asbd_client.mFramesPerPacket = 1;
-      asbd_client.mBitsPerChannel = asbd_client.mBytesPerFrame * 8;
-      asbd_client.mChannelsPerFrame = d_n_deviceChannels;
-      asbd_client.mBytesPerPacket = asbd_client.mBytesPerFrame;
-
-      propertySize = sizeof(AudioStreamBasicDescription);
-      err = AudioUnitSetProperty(d_InputAU,
-                                 kAudioUnitProperty_StreamFormat,
-                                 kAudioUnitScope_Output,
-                                 1,
-                                 &asbd_client,
-                                 propertySize);
-      CheckErrorAndThrow(err, "AudioUnitSetProperty Device Ouput Stream Format",
-                         "audio_osx_source::audio_osx_source");
-
-      // create an ASBD for the user's wants
-
-      asbd_user.mSampleRate = d_outputSampleRate;
-      asbd_user.mFormatID = kAudioFormatLinearPCM;
-      asbd_user.mFormatFlags = (kLinearPCMFormatFlagIsFloat |
-                                GR_PCM_ENDIANNESS |
-                                kLinearPCMFormatFlagIsPacked |
-                                kAudioFormatFlagIsNonInterleaved);
-      asbd_user.mBytesPerPacket = sizeof(float);
-      asbd_user.mFramesPerPacket = 1;
-      asbd_user.mBytesPerFrame = asbd_user.mBytesPerPacket;
-      asbd_user.mChannelsPerFrame = d_n_deviceChannels;
-      asbd_user.mBitsPerChannel = asbd_user.mBytesPerPacket * 8;
-
-      if(d_deviceSampleRate == d_outputSampleRate) {
-        // no need to do conversion if asbd_client matches user wants
-        d_passThrough = true;
-        d_leadSizeFrames = d_trailSizeFrames = 0L;
-      }
-      else {
-        d_passThrough = false;
         // Create the audio converter
 
-        err = AudioConverterNew(&asbd_client, &asbd_user, &d_AudioConverter);
-        CheckErrorAndThrow(err, "AudioConverterNew",
-                           "audio_osx_source::audio_osx_source");
+        err = AudioConverterNew(&d_asbd_client,
+				&d_asbd_user,
+				&d_audio_converter);
+        check_error_and_throw
+	  (err, "AudioConverterNew failed",
+	   "audio_osx_source::setup");
 
         // Set the audio converter sample rate quality to "max" ...
         // requires more samples, but should sound nicer
 
-        UInt32 ACQuality = kAudioConverterQuality_Max;
-        propertySize = sizeof(ACQuality);
-        err = AudioConverterSetProperty(d_AudioConverter,
-                                        kAudioConverterSampleRateConverterQuality,
-                                        propertySize,
-                                        &ACQuality);
-        CheckErrorAndThrow(err, "AudioConverterSetProperty "
-                           "SampleRateConverterQuality",
-                           "audio_osx_source::audio_osx_source");
+        UInt32 ac_quality = kAudioConverterQuality_Max;
+        prop_size = (UInt32)sizeof(ac_quality);
+        err = AudioConverterSetProperty
+	  (d_audio_converter,
+	   kAudioConverterSampleRateConverterQuality,
+	   prop_size, &ac_quality);
+        check_error_and_throw
+	  (err, "Set Sample Rate Converter Quality failed",
+	   "audio_osx_source::setup");
 
         // set the audio converter's prime method to "pre",
         // which uses both leading and trailing frames
@@ -396,59 +510,52 @@ namespace gr {
         // internally by the AudioConverter; we just supply
         // the frames for conversion.
 
-        //   UInt32 ACPrimeMethod = kConverterPrimeMethod_None;
-        UInt32 ACPrimeMethod = kConverterPrimeMethod_Pre;
-        propertySize = sizeof (ACPrimeMethod);
-        err = AudioConverterSetProperty(d_AudioConverter,
-                                        kAudioConverterPrimeMethod,
-                                        propertySize,
-                                        &ACPrimeMethod);
-        CheckErrorAndThrow(err, "AudioConverterSetProperty PrimeMethod",
-                           "audio_osx_source::audio_osx_source");
-
-        // Get the size of the I/O buffer(s) to allow for pre-allocated buffers
-
-        // lead frame info (trail frame info is ignored)
-
-        AudioConverterPrimeInfo ACPrimeInfo = {0, 0};
-        propertySize = sizeof(ACPrimeInfo);
-        err = AudioConverterGetProperty(d_AudioConverter,
-                                        kAudioConverterPrimeInfo,
-                                        &propertySize,
-                                        &ACPrimeInfo);
-        CheckErrorAndThrow(err, "AudioConverterGetProperty PrimeInfo",
-                           "audio_osx_source::audio_osx_source");
-
-        switch(ACPrimeMethod) {
-        case(kConverterPrimeMethod_None):
-          d_leadSizeFrames =
-            d_trailSizeFrames = 0L;
-          break;
-        case(kConverterPrimeMethod_Normal):
-          d_leadSizeFrames = 0L;
-          d_trailSizeFrames = ACPrimeInfo.trailingFrames;
-          break;
-        default:
-          d_leadSizeFrames = ACPrimeInfo.leadingFrames;
-          d_trailSizeFrames = ACPrimeInfo.trailingFrames;
-        }
+        UInt32 ac_prime_method = kConverterPrimeMethod_Pre;
+        prop_size = (UInt32)sizeof(ac_prime_method);
+        err = AudioConverterSetProperty
+	  (d_audio_converter,
+	   kAudioConverterPrimeMethod,
+	   prop_size, &ac_prime_method);
+        check_error_and_throw
+	  (err, "Set Prime Method failed",
+	   "audio_osx_source::setup");
+
+        // Get the size of the priming I/O buffer space to allow for
+        // pre-allocated buffers
+
+        AudioConverterPrimeInfo ac_prime_info = {0, 0};
+        prop_size = (UInt32)sizeof(ac_prime_info);
+        err = AudioConverterGetProperty
+	  (d_audio_converter,
+	   kAudioConverterPrimeInfo,
+	   &prop_size, &ac_prime_info);
+        check_error_and_throw
+	  (err, "Get Prime Info failed",
+	   "audio_osx_source::setup");
+
+	d_lead_size_frames = ac_prime_info.leadingFrames;
+	d_trail_size_frames = ac_prime_info.trailingFrames;
       }
-      d_leadSizeBytes = d_leadSizeFrames * sizeof(Float32);
-      d_trailSizeBytes = d_trailSizeFrames * sizeof(Float32);
-
-      propertySize = sizeof(d_deviceBufferSizeFrames);
-      err = AudioUnitGetProperty(d_InputAU,
-                                 kAudioDevicePropertyBufferFrameSize,
-                                 kAudioUnitScope_Global,
-                                 0,
-                                 &d_deviceBufferSizeFrames,
-                                 &propertySize);
-      CheckErrorAndThrow(err, "AudioUnitGetProperty Buffer Frame Size",
-                         "audio_osx_source::audio_osx_source");
-
-      d_deviceBufferSizeBytes = d_deviceBufferSizeFrames * sizeof(Float32);
-      d_inputBufferSizeBytes = d_deviceBufferSizeBytes + d_leadSizeBytes;
-      d_inputBufferSizeFrames = d_deviceBufferSizeFrames + d_leadSizeFrames;
+
+      d_lead_size_bytes = d_lead_size_frames * sizeof(float);
+      d_trail_size_bytes = d_trail_size_frames * sizeof(float);
+
+      prop_size = (UInt32)sizeof(d_device_buffer_size_frames);
+      err = AudioUnitGetProperty
+	(d_input_au,
+	 kAudioDevicePropertyBufferFrameSize,
+	 kAudioUnitScope_Global, 0,
+	 &d_device_buffer_size_frames, &prop_size);
+      check_error_and_throw
+	(err, "Get Buffer Frame Size failed",
+	 "audio_osx_source::setup");
+
+      d_device_buffer_size_bytes = (d_device_buffer_size_frames *
+				    sizeof(float));
+      d_input_buffer_size_bytes = (d_device_buffer_size_bytes +
+				   d_lead_size_bytes);
+      d_input_buffer_size_frames = (d_device_buffer_size_frames +
+				    d_lead_size_frames);
 
       // outBufSizeBytes = floor (inBufSizeBytes * rate_out / rate_in)
       // since this is rarely exact, we need another buffer to hold
@@ -457,197 +564,448 @@ namespace gr {
       // follows the rule that
       // extraBufSize =  ceil (rate_in / rate_out)*sizeof(float)
 
-      d_extraBufferSizeFrames = ((UInt32)ceil(d_deviceSampleRate
-                                              / d_outputSampleRate)
-                                 * sizeof(float));
-      if(d_extraBufferSizeFrames < 4)
-        d_extraBufferSizeFrames = 4;
-      d_extraBufferSizeBytes = d_extraBufferSizeFrames * sizeof(float);
-
-      d_outputBufferSizeFrames = (UInt32)ceil(((Float64)d_inputBufferSizeFrames)
-                                              * d_outputSampleRate
-                                              / d_deviceSampleRate);
-      d_outputBufferSizeBytes = d_outputBufferSizeFrames * sizeof(float);
-      d_inputBufferSizeFrames += d_extraBufferSizeFrames;
-
-      // pre-alloc all buffers
-
-      AllocAudioBufferList(&d_InputBuffer, d_n_deviceChannels,
-                           d_inputBufferSizeBytes);
-      if(d_passThrough == false) {
-        AllocAudioBufferList(&d_OutputBuffer, d_n_max_channels,
-                             d_outputBufferSizeBytes);
+      d_extra_buffer_size_frames =
+	((UInt32)ceil(d_device_sample_rate /
+		      d_output_sample_rate) *
+	 sizeof(float));
+      if(d_extra_buffer_size_frames < 4)
+        d_extra_buffer_size_frames = 4;
+      d_extra_buffer_size_bytes =
+	d_extra_buffer_size_frames * sizeof(float);
+
+      d_output_buffer_size_frames =
+	(UInt32)ceil(((Float64)d_input_buffer_size_frames) *
+		     d_output_sample_rate / d_device_sample_rate);
+      d_output_buffer_size_bytes =
+	d_output_buffer_size_frames * sizeof(float);
+      d_input_buffer_size_frames += d_extra_buffer_size_frames;
+
+      // pre-alloc all CoreAudio buffers
+
+      alloc_audio_buffer_list
+	(&d_input_buffer, d_n_dev_channels,
+	 d_input_buffer_size_bytes);
+      if(!d_pass_through) {
+        alloc_audio_buffer_list
+	  (&d_output_buffer, d_n_dev_channels,
+	   d_output_buffer_size_bytes);
       }
       else {
-        d_OutputBuffer = d_InputBuffer;
+        d_output_buffer = d_input_buffer;
+      }
+
+      // allocate the output circular buffer(s), one per device
+      // channel (the user may select fewer channels; those buffers
+      // just won't get used).
+
+      d_buffers.resize(d_n_dev_channels);
+      for(UInt32 nn = 0; nn < d_n_dev_channels; ++nn) {
+	d_buffers[nn] = new circular_buffer<float>
+	  (d_buffer_sample_count, false, false);
+      }
+
+      // clear the RunLoop (whatever that is); needed, for some
+      // reason, before a listener will work.
+
+      {
+	CFRunLoopRef the_run_loop = NULL;
+	AudioObjectPropertyAddress property = {
+	  kAudioHardwarePropertyRunLoop,
+	  kAudioObjectPropertyScopeGlobal,
+	  kAudioObjectPropertyElementMaster
+	};
+	prop_size = (UInt32)sizeof(the_run_loop);
+	err = AudioObjectSetPropertyData
+	  (kAudioObjectSystemObject, &property, 0, NULL,
+	   prop_size, &the_run_loop);
+	  check_error(err, "Clearing RunLoop failed; "
+		      "Audio Input Device Listener might not work.");
+      }
+
+      // set up listeners
+
+#ifndef GR_USE_OLD_AUDIO_UNIT
+
+      // 10.4 and newer
+
+      {
+
+	// set up a listener if hardware changes (at all)
+
+	AudioObjectPropertyAddress property = {
+	  kAudioHardwarePropertyDevices,
+	  kAudioObjectPropertyScopeGlobal,
+	  kAudioObjectPropertyElementMaster
+	};
+
+	err = AudioObjectAddPropertyListener
+	  (kAudioObjectSystemObject, &property,
+	   reinterpret_cast<AudioObjectPropertyListenerProc>
+	     (&osx_source::hardware_listener),
+	   reinterpret_cast<void*>(this));
+	check_error(err, "Adding Audio Hardware Listener failed");
       }
 
-      // create the stuff to regulate I/O
+      if (d_using_default_device) {
 
-      d_cond_data = new gr::thread::condition_variable();
-      if(d_cond_data == NULL)
-        CheckErrorAndThrow(errno, "new condition (data)",
-                           "audio_osx_source::audio_osx_source");
+	// set up a listener if default hardware input device changes
 
-      d_internal = new gr::thread::mutex();
-      if(d_internal == NULL)
-        CheckErrorAndThrow(errno, "new mutex (internal)",
-                           "audio_osx_source::audio_osx_source");
+	AudioObjectPropertyAddress property = {
+	  kAudioHardwarePropertyDefaultInputDevice,
+	  kAudioObjectPropertyScopeGlobal,
+	  kAudioObjectPropertyElementMaster
+	};
 
-      // initialize the AU for input
+	err = AudioObjectAddPropertyListener
+	  (kAudioObjectSystemObject, &property,
+	   reinterpret_cast<AudioObjectPropertyListenerProc>
+	     (&osx_source::default_listener),
+	   reinterpret_cast<void*>(this));
+	check_error(err, "Adding Default Input Audio Listener failed");
 
-      err = AudioUnitInitialize(d_InputAU);
-      CheckErrorAndThrow(err, "AudioUnitInitialize",
-                         "audio_osx_source::audio_osx_source");
+      }
+
+#else
+
+      // 10.5 and older
+
+      err = AudioHardwareAddPropertyListener
+	(kAudioHardwarePropertyDevices,
+	 reinterpret_cast<AudioHardwarePropertyListenerProc>
+	   (&osx_source::hardware_listener),
+	 reinterpret_cast<void*>(this));
+      check_error(err, "Adding Audio Hardware Listener failed");
+
+      if (d_using_default_device) {
+
+	err = AudioHardwareAddPropertyListener
+	  (kAudioHardwarePropertyDefaultInputDevice,
+	   reinterpret_cast<AudioHardwarePropertyListenerProc>
+	     (&osx_source::default_listener),
+	   reinterpret_cast<void*>(this));
+	check_error(err, "Adding Default Input Audio Listener failed");
+
+      }
+
+#endif
+
+      // initialize the AU for input, so that it is ready to be used
+
+      err = AudioUnitInitialize(d_input_au);
+      check_error_and_throw
+	(err, "AudioUnitInitialize",
+	 "audio_osx_source::check_channels");
 
 #if _OSX_AU_DEBUG_
-      std::cerr << "audio_osx_source Parameters:" << std::endl;
-      std::cerr << "  Device Sample Rate is " << d_deviceSampleRate << std::endl;
-      std::cerr << "  User Sample Rate is " << d_outputSampleRate << std::endl;
-      std::cerr << "  Max Sample Count is " << d_max_sample_count << std::endl;
-      std::cerr << "  # Device Channels is " << d_n_deviceChannels << std::endl;
-      std::cerr << "  # Max Channels is " << d_n_max_channels << std::endl;
-      std::cerr << "  Device Buffer Size is Frames = " << d_deviceBufferSizeFrames << std::endl;
-      std::cerr << "  Lead Size is Frames = " << d_leadSizeFrames << std::endl;
-      std::cerr << "  Trail Size is Frames = " << d_trailSizeFrames << std::endl;
-      std::cerr << "  Input Buffer Size is Frames = " << d_inputBufferSizeFrames << std::endl;
-      std::cerr << "  Output Buffer Size is Frames = " << d_outputBufferSizeFrames << std::endl;
+      std::cerr << std::endl << "audio_osx_source Parameters:"
+		<< std::endl << "  Device Sample Rate is "
+		<< d_device_sample_rate << std::endl
+		<< "  Client Sample Rate is "
+		<< (d_pass_through ? d_output_sample_rate :
+		    d_device_sample_rate) << std::endl
+		<< "  User Sample Rate is "
+		<< d_output_sample_rate << std::endl
+		<< "  Do Passthrough is "
+		<< (d_pass_through ? "true" : "false") << std::endl
+		<< "  Max Sample Count is "
+		<< d_buffer_sample_count << std::endl
+		<< "  # Device Channels is "
+		<< d_n_dev_channels << std::endl
+		<< "  Device Buffer Size in Frames = "
+		<< d_device_buffer_size_frames << std::endl
+		<< "  Lead Size in Frames = "
+		<< d_lead_size_frames << std::endl
+		<< "  Trail Size in Frames = "
+		<< d_trail_size_frames << std::endl
+		<< "  Input Buffer Size in Frames = "
+		<< d_input_buffer_size_frames << std::endl
+		<< "  Output Buffer Size in Frames = "
+		<< d_output_buffer_size_frames << std::endl
+		<< std::endl;
 #endif
     }
 
     void
-    osx_source::AllocAudioBufferList(AudioBufferList** t_ABL,
-                                     UInt32 n_channels,
-                                     UInt32 bufferSizeBytes)
+    osx_source::alloc_audio_buffer_list
+    (AudioBufferList** t_abl,
+     UInt32 n_channels,
+     UInt32 input_buffer_size_bytes)
     {
-      FreeAudioBufferList(t_ABL);
-      UInt32 propertySize = (offsetof(AudioBufferList, mBuffers[0]) +
-                             (sizeof(AudioBuffer) * n_channels));
-      *t_ABL = (AudioBufferList*)calloc(1, propertySize);
-      (*t_ABL)->mNumberBuffers = n_channels;
+      free_audio_buffer_list(t_abl);
+      UInt32 prop_size = (offsetof(AudioBufferList, mBuffers[0]) +
+			  (sizeof(AudioBuffer) * n_channels));
+      *t_abl = (AudioBufferList*)calloc(1, prop_size);
+      (*t_abl)->mNumberBuffers = n_channels;
 
       int counter = n_channels;
 
+#if _OSX_AU_DEBUG_
+      std::cerr << "alloc_audio_buffer_list: (#chan, #bytes) == ("
+		<< n_channels << ", " << input_buffer_size_bytes
+		<< ")" << std::endl;
+#endif
+
       while(--counter >= 0) {
-        (*t_ABL)->mBuffers[counter].mNumberChannels = 1;
-        (*t_ABL)->mBuffers[counter].mDataByteSize = bufferSizeBytes;
-        (*t_ABL)->mBuffers[counter].mData = calloc (1, bufferSizeBytes);
+	AudioBuffer* t_ab = &((*t_abl)->mBuffers[counter]);
+	t_ab->mNumberChannels = 1;
+	t_ab->mDataByteSize = input_buffer_size_bytes;
+	t_ab->mData = calloc(1, input_buffer_size_bytes);
       }
     }
 
     void
-    osx_source::FreeAudioBufferList(AudioBufferList** t_ABL)
+    osx_source::free_audio_buffer_list(AudioBufferList** t_abl)
     {
       // free pre-allocated audio buffer, if it exists
-      if(*t_ABL != NULL) {
-        int counter = (*t_ABL)->mNumberBuffers;
-        while(--counter >= 0)
-          free((*t_ABL)->mBuffers[counter].mData);
-        free(*t_ABL);
-        (*t_ABL) = 0;
+      if(*t_abl) {
+        int counter = (*t_abl)->mNumberBuffers;
+        while(--counter >= 0) {
+	  AudioBuffer* t_ab = &((*t_abl)->mBuffers[counter]);
+          free(t_ab->mData);
+	  t_ab->mData = 0;
+	}
+        free(*t_abl);
+        (*t_abl) = 0;
       }
     }
 
     bool
-    osx_source::IsRunning()
+    osx_source::is_running()
     {
-      UInt32 AURunning = 0, AUSize = sizeof(UInt32);
-
-      OSStatus err = AudioUnitGetProperty(d_InputAU,
-                                          kAudioOutputUnitProperty_IsRunning,
-                                          kAudioUnitScope_Global,
-                                          0,
-                                          &AURunning,
-                                          &AUSize);
-      CheckErrorAndThrow(err, "AudioUnitGetProperty IsRunning",
-                         "audio_osx_source::IsRunning");
-
-      return (AURunning);
+      UInt32 au_running = 0;
+      if (d_input_au) {
+
+	UInt32 prop_size = (UInt32)sizeof(au_running);
+	OSStatus err = AudioUnitGetProperty
+	  (d_input_au,
+	   kAudioOutputUnitProperty_IsRunning,
+	   kAudioUnitScope_Global, 0,
+	   &au_running, &prop_size);
+	check_error_and_throw
+	  (err, "AudioUnitGetProperty IsRunning",
+	   "audio_osx_source::is_running");
+      }
+
+      return(au_running != 0);
     }
 
     bool
     osx_source::start()
     {
-      if(! IsRunning ()) {
-        OSStatus err = AudioOutputUnitStart(d_InputAU);
-        CheckErrorAndThrow(err, "AudioOutputUnitStart",
+#if _OSX_AU_DEBUG_
+      std::cerr << ((void*)(pthread_self()))
+		<< " : audio_osx_source::start: Starting." << std::endl;
+#endif
+
+      if((!is_running ()) && d_input_au) {
+
+#if _OSX_AU_DEBUG_
+	std::cerr << ((void*)(pthread_self()))
+		  << " : audio_osx_source::start: Starting Audio Unit."
+		  << std::endl;
+#endif
+
+	// reset buffers before starting
+
+	for(UInt32 nn = 0; nn < d_buffers.size(); ++nn) {
+	  d_buffers[nn]->reset();
+	}
+
+	// start the audio unit
+
+        OSStatus err = AudioOutputUnitStart(d_input_au);
+        check_error_and_throw(err, "AudioOutputUnitStart",
                            "audio_osx_source::start");
+
+	// clear reset (will sometimes be necessary, and it has to
+	// happen after AudioOutputUnitStart)
+
+	d_do_reset = false;
+
       }
 
+#if _OSX_AU_DEBUG_
+      std::cerr << ((void*)(pthread_self()))
+		<< " : audio_osx_source::start: Returning." << std::endl;
+#endif
+
       return (true);
     }
 
     bool
     osx_source::stop()
     {
-      if(IsRunning ()) {
-        OSStatus err = AudioOutputUnitStop(d_InputAU);
-        CheckErrorAndThrow(err, "AudioOutputUnitStart",
+#if _OSX_AU_DEBUG_
+      std::cerr << ((void*)(pthread_self()))
+		<< " : audio_osx_source::stop: Starting." << std::endl;
+#endif
+      if(is_running ()) {
+
+#if _OSX_AU_DEBUG_
+	std::cerr << ((void*)(pthread_self()))
+		  << " : audio_osx_source::stop: stopping audio unit."
+		  << std::endl;
+#endif
+
+	// stop the audio unit
+
+        OSStatus err = AudioOutputUnitStop(d_input_au);
+        check_error_and_throw(err, "AudioOutputUnitStart",
                            "audio_osx_source::stop");
-        for(UInt32 n = 0; n < d_n_user_channels; n++) {
-          d_buffers[n]->abort ();
+
+	// abort all buffers
+
+        for(UInt32 nn = 0; nn < d_n_user_channels; ++nn) {
+          d_buffers[nn]->abort ();
         }
       }
 
+#if _OSX_AU_DEBUG_
+      std::cerr << ((void*)(pthread_self()))
+		<< " : audio_osx_source::stop: Returning." << std::endl;
+#endif
+
       return (true);
     }
 
-    osx_source::~osx_source()
+    void
+    osx_source::teardown()
     {
+#if _OSX_AU_DEBUG_
+      std::cerr << ((void*)(pthread_self()))
+		<< " : audio_osx_source::teardown: Starting." << std::endl;
+#endif
+
       OSStatus err = noErr;
 
       // stop the AudioUnit
+
       stop();
 
-#if _OSX_DO_LISTENERS_
       // remove the listeners
 
-      err = AudioUnitRemovePropertyListener
-        (d_InputAU,
-         kAudioUnitProperty_StreamFormat,
-         (AudioUnitPropertyListenerProc)UnitListener);
-      CheckError(err, "~audio_osx_source: AudioUnitRemovePropertyListener");
+#ifndef GR_USE_OLD_AUDIO_UNIT
+
+      // 10.4 and newer
+      {
+	AudioObjectPropertyAddress property = {
+	  kAudioHardwarePropertyDevices,
+	  kAudioObjectPropertyScopeGlobal,
+	  kAudioObjectPropertyElementMaster
+	};
+
+	err = AudioObjectRemovePropertyListener
+	  (kAudioObjectSystemObject, &property,
+	   reinterpret_cast<AudioObjectPropertyListenerProc>
+	     (&osx_source::hardware_listener),
+	   reinterpret_cast<void*>(this));
+#if _OSX_AU_DEBUG_
+	check_error(err, "teardown: AudioObjectRemovePropertyListener "
+		    "hardware failed");
+#endif
+
+      }
+
+      if (d_using_default_device) {
+
+	AudioObjectPropertyAddress property = {
+	  kAudioHardwarePropertyDefaultInputDevice,
+	  kAudioObjectPropertyScopeGlobal,
+	  kAudioObjectPropertyElementMaster
+	};
+
+	err = AudioObjectRemovePropertyListener
+	  (kAudioObjectSystemObject, &property,
+	   reinterpret_cast<AudioObjectPropertyListenerProc>
+	     (&osx_source::default_listener),
+	   reinterpret_cast<void*>(this));
+#if _OSX_AU_DEBUG_
+	check_error(err, "AudioObjectRemovePropertyListener default");
+#endif
+
+	d_using_default_device = false;
+
+      }
+#else
+
+      // 10.5 and older
 
       err = AudioHardwareRemovePropertyListener
-        (kAudioHardwarePropertyDefaultInputDevice,
-         (AudioHardwarePropertyListenerProc)HardwareListener);
-      CheckError(err, "~audio_osx_source: AudioHardwareRemovePropertyListener");
+	(kAudioHardwarePropertyDevices,
+	 reinterpret_cast<AudioHardwarePropertyListenerProc>
+	   (&osx_source::hardware_listener)
+	 reinterpret_cast<void*>(this));
+#if _OSX_AU_DEBUG_
+      check_error(err, "AudioObjectRemovePropertyListener hardware");
+#endif
+
+      if (d_using_default_device) {
+	err = AudioHardwareRemovePropertyListener
+	  (kAudioHardwarePropertyDefaultInputDevice,
+	   reinterpret_cast<AudioHardwarePropertyListenerProc>
+	     (&osx_source::default_listener),
+	   reinterpret_cast<void*>(this));
+#if _OSX_AU_DEBUG_
+	check_error(err, "AudioObjectRemovePropertyListener default");
 #endif
+	d_using_default_device = false;
+
+      }
+
+#endif // GR_USE_OLD_AUDIO_UNIT
 
       // free pre-allocated audio buffers
-      FreeAudioBufferList(&d_InputBuffer);
+      free_audio_buffer_list(&d_input_buffer);
 
-      if(d_passThrough == false) {
-        err = AudioConverterDispose(d_AudioConverter);
-        CheckError(err, "~audio_osx_source: AudioConverterDispose");
-        FreeAudioBufferList(&d_OutputBuffer);
+      if(!d_pass_through) {
+        err = AudioConverterDispose(d_audio_converter);
+#if _OSX_AU_DEBUG_
+        check_error(err, "~audio_osx_source: AudioConverterDispose");
+#endif
+        free_audio_buffer_list(&d_output_buffer);
       }
 
       // remove the audio unit
-      err = AudioUnitUninitialize(d_InputAU);
-      CheckError(err, "~audio_osx_source: AudioUnitUninitialize");
+      err = AudioUnitUninitialize(d_input_au);
+#if _OSX_AU_DEBUG_
+      check_error(err, "~audio_osx_source: AudioUnitUninitialize");
+#endif
 
 #ifndef GR_USE_OLD_AUDIO_UNIT
-      err = AudioComponentInstanceDispose(d_InputAU);
-      CheckError(err, "~audio_osx_source: AudioComponentInstanceDispose");
+      err = AudioComponentInstanceDispose(d_input_au);
+#if _OSX_AU_DEBUG_
+      check_error(err, "~audio_osx_source: AudioComponentInstanceDispose");
+#endif
 #else
-      err = CloseComponent(d_InputAU);
-      CheckError(err, "~audio_osx_source: CloseComponent");
+      err = CloseComponent(d_input_au);
+#if _OSX_AU_DEBUG_
+      check_error(err, "~audio_osx_source: CloseComponent");
+#endif
 #endif
 
       // empty and delete the queues
-      for(UInt32 n = 0; n < d_n_max_channels; n++) {
-        delete d_buffers[n];
-        d_buffers[n] = 0;
+
+      for(UInt32 nn = 0; nn < d_buffers.size(); ++nn) {
+        delete d_buffers[nn];
+        d_buffers[nn] = 0;
       }
-      delete [] d_buffers;
-      d_buffers = 0;
-
-      // close and delete the control stuff
-      delete d_cond_data;
-      d_cond_data = 0;
-      delete d_internal;
-      d_internal = 0;
+      d_buffers.resize(0);
+
+      // clear important variables; not # user channels
+
+      d_queue_sample_count = 0;
+      d_device_sample_rate = 0;
+      d_n_dev_channels = 0;
+      d_input_ad_id = 0;
+      d_input_au = 0;
+      d_input_buffer = d_output_buffer = 0;
+      d_audio_converter = 0;
+      d_using_default_device = false;
+
+#if _OSX_AU_DEBUG_
+      std::cerr << ((void*)(pthread_self()))
+		<< " : audio_osx_source::teardown: Returning." << std::endl;
+#endif
     }
 
     bool
@@ -655,22 +1013,30 @@ namespace gr {
     {
       // check # inputs to make sure it's valid
       if(ninputs != 0) {
-        std::cerr << "audio_osx_source::check_topology(): number of input "
-                  << "streams provided (" << ninputs
-                  << ") should be 0." << std::endl;
-        throw std::runtime_error("audio_osx_source::check_topology()");
+
+        GR_LOG_FATAL(d_logger, boost::format
+		     ("check_topology(): number of input "
+		      "streams provided (%d) should be 0.")
+		     % ninputs);
+        throw std::runtime_error
+	  ("audio_osx_source::check_topology");
+
       }
 
       // check # outputs to make sure it's valid
-      if((noutputs < 1) | (noutputs > (int) d_n_max_channels)) {
-        std::cerr << "audio_osx_source::check_topology(): number of output "
-                  << "streams provided (" << noutputs << ") should be in [1,"
-                  << d_n_max_channels << "] for the selected audio device."
-                  << std::endl;
-        throw std::runtime_error("audio_osx_source::check_topology()");
+      if((noutputs < 1) | (noutputs > (int) d_n_dev_channels)) {
+
+        GR_LOG_FATAL(d_logger, boost::format
+		     ("check_topology(): number of output "
+		      "streams provided (%d) should be in [1,%d] "
+		      "for the selected input audio device.")
+		     % noutputs % d_n_dev_channels);
+        throw std::runtime_error
+	  ("audio_osx_source::check_topology");
       }
 
       // save the actual number of output (user) channels
+
       d_n_user_channels = noutputs;
 
 #if _OSX_AU_DEBUG_
@@ -678,7 +1044,7 @@ namespace gr {
                 << noutputs << std::endl;
 #endif
 
-      return (true);
+      return(true);
     }
 
     int
@@ -686,109 +1052,222 @@ namespace gr {
                      gr_vector_const_void_star &input_items,
                      gr_vector_void_star &output_items)
     {
-      // acquire control to do processing here only
-      gr::thread::scoped_lock l(*d_internal);
+#if _OSX_AU_DEBUG_RENDER_
+      std::cerr << ((void*)(pthread_self()))
+		<< " : audio_osx_source::work: Starting." << std::endl;
+#endif
+      if (d_do_reset) {
+	if (d_hardware_changed) {
 
-#if _OSX_AU_DEBUG_
-      std::cerr << "work1: SC = " << d_queueSampleCount
+	  // see if the current AudioDeviceID is still available
+
+	  std::vector < AudioDeviceID > all_ad_ids;
+	  osx::find_audio_devices
+	    (d_desired_name, true,
+	     &all_ad_ids, NULL);
+	  bool found = false;
+	  for (UInt32 nn = 0; (nn < all_ad_ids.size()) && (!found);
+	       ++nn) {
+	    found = (all_ad_ids[nn] == d_input_ad_id);
+	  }
+	  if (!found) {
+
+	    GR_LOG_FATAL(d_logger, boost::format
+			 ("The selected input audio device ('%s') "
+			  "is no longer available.\n")
+			 % d_selected_name);
+	    return(gr::block::WORK_DONE);
+
+	  }
+
+	  d_do_reset = d_hardware_changed = false;
+
+	} else {
+
+#if _OSX_AU_DEBUG_RENDER_
+	  std::cerr << "audio_osx_source::work: doing reset."
+		    << std::endl;
+#endif
+
+	  GR_LOG_WARN(d_logger, boost::format
+		      ("\n\nThe default input audio device has "
+		       "changed; resetting audio.\nThere may "
+		       "be a sound glitch while resetting.\n"));
+
+	  // for any changes, just tear down the current
+	  // configuration, then set it up again using the user's
+	  // parameters to try to make selections.
+
+	  teardown();
+
+	  gr::thread::scoped_lock l(d_internal);
+
+#if _OSX_AU_DEBUG_RENDER_
+	  std::cerr << "audio_osx_source::work: mutex locked."
+		    << std::endl;
+#endif
+
+	  setup();
+	  start();
+
+#if _OSX_AU_DEBUG_RENDER_
+	  std::cerr << "audio_osx_source::work: returning after reset."
+		    << std::endl;
+#endif
+	  return(0);
+	}
+      }
+
+      gr::thread::scoped_lock l(d_internal);
+
+#if _OSX_AU_DEBUG_RENDER_
+      std::cerr << "audio_osx_source::work: mutex locked." << std::endl;
+#endif
+
+#if _OSX_AU_DEBUG_RENDER_
+      std::cerr << "work1: SC = " << d_queue_sample_count
                 << ", #OI = " << noutput_items
                 << ", #Chan = " << output_items.size() << std::endl;
 #endif
 
       // set the actual # of output items to the 'desired' amount then
-      // verify that data is available; if not enough data is available,
-      // either wait until it is (is "do_block" is true), return (0) is no
-      // data is available and "do_block" is false, or process the actual
-      // amount of available data.
+      // verify that data is available; if not enough data is
+      // available, either wait until it is (is "ok_to_block" is
+      // true), return (0) is no data is available and "ok_to_block"
+      // is false, or process the actual amount of available data.
 
       UInt32 actual_noutput_items = noutput_items;
 
-      if(d_queueSampleCount < actual_noutput_items) {
-        if(d_queueSampleCount == 0) {
-          // no data; do_block decides what to do
-          if(d_do_block == true) {
-            while(d_queueSampleCount == 0) {
+      if(d_queue_sample_count < actual_noutput_items) {
+        if(d_queue_sample_count == 0) {
+          // no data; ok_to_block decides what to do
+          if(d_ok_to_block == true) {
+	    // block until there is data to return, or on reset
+            while(d_queue_sample_count == 0) {
               // release control so-as to allow data to be retrieved;
               // block until there is data to return
-              d_cond_data->wait(l);
+#if _OSX_AU_DEBUG_RENDER_
+	      std::cerr << "audio_osx_source::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_source::work: done waiting."
+			<< std::endl;
+#endif
               // the condition's 'notify' was called; acquire control to
               // keep thread safe
+
+	      // if doing a reset, just return here; reset will pick
+	      // up the next time this method is called.
+	      if (d_do_reset) {
+#if _OSX_AU_DEBUG_RENDER_
+		std::cerr << "audio_osx_source::work: "
+		  "returning for reset." << std::endl;
+#endif
+		return(0);
+	      }
             }
           }
           else {
             // no data & not blocking; return nothing
+#if _OSX_AU_DEBUG_RENDER_
+	    std::cerr << "audio_osx_source::work: no data "
+	      "& not blocking; returning 0." << std::endl;
+#endif
             return (0);
           }
         }
+
         // use the actual amount of available data
-        actual_noutput_items = d_queueSampleCount;
+        actual_noutput_items = d_queue_sample_count;
       }
 
+#if _OSX_AU_DEBUG_RENDER_
+      std::cerr << "audio_osx_source::work: copying "
+		<< actual_noutput_items << " items per channel"
+		<< std::endl;
+#endif
+
       // number of channels
       int l_counter = (int)output_items.size();
 
-      // copy the items from the circular buffer(s) to 'work's output buffers
-      // verify that the number copied out is as expected.
+      // copy the items from the circular buffer(s) to 'work's output
+      // buffers; verify that the number copied out is as expected.
 
       while(--l_counter >= 0) {
+
         size_t t_n_output_items = actual_noutput_items;
-        d_buffers[l_counter]->dequeue((float*)output_items[l_counter],
-                                      &t_n_output_items);
+        d_buffers[l_counter]->dequeue
+	  ((float*)output_items[l_counter],
+	   &t_n_output_items);
+
         if(t_n_output_items != actual_noutput_items) {
-          std::cerr << "audio_osx_source::work(): ERROR: number of "
-                    << "available items changing unexpectedly; expecting "
-                    << actual_noutput_items << ", got "
-                    << t_n_output_items << "." << std::endl;
+
+          GR_LOG_FATAL(d_logger, boost::format
+		       ("work(): ERROR: number of available "
+			"items changing unexpectedly; expecting %d"
+			", got %d.")
+		       % actual_noutput_items % t_n_output_items);
           throw std::runtime_error("audio_osx_source::work()");
+
         }
       }
 
       // subtract the actual number of items removed from the buffer(s)
       // from the local accounting of the number of available samples
 
-      d_queueSampleCount -= actual_noutput_items;
+      d_queue_sample_count -= actual_noutput_items;
 
-#if _OSX_AU_DEBUG_
-      std::cerr << "work2: SC = " << d_queueSampleCount
+#if _OSX_AU_DEBUG_RENDER_
+      std::cerr << "work2: SC = " << d_queue_sample_count
                 << ", act#OI = " << actual_noutput_items << std::endl
                 << "Returning." << std::endl;
 #endif
+#if _OSX_AU_DEBUG_RENDER_
+	std::cerr << "audio_osx_source::work: returning." << std::endl;
+#endif
 
       return (actual_noutput_items);
     }
 
     OSStatus
-    osx_source::ConverterCallback(AudioConverterRef inAudioConverter,
-                                  UInt32* ioNumberDataPackets,
-                                  AudioBufferList* ioData,
-                                  AudioStreamPacketDescription** ioASPD,
-                                  void* inUserData)
+    osx_source::converter_callback
+    (AudioConverterRef in_audio_converter,
+     UInt32* io_number_data_packets,
+     AudioBufferList* io_data,
+     AudioStreamPacketDescription** out_aspd,
+     void* in_user_data)
     {
-      // take current device buffers and copy them to the tail of the
-      // input buffers the lead buffer is already there in the first
-      // d_leadSizeFrames slots
-
-      osx_source* This = static_cast<osx_source*>(inUserData);
-      AudioBufferList* l_inputABL = This->d_InputBuffer;
-      UInt32 totalInputBufferSizeBytes = ((*ioNumberDataPackets) * sizeof(float));
-      int counter = This->d_n_deviceChannels;
-      ioData->mNumberBuffers = This->d_n_deviceChannels;
-      This->d_n_ActualInputFrames = (*ioNumberDataPackets);
-
-#if _OSX_AU_DEBUG_
-      std::cerr << "cc1: io#DP = " << (*ioNumberDataPackets)
-                << ", TIBSB = " << totalInputBufferSizeBytes
+      // This callback is for us to provide the buffers to CoreAudio
+      // for conversion.  We need to set the buffers in the provided
+      // buffer list (io_data) to the buffers we know about and use to
+      // do data input (d_input_buffers).
+
+      osx_source* This = static_cast<osx_source*>(in_user_data);
+      AudioBufferList* l_input_abl = This->d_input_buffer;
+      UInt32 total_input_buffer_size_bytes =
+	((*io_number_data_packets) * sizeof(float));
+      int counter = This->d_n_dev_channels;
+      io_data->mNumberBuffers = This->d_n_dev_channels;
+      This->d_n_actual_input_frames = (*io_number_data_packets);
+
+#if _OSX_AU_DEBUG_RENDER_
+      std::cerr << "cc1: io#DP = " << (*io_number_data_packets)
+                << ", TIBSB = " << total_input_buffer_size_bytes
                 << ", #C = " << counter << std::endl;
 #endif
 
       while(--counter >= 0) {
-        AudioBuffer* l_ioD_AB = &(ioData->mBuffers[counter]);
-        l_ioD_AB->mNumberChannels = 1;
-        l_ioD_AB->mData = (float*)(l_inputABL->mBuffers[counter].mData);
-        l_ioD_AB->mDataByteSize = totalInputBufferSizeBytes;
+        AudioBuffer* t_ab = &(io_data->mBuffers[counter]);
+        t_ab->mNumberChannels = 1;
+        t_ab->mData = l_input_abl->mBuffers[counter].mData;
+        t_ab->mDataByteSize = total_input_buffer_size_bytes;
       }
 
-#if _OSX_AU_DEBUG_
+#if _OSX_AU_DEBUG_RENDER_
       std::cerr << "cc2: Returning." << std::endl;
 #endif
 
@@ -796,59 +1275,89 @@ namespace gr {
     }
 
     OSStatus
-    osx_source::AUInputCallback(void* inRefCon,
-                                AudioUnitRenderActionFlags* ioActionFlags,
-                                const AudioTimeStamp* inTimeStamp,
-                                UInt32 inBusNumber,
-                                UInt32 inNumberFrames,
-                                AudioBufferList* ioData)
+    osx_source::au_input_callback
+    (void *in_ref_con,
+     AudioUnitRenderActionFlags *io_action_flags,
+     const AudioTimeStamp *in_time_stamp,
+     UInt32 in_bus_number,
+     UInt32 in_number_frames,
+     AudioBufferList *io_data)
     {
-      OSStatus err = noErr;
-      osx_source* This = static_cast<osx_source*>(inRefCon);
+#if _OSX_AU_DEBUG_RENDER_
+      std::cerr << ((void*)(pthread_self()))
+		<< " : audio_osx_source::au_input_callback: Starting."
+		<< std::endl;
+#endif
 
-      gr::thread::scoped_lock l(*This->d_internal);
+      osx_source* This = reinterpret_cast
+	<osx_source*>(in_ref_con);
+      gr::thread::scoped_lock l(This->d_internal);
+      gr::logger_ptr d_logger = This->d_logger;
 
-#if _OSX_AU_DEBUG_
-      std::cerr << "cb0: in#F = " << inNumberFrames
-                << ", inBN = " << inBusNumber
-                << ", SC = " << This->d_queueSampleCount << std::endl;
+#if _OSX_AU_DEBUG_RENDER_
+      std::cerr << "audio_osx_source::au_input_callback: mutex locked."
+		<< std::endl;
 #endif
 
-      // Get the new audio data from the input device
+      OSStatus err = noErr;
 
-      err = AudioUnitRender(This->d_InputAU,
-                            ioActionFlags,
-                            inTimeStamp,
-                            1, //inBusNumber,
-                            inNumberFrames,
-                            This->d_InputBuffer);
-      CheckErrorAndThrow(err, "AudioUnitRender",
-                         "audio_osx_source::AUInputCallback");
+#if _OSX_AU_DEBUG_RENDER_
+      std::cerr << "cb0: in#Fr = " << in_number_frames
+                << ", inBus# = " << in_bus_number
+		<< ", idD = " << ((void*)io_data)
+		<< ", d_ib = " << ((void*)(This->d_input_buffer))
+		<< ", d_ib#c = " << This->d_input_buffer->mNumberBuffers
+                << ", SC = " << This->d_queue_sample_count << std::endl;
+#endif
 
-      UInt32 AvailableInputFrames = inNumberFrames;
-      This->d_n_AvailableInputFrames = inNumberFrames;
+      if (This->d_do_reset) {
 
-      // get the number of actual output frames,
-      // either via converting the buffer or not
+	// clear audio data; do not render since it will generate an error
+
+	AudioBufferList* t_abl = This->d_input_buffer;
+	for (UInt32 nn = 0; nn < t_abl->mNumberBuffers; ++nn) {
+	  AudioBuffer* t_ab = &(t_abl->mBuffers[nn]);
+	  memset(t_ab->mData, 0, (size_t)((t_ab->mDataByteSize) *
+					  (t_ab->mNumberChannels)));
+	}
+      } else {
+
+	// Get the new audio data from the input device
 
-      UInt32 ActualOutputFrames;
+	err = AudioUnitRender
+	  (This->d_input_au, io_action_flags,
+	   in_time_stamp, 1, //inBusNumber,
+	   in_number_frames, This->d_input_buffer);
+	check_error_and_throw
+	  (err, "AudioUnitRender",
+	   "audio_osx_source::au_input_callback");
 
-      if(This->d_passThrough == true) {
-        ActualOutputFrames = AvailableInputFrames;
       }
-      else {
-        UInt32 AvailableInputBytes = AvailableInputFrames * sizeof(float);
-        UInt32 AvailableOutputBytes = AvailableInputBytes;
-        UInt32 AvailableOutputFrames = AvailableOutputBytes / sizeof(float);
-        UInt32 propertySize = sizeof (AvailableOutputBytes);
-        err = AudioConverterGetProperty(This->d_AudioConverter,
-                                        kAudioConverterPropertyCalculateOutputBufferSize,
-                                        &propertySize,
-                                        &AvailableOutputBytes);
-        CheckErrorAndThrow(err, "AudioConverterGetProperty CalculateOutputBufferSize",
-                           "audio_osx_source::audio_osx_source");
-
-        AvailableOutputFrames = AvailableOutputBytes / sizeof(float);
+
+      UInt32 available_input_frames =
+	This->d_n_available_input_frames = in_number_frames;
+
+      // get the number of actual output frames,
+      // either via converting the buffer or not
+
+      UInt32 actual_output_frames = available_input_frames;
+
+      if(!This->d_pass_through) {
+        UInt32 available_input_bytes =
+	  available_input_frames * sizeof(float);
+        UInt32 available_output_bytes = available_input_bytes;
+        UInt32 prop_size = sizeof(available_output_bytes);
+        err = AudioConverterGetProperty
+	  (This->d_audio_converter,
+	   kAudioConverterPropertyCalculateOutputBufferSize,
+	   &prop_size,
+	   &available_output_bytes);
+        check_error_and_throw
+	  (err, "Get Output Buffer Size failed",
+	   "audio_osx_source::au_input_callback");
+
+        UInt32 available_output_frames =
+	  available_output_bytes / sizeof(float);
 
 #if 0
         // when decimating too much, the output sounds warbly due to
@@ -857,65 +1366,73 @@ namespace gr {
         // clever programming that could lessed the effect ...
         // like finding the "ideal" # of output frames, and keeping
         // that number constant no matter the # of input frames
-        UInt32 l_InputBytes = AvailableOutputBytes;
-        propertySize = sizeof(AvailableOutputBytes);
-        err = AudioConverterGetProperty(This->d_AudioConverter,
-                                        kAudioConverterPropertyCalculateInputBufferSize,
-                                        &propertySize,
-                                        &l_InputBytes);
-        CheckErrorAndThrow(err, "AudioConverterGetProperty CalculateInputBufferSize",
-                           "audio_osx_source::audio_osx_source");
-
-        if(l_InputBytes < AvailableInputBytes) {
+
+        UInt32 l_input_bytes = available_output_bytes;
+        prop_size = sizeof(available_output_bytes);
+        err = AudioConverterGetProperty
+	  (This->d_audio_converter,
+	   kAudioConverterPropertyCalculateInputBufferSize,
+	   &prop_size, &l_input_bytes);
+        check_error_and_throw
+	  (err, "Get Input Buffer Size failed",
+	   "audio_osx_source::au_input_callback");
+
+        if(l_input_bytes < available_input_bytes) {
           // OK to zero pad the input a little
-          AvailableOutputFrames += 1;
-          AvailableOutputBytes = AvailableOutputFrames * sizeof(float);
+          ++available_output_frames;
+          available_output_bytes = available_output_frames * sizeof(float);
         }
-#endif
 
-#if _OSX_AU_DEBUG_
-        std::cerr << "cb1:  avail: #IF = " << AvailableInputFrames
-                  << ", #OF = " << AvailableOutputFrames << std::endl;
 #endif
-        ActualOutputFrames = AvailableOutputFrames;
-
-        // convert the data to the correct rate
-        // on input, ActualOutputFrames is the number of available output frames
 
-        err = AudioConverterFillComplexBuffer(This->d_AudioConverter,
-                                              (AudioConverterComplexInputDataProc)
-                                              (This->ConverterCallback),
-                                              inRefCon,
-                                              &ActualOutputFrames,
-                                              This->d_OutputBuffer,
-                                              NULL);
-        CheckErrorAndThrow(err, "AudioConverterFillComplexBuffer",
-                           "audio_osx_source::AUInputCallback");
-
-        // on output, ActualOutputFrames is the actual number of output frames
-
-#if _OSX_AU_DEBUG_
-        std::cerr << "cb2: actual: #IF = " << This->d_n_ActualInputFrames
-                  << ", #OF = " << AvailableOutputFrames << std::endl;
-        if(This->d_n_ActualInputFrames != AvailableInputFrames)
-          std::cerr << "cb2.1: avail#IF = " << AvailableInputFrames
-                    << ", actual#IF = " << This->d_n_ActualInputFrames << std::endl;
+#if _OSX_AU_DEBUG_RENDER_
+        std::cerr << "cb1:  avail: #IF = " << available_input_frames
+                  << ", #OF = " << available_output_frames << std::endl;
+#endif
+        actual_output_frames = available_output_frames;
+
+        // convert the data to the correct rate; on input,
+        // actual_output_frames is the number of available output frames
+
+        err = AudioConverterFillComplexBuffer
+	  (This->d_audio_converter,
+	   reinterpret_cast<AudioConverterComplexInputDataProc>
+	     (&(This->converter_callback)),
+	   in_ref_con,
+	   &actual_output_frames,
+	   This->d_output_buffer,
+	   NULL);
+        check_error_and_throw
+	  (err, "AudioConverterFillComplexBuffer failed",
+	   "audio_osx_source::au_input_callback");
+
+        // on output, actual_output_frames is the actual number of
+        // output frames
+
+#if _OSX_AU_DEBUG_RENDER_
+        std::cerr << "cb2: actual: #IF = " << This->d_n_actual_input_frames
+                  << ", #OF = " << actual_output_frames << std::endl;
+        if(This->d_n_actual_input_frames != available_input_frames)
+          std::cerr << "cb2.1: avail#IF = " << available_input_frames
+                    << ", actual#IF = " << This->d_n_actual_input_frames << std::endl;
 #endif
       }
 
       // add the output frames to the buffers' queue, checking for overflow
 
-      int l_counter = This->d_n_user_channels;
+      int counter = This->d_n_user_channels;
       int res = 0;
 
-      while(--l_counter >= 0) {
-        float* inBuffer = (float*) This->d_OutputBuffer->mBuffers[l_counter].mData;
+      while(--counter >= 0) {
+        float* in_buffer = (float*)
+	  This->d_output_buffer->mBuffers[counter].mData;
 
-#if _OSX_AU_DEBUG_
+#if _OSX_AU_DEBUG_RENDER_
         std::cerr << "cb3: enqueuing audio data." << std::endl;
 #endif
 
-        int l_res = This->d_buffers[l_counter]->enqueue(inBuffer, ActualOutputFrames);
+        int l_res = This->d_buffers[counter]->enqueue
+	  (in_buffer, actual_output_frames);
         if(l_res == -1)
           res = -1;
       }
@@ -926,152 +1443,80 @@ namespace gr {
         fputs("aO", stderr);
         fflush(stderr);
         // set the local number of samples available to the max
-        This->d_queueSampleCount = This->d_buffers[0]->buffer_length_items();
+        This->d_queue_sample_count =
+	  This->d_buffers[0]->buffer_length_items();
       }
       else {
         // keep up the local sample count
-        This->d_queueSampleCount += ActualOutputFrames;
+        This->d_queue_sample_count += actual_output_frames;
       }
 
-#if _OSX_AU_DEBUG_
-      std::cerr << "cb4: #OI = " << ActualOutputFrames
-                << ", #Cnt = " << This->d_queueSampleCount
-                << ", mSC = " << This->d_max_sample_count << std::endl;
+#if _OSX_AU_DEBUG_RENDER_
+      std::cerr << "cb4: #OI = " << actual_output_frames
+                << ", #Cnt = " << This->d_queue_sample_count
+                << ", mSC = " << This->d_buffer_sample_count << std::endl;
 #endif
 
       // signal that data is available, if appropraite
-      This->d_cond_data->notify_one();
 
-#if _OSX_AU_DEBUG_
+      if (This->d_waiting_for_data) {
+	This->d_cond_data.notify_one();
+      }
+
+#if _OSX_AU_DEBUG_RENDER_
       std::cerr << "cb5: returning." << std::endl;
 #endif
 
-      return (err);
+      return(err);
     }
 
-    void
-    osx_source::SetDefaultInputDeviceAsCurrent()
-    {
-      // set the default input device
-      AudioDeviceID deviceID = 0;
-      UInt32 dataSize = sizeof (AudioDeviceID);
-      OSStatus err = noErr;
-
 #ifndef GR_USE_OLD_AUDIO_UNIT
-      AudioObjectPropertyAddress theAddress =
-        { kAudioHardwarePropertyDefaultInputDevice,
-          kAudioObjectPropertyScopeGlobal,
-          kAudioObjectPropertyElementMaster };
-
-      err = AudioObjectGetPropertyData(kAudioObjectSystemObject,
-                                       &theAddress,
-                                       0,
-                                       NULL,
-                                       &dataSize,
-                                       &deviceID);
-#else
-      err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
-                                     &dataSize,
-                                     &deviceID);
-#endif
-
-      CheckErrorAndThrow(err, "Get Audio Unit Property for Current Device",
-                         "audio_osx_source::SetDefaultInputDeviceAsCurrent");
-
-      err = AudioUnitSetProperty(d_InputAU,
-                                 kAudioOutputUnitProperty_CurrentDevice,
-                                 kAudioUnitScope_Global,
-                                 0,
-                                 &deviceID,
-                                 sizeof(AudioDeviceID));
 
-      CheckErrorAndThrow(err, "AudioUnitSetProperty Current Device",
-                         "audio_osx_source::SetDefaultInputDeviceAsCurrent");
-}
-
-#if _OSX_DO_LISTENERS_
     OSStatus
-    osx_source::HardwareListener(AudioHardwarePropertyID inPropertyID,
-                                 void *inClientData)
-    {
-      OSStatus err = noErr;
-      osx_source* This = static_cast<osx_source*>(inClientData);
-
-      std::cerr << "a_o_s::HardwareListener" << std::endl;
-
-      // set the new default hardware input device for use by our AU
+    osx_source::hardware_listener
+    (AudioObjectID in_object_id,
+     UInt32 in_num_addresses,
+     const AudioObjectPropertyAddress in_addresses[],
+     void* in_client_data)
 
-      This->SetDefaultInputDeviceAsCurrent();
-
-      // reset the converter to tell it that the stream has changed
-
-      err = AudioConverterReset(This->d_AudioConverter);
-      CheckErrorAndThrow(err, "AudioConverterReset",
-                         "audio_osx_source::UnitListener");
-
-      return (err);
-    }
+#else
 
     OSStatus
-    osx_source::UnitListener(void *inRefCon,
-                             AudioUnit ci,
-                             AudioUnitPropertyID inID,
-                             AudioUnitScope inScope,
-                             AudioUnitElement inElement)
-    {
-      OSStatus err = noErr;
-      osx_source* This = static_cast<osx_source*>(inRefCon);
-      AudioStreamBasicDescription asbd;
-
-      std::cerr << "a_o_s::UnitListener" << std::endl;
-
-      // get the converter's input ASBD (for printing)
-
-      UInt32 propertySize = sizeof(asbd);
-      err = AudioConverterGetProperty(This->d_AudioConverter,
-                                      kAudioConverterCurrentInputStreamDescription,
-                                      &propertySize,
-                                      &asbd);
-      CheckErrorAndThrow(err, "AudioConverterGetProperty "
-                         "CurrentInputStreamDescription",
-                         "audio_osx_source::UnitListener");
-
-      std::cerr << "UnitListener: Input Source changed." << std::endl
-                << "Old Source Output Info:" << std::endl;
-      PrintStreamDesc(&asbd);
-
-      // get the new input unit's output ASBD
-
-      propertySize = sizeof(asbd);
-      err = AudioUnitGetProperty(This->d_InputAU,
-                                 kAudioUnitProperty_StreamFormat,
-                                 kAudioUnitScope_Output, 1,
-                                 &asbd, &propertySize);
-      CheckErrorAndThrow(err, "AudioUnitGetProperty StreamFormat",
-                         "audio_osx_source::UnitListener");
+    osx_source::hardware_listener
+    (AudioHardwarePropertyID in_property_id,
+     void* in_client_data)
 
-      std::cerr << "New Source Output Info:" << std::endl;
-      PrintStreamDesc(&asbd);
+#endif
+    {
+      osx_source* This = reinterpret_cast
+	<osx_source*>(in_client_data);
+      This->reset(true);
+      return(noErr);
+    }
 
-      // set the converter's input ASBD to this
+#ifndef GR_USE_OLD_AUDIO_UNIT
 
-      err = AudioConverterSetProperty(This->d_AudioConverter,
-                                      kAudioConverterCurrentInputStreamDescription,
-                                      propertySize,
-                                      &asbd);
-      CheckErrorAndThrow(err, "AudioConverterSetProperty "
-                         "CurrentInputStreamDescription",
-                         "audio_osx_source::UnitListener");
+    OSStatus
+    osx_source::default_listener
+    (AudioObjectID in_object_id,
+     UInt32 in_num_addresses,
+     const AudioObjectPropertyAddress in_addresses[],
+     void* in_client_data)
 
-      // reset the converter to tell it that the stream has changed
+#else
 
-      err = AudioConverterReset(This->d_AudioConverter);
-      CheckErrorAndThrow(err, "AudioConverterReset",
-                         "audio_osx_source::UnitListener");
+    OSStatus
+    osx_source::default_listener
+    (AudioHardwarePropertyID in_property_id,
+     void* in_client_data)
 
-      return (err);
+#endif
+    {
+      osx_source* This = reinterpret_cast
+	<osx_source*>(in_client_data);
+      This->reset(false);
+      return(noErr);
     }
-#endif /* _OSX_DO_LISTENERS_ */
 
   } /* namespace audio */
 } /* namespace gr */
-- 
cgit v1.2.3