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