diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index d405185c3a..ea1179c509 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -108,6 +108,7 @@ public: uint32_t process_thread_count (); void request_backend_reset(); + void request_device_list_update(); bool is_realtime() const; bool connected() const; @@ -190,7 +191,6 @@ public: */ int process_callback (pframes_t nframes); int buffer_size_change (pframes_t nframes); - int device_list_change (); int sample_rate_change (pframes_t nframes); void freewheel_callback (bool); void timebase_callback (TransportState state, pframes_t nframes, framepos_t pos, int new_position); @@ -232,7 +232,6 @@ public: /// the number of frames processed since start() was called framecnt_t _processed_frames; Glib::Threads::Thread* m_meter_thread; - Glib::Threads::Thread* m_hw_event_thread; ProcessThread* _main_thread; MTDM* _mtdm; bool _measuring_latency; @@ -246,8 +245,17 @@ public: bool _started_for_latency; bool _in_destructor; + Glib::Threads::Thread* _hw_reset_event_thread; + uint16_t _hw_reset_request_count; + bool _stop_hw_reset_processing; + Glib::Threads::Thread* _hw_devicelist_update_thread; + uint16_t _hw_devicelist_update_count; + bool _stop_hw_devicelist_processing; + + void start_hw_event_processing(); + void stop_hw_event_processing(); void do_reset_backend(); - void wait_hw_event_processing_complete(); + void do_devicelist_update(); void meter_thread (); void start_metering_thread (); diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 4e763006bc..20c2ce2ed4 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -80,8 +80,15 @@ AudioEngine::AudioEngine () , _latency_signal_latency (0) , _stopped_for_latency (false) , _in_destructor (false) + , _hw_reset_event_thread(0) + , _hw_reset_request_count(0) + , _stop_hw_reset_processing(false) + , _hw_devicelist_update_thread(0) + , _hw_devicelist_update_count(0) + , _stop_hw_devicelist_processing(false) { g_atomic_int_set (&m_meter_exit, 0); + start_hw_event_processing(); discover_backends (); } @@ -89,7 +96,7 @@ AudioEngine::~AudioEngine () { _in_destructor = true; stop_metering_thread (); - wait_hw_event_processing_complete(); + stop_hw_event_processing(); drop_backend (); } @@ -168,14 +175,6 @@ AudioEngine::buffer_size_change (pframes_t bufsiz) return 0; } -int -AudioEngine::device_list_change () -{ - DeviceListChanged (); /* EMIT SIGNAL */ - - return 0; -} - /** Method called by our ::process_thread when there is work to be done. * @param nframes Number of frames to process. */ @@ -366,37 +365,98 @@ AudioEngine::process_callback (pframes_t nframes) void AudioEngine::request_backend_reset() { - if (m_hw_event_thread != 0) { - m_hw_event_thread->join (); - m_hw_event_thread = 0; - } - - m_hw_event_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_reset_backend, this)); + g_atomic_int_inc(&_hw_reset_request_count); } void AudioEngine::do_reset_backend() { - SessionEvent::create_per_thread_pool (X_("Backend reset processing thread"), 512); - - if (_backend) { - std::string name = _backend->device_name (); - stop(); - _backend->drop_device(); - _backend->set_device_name(name); - start(); - SampleRateChanged(_backend->sample_rate() ); - BufferSizeChanged(_backend->buffer_size() ); - } + SessionEvent::create_per_thread_pool (X_("Backend reset processing thread"), 512); + + while (!_stop_hw_reset_processing) { + + if (_hw_reset_request_count && _backend) { + + g_atomic_int_dec_and_test (&_hw_reset_request_count); + + // backup the device name + std::string name = _backend->device_name (); + + stop(); + + // "hard reset" the device + _backend->drop_device(); + _backend->set_device_name(name); + + start(); + + // inform about possible changes + SampleRateChanged(_backend->sample_rate() ); + BufferSizeChanged(_backend->buffer_size() ); + } + + g_usleep(0); + } } void -AudioEngine::wait_hw_event_processing_complete() +AudioEngine::request_device_list_update() { - m_hw_event_thread->join (); - m_hw_event_thread = 0; + g_atomic_int_inc (&_hw_devicelist_update_count); +} + + +void +AudioEngine::do_devicelist_update() +{ + SessionEvent::create_per_thread_pool (X_("Device list update processing thread"), 512); + + while (!_stop_hw_devicelist_processing) { + if (_hw_devicelist_update_count) { + g_atomic_int_dec_and_test (&_hw_devicelist_update_count); + DeviceListChanged (); /* EMIT SIGNAL */ + } + g_usleep(0); + } +} + + +void +AudioEngine::start_hw_event_processing() +{ + if (_hw_reset_event_thread == 0) { + g_atomic_int_set(&_hw_reset_request_count, 0); + g_atomic_int_set(&_stop_hw_reset_processing, 0); + _hw_reset_event_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_reset_backend, this)); + } + + if (_hw_devicelist_update_thread == 0) { + g_atomic_int_set(&_hw_devicelist_update_count, 0); + g_atomic_int_set(&_stop_hw_devicelist_processing, 0); + _hw_devicelist_update_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_devicelist_update, this)); + } +} + + +void +AudioEngine::stop_hw_event_processing() +{ + if (_hw_reset_event_thread) { + g_atomic_int_set(&_stop_hw_reset_processing, 1); + g_atomic_int_set(&_hw_reset_request_count, 0); + _hw_reset_event_thread->join (); + _hw_reset_event_thread = 0; + } + + if (_hw_devicelist_update_thread) { + g_atomic_int_set(&_stop_hw_devicelist_processing, 1); + g_atomic_int_set(&_hw_devicelist_update_count, 0); + _hw_devicelist_update_thread->join (); + _hw_devicelist_update_thread = 0; + } + } diff --git a/libs/backends/wavesaudio/waves_audiobackend.cc b/libs/backends/wavesaudio/waves_audiobackend.cc index f20cc3a521..07d786239f 100644 --- a/libs/backends/wavesaudio/waves_audiobackend.cc +++ b/libs/backends/wavesaudio/waves_audiobackend.cc @@ -64,11 +64,11 @@ void WavesAudioBackend::AudioDeviceManagerNotification (NotificationReason reaso break; case WCMRAudioDeviceManagerClient::DeviceListChanged: std::cout << "------------------------------- WCMRAudioDeviceManagerClient::DeviceListChanged" << std::endl; - _device_list_change(); + engine.request_device_list_update(); break; case WCMRAudioDeviceManagerClient::IODeviceDisconnected: std::cout << "------------------------------- WCMRAudioDeviceManagerClient::DeviceListChanged" << std::endl; - _device_list_change(); + engine.request_device_list_update(); break; case WCMRAudioDeviceManagerClient::AudioCallback: if (parameter) { @@ -585,14 +585,6 @@ WavesAudioBackend::_sample_rate_change (float new_sample_rate) } -int -WavesAudioBackend::_device_list_change () -{ - // requires GZ changes for device list update - return engine.device_list_change (); -} - - int WavesAudioBackend::set_interleaved (bool yn) { diff --git a/libs/backends/wavesaudio/waves_audiobackend.h b/libs/backends/wavesaudio/waves_audiobackend.h index 6fd91913d1..242d40fca9 100644 --- a/libs/backends/wavesaudio/waves_audiobackend.h +++ b/libs/backends/wavesaudio/waves_audiobackend.h @@ -331,8 +331,6 @@ class WavesMidiPort; int _buffer_size_change(uint32_t new_buffer_size); int _sample_rate_change(float new_sample_rate); - int _device_list_change(); - int _register_system_audio_ports (); int _register_system_midi_ports (); diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp index ec19b9fd43..8cb3085486 100644 --- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp +++ b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp @@ -1248,12 +1248,17 @@ WTErr WCMRCoreAudioDevice::EnableListeners() goto Exit; } -#if ENABLE_DEVICE_CHANGE_LISTNER +#if ENABLE_DEVICE_CHANGE_LISTNER { //listner for device change... - err = AudioDeviceAddPropertyListener(m_DeviceID, 0, 0, kAudioDevicePropertyDeviceHasChanged, - StaticPropertyChangeProc, this); + err = AudioDeviceAddPropertyListener (m_DeviceID, + kAudioPropertyWildcardChannel, + true, + kAudioDevicePropertyDeviceHasChanged, + StaticPropertyChangeProc, + this); + if (err) { DEBUG_MSG("Couldn't Setup device change Property Listner, error = " << err); @@ -1309,14 +1314,18 @@ WTErr WCMRCoreAudioDevice::DisableListeners() #if ENABLE_DEVICE_CHANGE_LISTNER { - err = AudioDeviceRemovePropertyListener(m_DeviceID, 0, 0, kAudioDevicePropertyDeviceHasChanged, - StaticPropertyChangeProc); - + err = AudioDeviceRemovePropertyListener (m_DeviceID, + kAudioPropertyWildcardChannel, + true/* Input */, + kAudioDevicePropertyDeviceHasChanged, + StaticPropertyChangeProc); + if (err) { - DEBUG_MSG("Couldn't Cleanup device change Property Listner, error = " << err); + DEBUG_MSG("Couldn't Cleanup device input stream change Property Listner, error = " << err); //not sure if we need to report this... } + } #endif //ENABLE_DEVICE_CHANGE_LISTNER @@ -1385,15 +1394,19 @@ void WCMRCoreAudioDevice::PropertyChangeProc (AudioDevicePropertyID inPropertyID case kAudioDevicePropertyDeviceHasChanged: { m_ResetRequested++; + m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset); } break; #endif //ENABLE_DEVICE_CHANGE_LISTNER case kAudioDeviceProcessorOverload: + { if (m_IgnoreThisDrop) m_IgnoreThisDrop = false; //We'll ignore once, just once! else m_DropsDetected++; + m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::Dropout ); break; + } default: break; } @@ -1659,35 +1672,7 @@ WTErr WCMRCoreAudioDevice::SetupAUHAL() retVal = EnableListeners(); if (retVal != eNoErr) goto Exit; - - //also prepare the buffer list for input... - if (!m_InputChannels.empty()) - { - - //now setup the buffer list. - memset (&m_InputAudioBufferList, 0, sizeof (m_InputAudioBufferList)); - m_InputAudioBufferList.mNumberBuffers = 1; - m_InputAudioBufferList.mBuffers[0].mNumberChannels = m_InputChannels.size(); - m_InputAudioBufferList.mBuffers[0].mDataByteSize = m_InputAudioBufferList.mBuffers[0].mNumberChannels * - m_CurrentBufferSize * sizeof(float); - //allocate the data buffer... - try - { - m_pInputData = new float[m_InputAudioBufferList.mBuffers[0].mNumberChannels * m_CurrentBufferSize]; - } - catch (...) - { - retVal = eMemNewFailed; - goto Exit; - } - - m_InputAudioBufferList.mBuffers[0].mData = m_pInputData; - - //zero it out... - memset (m_InputAudioBufferList.mBuffers[0].mData, 0, m_InputAudioBufferList.mBuffers[0].mDataByteSize); - } - //initialize the audio-unit now! err = AudioUnitInitialize(m_AUHALAudioUnit); if (err != kAudioHardwareNoError) @@ -1727,8 +1712,6 @@ WTErr WCMRCoreAudioDevice::TearDownAUHAL() CloseComponent(m_AUHALAudioUnit); m_AUHALAudioUnit = NULL; } - - safe_delete_array(m_pInputData); return retVal; } @@ -1759,7 +1742,6 @@ WTErr WCMRCoreAudioDevice::SetActive (bool newState) if (newState) { - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Setting up AUHAL."); retVal = SetupAUHAL(); @@ -1907,7 +1889,6 @@ WTErr WCMRCoreAudioDevice::SetStreaming (bool newState) SetupToneGenerator (); #endif //WV_USE_TONE_GEN - m_StopRequested = false; m_SampleCountAtLastIdle = 0; m_StalledSampleCounter = 0; m_SampleCounter = 0; @@ -1924,6 +1905,8 @@ WTErr WCMRCoreAudioDevice::SetStreaming (bool newState) err = AudioOutputUnitStart (m_AUHALAudioUnit); + m_StopRequested = false; + if(err) { DEBUG_MSG( "Failed to start AudioUnit, err " << err ); @@ -1938,11 +1921,11 @@ WTErr WCMRCoreAudioDevice::SetStreaming (bool newState) err = AudioOutputUnitStop (m_AUHALAudioUnit); if (!err) { - if (!m_InputChannels.empty()); + //if (!m_InputChannels.empty()); { err = AudioUnitReset (m_AUHALAudioUnit, kAudioUnitScope_Global, AUHAL_INPUT_ELEMENT); } - if (!m_OutputChannels.empty()); + //if (!m_OutputChannels.empty()); { err = AudioUnitReset (m_AUHALAudioUnit, kAudioUnitScope_Global, AUHAL_OUTPUT_ELEMENT); } @@ -1981,6 +1964,7 @@ Exit: //********************************************************************************************** WTErr WCMRCoreAudioDevice::DoIdle () { + /* if (m_BufferSizeChangeRequested != m_BufferSizeChangeReported) { m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged); @@ -2033,7 +2017,7 @@ WTErr WCMRCoreAudioDevice::DoIdle () m_StalledSampleCounter = 0; m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStoppedStreaming, (void *)currentSampleCount); } - } + }*/ return (eNoErr); @@ -2198,19 +2182,38 @@ OSStatus WCMRCoreAudioDevice::AudioIOProc(AudioUnitRenderActionFlags * ioAction OSStatus retVal = 0; if (m_StopRequested) - goto Exit; + return retVal; if (m_IOProcThreadPort == 0) m_IOProcThreadPort = mach_thread_self (); //cannot really deal with it unless the number of frames are the same as our buffer size! if (inNumberFrames != (UInt32)m_CurrentBufferSize) - goto Exit; + return retVal; //Retrieve the input data... if (!m_InputChannels.empty()) { - retVal = AudioUnitRender(m_AUHALAudioUnit, ioActionFlags, inTimeStamp, AUHAL_INPUT_ELEMENT, inNumberFrames, &m_InputAudioBufferList); + UInt32 expectedDataSize = m_InputChannels.size() * m_CurrentBufferSize * sizeof(float); + AudioBufferList inputAudioBufferList; + inputAudioBufferList.mNumberBuffers = 1; + inputAudioBufferList.mBuffers[0].mNumberChannels = m_InputChannels.size(); + inputAudioBufferList.mBuffers[0].mDataByteSize = expectedDataSize*10; + inputAudioBufferList.mBuffers[0].mData = NULL;//new float[expectedDataSize]; // we are going to get buffer from CoreAudio + + retVal = AudioUnitRender(m_AUHALAudioUnit, ioActionFlags, inTimeStamp, AUHAL_INPUT_ELEMENT, inNumberFrames, &inputAudioBufferList); + + if (retVal == kAudioHardwareNoError && + inputAudioBufferList.mBuffers[0].mNumberChannels == m_InputChannels.size() && + inputAudioBufferList.mBuffers[0].mDataByteSize == expectedDataSize ) + { + m_pInputData = (float*)inputAudioBufferList.mBuffers[0].mData; + } + else + { + m_pInputData = NULL; + return retVal; + } } //is this an input only device? @@ -2219,7 +2222,6 @@ OSStatus WCMRCoreAudioDevice::AudioIOProc(AudioUnitRenderActionFlags * ioAction else if ((!m_OutputChannels.empty()) && (ioData->mBuffers[0].mNumberChannels == m_OutputChannels.size())) AudioCallback ((float *)ioData->mBuffers[0].mData, inNumberFrames, (uint32_t)inTimeStamp->mSampleTime, theStartTime); -Exit: return retVal; } @@ -2398,7 +2400,7 @@ WCMRCoreAudioDeviceManager::WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerCli } //add a listener to find out when devices change... - AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, DevicePropertyChangeCallback, this); + AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, HardwarePropertyChangeCallback, this); //Always add the None device first... m_NoneDevice = new WCMRNativeAudioNoneDevice(this); @@ -2929,7 +2931,7 @@ WTErr WCMRCoreAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & d } -OSStatus WCMRCoreAudioDeviceManager::DevicePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* inClientData) +OSStatus WCMRCoreAudioDeviceManager::HardwarePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* inClientData) { switch (inPropertyID) { @@ -2940,9 +2942,10 @@ OSStatus WCMRCoreAudioDeviceManager::DevicePropertyChangeCallback (AudioHardware pManager->updateDeviceListImpl(); } break; + default: break; } return 0; -} +} \ No newline at end of file diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.h b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.h index 5cfbedb9c9..143c4eaf9c 100644 --- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.h +++ b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.h @@ -81,7 +81,7 @@ protected: AudioDeviceID m_DeviceID; ///< The CoreAudio device id bool m_StopRequested; ///< should be set to true when want to stop, set to false otherwise. - float *m_pInputData; ///< This is what came in with the most recent callback. + float *m_pInputData; ///< This is what came in with the most recent callback. int m_SampleCounter; ///< The current running sample counter, updated by the audio callback. int m_SampleCountAtLastIdle; ///< What was the sample count last time we checked... int m_StalledSampleCounter; ///< The number of idle calls with same sample count detected @@ -93,9 +93,7 @@ protected: // int m_CyclesToAccumulate; ///< The number of cycles to accumulate the values for - maximum for last one second. // unsigned int m_CyclePeriod; ///< The number of host time units for a cycle period - determined by buffer size and sampling rate - - - AudioBufferList m_InputAudioBufferList; ///< The buffer list used to get AHHAL to render input to. + AudioUnit m_AUHALAudioUnit;///< The AUHAL AudioUnit int m_BufferSizeChangeRequested; @@ -152,6 +150,7 @@ protected: AudioDevicePropertyID inPropertyID, void *inClientData); void PropertyChangeProc (AudioDevicePropertyID inPropertyID); + void resetAudioDevice(); private: }; @@ -168,7 +167,7 @@ public: virtual ~WCMRCoreAudioDeviceManager(void); ///< Destructor protected: - static OSStatus DevicePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* inClientData); + static OSStatus HardwarePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* inClientData); virtual WCMRAudioDevice* initNewCurrentDeviceImpl(const std::string & deviceName); virtual void destroyCurrentDeviceImpl();