commit-gnuradio
[Top][All Lists]
Advanced

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

[Commit-gnuradio] [gnuradio] 01/06: fix gr-audio osx: + use GNU Radio pr


From: git
Subject: [Commit-gnuradio] [gnuradio] 01/06: 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.
Date: Sat, 8 Mar 2014 16:32:44 +0000 (UTC)

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

trondeau pushed a commit to branch master
in repository gnuradio.

commit 6e0895cb3cbc355060eab037ef74b8e237dcf133
Author: Michael Dickens <address@hidden>
Date:   Fri Mar 7 11:10:07 2014 -0500

    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/CMakeLists.txt                        |    2 +-
 gr-audio/include/gnuradio/audio/CMakeLists.txt |   14 +-
 gr-audio/include/gnuradio/audio/osx_impl.h     |   84 ++
 gr-audio/lib/CMakeLists.txt                    |    9 +
 gr-audio/lib/osx/gr-audio-osx.conf             |   11 +
 gr-audio/lib/osx/osx_common.h                  |   73 +
 gr-audio/lib/osx/osx_impl.cc                   |  313 ++++
 gr-audio/lib/osx/osx_impl.h                    |   78 -
 gr-audio/lib/osx/osx_sink.cc                   | 1015 ++++++++++---
 gr-audio/lib/osx/osx_sink.h                    |  117 +-
 gr-audio/lib/osx/osx_source.cc                 | 1881 +++++++++++++++---------
 gr-audio/lib/osx/osx_source.h                  |  192 ++-
 12 files changed, 2648 insertions(+), 1141 deletions(-)

diff --git a/gr-audio/CMakeLists.txt b/gr-audio/CMakeLists.txt
index ad39105..99e0bc1 100644
--- a/gr-audio/CMakeLists.txt
+++ b/gr-audio/CMakeLists.txt
@@ -86,8 +86,8 @@ CPACK_COMPONENT("audio_swig"
 ########################################################################
 # Add subdirectories
 ########################################################################
-add_subdirectory(include/gnuradio/audio)
 add_subdirectory(lib)
+add_subdirectory(include/gnuradio/audio)
 add_subdirectory(doc)
 if(ENABLE_PYTHON)
     add_subdirectory(swig)
diff --git a/gr-audio/include/gnuradio/audio/CMakeLists.txt 
b/gr-audio/include/gnuradio/audio/CMakeLists.txt
index 1cfbb9b..7e068e3 100644
--- a/gr-audio/include/gnuradio/audio/CMakeLists.txt
+++ b/gr-audio/include/gnuradio/audio/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2011,2013 Free Software Foundation, Inc.
+# Copyright 2011,2013-2014 Free Software Foundation, Inc.
 #
 # This file is part of GNU Radio
 #
@@ -20,10 +20,14 @@
 ########################################################################
 # Install header files
 ########################################################################
-install(FILES
-    api.h
-    source.h
-    sink.h
+
+SET(gr_audio_install_files api.h source.h sink.h)
+
+if(OSX_AUDIO_VALID)
+    list(APPEND gr_audio_install_files osx_impl.h)
+endif(OSX_AUDIO_VALID)
+
+install(FILES ${gr_audio_install_files}
     DESTINATION ${GR_INCLUDE_DIR}/gnuradio/audio
     COMPONENT "audio_devel"
 )
diff --git a/gr-audio/include/gnuradio/audio/osx_impl.h 
b/gr-audio/include/gnuradio/audio/osx_impl.h
new file mode 100644
index 0000000..891685a
--- /dev/null
+++ b/gr-audio/include/gnuradio/audio/osx_impl.h
@@ -0,0 +1,84 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006, 2013-2014 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio.
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_AUDIO_OSX_IMPL_H
+#define INCLUDED_AUDIO_OSX_IMPL_H
+
+#include <gnuradio/audio/api.h>
+
+#include <iostream>
+#include <vector>
+
+#include <string.h>
+
+#include <AudioToolbox/AudioToolbox.h>
+#include <AudioUnit/AudioUnit.h>
+
+namespace gr {
+namespace audio {
+namespace osx {
+
+// Check the version of MacOSX being used
+#ifdef __APPLE_CC__
+#include <AvailabilityMacros.h>
+#ifndef MAC_OS_X_VERSION_10_6
+#define MAC_OS_X_VERSION_10_6 1060
+#endif
+#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
+#define GR_USE_OLD_AUDIO_UNIT
+#endif
+#endif
+
+// helper function to print an ASBD
+
+extern std::ostream& GR_AUDIO_API
+operator<<
+(std::ostream& s,
+ const AudioStreamBasicDescription& asbd);
+
+// returns the number of channels for the provided AudioDeviceID,
+// input and/or output depending on if the pointer is valid.
+
+extern void GR_AUDIO_API
+get_num_channels_for_audio_device_id
+(AudioDeviceID ad_id,
+ UInt32* n_input,
+ UInt32* n_output);
+
+// search all known audio devices, input or output, for all that
+// match the provided device_name string (in part or in whole).
+// Returns a vector of all matching IDs, and another of all
+// matching names.  If the device name is empty, then match all
+// input or output devices.
+
+extern void GR_AUDIO_API
+find_audio_devices
+(const std::string& device_name,
+ bool is_input,
+ std::vector < AudioDeviceID >* all_ad_ids,
+ std::vector < std::string >* all_names);
+
+} /* namespace osx */
+} /* namespace audio */
+} /* namespace gr */
+
+#endif /* INCLUDED_AUDIO_OSX_IMPL_H */
diff --git a/gr-audio/lib/CMakeLists.txt b/gr-audio/lib/CMakeLists.txt
index 4eb6f8e..f07373d 100644
--- a/gr-audio/lib/CMakeLists.txt
+++ b/gr-audio/lib/CMakeLists.txt
@@ -106,6 +106,8 @@ CHECK_INCLUDE_FILE_CXX(AudioToolbox/AudioToolbox.h 
AUDIO_TOOLBOX_H)
 
 if(AUDIO_UNIT_H AND AUDIO_TOOLBOX_H)
 
+    set(OSX_AUDIO_VALID 1 CACHE INTERNAL "OSX Audio is valid")
+
     include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/osx)
     list(APPEND gr_audio_libs
         "-framework AudioUnit"
@@ -114,10 +116,17 @@ if(AUDIO_UNIT_H AND AUDIO_TOOLBOX_H)
         "-framework Carbon"
     )
     list(APPEND gr_audio_sources
+        ${CMAKE_CURRENT_SOURCE_DIR}/osx/osx_impl.cc
         ${CMAKE_CURRENT_SOURCE_DIR}/osx/osx_source.cc
         ${CMAKE_CURRENT_SOURCE_DIR}/osx/osx_sink.cc
     )
 
+    list(APPEND gr_audio_confs 
${CMAKE_CURRENT_SOURCE_DIR}/osx/gr-audio-osx.conf)
+
+else(AUDIO_UNIT_H AND AUDIO_TOOLBOX_H)
+
+    set(OSX_AUDIO_VALID 0 CACHE INTERNAL "OSX Audio is not valid")
+
 endif(AUDIO_UNIT_H AND AUDIO_TOOLBOX_H)
 
 ########################################################################
diff --git a/gr-audio/lib/osx/gr-audio-osx.conf 
b/gr-audio/lib/osx/gr-audio-osx.conf
new file mode 100644
index 0000000..a4fed33
--- /dev/null
+++ b/gr-audio/lib/osx/gr-audio-osx.conf
@@ -0,0 +1,11 @@
+# This file contains system wide configuration data for GNU Radio.
+# You may override any setting on a per-user basis by editing
+# ~/.gnuradio/config.conf.  For OSX audio only, you can use a unique
+# subset of the actual device name to set these variables.  By this
+# default, the OSX audio will use whatever devices are selected in
+# System Preferences::Sound for input and output.
+
+[audio_osx]
+
+default_input_device = 
+default_output_device = 
diff --git a/gr-audio/lib/osx/osx_common.h b/gr-audio/lib/osx/osx_common.h
new file mode 100644
index 0000000..34266f2
--- /dev/null
+++ b/gr-audio/lib/osx/osx_common.h
@@ -0,0 +1,73 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2014 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio.
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_AUDIO_OSX_COMMON_H
+#define INCLUDED_AUDIO_OSX_COMMON_H
+
+#include <gnuradio/audio/osx_impl.h>
+
+namespace gr {
+namespace audio {
+namespace osx {
+
+#define _OSX_AU_DEBUG_ 0
+#define _OSX_AU_DEBUG_RENDER_ 0
+
+#define check_error_and_throw(err,what,throw_str)                      \
+  if(err) {                                                             \
+    OSStatus error = static_cast<OSStatus>(err);                        \
+    char err_str[5];                                                    \
+    *((UInt32*)err_str) = error;                                       \
+    err_str[4] = 0;                                                    \
+    GR_LOG_FATAL(d_logger, boost::format(what));                       \
+    GR_LOG_FATAL(d_logger, boost::format("  Error# %u ('%s')")         \
+                % error % err_str);                                    \
+    GR_LOG_FATAL(d_logger, boost::format("  %s:%d")                    \
+                % __FILE__ %__LINE__);                                 \
+    throw std::runtime_error(throw_str);                                \
+  }
+
+#define check_error(err,what)                                           \
+  if(err) {                                                             \
+    OSStatus error = static_cast<OSStatus>(err);                        \
+    char err_str[5];                                                    \
+    *((UInt32*)err_str) = error;                                       \
+    err_str[4] = 0;                                                    \
+    GR_LOG_WARN(d_logger, boost::format(what));                                
\
+    GR_LOG_WARN(d_logger, boost::format("  Error# %u ('%s')")          \
+                  % error % err_str);                                  \
+    GR_LOG_WARN(d_logger, boost::format("  %s:%d")                     \
+                  % __FILE__ %__LINE__);                               \
+  }
+
+#include <boost/detail/endian.hpp> //BOOST_BIG_ENDIAN
+#ifdef BOOST_BIG_ENDIAN
+#define GR_PCM_ENDIANNESS kLinearPCMFormatFlagIsBigEndian
+#else
+#define GR_PCM_ENDIANNESS 0
+#endif
+
+} /* namespace osx */
+} /* namespace audio */
+} /* namespace gr */
+
+#endif /* INCLUDED_AUDIO_OSX_COMMON_H */
diff --git a/gr-audio/lib/osx/osx_impl.cc b/gr-audio/lib/osx/osx_impl.cc
new file mode 100644
index 0000000..c4e580b
--- /dev/null
+++ b/gr-audio/lib/osx/osx_impl.cc
@@ -0,0 +1,313 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2014 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio.
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "audio_registry.h"
+
+#include <gnuradio/audio/osx_impl.h>
+
+#include <algorithm>
+#include <iostream>
+#include <locale>
+#include <stdexcept>
+
+namespace gr {
+namespace audio {
+namespace osx {
+
+std::ostream&
+operator<<
+(std::ostream& s,
+ const AudioStreamBasicDescription& asbd)
+{
+  char format_id[5];
+  *((UInt32*)format_id) = asbd.mFormatID;
+  format_id[4] = 0;
+  s << "  Sample Rate      : " << asbd.mSampleRate << std::endl;
+  s << "  Format ID        : " << format_id << std::endl;
+  s << "  Format Flags     : " << asbd.mFormatFlags << std::endl;
+  s << "    " << ((asbd.mFormatFlags & kAudioFormatFlagIsFloat) != 0)
+    << " : Is Float" << std::endl;
+  s << "    " << ((asbd.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0)
+    << " : Is Big Endian" << std::endl;
+  s << "    " << ((asbd.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
+    << " : Is Signed Integer" << std::endl;
+  s << "    " << ((asbd.mFormatFlags & kAudioFormatFlagIsPacked) != 0)
+    << " : Is Packed" << std::endl;
+  s << "    " << ((asbd.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0)
+    << " : Is Aligned High" << std::endl;
+  s << "    " << ((asbd.mFormatFlags & kAudioFormatFlagIsNonInterleaved) != 0)
+    << " : Is Non-Interleaved" << std::endl;
+  s << "    " << ((asbd.mFormatFlags & kAudioFormatFlagIsNonMixable) != 0)
+    << " : Is Non-Mixable" << std::endl;
+  s << "  Bytes / Packet   : " << asbd.mBytesPerPacket << std::endl;
+  s << "  Frames / Packet  : " << asbd.mFramesPerPacket << std::endl;
+  s << "  Bytes / Frame    : " << asbd.mBytesPerFrame << std::endl;
+  s << "  Channels / Frame : " << asbd.mChannelsPerFrame << std::endl;
+  s << "  Bits / Channel   : " << asbd.mBitsPerChannel;
+  return(s);
+};
+
+static UInt32
+_get_num_channels
+(AudioDeviceID ad_id,
+ AudioObjectPropertyScope scope)
+{
+  // retrieve the AudioBufferList associated with this ID using
+  // the provided scope
+
+  UInt32 num_channels = 0;
+  UInt32 prop_size = 0;
+  AudioObjectPropertyAddress ao_address = {
+    kAudioDevicePropertyStreamConfiguration, scope, 0
+  };
+  OSStatus err = noErr;
+  if ((err = AudioObjectGetPropertyDataSize
+       (ad_id, &ao_address, 0, NULL,
+       &prop_size)) == noErr) {
+    boost::scoped_array<AudioBufferList> buf_list
+      (reinterpret_cast<AudioBufferList*>
+       (new char[prop_size]));
+    if ((err = AudioObjectGetPropertyData
+        (ad_id, &ao_address, 0, NULL,
+         &prop_size, buf_list.get())) == noErr) {
+      for (UInt32 mm = 0; mm < buf_list.get()->mNumberBuffers; ++mm) {
+       num_channels += buf_list.get()->mBuffers[mm].mNumberChannels;
+      }
+    }
+    else {
+      // assume 2 channels
+      num_channels = 2;
+    }
+  }
+  else {
+    // assume 2 channels
+    num_channels = 2;
+  }
+  return(num_channels);
+}
+
+// works with both char and wchar_t
+template<typename charT>
+struct ci_equal {
+  ci_equal( const std::locale& loc ) : loc_(loc) {}
+  bool operator()(charT ch1, charT ch2) {
+    return std::tolower(ch1, loc_) == std::tolower(ch2, loc_);
+  }
+private:
+  const std::locale& loc_;
+};
+
+// find substring (case insensitive)
+static std::string::size_type ci_find_substr
+(const std::string& str1, const std::string& str2,
+ const std::locale& loc = std::locale())
+{
+  std::string::const_iterator it = std::search
+    (str1.begin(), str1.end(),
+     str2.begin(), str2.end(),
+     ci_equal<std::string::value_type>(loc));
+  if (it != str1.end()) {
+    return(it - str1.begin());
+  }
+  // not found
+  return(std::string::npos);
+}
+
+void
+get_num_channels_for_audio_device_id
+(AudioDeviceID ad_id,
+ UInt32* n_input,
+ UInt32* n_output)
+{
+  if (n_input) {
+    *n_input = _get_num_channels
+      (ad_id, kAudioDevicePropertyScopeInput);
+  }
+  if (n_output) {
+    *n_output = _get_num_channels
+      (ad_id, kAudioDevicePropertyScopeOutput);
+  }
+}
+
+void
+find_audio_devices
+(const std::string& device_name,
+ bool is_input,
+ std::vector < AudioDeviceID >* all_ad_ids,
+ std::vector < std::string >* all_names)
+{
+  if ((!all_ad_ids) && (!all_names)) {
+    // if nothing is requested, no point in doing anything!
+    return;
+  }
+
+  OSStatus err = noErr;
+
+  // set the default audio device id to "unknown"
+
+  AudioDeviceID d_ad_id = kAudioDeviceUnknown;
+
+  // retrieve the size of the array of known audio device IDs
+
+  UInt32 prop_size = 0;
+
+  AudioObjectPropertyAddress ao_address = {
+    kAudioHardwarePropertyDevices,
+    kAudioObjectPropertyScopeGlobal,
+    kAudioObjectPropertyElementMaster
+  };
+
+  if ((err = AudioObjectGetPropertyDataSize
+       (kAudioObjectSystemObject, &ao_address,
+       0, NULL, &prop_size)) != noErr) {
+#if _OSX_AU_DEBUG_
+    std::cerr << "audio_osx::find_audio_devices: "
+             << "Unable to retrieve number of audio objects: "
+             << err << std::endl;
+#endif
+    return;
+  }
+
+  // get the total number of audio devices (input and output)
+
+  UInt32 num_devices = prop_size / sizeof(AudioDeviceID);
+
+  // retrieve all audio device ids
+
+  boost::scoped_array < AudioDeviceID > all_dev_ids
+    (new AudioDeviceID[num_devices]);
+
+  if ((err = AudioObjectGetPropertyData
+       (kAudioObjectSystemObject, &ao_address,
+       0, NULL, &prop_size, all_dev_ids.get())) != noErr) {
+#if _OSX_AU_DEBUG_
+    std::cerr << "audio_osx::find_audio_devices: "
+             << "Unable to retrieve audio object ids: "
+             << err << std::endl;
+#endif
+    return;
+  }
+
+  // success; loop over all retrieved output device ids, retrieving
+  // the name for each and comparing with the desired name.
+
+  std::vector< std::string > valid_names(num_devices);
+  std::vector< UInt32 > valid_indices(num_devices);
+  UInt32 num_found_devices = 0;
+  AudioObjectPropertyScope scope = is_input ?
+    kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
+
+  for (UInt32 nn = 0; nn < num_devices; ++nn) {
+
+    // make sure this device has input / output channels (it might
+    // also have output / input channels, too, but we do not care
+    // about that here)
+
+    AudioDeviceID t_id = all_dev_ids[nn];
+
+    if (is_input) {
+      UInt32 n_input_channels = 0;
+      get_num_channels_for_audio_device_id
+       (t_id, &n_input_channels, NULL);
+      if (n_input_channels == 0) {
+       // no input channels; must be output device; just continue
+       // to the next audio device.
+       continue;
+      }
+    } else {
+      UInt32 n_output_channels = 0;
+      get_num_channels_for_audio_device_id
+       (t_id, NULL, &n_output_channels);
+      if (n_output_channels == 0) {
+       // no output channels; must be input device; just continue
+       // to the next audio device.
+       continue;
+      }
+    }
+
+    // retrieve the device name; max name length is 64 characters.
+
+    prop_size = 65;
+    char c_name_buf[prop_size];
+    bzero((void*)c_name_buf, prop_size);
+    --prop_size;
+
+    AudioObjectPropertyAddress ao_address = {
+      kAudioDevicePropertyDeviceName, scope, 0
+    };
+
+    if ((err = AudioObjectGetPropertyData
+        (t_id, &ao_address, 0, NULL,
+         &prop_size, (void*)c_name_buf)) != noErr) {
+#if _OSX_AU_DEBUG_
+      std::cerr << "audio_osx::find_audio_devices: "
+               << "Unable to retrieve audio device name #"
+               << (nn+1) << ": " << err << std::endl;
+#endif
+      continue;
+    }
+    std::string name_buf(c_name_buf);
+
+    // compare the retreived name with the desired one, if
+    // provided; case insensitive.
+
+    if (device_name.length() > 0) {
+
+      std::string::size_type found =
+       ci_find_substr(name_buf, device_name);
+      if (found == std::string::npos) {
+       // not found; continue to the next ID
+       continue;
+      }
+    }
+
+    // store this info
+
+    valid_names[nn] = name_buf;
+    valid_indices[num_found_devices++] = nn;
+
+  }
+
+  // resize valid function arguments, then copy found values
+
+  if (all_ad_ids) {
+    all_ad_ids->resize(num_found_devices);
+    for (UInt32 nn = 0; nn < num_found_devices; ++nn) {
+      (*all_ad_ids)[nn] = all_dev_ids[valid_indices[nn]];
+    }
+  }
+
+  if (all_names) {
+    all_names->resize(num_found_devices);
+    for (UInt32 nn = 0; nn < num_found_devices; ++nn) {
+      (*all_names)[nn] = valid_names[valid_indices[nn]];
+    }
+  }
+}
+
+} /* namespace osx */
+} /* namespace audio */
+} /* namespace gr */
diff --git a/gr-audio/lib/osx/osx_impl.h b/gr-audio/lib/osx/osx_impl.h
deleted file mode 100644
index 5a12bac..0000000
--- a/gr-audio/lib/osx/osx_impl.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006, 2013 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio.
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING.  If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef INCLUDED_AUDIO_OSX_IMPL_H
-#define INCLUDED_AUDIO_OSX_IMPL_H
-
-#include <iostream>
-#include <string.h>
-
-namespace gr {
-  namespace audio {
-
-#define CheckErrorAndThrow(err,what,throw_str)                          \
-  if(err) {                                                             \
-    OSStatus error = static_cast<OSStatus>(err);                        \
-    char err_str[4];                                                    \
-    strncpy(err_str, (char*)(&err), 4);                                 \
-    std::cerr << what << std::endl;                                     \
-    std::cerr << "  Error# " << error << " ('" << err_str               \
-              << "')" << std::endl;                                     \
-    std::cerr << "  " << __FILE__ << ":" << __LINE__ << std::endl;      \
-    fflush(stderr);                                                     \
-    throw std::runtime_error(throw_str);                                \
-  }
-
-#define CheckError(err,what)                                            \
-  if(err) {                                                             \
-    OSStatus error = static_cast<OSStatus>(err);                        \
-    char err_str[4];                                                    \
-    strncpy(err_str, (char*)(&err), 4);                                 \
-    std::cerr << what << std::endl;                                     \
-    std::cerr << "  Error# " << error << " ('" << err_str               \
-              << "')" << std::endl;                                     \
-    std::cerr << "  " << __FILE__ << ":" << __LINE__ << std::endl;      \
-    fflush(stderr);                                                     \
-  }
-
-#include <boost/detail/endian.hpp> //BOOST_BIG_ENDIAN
-#ifdef BOOST_BIG_ENDIAN
-#define GR_PCM_ENDIANNESS kLinearPCMFormatFlagIsBigEndian
-#else
-#define GR_PCM_ENDIANNESS 0
-#endif
-
-// Check the version of MacOSX being used
-#ifdef __APPLE_CC__
-#include <AvailabilityMacros.h>
-#ifndef MAC_OS_X_VERSION_10_6
-#define MAC_OS_X_VERSION_10_6 1060
-#endif
-#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
-#define GR_USE_OLD_AUDIO_UNIT
-#endif
-#endif
-
-  } /* namespace audio */
-} /* namespace gr */
-
-#endif /* INCLUDED_AUDIO_OSX_IMPL_H */
diff --git a/gr-audio/lib/osx/osx_sink.cc b/gr-audio/lib/osx/osx_sink.cc
index 7c5be43..90c3745 100644
--- a/gr-audio/lib/osx/osx_sink.cc
+++ b/gr-audio/lib/osx/osx_sink.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,91 +25,212 @@
 #endif
 
 #include "audio_registry.h"
-#include <osx_sink.h>
-#include <osx_impl.h>
+#include "osx_sink.h"
+
 #include <gnuradio/io_signature.h>
+#include <gnuradio/prefs.h>
 #include <stdexcept>
 
 namespace gr {
   namespace audio {
 
-#define _OSX_AU_DEBUG_ 0
-
-    AUDIO_REGISTER_SINK(REG_PRIO_HIGH, osx)(int sampling_rate,
-                                            const std::string &device_name,
-                                            bool ok_to_block)
+    AUDIO_REGISTER_SINK(REG_PRIO_HIGH, osx)
+      (int sampling_rate,
+       const std::string& device_name,
+       bool ok_to_block)
     {
       return sink::sptr
         (new osx_sink(sampling_rate, device_name, ok_to_block));
     }
 
+    static std::string
+    default_device_name()
+    {
+      return prefs::singleton()->get_string
+        ("audio_osx", "default_input_device", "built-in");
+    }
+
     osx_sink::osx_sink(int sample_rate,
-                       const std::string device_name,
-                       bool do_block,
-                       int channel_config,
-                       int max_sample_count)
+                       const std::string& device_name,
+                       bool ok_to_block)
       : sync_block("audio_osx_sink",
                       io_signature::make(0, 0, 0),
                       io_signature::make(0, 0, 0)),
-        d_sample_rate(0.0), d_channel_config(0), d_n_channels(0),
-        d_queueSampleCount(0), d_max_sample_count(0),
-        d_do_block(do_block), d_internal(0), d_cond_data(0),
-        d_OutputAU(0)
+        d_input_sample_rate(0.0), d_n_user_channels(0),
+       d_n_dev_channels(0), d_queue_sample_count(0),
+       d_buffer_sample_count(0), d_ok_to_block(ok_to_block),
+       d_do_reset(false), d_hardware_changed(false),
+       d_using_default_device(false), d_waiting_for_data(false),
+       d_desired_name(device_name.empty() ? default_device_name()
+                      : device_name),
+       d_output_au(0), d_output_ad_id(0)
     {
       if(sample_rate <= 0) {
-        std::cerr << "Invalid Sample Rate: " << sample_rate << std::endl;
-        throw std::invalid_argument ("audio_osx_sink::audio_osx_sink");
-      }
-      else
-        d_sample_rate = (Float64)sample_rate;
-
-      if(channel_config <= 0 & channel_config != -1) {
-        std::cerr << "Invalid Channel Config: " << channel_config << std::endl;
-        throw std::invalid_argument ("audio_osx_sink::audio_osx_sink");
-      }
-      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_sink::audio_osx_sink");
-        }
-        if(l_n_channels <= 0)
-          channel_config = 2;
-        else
-          channel_config = l_n_channels;
+       GR_LOG_ERROR(d_logger, boost::format
+                    ("Invalid Sample Rate: %d")
+                    % sample_rate);
+        throw std::invalid_argument("audio_osx_sink");
+      }
+      else {
+        d_input_sample_rate = (Float64)sample_rate;
       }
 
-      d_n_channels = d_channel_config = channel_config;
+      // set up for audio output using the stored desired parameters
+
+      setup();
+    }
+
+    void osx_sink::setup()
+    {
+      OSStatus err = noErr;
+
+      // set the default output audio device id to "unknown"
+
+      d_output_ad_id = kAudioDeviceUnknown;
 
-      // set the input signature
+      // try to find the output audio device, if specified
 
-      set_input_signature(io_signature::make(1, d_n_channels, sizeof(float)));
+      std::vector < AudioDeviceID > all_ad_ids;
+      std::vector < std::string > all_names;
 
-      // check that the max # of samples to store is valid
+      osx::find_audio_devices
+       (d_desired_name, false,
+        &all_ad_ids, &all_names);
 
-      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_sink::audio_osx_sink");
+      // 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 output audio device '%s'.")
+                       % all_names[0]);
+
+         }
+
+         // store info on this device
+
+         d_output_ad_id = all_ad_ids[0];
+         d_selected_name = all_names[0];
+
+       } else {
+
+         // either 0 or more than 1 device was found; get all output
+         // device names, print those, and error out.
+
+         osx::find_audio_devices("", false, NULL, &all_names);
+
+         std::string err_str("\n\nA unique output audio device name "
+                             "matching the string '");
+         err_str += d_desired_name;
+         err_str += "' was not found.\n\n";
+         err_str += "The current known output 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_sink::setup");
+
+       }
       }
 
-      d_max_sample_count = max_sample_count;
+      // if no output audio device id was found, use the default
+      // output audio device as set in System Preferences.
+
+      if (d_output_ad_id == kAudioDeviceUnknown) {
+
+        UInt32 size = sizeof(AudioDeviceID);
+        AudioObjectPropertyAddress ao_address = {
+         kAudioHardwarePropertyDefaultOutputDevice,
+         kAudioObjectPropertyScopeGlobal,
+         kAudioObjectPropertyElementMaster
+        };
 
-      // allocate the output circular buffer(s), one per channel
+        err = AudioObjectGetPropertyData
+         (kAudioObjectSystemObject, &ao_address,
+          0, NULL, &size, &d_output_ad_id);
+       check_error_and_throw
+         (err, "Getting the default output audio device ID failed",
+          "audio_osx_sink::setup");
+
+       {
+         // retrieve the device name; max name length is 64 characters.
+
+         UInt32 prop_size = 65;
+         char c_name_buf[prop_size];
+         bzero((void*)c_name_buf, prop_size);
+         --prop_size;
+
+         AudioObjectPropertyAddress ao_address = {
+           kAudioDevicePropertyDeviceName,
+           kAudioDevicePropertyScopeOutput, 0
+         };
+
+         if ((err = AudioObjectGetPropertyData
+              (d_output_ad_id, &ao_address, 0, NULL,
+               &prop_size, (void*)c_name_buf)) != noErr) {
+
+           check_error(err, "Unable to retrieve output audio device name");
+
+         } else {
+
+           GR_LOG_INFO(d_logger, boost::format
+                        ("\n\nUsing output audio device '%s'.\n  ... "
+                         "which is the current default output audio"
+                         " device.\n  Changing the default output"
+                         " 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_buffers = (circular_buffer<float>**) new
-        circular_buffer<float>* [d_n_channels];
-      UInt32 n_alloc = (UInt32) ceil((double)d_max_sample_count);
-      for(UInt32 n = 0; n < d_n_channels; n++) {
-        d_buffers[n] = new circular_buffer<float>(n_alloc, false, false);
       }
 
-      // create the default AudioUnit for output
-      OSStatus err = noErr;
+      // retrieve the total number of channels for the selected audio
+      // output device
+
+      osx::get_num_channels_for_audio_device_id
+       (d_output_ad_id, NULL, &d_n_dev_channels);
+
+      // set the block input signature, if not already set
+      // (d_n_user_channels is set in check_topology, which is called
+      // before the flow-graph is running)
+
+      if (d_n_user_channels == 0) {
+       set_input_signature(io_signature::make
+                            (1, d_n_dev_channels, sizeof(float)));
+      }
+
+      // 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_input_sample_rate < 50000.0 ?
+                              50000 : (UInt32)d_input_sample_rate);
+
+#if _OSX_AU_DEBUG_
+      std::cerr << "sink(): max # samples = "
+               << d_buffer_sample_count << std::endl;
+#endif
+
+      // create the default AudioUnit for output:
 
       // Open the default output unit
+
 #ifndef GR_USE_OLD_AUDIO_UNIT
       AudioComponentDescription desc;
 #else
@@ -123,164 +244,440 @@ namespace gr {
       desc.componentFlagsMask = 0;
 
 #ifndef GR_USE_OLD_AUDIO_UNIT
+
       AudioComponent comp = AudioComponentFindNext(NULL, &desc);
-      if(comp == NULL) {
-        std::cerr << "AudioComponentFindNext Error" << std::endl;
-        throw std::runtime_error("audio_osx_sink::audio_osx_sink");
+      if(!comp) {
+        GR_LOG_FATAL(d_logger, boost::format
+                    ("AudioComponentFindNext Failed"));
+        throw std::runtime_error("audio_osx_sink::setup");
       }
+      err = AudioComponentInstanceNew(comp, &d_output_au);
+      check_error_and_throw(err, "AudioComponentInstanceNew Failed",
+                         "audio_osx_sink::setup");
+
 #else
+
       Component comp = FindNextComponent(NULL, &desc);
       if(comp == NULL) {
-        std::cerr << "FindNextComponent Error" << std::endl;
-        throw std::runtime_error("audio_osx_sink::audio_osx_sink");
+        GR_LOG_FATAL(d_logger, boost::format
+                    ("FindNextComponent Failed"));
+        throw std::runtime_error("audio_osx_sink::setup");
       }
-#endif
+      err = OpenAComponent(comp, &d_output_au);
+      check_error_and_throw(err, "OpenAComponent Failed",
+                           "audio_osx_sink::setup");
 
-#ifndef GR_USE_OLD_AUDIO_UNIT
-      err = AudioComponentInstanceNew(comp, &d_OutputAU);
-      CheckErrorAndThrow(err, "AudioComponentInstanceNew",
-                         "audio_osx_sink::audio_osx_sink");
-#else
-      err = OpenAComponent(comp, &d_OutputAU);
-      CheckErrorAndThrow(err, "OpenAComponent",
-                         "audio_osx_sink::audio_osx_sink");
 #endif
 
+      // set the selected device ID as the current output device
+
+      err = AudioUnitSetProperty
+       (d_output_au, kAudioOutputUnitProperty_CurrentDevice,
+        kAudioUnitScope_Global, 0,
+        &d_output_ad_id, sizeof(d_output_ad_id));
+      check_error_and_throw
+       (err, "Setting selected output device as current failed",
+        "audio_osx_sink::setup");
+
       // Set up a callback function to generate output to the output unit
 
-      AURenderCallbackStruct input;
-      input.inputProc = (AURenderCallback)(osx_sink::AUOutputCallback);
-      input.inputProcRefCon = this;
-
-      err = AudioUnitSetProperty(d_OutputAU,
-                                 kAudioUnitProperty_SetRenderCallback,
-                                 kAudioUnitScope_Input,
-                                 0,
-                                 &input,
-                                 sizeof (input));
-      CheckErrorAndThrow(err, "AudioUnitSetProperty Render Callback",
-                         "audio_osx_sink::audio_osx_sink");
-
-      // tell the Output Unit what format data will be supplied to it
-      // so that it handles any format conversions
-
-      AudioStreamBasicDescription streamFormat;
-      streamFormat.mSampleRate = (Float64)(sample_rate);
-      streamFormat.mFormatID = kAudioFormatLinearPCM;
-      streamFormat.mFormatFlags = (kLinearPCMFormatFlagIsFloat |
+      AURenderCallbackStruct au_callback = {
+       reinterpret_cast<AURenderCallback>
+         (&osx_sink::au_output_callback),
+        reinterpret_cast<void*>(this)
+      };
+      UInt32 prop_size = (UInt32)sizeof(au_callback);
+
+      err = AudioUnitSetProperty
+       (d_output_au,
+        kAudioUnitProperty_SetRenderCallback,
+        kAudioUnitScope_Input, 0,
+        &au_callback, prop_size);
+      check_error_and_throw
+       (err, "Set Render Callback",
+        "audio_osx_sink::setup");
+
+      // create the stream format for the output unit, so that it
+      // handles any format conversions.  Set number of channels in
+      // ::start, once the actual number of channels is known.
+
+      memset((void*)(&d_stream_format), 0, sizeof(d_stream_format));
+      d_stream_format.mSampleRate = d_input_sample_rate;
+      d_stream_format.mFormatID = kAudioFormatLinearPCM;
+      d_stream_format.mFormatFlags = (kLinearPCMFormatFlagIsFloat |
                                    GR_PCM_ENDIANNESS |
                                    kLinearPCMFormatFlagIsPacked |
                                    kAudioFormatFlagIsNonInterleaved);
-      streamFormat.mBytesPerPacket = 4;
-      streamFormat.mFramesPerPacket = 1;
-      streamFormat.mBytesPerFrame = 4;
-      streamFormat.mChannelsPerFrame = d_n_channels;
-      streamFormat.mBitsPerChannel = 32;
-
-      err = AudioUnitSetProperty(d_OutputAU,
-                                 kAudioUnitProperty_StreamFormat,
-                                 kAudioUnitScope_Input,
-                                 0,
-                                 &streamFormat,
-                                 sizeof(AudioStreamBasicDescription));
-      CheckErrorAndThrow(err, "AudioUnitSetProperty StreamFormat",
-                         "audio_osx_sink::audio_osx_sink");
-
-      // create the stuff to regulate I/O
-
-      d_cond_data = new gr::thread::condition_variable();
-      if(d_cond_data == NULL)
-        CheckErrorAndThrow(errno, "new condition (data)",
-                           "audio_osx_sink::audio_osx_sink");
-
-      d_internal = new gr::thread::mutex();
-      if(d_internal == NULL)
-        CheckErrorAndThrow(errno, "new mutex (internal)",
-                           "audio_osx_sink::audio_osx_sink");
-
-      // initialize the AU for output
-
-      err = AudioUnitInitialize(d_OutputAU);
-      CheckErrorAndThrow(err, "AudioUnitInitialize",
-                         "audio_osx_sink::audio_osx_sink");
+      d_stream_format.mBytesPerPacket = sizeof(float);
+      d_stream_format.mFramesPerPacket = 1;
+      d_stream_format.mBytesPerFrame = sizeof(float);
+      d_stream_format.mBitsPerChannel = 8*sizeof(float);
+
+      // set the render quality to maximum
+
+      UInt32 render_quality = kRenderQuality_Max;
+      prop_size = (UInt32)sizeof(render_quality);
+      err = AudioUnitSetProperty
+       (d_output_au,
+        kAudioUnitProperty_RenderQuality,
+        kAudioUnitScope_Global, 0,
+        &render_quality, prop_size);
+      check_error(err, "Setting render quality failed");
+
+      // 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 Output 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_sink::hardware_listener),
+          reinterpret_cast<void*>(this));
+       check_error(err, "Adding Audio Hardware Listener failed");
+      }
+
+      if (d_using_default_device) {
+
+       // set up a listener for the default output device so that if
+       // the device changes, this routine will be called and we can
+       // internally handle this change (if/as necesary)
+
+       {
+         AudioObjectPropertyAddress property = {
+           kAudioHardwarePropertyDefaultOutputDevice,
+           kAudioObjectPropertyScopeGlobal,
+           kAudioObjectPropertyElementMaster
+         };
+         err = AudioObjectAddPropertyListener
+           (kAudioObjectSystemObject, &property,
+            reinterpret_cast<AudioObjectPropertyListenerProc>
+              (&osx_sink::hardware_listener),
+            reinterpret_cast<void*>(this));
+         check_error(err, "Adding Default Output Audio Listener failed");
+       }
+      }
+
+#else
+
+      // 10.5 and older
+
+      err = AudioHardwareAddPropertyListener
+       (kAudioHardwarePropertyDevices,
+        reinterpret_cast<AudioHardwarePropertyListenerProc>
+          (&osx_sink::hardware_listener),
+        reinterpret_cast<void*>(this));
+      check_error(err, "Adding Audio Hardware Listener failed");
+
+      if (d_using_default_device) {
+
+       err = AudioHardwareAddPropertyListener
+         (kAudioHardwarePropertyDefaultOutputDevice,
+          reinterpret_cast<AudioHardwarePropertyListenerProc>
+            (&osx_sink::default_listener),
+          reinterpret_cast<void*>(this));
+       check_error(err, "Adding Default Output Audio Listener failed");
+
+      }
+
+#endif
+
+      // initialize the AU for output, so that it is ready to be used
+
+      err = AudioUnitInitialize(d_output_au);
+      check_error_and_throw
+       (err, "AudioUnit Initialize Failed",
+        "audio_osx_sink::setup");
 
+
+#if _OSX_AU_DEBUG_
+      std::cerr << "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;
+#endif
+    }
+
+    void osx_sink::teardown()
+    {
+      OSStatus err = noErr;
+
+      // stop the AudioUnit
+
+      stop();
+
+      if (d_using_default_device) {
+       // remove the listener
+
+       OSStatus err = noErr;
+       AudioObjectPropertyAddress property = {
+         kAudioHardwarePropertyDefaultOutputDevice,
+         kAudioObjectPropertyScopeGlobal,
+         kAudioObjectPropertyElementMaster
+       };
+       err = AudioObjectRemovePropertyListener
+         (kAudioObjectSystemObject, &property,
+          reinterpret_cast<AudioObjectPropertyListenerProc>
+            (&osx_sink::hardware_listener),
+          reinterpret_cast<void*>(this));
+#if _OSX_AU_DEBUG_
+       check_error(err, "teardown: AudioObjectRemovePropertyListener "
+                   "hardware failed");
+#endif
+      }
+
+      // uninitialize the AudioUnit
+
+      err = AudioUnitUninitialize(d_output_au);
+#if _OSX_AU_DEBUG_
+      check_error(err, "teardown: AudioUnitUninitialize failed");
+#endif
+
+      // dispose / close the AudioUnit
+
+#ifndef GR_USE_OLD_AUDIO_UNIT
+      err = AudioComponentInstanceDispose(d_output_au);
 #if _OSX_AU_DEBUG_
-      std::cerr << "audio_osx_sink Parameters:" << std::endl;
-      std::cerr << "  Sample Rate is " << d_sample_rate << std::endl;
-      std::cerr << "  Number of Channels is " << d_n_channels << std::endl;
-      std::cerr << "  Max # samples to store per channel is " << 
d_max_sample_count << std::endl;
+      check_error(err, "teardown: AudioComponentInstanceDispose failed");
 #endif
-}
+#else
+      CloseComponent(d_output_au);
+#if _OSX_AU_DEBUG_
+      check_error(err, "teardown: CloseComponent failed");
+#endif
+#endif
+
+      // delete buffers
+
+      for(UInt32 nn = 0; nn < d_buffers.size(); ++nn) {
+        delete d_buffers[nn];
+        d_buffers[nn] = 0;
+      }
+      d_buffers.resize(0);
+
+      // clear important variables; not # user channels
+
+      d_n_dev_channels = d_n_buffer_channels =
+       d_queue_sample_count = d_buffer_sample_count = 0;
+      d_using_default_device = false;
+      d_output_au = 0;
+      d_output_ad_id = 0;
+    }
 
     bool
-    osx_sink::IsRunning()
+    osx_sink::is_running()
     {
-      UInt32 AURunning = 0, AUSize = sizeof(UInt32);
-
-      OSStatus err = AudioUnitGetProperty(d_OutputAU,
-                                          kAudioOutputUnitProperty_IsRunning,
-                                          kAudioUnitScope_Global,
-                                          0,
-                                          &AURunning,
-                                          &AUSize);
-      CheckErrorAndThrow(err, "AudioUnitGetProperty IsRunning",
-                         "audio_osx_sink::IsRunning");
-
-      return (AURunning);
+      UInt32 au_running = 0;
+
+      if (d_output_au) {
+
+       UInt32 prop_size = (UInt32)sizeof(UInt32);
+       OSStatus err = AudioUnitGetProperty
+         (d_output_au,
+          kAudioOutputUnitProperty_IsRunning,
+          kAudioUnitScope_Global, 0,
+          &au_running, &prop_size);
+       check_error_and_throw
+         (err, "AudioUnitGetProperty IsRunning",
+          "audio_osx_sink::is_running");
+
+      }
+
+      return(au_running != 0);
     }
 
     bool
-    osx_sink::start()
+    osx_sink::check_topology(int ninputs, int noutputs)
     {
-      if(!IsRunning()) {
-        OSStatus err = AudioOutputUnitStart(d_OutputAU);
-        CheckErrorAndThrow(err, "AudioOutputUnitStart",
-                           "audio_osx_sink::start");
+      // check # output to make sure it's valid
+      if(noutputs != 0) {
+
+        GR_LOG_FATAL(d_logger, boost::format
+                    ("check_topology(): number of output "
+                     "streams provided (%d) should be 0.")
+                    % noutputs);
+        throw std::runtime_error
+          ("audio_osx_sink::check_topology");
+
+      }
+
+      // check # outputs to make sure it's valid
+      if((ninputs < 1) | (ninputs > (int) d_n_dev_channels)) {
+
+        GR_LOG_FATAL(d_logger, boost::format
+                    ("check_topology(): number of input "
+                     "streams provided (%d) should be in [1,%d] "
+                     "for the selected output audio device.")
+                    % ninputs % d_n_dev_channels);
+        throw std::runtime_error("audio_osx_sink::check_topology");
+
       }
 
+      // save the actual number of input (user) channels
+
+      d_n_user_channels = ninputs;
+
+#if _OSX_AU_DEBUG_
+      std::cerr << "chk_topo: Actual # user input channels = "
+                << d_n_user_channels << std::endl;
+#endif
+
       return (true);
     }
 
+    void
+    osx_sink::check_channels(bool force_reset)
+    {
+      if (d_buffers.size() == 0) {
+
+       // allocate the output circular buffer(s), one per user channel
+
+       d_buffers.resize(d_n_user_channels);
+       for(UInt32 nn = 0; nn < d_n_user_channels; ++nn) {
+         d_buffers[nn] = new circular_buffer<float>
+           (d_buffer_sample_count, false, false);
+       }
+      }
+      else {
+       if(d_buffers.size() == d_n_user_channels) {
+         if (force_reset) {
+           for(UInt32 nn = 0; nn < d_buffers.size(); ++nn) {
+             d_buffers[nn]->reset();
+           }
+         }
+         return;
+       }
+
+       // reallocate the output circular buffer(s)
+
+       if (d_n_user_channels < d_buffers.size()) {
+
+         // too many buffers; delete some
+
+         for (UInt32 nn = d_n_user_channels; nn < d_buffers.size(); ++nn) {
+           delete d_buffers[nn];
+           d_buffers[nn] = 0;
+         }
+         d_buffers.resize(d_n_user_channels);
+
+         // reset remaining buffers
+
+         for(UInt32 nn = 0; nn < d_buffers.size(); ++nn) {
+           d_buffers[nn]->reset();
+         }
+       }
+       else {
+
+         // too few buffers; create some more
+
+         // reset old buffers first
+
+         for(UInt32 nn = 0; nn < d_buffers.size(); ++nn) {
+           d_buffers[nn]->reset();
+         }
+
+         d_buffers.resize(d_n_user_channels);
+         for (UInt32 nn = d_buffers.size(); nn < d_n_user_channels; ++nn) {
+           d_buffers[nn] = new circular_buffer<float>
+             (d_buffer_sample_count, false, false);
+         }
+       }
+      }
+
+      // reset the output audio unit for the correct number of channels
+      // have to uninitialize, set, initialize.
+
+      OSStatus err = AudioUnitUninitialize(d_output_au);
+      check_error(err, "AudioUnitUninitialize");
+
+      d_stream_format.mChannelsPerFrame = d_n_user_channels;
+
+      err = AudioUnitSetProperty
+       (d_output_au,
+        kAudioUnitProperty_StreamFormat,
+        kAudioUnitScope_Input, 0,
+        &d_stream_format, sizeof(d_stream_format));
+      check_error_and_throw
+       (err, "AudioUnitSetProperty StreamFormat",
+        "audio_osx_sink::check_channels");
+
+      // initialize the AU for output, so that it is ready to be used
+
+      err = AudioUnitInitialize(d_output_au);
+      check_error_and_throw
+       (err, "AudioUnitInitialize",
+        "audio_osx_sink::check_channels");
+    }
+
     bool
-    osx_sink::stop()
+    osx_sink::start()
     {
-      if(IsRunning ()) {
-        OSStatus err = AudioOutputUnitStop(d_OutputAU);
-        CheckErrorAndThrow(err, "AudioOutputUnitStop",
-                           "audio_osx_sink::stop");
+      if(!is_running() && d_output_au) {
 
-        for(UInt32 n = 0; n < d_n_channels; n++) {
-          d_buffers[n]->abort();
-        }
+       // check channels, (re)allocate and reset buffers if/as necessary
+
+       check_channels(true);
+
+       // start the audio unit (should never fail)
+
+        OSStatus err = AudioOutputUnitStart(d_output_au);
+        check_error_and_throw
+         (err, "AudioOutputUnitStart",
+          "audio_osx_sink::start");
       }
 
       return (true);
     }
 
-    osx_sink::~osx_sink()
+    bool
+    osx_sink::stop()
     {
-      // stop and close the AudioUnit
-      stop();
-      AudioUnitUninitialize(d_OutputAU);
-#ifndef GR_USE_OLD_AUDIO_UNIT
-      AudioComponentInstanceDispose(d_OutputAU);
-#else
-      CloseComponent(d_OutputAU);
-#endif
+      if(is_running()) {
 
-      // empty and delete the queues
-      for(UInt32 n = 0; n < d_n_channels; n++) {
-        delete d_buffers[n];
-        d_buffers[n] = 0;
+       // stop the audio unit (should never fail)
+
+        OSStatus err = AudioOutputUnitStop(d_output_au);
+        check_error_and_throw
+         (err, "AudioOutputUnitStop",
+          "audio_osx_sink::stop");
+
+       // abort all buffers
+
+        for(UInt32 nn = 0; nn < d_n_user_channels; ++nn) {
+          d_buffers[nn]->abort();
+        }
       }
-      delete [] d_buffers;
-      d_buffers = 0;
 
-      // close and delete control stuff
-      delete d_cond_data;
-      d_cond_data = 0;
-      delete d_internal;
-      d_internal = 0;
+      return(true);
     }
 
     int
@@ -288,19 +685,90 @@ namespace gr {
                    gr_vector_const_void_star &input_items,
                    gr_vector_void_star &output_items)
     {
-      gr::thread::scoped_lock l(*d_internal);
+#if _OSX_AU_DEBUG_RENDER_
+      std::cerr << ((void*)(pthread_self()))
+               << " : audio_osx_sink::work: Starting." << std::endl;
+#endif
+      if (d_do_reset) {
+       if (d_hardware_changed) {
+
+         // see if the current AudioDeviceID is still available
+
+         std::vector < AudioDeviceID > all_ad_ids;
+         osx::find_audio_devices
+           (d_desired_name, false,
+            &all_ad_ids, NULL);
+         bool found = false;
+         for (UInt32 nn = 0; (nn < all_ad_ids.size()) && (!found);
+              ++nn) {
+           found = (all_ad_ids[nn] == d_output_ad_id);
+         }
+         if (!found) {
+
+           GR_LOG_FATAL(d_logger, boost::format
+                        ("The selected output 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_sink::work: doing reset."
+                   << std::endl;
+#endif
+
+         GR_LOG_WARN(d_logger, boost::format
+                     ("\n\nThe default output 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_sink::work: mutex locked."
+                   << std::endl;
+#endif
+
+         setup();
+         start();
+
+#if _OSX_AU_DEBUG_RENDER_
+         std::cerr << "audio_osx_sink: returning after reset."
+                   << std::endl;
+#endif
+         return(0);
+       }
+      }
 
-      /* 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].
-         Start the AudioUnit if necessary. */
+      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
+      // channels is less than the number of device channels, copy the
+      // data from the last / highest number channel to remaining
+      // device channels.
 
       UInt32 l_max_count;
-      int diff_count = d_max_sample_count - noutput_items;
-      if(diff_count < 0)
+      int diff_count = d_buffer_sample_count - noutput_items;
+      if(diff_count < 0) {
         l_max_count = 0;
-      else
+      }
+      else {
         l_max_count = (UInt32)diff_count;
+      }
 
 #if 0
       if(l_max_count < d_queueItemLength->back()) {
@@ -309,47 +777,66 @@ namespace gr {
       }
 #endif
 
-#if _OSX_AU_DEBUG_
-      std::cerr << "work1: qSC = " << d_queueSampleCount
+#if _OSX_AU_DEBUG_RENDER_
+      std::cerr << "work1: qSC = " << d_queue_sample_count
                 << ", lMC = "<< l_max_count
-                << ", dmSC = " << d_max_sample_count
+                << ", dmSC = " << d_buffer_sample_count
                 << ", nOI = " << noutput_items << std::endl;
 #endif
 
-      if(d_queueSampleCount > l_max_count) {
-        // data coming in too fast; do_block decides what to do
-        if(d_do_block == true) {
-          // block until there is data to return
-          while(d_queueSampleCount > l_max_count) {
-            // release control so-as to allow data to be retrieved;
-            // block until there is data to return
-            d_cond_data->wait(l);
-            // the condition's 'notify' was called; acquire control
-            // to keep thread safe
-          }
-        }
+      if(d_queue_sample_count > l_max_count) {
+        // data coming in too fast; 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 > 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;
+#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;
+#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_sink::work: "
+               "returning for reset." << std::endl;
+#endif
+             return(0);
+           }
+         }
+       }
       }
+
       // not blocking case and overflow is handled by the circular buffer
 
       // add the input frames to the buffers' queue, checking for overflow
 
-      UInt32 l_counter;
+      UInt32 nn;
       int res = 0;
       float* inBuffer = (float*)input_items[0];
       const UInt32 l_size = input_items.size();
-      for(l_counter = 0; l_counter < l_size; l_counter++) {
-        inBuffer = (float*)input_items[l_counter];
-        int l_res = d_buffers[l_counter]->enqueue(inBuffer,
-                                                  noutput_items);
-        if(l_res == -1)
+      for(nn = 0; nn < l_size; ++nn) {
+        inBuffer = (float*)input_items[nn];
+        int l_res = d_buffers[nn]->enqueue(inBuffer, noutput_items);
+        if(l_res == -1) {
           res = -1;
+       }
       }
-      while(l_counter < d_n_channels) {
+      while(nn < d_n_user_channels) {
         // for extra channels, copy the last input's data
-        int l_res = d_buffers[l_counter++]->enqueue(inBuffer,
-                                                    noutput_items);
-        if(l_res == -1)
+        int l_res = d_buffers[nn++]->enqueue(inBuffer, noutput_items);
+        if(l_res == -1) {
           res = -1;
+       }
       }
 
       if(res == -1) {
@@ -358,72 +845,126 @@ namespace gr {
         fputs("aO", stderr);
         fflush(stderr);
         // set the local number of samples available to the max
-        d_queueSampleCount = d_buffers[0]->buffer_length_items();
+        d_queue_sample_count = d_buffers[0]->buffer_length_items();
       }
       else {
         // keep up the local sample count
-        d_queueSampleCount += noutput_items;
+        d_queue_sample_count += noutput_items;
       }
 
-#if _OSX_AU_DEBUG_
+#if _OSX_AU_DEBUG_RENDER_
       std::cerr << "work2: #OI = "
                 << noutput_items << ", #Cnt = "
-                << d_queueSampleCount << ", mSC = "
-                << d_max_sample_count << std::endl;
+                << d_queue_sample_count << ", mSC = "
+                << d_buffer_sample_count << std::endl;
 #endif
 
       return (noutput_items);
     }
 
     OSStatus
-    osx_sink::AUOutputCallback(void *inRefCon,
-                               AudioUnitRenderActionFlags *ioActionFlags,
-                               const AudioTimeStamp *inTimeStamp,
-                               UInt32 inBusNumber,
-                               UInt32 inNumberFrames,
-                               AudioBufferList *ioData)
+    osx_sink::au_output_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)
     {
-      osx_sink* This = (osx_sink*)inRefCon;
+      osx_sink* This = reinterpret_cast<osx_sink*>(in_ref_con);
       OSStatus err = noErr;
 
-      gr::thread::scoped_lock l(*This->d_internal);
+      gr::thread::scoped_lock l(This->d_internal);
 
-#if _OSX_AU_DEBUG_
-      std::cerr << "cb_in: SC = " << This->d_queueSampleCount
-                << ", in#F = " << inNumberFrames << std::endl;
+#if _OSX_AU_DEBUG_RENDER_
+      std::cerr << "cb_in: SC = " << This->d_queue_sample_count
+                << ", in#F = " << in_number_frames << std::endl;
 #endif
 
-      if(This->d_queueSampleCount < inNumberFrames) {
+      if(This->d_queue_sample_count < in_number_frames) {
         // not enough data to fill request
         err = -1;
       }
       else {
         // enough data; remove data from our buffers into the AU's buffers
-        int l_counter = This->d_n_channels;
-
-        while(--l_counter >= 0) {
-          size_t t_n_output_items = inNumberFrames;
-          float* outBuffer = (float*)ioData->mBuffers[l_counter].mData;
-          This->d_buffers[l_counter]->dequeue(outBuffer, &t_n_output_items);
-          if(t_n_output_items != inNumberFrames) {
-            throw std::runtime_error("audio_osx_sink::AUOutputCallback(): "
-                                     "number of available items changing "
-                                     "unexpectedly.\n");
+        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).");
           }
         }
 
-        This->d_queueSampleCount -= inNumberFrames;
+        This->d_queue_sample_count -= in_number_frames;
       }
 
-#if _OSX_AU_DEBUG_
-      std::cerr << "cb_out: SC = " << This->d_queueSampleCount << std::endl;
+#if _OSX_AU_DEBUG_RENDER_
+      std::cerr << "cb_out: SC = "
+                << This->d_queue_sample_count << std::endl;
 #endif
 
-      // signal that data is available
-      This->d_cond_data->notify_one();
+      // signal that data is available, if appropraite
+
+      if (This->d_waiting_for_data) {
+       This->d_cond_data.notify_one();
+      }
 
       return (err);
     }
 
+#ifndef GR_USE_OLD_AUDIO_UNIT
+
+    OSStatus
+    osx_sink::hardware_listener
+    (AudioObjectID in_object_id,
+     UInt32 in_num_addresses,
+     const AudioObjectPropertyAddress in_addresses[],
+     void* in_client_data)
+
+#else
+
+    OSStatus
+    osx_sink::hardware_listener
+    (AudioHardwarePropertyID in_property_id,
+     void* in_client_data)
+
+#endif
+    {
+      osx_sink* This = static_cast
+       <osx_sink*>(in_client_data);
+      This->reset(true);
+      return(noErr);
+    }
+
+#ifndef GR_USE_OLD_AUDIO_UNIT
+
+    OSStatus
+    osx_sink::default_listener
+    (AudioObjectID in_object_id,
+     UInt32 in_num_addresses,
+     const AudioObjectPropertyAddress in_addresses[],
+     void* in_client_data)
+
+#else
+
+    OSStatus
+    osx_sink::default_listener
+    (AudioHardwarePropertyID in_property_id,
+     void* in_client_data)
+
+#endif
+    {
+      osx_sink* This = reinterpret_cast
+       <osx_sink*>(in_client_data);
+      This->reset(false);
+      return(noErr);
+    }
+
   } /* namespace audio */
 } /* namespace gr */
diff --git a/gr-audio/lib/osx/osx_sink.h b/gr-audio/lib/osx/osx_sink.h
index 241e10a..ec38b10 100644
--- a/gr-audio/lib/osx/osx_sink.h
+++ b/gr-audio/lib/osx/osx_sink.h
@@ -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.
  *
@@ -24,10 +24,9 @@
 #define INCLUDED_AUDIO_OSX_SINK_H
 
 #include <gnuradio/audio/sink.h>
-#include <string>
-#include <list>
-#include <AudioUnit/AudioUnit.h>
-#include <circular_buffer.h>
+
+#include "osx_common.h"
+#include "circular_buffer.h"
 
 namespace gr {
   namespace audio {
@@ -42,44 +41,96 @@ namespace gr {
 
     class osx_sink : public sink
     {
-      Float64 d_sample_rate;
-      int     d_channel_config;
-      UInt32  d_n_channels;
-      UInt32  d_queueSampleCount, d_max_sample_count;
-      bool    d_do_block;
-      gr::thread::mutex* d_internal;
-      gr::thread::condition_variable* d_cond_data;
-      circular_buffer<float>** d_buffers;
+    protected:
+
+      Float64 d_input_sample_rate;
+      UInt32  d_n_user_channels, d_n_dev_channels, d_n_buffer_channels;
+      UInt32  d_queue_sample_count, d_buffer_sample_count;
+      bool    d_ok_to_block, d_do_reset, d_hardware_changed;
+      bool    d_using_default_device, d_waiting_for_data;
+      gr::thread::mutex d_internal;
+      gr::thread::condition_variable d_cond_data;
+      std::vector < circular_buffer < float > *> d_buffers;
+      std::string d_desired_name, d_selected_name;
 
       // AudioUnits and Such
-      AudioUnit d_OutputAU;
+
+      AudioUnit d_output_au;
+      AudioDeviceID d_output_ad_id;
+      AudioStreamBasicDescription d_stream_format;
 
     public:
-      osx_sink(int sample_rate = 44100,
-               const std::string device_name = "2",
-               bool do_block = true,
-               int channel_config = -1,
-               int max_sample_count = -1);
 
-      ~osx_sink();
+      osx_sink(int sample_rate,
+               const std::string& device_name,
+               bool ok_to_block);
 
-      bool IsRunning();
-      bool start();
-      bool stop();
+      inline virtual ~osx_sink() {
+       teardown();
+      }
 
-      int work(int noutput_items,
-               gr_vector_const_void_star &input_items,
-               gr_vector_void_star &output_items);
+      virtual bool check_topology(int ninputs, int noutputs);
+      virtual bool start();
+      virtual bool stop();
+
+      virtual int work(int noutput_items,
+                      gr_vector_const_void_star &input_items,
+                      gr_vector_void_star &output_items);
+
+      inline void reset(bool hardware_changed) {
+       d_hardware_changed = hardware_changed;
+       d_do_reset = true;
+      }
 
     private:
-      static OSStatus AUOutputCallback(void *inRefCon,
-                                       AudioUnitRenderActionFlags 
*ioActionFlags,
-                                       const AudioTimeStamp *inTimeStamp,
-                                       UInt32 inBusNumber,
-                                       UInt32 inNumberFrames,
-                                       AudioBufferList *ioData);
-    };
 
+      bool is_running();
+
+      void setup();
+
+      void teardown();
+
+      void check_channels(bool force_reset);
+
+      static OSStatus au_output_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);
+
+#ifndef GR_USE_OLD_AUDIO_UNIT
+
+      // OSX 10.4 and newer
+
+      static OSStatus hardware_listener
+      (AudioObjectID in_object_id,
+       UInt32 in_num_addresses,
+       const AudioObjectPropertyAddress in_addresses[],
+       void* in_client_data);
+
+      static OSStatus default_listener
+      (AudioObjectID in_object_id,
+       UInt32 in_num_addresses,
+       const AudioObjectPropertyAddress in_addresses[],
+       void* in_client_data);
+
+#else
+
+      // OSX 10.6 and older; removed as of 10.7
+
+      static OSStatus hardware_listener
+      (AudioHardwarePropertyID in_property_id,
+       void* in_client_data);
+
+      static OSStatus default_listener
+      (AudioHardwarePropertyID in_property_id,
+       void* in_client_data);
+
+#endif
+
+    };
   } /* namespace audio */
 } /* namespace gr */
 
diff --git a/gr-audio/lib/osx/osx_source.cc b/gr-audio/lib/osx/osx_source.cc
index 3e2dcef..93d857e 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 */
diff --git a/gr-audio/lib/osx/osx_source.h b/gr-audio/lib/osx/osx_source.h
index 0b675f8..3c9147d 100644
--- a/gr-audio/lib/osx/osx_source.h
+++ b/gr-audio/lib/osx/osx_source.h
@@ -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.
  *
@@ -24,10 +24,9 @@
 #define INCLUDED_AUDIO_OSX_SOURCE_H
 
 #include <gnuradio/audio/source.h>
-#include <string>
-#include <AudioToolbox/AudioToolbox.h>
-#include <AudioUnit/AudioUnit.h>
-#include <circular_buffer.h>
+
+#include "osx_common.h"
+#include "circular_buffer.h"
 
 namespace gr {
   namespace audio {
@@ -41,80 +40,135 @@ namespace gr {
      */
     class osx_source : public source
     {
-      Float64             d_deviceSampleRate, d_outputSampleRate;
-      int                 d_channel_config;
-      UInt32              d_inputBufferSizeFrames, d_inputBufferSizeBytes;
-      UInt32              d_outputBufferSizeFrames, d_outputBufferSizeBytes;
-      UInt32              d_deviceBufferSizeFrames, d_deviceBufferSizeBytes;
-      UInt32              d_leadSizeFrames, d_leadSizeBytes;
-      UInt32              d_trailSizeFrames, d_trailSizeBytes;
-      UInt32              d_extraBufferSizeFrames, d_extraBufferSizeBytes;
-      UInt32              d_queueSampleCount, d_max_sample_count;
-      UInt32              d_n_AvailableInputFrames, d_n_ActualInputFrames;
-      UInt32              d_n_user_channels, d_n_max_channels, 
d_n_deviceChannels;
-      bool                d_do_block, d_passThrough, d_waiting_for_data;
-      gr::thread::mutex*       d_internal;
-      gr::thread::condition_variable* d_cond_data;
-      circular_buffer<float>** d_buffers;
-
-      // AudioUnits and Such
-      AudioUnit           d_InputAU;
-      AudioBufferList*    d_InputBuffer;
-      AudioBufferList*    d_OutputBuffer;
-      AudioConverterRef   d_AudioConverter;
+    private:
+
+      Float64 d_device_sample_rate, d_output_sample_rate;
+      UInt32 d_input_buffer_size_frames, d_input_buffer_size_bytes;
+      UInt32 d_output_buffer_size_frames, d_output_buffer_size_bytes;
+      UInt32 d_device_buffer_size_frames, d_device_buffer_size_bytes;
+      UInt32 d_lead_size_frames, d_lead_size_bytes;
+      UInt32 d_trail_size_frames, d_trail_size_bytes;
+      UInt32 d_extra_buffer_size_frames, d_extra_buffer_size_bytes;
+      UInt32 d_queue_sample_count, d_buffer_sample_count;
+      UInt32 d_n_available_input_frames, d_n_actual_input_frames;
+      UInt32 d_n_user_channels, d_n_dev_channels;
+      bool d_ok_to_block, d_pass_through;
+      bool d_waiting_for_data, d_do_reset, d_hardware_changed;
+      bool d_using_default_device;
+      gr::thread::mutex d_internal;
+      gr::thread::condition_variable d_cond_data;
+      std::vector < circular_buffer<float>* > d_buffers;
+      std::string d_desired_name, d_selected_name;
+
+      // CoreAudio variables
+
+      AudioDeviceID       d_input_ad_id;
+      AudioUnit           d_input_au;
+      AudioBufferList*    d_input_buffer;
+      AudioBufferList*    d_output_buffer;
+      AudioConverterRef   d_audio_converter;
+
+      // d_asbd_device: ASBD of the device that is creating the input
+      // data stream
+
+      AudioStreamBasicDescription d_asbd_device;
+
+      // d_asbd_client: ASBD of the client side (output) of the
+      // hardware device
+
+      AudioStreamBasicDescription d_asbd_client;
+
+      // d_asbd_user: ASBD of the user's arguments, if an audio
+      // converter is needed outside that provided by the client side.
+
+      AudioStreamBasicDescription d_asbd_user;
 
     public:
-      osx_source(int sample_rate = 44100,
-                 const std::string device_name = "",
-                 bool do_block = true,
-                 int channel_config = -1,
-                 int max_sample_count = -1);
 
-      ~osx_source();
+      osx_source(int sample_rate,
+                 const std::string& device_name,
+                 bool ok_to_block);
+
+      virtual inline ~osx_source() {
+       teardown();
+      }
 
-      bool start();
-      bool stop();
-      bool IsRunning();
+      virtual bool start();
+      virtual bool stop();
 
-      bool check_topology(int ninputs, int noutputs);
+      virtual bool check_topology(int ninputs, int noutputs);
 
-      int work(int noutput_items,
-               gr_vector_const_void_star &input_items,
-               gr_vector_void_star &output_items);
+      virtual int work(int noutput_items,
+                      gr_vector_const_void_star &input_items,
+                      gr_vector_void_star &output_items);
+
+      inline void reset(bool hardware_changed) {
+       d_hardware_changed = hardware_changed;
+       d_do_reset = true;
+      }
 
     private:
-      void SetDefaultInputDeviceAsCurrent();
-
-      void AllocAudioBufferList(AudioBufferList** t_ABL,
-                                UInt32 n_channels,
-                                UInt32 inputBufferSizeBytes);
-
-      void FreeAudioBufferList(AudioBufferList** t_ABL);
-
-      static OSStatus ConverterCallback(AudioConverterRef inAudioConverter,
-                                        UInt32* ioNumberDataPackets,
-                                        AudioBufferList* ioData,
-                                        AudioStreamPacketDescription** outASPD,
-                                        void* inUserData);
-
-      static OSStatus AUInputCallback(void *inRefCon,
-                                      AudioUnitRenderActionFlags 
*ioActionFlags,
-                                      const AudioTimeStamp *inTimeStamp,
-                                      UInt32 inBusNumber,
-                                      UInt32 inNumberFrames,
-                                      AudioBufferList *ioData);
-#if _OSX_DO_LISTENERS_
-      static OSStatus UnitListener(void *inRefCon,
-                                   AudioUnit ci,
-                                   AudioUnitPropertyID inID,
-                                   AudioUnitScope inScope,
-                                   AudioUnitElement inElement);
-
-      static OSStatus HardwareListener(AudioHardwarePropertyID inPropertyID,
-                                       void *inClientData);
+
+      bool is_running();
+
+      void setup();
+
+      void teardown();
+
+      void alloc_audio_buffer_list
+      (AudioBufferList** t_abl,
+       UInt32 n_channels,
+       UInt32 input_buffer_size_bytes);
+
+      void free_audio_buffer_list
+      (AudioBufferList** t_abl);
+
+      static OSStatus converter_callback
+      (AudioConverterRef in_audio_converter,
+       UInt32* io_number_data_packets,
+       AudioBufferList* io_data,
+       AudioStreamPacketDescription** out_aspd,
+       void* in_user_data);
+
+      static OSStatus 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);
+
+#ifndef GR_USE_OLD_AUDIO_UNIT
+
+      // OSX 10.4 and newer
+
+      static OSStatus hardware_listener
+      (AudioObjectID in_object_id,
+       UInt32 in_num_addresses,
+       const AudioObjectPropertyAddress in_addresses[],
+       void* in_client_data);
+
+      static OSStatus default_listener
+      (AudioObjectID in_object_id,
+       UInt32 in_num_addresses,
+       const AudioObjectPropertyAddress in_addresses[],
+       void* in_client_data);
+
+#else
+
+      // OSX 10.6 and older; removed as of 10.7
+
+      static OSStatus hardware_listener
+      (AudioHardwarePropertyID in_property_id,
+       void* in_client_data);
+
+      static OSStatus default_listener
+      (AudioHardwarePropertyID in_property_id,
+       void* in_client_data);
+
 #endif
-    };
 
+    };
   } /* namespace audio */
 } /* namespace gr */
 



reply via email to

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