diff options
author | Tom Rondeau <tom@trondeau.com> | 2014-04-25 10:17:23 -0400 |
---|---|---|
committer | Tom Rondeau <tom@trondeau.com> | 2014-04-25 10:17:23 -0400 |
commit | 566d8578955c0e94de17aea98de2f5f753d6b67d (patch) | |
tree | 4857d803124bdeeced746075a575b4402e005a5e | |
parent | d78d1ce2069ae20c86f9f301d89f303c2ae5942e (diff) | |
parent | 2db3dc73eb632bc853db70a41148e8f2cfecd3b0 (diff) |
Merge branch 'maint'
-rw-r--r-- | docs/doxygen/other/logger.dox | 2 | ||||
-rw-r--r-- | gnuradio-runtime/include/gnuradio/thread/thread.h | 8 | ||||
-rw-r--r-- | gnuradio-runtime/lib/thread/thread.cc | 38 | ||||
-rw-r--r-- | gr-audio/lib/osx/circular_buffer.h | 15 | ||||
-rw-r--r-- | gr-audio/lib/osx/osx_sink.cc | 820 | ||||
-rw-r--r-- | gr-audio/lib/osx/osx_sink.h | 2 | ||||
-rw-r--r-- | gr-channels/lib/flat_fader_impl.cc | 2 |
7 files changed, 502 insertions, 385 deletions
diff --git a/docs/doxygen/other/logger.dox b/docs/doxygen/other/logger.dox index c235bfe6f8..7b0f64e12b 100644 --- a/docs/doxygen/other/logger.dox +++ b/docs/doxygen/other/logger.dox @@ -210,7 +210,7 @@ of the logger can be manipulated via the following calls: \code from gnuradio import gr gr.logger_config(filename,watch_period) # Configures the logger with conf file filename - names = gr.logger_get_logger_names() # Returns the names of all loggers + names = gr.logger_get_names() # Returns the names of all loggers gr.logger_reset_config() # Resets logger config by removing all appenders \endcode diff --git a/gnuradio-runtime/include/gnuradio/thread/thread.h b/gnuradio-runtime/include/gnuradio/thread/thread.h index 6cd84ae7e5..f646ab65f6 100644 --- a/gnuradio-runtime/include/gnuradio/thread/thread.h +++ b/gnuradio-runtime/include/gnuradio/thread/thread.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2009-2013 Free Software Foundation, Inc. + * Copyright 2009-2014 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -139,14 +139,10 @@ namespace gr { GR_RUNTIME_API void thread_unbind(gr_thread_t thread); /*! \brief get current thread priority for a given thread ID - * - * Note: this does not work on OSX */ GR_RUNTIME_API int thread_priority(gr_thread_t thread); - /*! \brief get current thread priority for a given thread ID - * - * Note: this does not work on OSX + /*! \brief set current thread priority for a given thread ID */ GR_RUNTIME_API int set_thread_priority(gr_thread_t thread, int priority); diff --git a/gnuradio-runtime/lib/thread/thread.cc b/gnuradio-runtime/lib/thread/thread.cc index 53eb23b2f0..8c59b6df74 100644 --- a/gnuradio-runtime/lib/thread/thread.cc +++ b/gnuradio-runtime/lib/thread/thread.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2012-2013 Free Software Foundation, Inc. + * Copyright 2012-2014 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -73,7 +73,7 @@ namespace gr { DWORD_PTR ret = SetThreadAffinityMask(thread, dword_mask); if(ret == 0) { std::stringstream s; - s << "thread_bind_to_processor failed with error: " + s << "thread_bind_to_processor failed with error: " << GetLastError() << std::endl; throw std::runtime_error(s.str()); } @@ -98,14 +98,14 @@ namespace gr { } } - int + int thread_priority(gr_thread_t thread) { // Not implemented on Windows return -1; } - - int + + int set_thread_priority(gr_thread_t thread, int priority) { // Not implemented on Windows @@ -200,18 +200,26 @@ namespace gr { // Not implemented on OSX } - int + int thread_priority(gr_thread_t thread) { - // Not implemented on OSX - return -1; + sched_param param; + int priority; + int policy; + int ret; + ret = pthread_getschedparam (thread, &policy, ¶m); + priority = param.sched_priority; + return (ret==0)?priority:ret; } - - int + + int set_thread_priority(gr_thread_t thread, int priority) { - // Not implemented on OSX - return -1; + int policy; + struct sched_param param; + pthread_getschedparam (thread, &policy, ¶m); + param.sched_priority = priority; + return pthread_setschedparam(thread, policy, ¶m); } void @@ -305,7 +313,7 @@ namespace gr { } } - int + int thread_priority(gr_thread_t thread) { sched_param param; @@ -316,8 +324,8 @@ namespace gr { priority = param.sched_priority; return (ret==0)?priority:ret; } - - int + + int set_thread_priority(gr_thread_t thread, int priority) { int policy; diff --git a/gr-audio/lib/osx/circular_buffer.h b/gr-audio/lib/osx/circular_buffer.h index fee9eeafbc..7a5cde0540 100644 --- a/gr-audio/lib/osx/circular_buffer.h +++ b/gr-audio/lib/osx/circular_buffer.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006,2009,2010 Free Software Foundation, Inc. + * Copyright 2006,2009,2010,2014 Free Software Foundation, Inc. * * This file is part of GNU Radio. * @@ -218,13 +218,17 @@ public: * inputs: * buf: a pointer to the buffer into which to copy the data * - * bufLen_I: pointer to the number of items to remove in items - * (of the instantiated type) + * bufLen_I: pointer to the requested number of items to remove + * + * outputs: + * bufLen_I: pointer to the actual number of items removed * * returns: * 0: if nothing to do (0 length buffer) * 1: if success * 2: in the process of aborting, do doing nothing + * 3: if the number of requested items to remove is not the same + * as the actual number of items removed. * * will throw runtime errors if inputs are improper: * buffer pointer is NULL @@ -297,11 +301,14 @@ public: d_readNdx_I = n_start_I; } else d_readNdx_I += n_now_I; + int rv = 1; + if (*bufLen_I != l_bufLen_I) + rv = 3; *bufLen_I = l_bufLen_I; d_n_avail_read_I -= l_bufLen_I; d_n_avail_write_I += l_bufLen_I; d_writeBlock->notify_one (); - return (1); + return (rv); }; void abort () { diff --git a/gr-audio/lib/osx/osx_sink.cc b/gr-audio/lib/osx/osx_sink.cc index f027e2ebec..dc21ab2025 100644 --- a/gr-audio/lib/osx/osx_sink.cc +++ b/gr-audio/lib/osx/osx_sink.cc @@ -57,18 +57,18 @@ namespace gr { io_signature::make(0, 0, 0), io_signature::make(0, 0, 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) + d_n_dev_channels(0), d_queue_sample_count(0), + d_buffer_size_samples(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) { - GR_LOG_ERROR(d_logger, boost::format - ("Invalid Sample Rate: %d") - % sample_rate); + GR_LOG_ERROR(d_logger, boost::format + ("Invalid Sample Rate: %d") + % sample_rate); throw std::invalid_argument("audio_osx_sink"); } else { @@ -94,51 +94,51 @@ namespace gr { std::vector < std::string > all_names; osx::find_audio_devices - (d_desired_name, false, - &all_ad_ids, &all_names); + (d_desired_name, false, + &all_ad_ids, &all_names); // check number of device(s) returned if (d_desired_name.length() != 0) { - if (all_ad_ids.size() == 1) { + if (all_ad_ids.size() == 1) { - // exactly 1 match was found; see if it was partial + // exactly 1 match was found; see if it was partial - if (all_names[0].compare(d_desired_name) != 0) { + 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]); + // 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 + // store info on this device - d_output_ad_id = all_ad_ids[0]; - d_selected_name = all_names[0]; + d_output_ad_id = all_ad_ids[0]; + d_selected_name = all_names[0]; - } else { + } else { - // either 0 or more than 1 device was found; get all output - // device names, print those, and error out. + // 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); + 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"); + 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"); - } + } } // if no output audio device id was found, use the default @@ -148,55 +148,55 @@ namespace gr { UInt32 size = sizeof(AudioDeviceID); AudioObjectPropertyAddress ao_address = { - kAudioHardwarePropertyDefaultOutputDevice, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster + kAudioHardwarePropertyDefaultOutputDevice, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; 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"); + (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. + { + // 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; + 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 - }; + AudioObjectPropertyAddress ao_address = { + kAudioDevicePropertyDeviceName, + kAudioDevicePropertyScopeOutput, 0 + }; - if ((err = AudioObjectGetPropertyData - (d_output_ad_id, &ao_address, 0, NULL, - &prop_size, (void*)c_name_buf)) != noErr) { + 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"); + check_error(err, "Unable to retrieve output audio device name"); - } else { + } 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)); + 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_selected_name = c_name_buf; - } + } - d_using_default_device = true; + d_using_default_device = true; } @@ -204,27 +204,28 @@ namespace gr { // output device osx::get_num_channels_for_audio_device_id - (d_output_ad_id, NULL, &d_n_dev_channels); + (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_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 + // must be at least 16kB. Pick 50 kS since that's plenty yet // not very much. - d_buffer_sample_count = (d_input_sample_rate < 50000.0 ? - 50000 : (UInt32)d_input_sample_rate); + d_buffer_size_samples = (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; + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink: max # samples = " + << d_buffer_size_samples << std::endl; #endif // create the default AudioUnit for output: @@ -248,7 +249,7 @@ namespace gr { AudioComponent comp = AudioComponentFindNext(NULL, &desc); if(!comp) { GR_LOG_FATAL(d_logger, boost::format - ("AudioComponentFindNext Failed")); + ("AudioComponentFindNext Failed")); throw std::runtime_error("audio_osx_sink::setup"); } err = AudioComponentInstanceNew(comp, &d_output_au); @@ -260,42 +261,42 @@ namespace gr { Component comp = FindNextComponent(NULL, &desc); if(comp == NULL) { GR_LOG_FATAL(d_logger, boost::format - ("FindNextComponent Failed")); + ("FindNextComponent Failed")); throw std::runtime_error("audio_osx_sink::setup"); } err = OpenAComponent(comp, &d_output_au); check_error_and_throw(err, "OpenAComponent Failed", - "audio_osx_sink::setup"); + "audio_osx_sink::setup"); #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)); + (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"); + (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 au_callback = { - reinterpret_cast<AURenderCallback> - (&osx_sink::au_output_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); + (d_output_au, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, 0, + &au_callback, prop_size); check_error_and_throw - (err, "Set Render Callback", - "audio_osx_sink::setup"); + (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 @@ -318,28 +319,28 @@ namespace gr { 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); + (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."); + 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 @@ -350,41 +351,41 @@ namespace gr { { - // set up a listener if hardware changes (at all) + // set up a listener if hardware changes (at all) - AudioObjectPropertyAddress property = { - kAudioHardwarePropertyDevices, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; + 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"); + 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"); - } + // 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 @@ -392,20 +393,20 @@ namespace gr { // 10.5 and older err = AudioHardwareAddPropertyListener - (kAudioHardwarePropertyDevices, - reinterpret_cast<AudioHardwarePropertyListenerProc> - (&osx_sink::hardware_listener), - reinterpret_cast<void*>(this)); + (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"); + err = AudioHardwareAddPropertyListener + (kAudioHardwarePropertyDefaultOutputDevice, + reinterpret_cast<AudioHardwarePropertyListenerProc> + (&osx_sink::default_listener), + reinterpret_cast<void*>(this)); + check_error(err, "Adding Default Output Audio Listener failed"); } @@ -415,20 +416,27 @@ namespace gr { err = AudioUnitInitialize(d_output_au); check_error_and_throw - (err, "AudioUnit Initialize Failed", - "audio_osx_sink::setup"); + (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; + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink Parameters:" << std::endl + << " Sample Rate is " << d_input_sample_rate << std::endl + << " Max # samples to store per channel is " + << d_buffer_size_samples << std::endl; #endif } void osx_sink::teardown() { +#if _OSX_AU_DEBUG_ + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::teardown: starting" + << std::endl; +#endif + OSStatus err = noErr; // stop the AudioUnit @@ -436,22 +444,22 @@ namespace gr { 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)); + // 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"); + check_error(err, "teardown: AudioObjectRemovePropertyListener " + "hardware failed"); #endif } @@ -487,10 +495,16 @@ namespace gr { // clear important variables; not # user channels d_n_dev_channels = d_n_buffer_channels = - d_queue_sample_count = d_buffer_sample_count = 0; + d_queue_sample_count = d_buffer_size_samples = 0; d_using_default_device = false; d_output_au = 0; d_output_ad_id = 0; + +#if _OSX_AU_DEBUG_ + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::teardown: finished" + << std::endl; +#endif } bool @@ -500,15 +514,15 @@ namespace gr { 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"); + 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"); } @@ -522,9 +536,9 @@ namespace gr { if(noutputs != 0) { GR_LOG_FATAL(d_logger, boost::format - ("check_topology(): number of output " - "streams provided (%d) should be 0.") - % noutputs); + ("check_topology(): number of output " + "streams provided (%d) should be 0.") + % noutputs); throw std::runtime_error ("audio_osx_sink::check_topology"); @@ -534,10 +548,10 @@ namespace gr { 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); + ("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"); } @@ -547,7 +561,9 @@ namespace gr { d_n_user_channels = ninputs; #if _OSX_AU_DEBUG_ - std::cerr << "chk_topo: Actual # user input channels = " + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::check_topology: " + << "Actual # user input channels = " << d_n_user_channels << std::endl; #endif @@ -559,58 +575,58 @@ namespace gr { { if (d_buffers.size() == 0) { - // allocate the output circular buffer(s), one per user channel + // 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); - } + 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_size_samples, 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; - } + 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) + // reallocate the output circular buffer(s) - if (d_n_user_channels < d_buffers.size()) { + if (d_n_user_channels < d_buffers.size()) { - // too many buffers; delete some + // 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); + 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 + // reset remaining buffers - for(UInt32 nn = 0; nn < d_buffers.size(); ++nn) { - d_buffers[nn]->reset(); - } - } - else { + for(UInt32 nn = 0; nn < d_buffers.size(); ++nn) { + d_buffers[nn]->reset(); + } + } + else { - // too few buffers; create some more + // too few buffers; create some more - // reset old buffers first + // reset old buffers first - for(UInt32 nn = 0; nn < d_buffers.size(); ++nn) { - d_buffers[nn]->reset(); - } + 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); - } - } + 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_size_samples, false, false); + } + } } // reset the output audio unit for the correct number of channels @@ -622,20 +638,20 @@ namespace gr { 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)); + (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"); + (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"); + (err, "AudioUnitInitialize", + "audio_osx_sink::check_channels"); } bool @@ -643,18 +659,32 @@ namespace gr { { if(!is_running() && d_output_au) { - // check channels, (re)allocate and reset buffers if/as necessary +#if _OSX_AU_DEBUG_ + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::start: starting Output AudioUnit." + << std::endl; +#endif + + // check channels, (re)allocate and reset buffers if/as necessary - check_channels(true); + check_channels(true); - // start the audio unit (should never fail) + // start the audio unit (should never fail) OSStatus err = AudioOutputUnitStart(d_output_au); check_error_and_throw - (err, "AudioOutputUnitStart", - "audio_osx_sink::start"); + (err, "AudioOutputUnitStart", + "audio_osx_sink::start"); } +#if _OSX_AU_DEBUG_ + else { + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::start: " + << "already running." << std::endl; + } +#endif + return (true); } @@ -663,19 +693,49 @@ namespace gr { { if(is_running()) { - // stop the audio unit (should never fail) +#if _OSX_AU_DEBUG_ + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::stop: " + << "stopping Output AudioUnit." + << std::endl; +#endif + + // if waiting in ::work, signal to wake up + if (d_waiting_for_data) { +#if _OSX_AU_DEBUG_ + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::stop: " + << "signaling waiting condition" << std::endl; +#endif + d_cond_data.notify_one(); + } + + // stop the audio unit (should never fail) OSStatus err = AudioOutputUnitStop(d_output_au); check_error_and_throw - (err, "AudioOutputUnitStop", - "audio_osx_sink::stop"); + (err, "AudioOutputUnitStop", + "audio_osx_sink::stop"); - // abort all buffers + // abort and reset all buffers for(UInt32 nn = 0; nn < d_n_user_channels; ++nn) { d_buffers[nn]->abort(); + d_buffers[nn]->reset(); } + + // reset local knowledge of amount of data in queues + + d_queue_sample_count = 0; + } +#if _OSX_AU_DEBUG_ + else { + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::stop: " + << "already stopped." << std::endl; + } +#endif return(true); } @@ -686,83 +746,92 @@ namespace gr { gr_vector_void_star &output_items) { #if _OSX_AU_DEBUG_RENDER_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::work: Starting." << std::endl; + { + gr::thread::scoped_lock l(d_internal); + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::work: " + << "Starting: #OI = " + << noutput_items << ", reset = " + << (d_do_reset ? "true" : "false") << std::endl; + } #endif if (d_do_reset) { - if (d_hardware_changed) { - - // 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) { + 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); + 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; + d_do_reset = d_hardware_changed = false; - } - else { + } + else { #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "audio_osx_sink::work: doing reset." - << std::endl; + { + gr::thread::scoped_lock l(d_internal); + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::work: " + << "doing reset." << std::endl; + } #endif - GR_LOG_WARN(d_logger, boost::format - ("\n\nThe default output audio device has " - "changed; resetting audio.\nThere may " - "be a sound glitch while resetting.\n")); + 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. + // 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(); + teardown(); - gr::thread::scoped_lock l(d_internal); + 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(); + setup(); + start(); #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "audio_osx_sink: returning after reset." - << std::endl; + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink: " + << "returning 0 after reset." + << std::endl; #endif - return(0); - } + return(0); + } } gr::thread::scoped_lock l(d_internal); // take the input data, copy it, and push it to the bottom of - // the queue mono input are pushed onto queue[0]; stereo input - // are pushed onto queue[1]. If the number of user/graph + // the queue. mono input is pushed onto queue[0]; stereo input + // is pushed onto queue[1]. If the number of user/graph // channels is less than the number of device channels, copy the // data from the last / highest number channel to remaining // device channels. + // find the maximum amount of buffer space available right now + UInt32 l_max_count; - int diff_count = d_buffer_sample_count - noutput_items; + int diff_count = ((int)d_buffer_size_samples) - noutput_items; if(diff_count < 0) { l_max_count = 0; } @@ -770,53 +839,59 @@ namespace gr { l_max_count = (UInt32)diff_count; } -#if 0 - if(l_max_count < d_queueItemLength->back()) { - // allow 2 buffers at a time, regardless of length - l_max_count = d_queueItemLength->back(); - } -#endif - #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "work1: qSC = " << d_queue_sample_count + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::work: " + << "qSC = " << d_queue_sample_count << ", lMC = "<< l_max_count - << ", dmSC = " << d_buffer_sample_count - << ", nOI = " << noutput_items << std::endl; + << ", dBSC = " << d_buffer_size_samples + << ", #OI = " << noutput_items << std::endl; #endif if(d_queue_sample_count > l_max_count) { - // data coming in too fast; ok_to_block decides what to do + + // data coming in too fast; ok_to_block decides what to do: if + // ok to block, then wait until the render callback makes + // enough space. If not blocking, detect overflow via writing + // data to the circular buffer. + if(d_ok_to_block == true) { // block until there is data to return, or on reset while(d_queue_sample_count > l_max_count) { - // release control so-as to allow data to be retrieved; - // block until there is data to return + // release control so-as to allow data to be retrieved; + // block until there is data to return #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "audio_osx_sink::work: waiting." << std::endl; + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::work: " + << "waiting." << std::endl; #endif - d_waiting_for_data = true; - d_cond_data.wait(l); - d_waiting_for_data = false; + d_waiting_for_data = true; + d_cond_data.wait(l); + d_waiting_for_data = false; #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "audio_osx_sink::work: done waiting." << std::endl; + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::work: " + << "done waiting." << std::endl; #endif - // the condition's 'notify' was called; acquire control to - // keep thread safe + // 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 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; + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::work: " + << "returning 0 for reset." << std::endl; #endif - return(0); - } - } - } + return(0); + } + } + } } - // not blocking case and overflow is handled by the circular buffer + // not blocking and overflow is handled by the circular buffer, + // or enough data space is available // add the input frames to the buffers' queue, checking for overflow @@ -829,34 +904,37 @@ namespace gr { int l_res = d_buffers[nn]->enqueue(inBuffer, noutput_items); if(l_res == -1) { res = -1; - } + } } while(nn < d_n_user_channels) { // for extra channels, copy the last input's data int l_res = d_buffers[nn++]->enqueue(inBuffer, noutput_items); if(l_res == -1) { res = -1; - } + } } + // did overflow occur? + if(res == -1) { - // data coming in too fast - // drop oldest buffer + // yes: data coming in too fast; drop oldest data. fputs("aO", stderr); fflush(stderr); // set the local number of samples available to the max d_queue_sample_count = d_buffers[0]->buffer_length_items(); } else { - // keep up the local sample count + // no: keep up the local sample count d_queue_sample_count += noutput_items; } #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "work2: #OI = " - << noutput_items << ", #Cnt = " - << d_queue_sample_count << ", mSC = " - << d_buffer_sample_count << std::endl; + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::work: " + << "returning: #OI = " + << noutput_items << ", qSC = " + << d_queue_sample_count << ", bSS = " + << d_buffer_size_samples << std::endl; #endif return (noutput_items); @@ -871,50 +949,78 @@ namespace gr { UInt32 in_number_frames, AudioBufferList* io_data) { + // NOTE: This is a callback from the OS, so throwing here does + // not work; return an error instead when something does not go + // as planned. + osx_sink* This = reinterpret_cast<osx_sink*>(in_ref_con); OSStatus err = noErr; gr::thread::scoped_lock l(This->d_internal); #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "cb_in: SC = " << This->d_queue_sample_count - << ", in#F = " << in_number_frames << std::endl; + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::au_output_callback: " + << "starting: qSC = " + << This->d_queue_sample_count + << ", in#F = " << in_number_frames + << ", in#C = " << This->d_n_user_channels << std::endl; #endif if(This->d_queue_sample_count < in_number_frames) { - // not enough data to fill request - err = -1; + + // not enough data to fill request; probably happened on + // start-up, where this callback was called before ::work was. + + fputs("aU", stderr); + fflush(stderr); + err = kAudioUnitErr_Initialized; + } else { // enough data; remove data from our buffers into the AU's buffers int nn = This->d_n_user_channels; - while(--nn >= 0) { + size_t t_n_output_items = in_number_frames; float* out_buffer = (float*)(io_data->mBuffers[nn].mData); - This->d_buffers[nn]->dequeue(out_buffer, &t_n_output_items); - if(t_n_output_items != in_number_frames) { - throw std::runtime_error - ("audio_osx_sink::au_output_callback: " - "number of available items changing " - "unexpectedly (should never happen)."); + int rv = This->d_buffers[nn]->dequeue + (out_buffer, &t_n_output_items); + + if((rv != 1) || (t_n_output_items != in_number_frames)) { + + std::cerr << "audio_osx_sink::au_output_callback: " + << "number of available items changing " + << "unexpectedly (should never happen): was " + << in_number_frames << " now " + << t_n_output_items<< std::endl; + err = kAudioUnitErr_TooManyFramesToProcess; + } } This->d_queue_sample_count -= in_number_frames; } -#if _OSX_AU_DEBUG_RENDER_ - std::cerr << "cb_out: SC = " - << This->d_queue_sample_count << std::endl; -#endif - // signal that data is available, if appropraite if (This->d_waiting_for_data) { - This->d_cond_data.notify_one(); +#if _OSX_AU_DEBUG_RENDER_ + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::au_output_callback: " + << "signaling waiting condition" << std::endl; +#endif + This->d_cond_data.notify_one(); } +#if _OSX_AU_DEBUG_RENDER_ + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink::au_output_callback: " + << "returning: qSC = " + << This->d_queue_sample_count + << ", err = " << err << std::endl; +#endif + return (err); } @@ -937,7 +1043,7 @@ namespace gr { #endif { osx_sink* This = static_cast - <osx_sink*>(in_client_data); + <osx_sink*>(in_client_data); This->reset(true); return(noErr); } @@ -961,7 +1067,7 @@ namespace gr { #endif { osx_sink* This = reinterpret_cast - <osx_sink*>(in_client_data); + <osx_sink*>(in_client_data); This->reset(false); return(noErr); } diff --git a/gr-audio/lib/osx/osx_sink.h b/gr-audio/lib/osx/osx_sink.h index ec38b10926..127f243495 100644 --- a/gr-audio/lib/osx/osx_sink.h +++ b/gr-audio/lib/osx/osx_sink.h @@ -45,7 +45,7 @@ namespace gr { 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; + UInt32 d_queue_sample_count, d_buffer_size_samples; 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; diff --git a/gr-channels/lib/flat_fader_impl.cc b/gr-channels/lib/flat_fader_impl.cc index af35e29ef4..33cf37d23b 100644 --- a/gr-channels/lib/flat_fader_impl.cc +++ b/gr-channels/lib/flat_fader_impl.cc @@ -64,7 +64,7 @@ namespace gr { gr_complex H(0,0); for(int n=1; n<d_N; n++){ - float alpha_n = (2*M_PI*n - M_PI + d_theta)/4*d_N; + float alpha_n = (2*M_PI*n - M_PI + d_theta)/(4*d_N); #if FASTSINCOS == 1 float s_i = scale_sin*gr::fxpt::cos(gr::fxpt::float_to_fixed(2*M_PI*d_fDTs*d_m*gr::fxpt::cos(gr::fxpt::float_to_fixed(alpha_n))+d_psi[n+1])); float s_q = scale_sin*gr::fxpt::cos(gr::fxpt::float_to_fixed(2*M_PI*d_fDTs*d_m*gr::fxpt::sin(gr::fxpt::float_to_fixed(alpha_n))+d_phi[n+1])); |