diff options
Diffstat (limited to 'libs/backends/wavesaudio/wavesapi/devicemanager')
9 files changed, 0 insertions, 6686 deletions
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/IncludeWindows.h b/libs/backends/wavesaudio/wavesapi/devicemanager/IncludeWindows.h deleted file mode 100644 index 53ed7e69bc..0000000000 --- a/libs/backends/wavesaudio/wavesapi/devicemanager/IncludeWindows.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - Copyright (C) 2014 Waves Audio Ltd. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef __IncludeWindows_h__ -#define __IncludeWindows_h__ - -#ifdef PLATFORM_WINDOWS - -/* Copy to include -#include "IncludeWindows.h" -*/ - -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0601 // Windows 7 -#endif - -#ifndef WINVER -#define WINVER 0x0601 // Windows 7 -#endif - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif - -#ifndef NOMINMAX -#define NOMINMAX // DO NOT REMOVE NOMINMAX - DOING SO CAUSES CONFLICTS WITH STD INCLUDES (<limits> ...) -#endif - -#include <winsock2.h> -#include <windows.h> -#include <objbase.h> -#endif // #if PLATFORM_WINDOWS -#endif // #ifndef __IncludeWindows_h__ - diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.cpp b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.cpp deleted file mode 100644 index 7c4a3e9962..0000000000 --- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.cpp +++ /dev/null @@ -1,692 +0,0 @@ -//---------------------------------------------------------------------------------- -// -// Copyright (c) 2008 Waves Audio Ltd. All rights reserved. -// -//! \file WCMRAudioDeviceManager.cpp -//! -//! WCMRAudioDeviceManager and related class declarations -//! -//---------------------------------------------------------------------------------*/ -#include <iostream> -#include "WCMRAudioDeviceManager.h" - - -//********************************************************************************************** -// WCMRAudioDevice::WCMRAudioDevice -// -//! Constructor for the audio device. The derived classes will need to do more actual work, such -//! as determining supported sampling rates, buffer sizes, and channel counts. Connection -//! and streaming will also be provided by the derived implementations. -//! -//! \param *pManager : The audio device manager that's managing this device. -//! \return Nothing. -//! -//********************************************************************************************** -WCMRAudioDevice::WCMRAudioDevice (WCMRAudioDeviceManager *pManager) : - m_pMyManager (pManager) - , m_ConnectionStatus (DeviceDisconnected) - , m_IsActive (false) - , m_IsStreaming (false) - , m_CurrentSamplingRate (-1) - , m_CurrentBufferSize (0) - , m_LeftMonitorChannel (-1) - , m_RightMonitorChannel (-1) - , m_MonitorGain (1.0f) -{ - m_DeviceName = "Unknown"; -} - - - -//********************************************************************************************** -// WCMRAudioDevice::~WCMRAudioDevice -// -//! Destructor for the audio device. It release all the connections that were created. -//! -//! \param none -//! -//! \return Nothing. -//! -//********************************************************************************************** -WCMRAudioDevice::~WCMRAudioDevice () -{ - AUTO_FUNC_DEBUG; - try - { - } - catch (...) - { - //destructors should absorb exceptions, no harm in logging though!! - DEBUG_MSG ("Exception during destructor"); - } -} - - - - -//********************************************************************************************** -// WCMRAudioDevice::DeviceName -// -//! Retrieves Device's name. -//! -//! \param none -//! -//! \return The device name. -//! -//********************************************************************************************** -const std::string& WCMRAudioDevice::DeviceName () const -{ - return (m_DeviceName); - -} - - - -//********************************************************************************************** -// WCMRAudioDevice::InputChannels -// -//! Retrieves Input Channel information. Note that the list may be changed at run-time. -//! -//! \param none -//! -//! \return A vector with Input Channel Names. -//! -//********************************************************************************************** -const std::vector<std::string>& WCMRAudioDevice::InputChannels () -{ - return (m_InputChannels); - -} - - - -//********************************************************************************************** -// WCMRAudioDevice::OutputChannels -// -//! Retrieves Output Channel Information. Note that the list may be changed at run-time. -//! -//! \param none -//! -//! \return A vector with Output Channel Names. -//! -//********************************************************************************************** -const std::vector<std::string>& WCMRAudioDevice::OutputChannels () -{ - return (m_OutputChannels); -} - - - - -//********************************************************************************************** -// WCMRAudioDevice::SamplingRates -// -//! Retrieves supported sampling rate information. -//! -//! \param none -//! -//! \return A vector with supported sampling rates. -//! -//********************************************************************************************** -const std::vector<int>& WCMRAudioDevice::SamplingRates () -{ - return (m_SamplingRates); -} - - - -//********************************************************************************************** -// WCMRAudioDevice::CurrentSamplingRate -// -//! The device's current sampling rate. This may be overridden, if the device needs to -//! query the driver for the current rate. -//! -//! \param none -//! -//! \return The device's current sampling rate. -1 on error. -//! -//********************************************************************************************** -int WCMRAudioDevice::CurrentSamplingRate () -{ - return (m_CurrentSamplingRate); -} - - - - -//********************************************************************************************** -// WCMRAudioDevice::SetCurrentSamplingRate -// -//! Change the sampling rate to be used by the device. This will most likely be overridden, -//! the base class simply updates the member variable. -//! -//! \param newRate : The rate to use (samples per sec). -//! -//! \return eNoErr always. The derived classes may return error codes. -//! -//********************************************************************************************** -WTErr WCMRAudioDevice::SetCurrentSamplingRate (int newRate) -{ - //changes the status. - m_CurrentSamplingRate = newRate; - return (eNoErr); -} - - - - -//********************************************************************************************** -// WCMRAudioDevice::BufferSizes -// -//! Retrieves supported buffer size information. -//! -//! \param none -//! -//! \return A vector with supported buffer sizes. -//! -//********************************************************************************************** -const std::vector<int>& WCMRAudioDevice::BufferSizes () -{ - return (m_BufferSizes); -} - - - -//********************************************************************************************** -// WCMRAudioDevice::CurrentBufferSize -// -//! The device's current buffer size in use. This may be overridden, if the device needs to -//! query the driver for the current size. -//! -//! \param none -//! -//! \return The device's current buffer size. 0 on error. -//! -//********************************************************************************************** -int WCMRAudioDevice::CurrentBufferSize () -{ - return (m_CurrentBufferSize); -} - -//********************************************************************************************** -// WCMRAudioDevice::CurrentBlockSize -// -//! Device's block size we use for holding the audio samples. -//! Usually this is equal to the buffer size, but in some cases the buffer size holds additional -//! data other then the audio buffers, like frames info in SG, so it can be overridden -//! -//! \param none -//! -//! \return The device's current block size. 0 on error. -//! -//********************************************************************************************** -int WCMRAudioDevice::CurrentBlockSize() -{ - // By default - return the buffer size - return CurrentBufferSize(); -} - - -//********************************************************************************************** -// WCMRAudioDevice::SetCurrentBufferSize -// -//! Change the buffer size to be used by the device. This will most likely be overridden, -//! the base class simply updates the member variable. -//! -//! \param newSize : The buffer size to use (in sample-frames) -//! -//! \return eNoErr always. The derived classes may return error codes. -//! -//********************************************************************************************** -WTErr WCMRAudioDevice::SetCurrentBufferSize (int newSize) -{ - //This will most likely be overridden, the base class simply - //changes the member. - m_CurrentBufferSize = newSize; - return (eNoErr); -} - - - - -//********************************************************************************************** -// WCMRAudioDevice::ConnectionStatus -// -//! Retrieves the device's current connection status. This will most likely be overridden, -//! in case some driver communication is required to query the status. -//! -//! \param none -//! -//! \return A ConnectionStates value. -//! -//********************************************************************************************** -WCMRAudioDevice::ConnectionStates WCMRAudioDevice::ConnectionStatus () -{ - return (m_ConnectionStatus); - -} - - - - -//********************************************************************************************** -// WCMRAudioDevice::Active -// -//! Retrieves Device activation status. -//! -//! \param none -//! -//! \return true if device is active, false otherwise. -//! -//********************************************************************************************** -bool WCMRAudioDevice::Active () -{ - return (m_IsActive); - -} - - - -//********************************************************************************************** -// WCMRAudioDevice::SetActive -// -//! Sets the device's activation status. -//! -//! \param newState : Should be true to activate, false to deactivate. This roughly corresponds -//! to opening and closing the device handle/stream/audio unit. -//! -//! \return eNoErr always, the derived classes may return appropriate error code. -//! -//********************************************************************************************** -WTErr WCMRAudioDevice::SetActive (bool newState) -{ - //This will most likely be overridden, the base class simply - //changes the member. - m_IsActive = newState; - return (eNoErr); -} - - - - -//********************************************************************************************** -// WCMRAudioDevice::Streaming -// -//! Retrieves Device streaming status. -//! -//! \param none -//! -//! \return true if device is streaming, false otherwise. -//! -//********************************************************************************************** -bool WCMRAudioDevice::Streaming () -{ - return (m_IsStreaming); -} - - - -//********************************************************************************************** -// WCMRAudioDevice::SetStreaming -// -//! Sets the device's streaming status. -//! -//! \param newState : Should be true to start streaming, false to stop streaming. This roughly -//! corresponds to calling Start/Stop on the lower level interface. -//! -//! \return eNoErr always, the derived classes may return appropriate error code. -//! -//********************************************************************************************** -WTErr WCMRAudioDevice::SetStreaming (bool newState) -{ - // We must notify angine about our intention to start streming - // so Engine will provide all the initializations in the first audio callback - if (newState) { - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStartsStreaming); - } - - //This will most likely be overridden, the base class simply - //changes the member. - m_IsStreaming = newState; - return (eNoErr); -} - - -WTErr WCMRAudioDevice::ResetDevice () -{ - // Keep device sates - bool wasStreaming = Streaming(); - bool wasActive = Active(); - - WTErr err = SetStreaming(false); - - if (err == eNoErr) - err = SetActive(false); - - if (err == eNoErr && wasActive) - err = SetActive(true); - - if (err == eNoErr && wasStreaming) - SetStreaming(true); - - return err; -} - - -/////////////////////////////////////////////////////////////////////////////////////////////////////// -// IsProcessActive - returns true if process code is running. -// A normal audio device should return the Streaming() value -/////////////////////////////////////////////////////////////////////////////////////////////////////// -bool WCMRAudioDevice::IsProcessActive() -{ - return Streaming(); -} - - - - - -//********************************************************************************************** -// WCMRAudioDevice::DoIdle -// -//! A place for doing idle time processing. The derived classes will probably do something -//! meaningful. -//! -//! \param none -//! -//! \return eNoErr always. -//! -//********************************************************************************************** -WTErr WCMRAudioDevice::DoIdle () -{ - //We don't need to do anything here... - //the derived classes may want to use this however. - return (eNoErr); -} - - - - -//********************************************************************************************** -// WCMRAudioDevice::InputLevels -// -//! Retrieve current input levels. -//! -//! \param none -//! -//! \return A vector (the same size as input channels list) that contains current input levels. -//! -//********************************************************************************************** -const std::vector<float>& WCMRAudioDevice::InputLevels () -{ - //The derived classes may override if they need to query - //the driver for the levels. - return (m_InputLevels); -} - - - -//********************************************************************************************** -// WCMRAudioDevice::OutputLevels -// -//! Retrieve current output levels. -//! -//! \param none -//! -//! \return A vector (the same size as output channels list) that contains current output levels. -//! -//********************************************************************************************** -const std::vector<float>& WCMRAudioDevice::OutputLevels () -{ - //The derived classes may override if they need to query - //the driver for the levels. - return (m_OutputLevels); -} - - - -//********************************************************************************************** -// WCMRAudioDevice::GetMonitorInfo -// -//! Retrieves current monitoring information. -//! -//! \param *pLeftChannel : Pointer to receive left monitor channel index. -//! \param *pRightChannel : Pointer to receive right monitor channel index. -//! \param *pGain : Pointer to receive the gain (linear) to be applied. -//! -//! \return Nothing. -//! -//********************************************************************************************** -void WCMRAudioDevice::GetMonitorInfo (int *pLeftChannel, int *pRightChannel, float *pGain) -{ - if (pLeftChannel) - *pLeftChannel = m_LeftMonitorChannel; - if (pRightChannel) - *pRightChannel = m_RightMonitorChannel; - if (pGain) - *pGain = m_MonitorGain; - return; -} - - - -//********************************************************************************************** -// WCMRAudioDevice::SetMonitorChannels -// -//! Used to set the channels to be used for monitoring. -//! -//! \param leftChannel : Left monitor channel index. -//! \param rightChannel : Right monitor channel index. -//! -//! \return eNoErr always, the derived classes may return appropriate errors. -//! -//********************************************************************************************** -WTErr WCMRAudioDevice::SetMonitorChannels (int leftChannel, int rightChannel) -{ - //This will most likely be overridden, the base class simply - //changes the member. - m_LeftMonitorChannel = leftChannel; - m_RightMonitorChannel = rightChannel; - return (eNoErr); -} - - - -//********************************************************************************************** -// WCMRAudioDevice::SetMonitorGain -// -//! Used to set monitor gain (or atten). -//! -//! \param newGain : The new gain or atten. value to use. Specified as a linear multiplier (not dB) -//! -//! \return eNoErr always, the derived classes may return appropriate errors. -//! -//********************************************************************************************** -WTErr WCMRAudioDevice::SetMonitorGain (float newGain) -{ - //This will most likely be overridden, the base class simply - //changes the member. - m_MonitorGain = newGain; - return (eNoErr); -} - - - - -//********************************************************************************************** -// WCMRAudioDevice::ShowConfigPanel -// -//! Used to show device specific config/control panel. Some interfaces may not support it. -//! Some interfaces may require the device to be active before it can display a panel. -//! -//! \param pParam : A device/interface specific parameter - optional. -//! -//! \return eNoErr always, the derived classes may return errors. -//! -//********************************************************************************************** -WTErr WCMRAudioDevice::ShowConfigPanel (void *WCUNUSEDPARAM(pParam)) -{ - //This will most likely be overridden... - return (eNoErr); -} - - -//********************************************************************************************** -// WCMRAudioDevice::SendCustomCommand -// -//! Used to Send a custom command to the audiodevice. Some interfaces may require the device -//! to be active before it can do anything in this. -//! -//! \param customCommand : A device/interface specific command. -//! \param pCommandParam : A device/interface/command specific parameter - optional. -//! -//! \return eNoErr always, the derived classes may return errors. -//! -//********************************************************************************************** -WTErr WCMRAudioDevice::SendCustomCommand (int WCUNUSEDPARAM(customCommand), void *WCUNUSEDPARAM(pCommandParam)) -{ - //This will most likely be overridden... - return (eNoErr); -} - -//********************************************************************************************** -// WCMRAudioDevice::GetLatency -// -//! Get Latency for device. -//! -//! Use 'kAudioDevicePropertyLatency' and 'kAudioDevicePropertySafetyOffset' + GetStreamLatencies -//! -//! \param isInput : Return latency for the input if isInput is true, otherwise the output latency -//! wiil be returned. -//! \return Latency in samples. -//! -//********************************************************************************************** -uint32_t WCMRAudioDevice::GetLatency (bool isInput) -{ - //This will most likely be overridden... - return 0; -} - - -//********************************************************************************************** -// WCMRAudioDeviceManager::WCMRAudioDeviceManager -// -//! The constructuor, most of the work will be done in the derived class' constructor. -//! -//! \param *pTheClient : -//! -//! \return Nothing. -//! -//********************************************************************************************** -WCMRAudioDeviceManager::WCMRAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter) - : m_eAudioDeviceFilter(eCurAudioDeviceFilter) - , m_CurrentDevice(0) - , m_pTheClient (pTheClient) -{ -} - - -//********************************************************************************************** -// WCMRAudioDeviceManager::~WCMRAudioDeviceManager -// -//! It clears the device list, releasing each of the device. -//! -//! \param none -//! -//! \return Nothing. -//! -//********************************************************************************************** -WCMRAudioDeviceManager::~WCMRAudioDeviceManager() -{ - AUTO_FUNC_DEBUG; - - std::cout << "API::Destroying AudioDeviceManager " << std::endl; - try - { - // clean up device info list - { - wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex); - while( m_DeviceInfoVec.size() ) - { - DeviceInfo* devInfo = m_DeviceInfoVec.back(); - m_DeviceInfoVec.pop_back(); - delete devInfo; - } - } - delete m_CurrentDevice; - - } - catch (...) - { - //destructors should absorb exceptions, no harm in logging though!! - DEBUG_MSG ("Exception during destructor"); - } -} - - -WCMRAudioDevice* WCMRAudioDeviceManager::InitNewCurrentDevice(const std::string & deviceName) -{ - return initNewCurrentDeviceImpl(deviceName); -} - - -void WCMRAudioDeviceManager::DestroyCurrentDevice() -{ - return destroyCurrentDeviceImpl(); -} - - -const DeviceInfoVec WCMRAudioDeviceManager::DeviceInfoList() const -{ - wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex); - return m_DeviceInfoVec; -} - - -WTErr WCMRAudioDeviceManager::GetDeviceInfoByName(const std::string & nameToMatch, DeviceInfo & devInfo) const -{ - wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex); - DeviceInfoVecConstIter iter = m_DeviceInfoVec.begin(); - for (; iter != m_DeviceInfoVec.end(); ++iter) - { - if (nameToMatch == (*iter)->m_DeviceName) - { - devInfo = *(*iter); - return eNoErr; - } - } - - return eRMResNotFound; -} - - -WTErr WCMRAudioDeviceManager::GetDeviceSampleRates(const std::string & nameToMatch, std::vector<int>& sampleRates) const -{ - return getDeviceSampleRatesImpl(nameToMatch, sampleRates); -} - - - -WTErr WCMRAudioDeviceManager::GetDeviceBufferSizes(const std::string & nameToMatch, std::vector<int>& bufferSizes) const -{ - return getDeviceBufferSizesImpl(nameToMatch, bufferSizes); -} - - -//********************************************************************************************** -// WCMRAudioDeviceManager::NotifyClient -// -//! A helper routine used to call the client for notification. -//! -//! \param forReason : The reason for notification. -//! \param *pParam : A parameter (if required) for notification. -//! -//! \return Nothing. -//! -//********************************************************************************************** -void WCMRAudioDeviceManager::NotifyClient (WCMRAudioDeviceManagerClient::NotificationReason forReason, void *pParam) -{ - if (m_pTheClient) - m_pTheClient->AudioDeviceManagerNotification (forReason, pParam); - return; -} diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.h b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.h deleted file mode 100644 index b22e35263d..0000000000 --- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.h +++ /dev/null @@ -1,271 +0,0 @@ -/* - Copyright (C) 2014 Waves Audio Ltd. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -//---------------------------------------------------------------------------------- -// -// -//! \file WCMRAudioDeviceManager.h -//! -//! WCMRAudioDeviceManager and related class declarations -//! -//---------------------------------------------------------------------------------*/ -#ifndef __WCMRAudioDeviceManager_h_ - #define __WCMRAudioDeviceManager_h_ - -/* Copy to include -#include "WCMRAudioDeviceManager.h" -*/ - -#define AUTO_FUNC_DEBUG -#define DEBUG_MSG(a) -#define ASSERT_ERROR(a, b) -#define TRACE_MSG(a) - -#include <string> -#include <vector> -#include <map> -#include "WCRefManager.h" -#include "BasicTypes/WUTypes.h" -#include "WUErrors.h" -#include "WCThreadSafe.h" - -#define WCUNUSEDPARAM(a) - -class WCMRAudioDevice; -class WCMRAudioDeviceManager; - -typedef unsigned int DeviceID; - -struct DeviceInfo -{ - DeviceID m_DeviceId; - std::string m_DeviceName; - std::vector<int> m_AvailableSampleRates; - std::vector<int> m_AvailableBufferSizes; - unsigned int m_MaxInputChannels; - unsigned int m_MaxOutputChannels; - - DeviceInfo(): - m_DeviceId(-1), m_DeviceName("Unknown"), m_MaxInputChannels(0), m_MaxOutputChannels(0) - {}; - - DeviceInfo(unsigned int deviceID, const std::string & deviceName): - m_DeviceId(deviceID), m_DeviceName(deviceName), m_MaxInputChannels(0), m_MaxOutputChannels(0) - {}; -}; - -typedef std::vector<DeviceInfo*> DeviceInfoVec; -typedef DeviceInfoVec::iterator DeviceInfoVecIter; -typedef DeviceInfoVec::const_iterator DeviceInfoVecConstIter; - -/// for notification... A client must derive it's class from us. -class WCMRAudioDeviceManagerClient -{ - public: - enum NotificationReason - { - DeviceListChanged, - Dropout, - RequestReset, - RequestResync, - SamplingRateChanged, //param has new SR, or -1 if not known - SamplingRateChangedSilent, //To indicate sampling rate changed but no need to notify user - BufferSizeChanged, - ClockSourceChanged, - DeviceStoppedStreaming, - DeviceStartsStreaming, - DeviceDroppedSamples, - DeviceConnectionLost, - DeviceGenericError, - DeviceStatusChanged, - DeviceStatisticsUpdated, - DeviceDebugInfo, //param has c string - DeviceProgressInfo, //param has c string - MIDIData, - MIDINodeUp, - MIDINodeDown, - DeviceSampleRateMisMatch, - SystemSamplingRateChangedInfoOnly, - LostClockSource, - IODeviceDisconnected, - ChannelCountModified, - MasterUp, - MasterDown, - AudioDropFound, - ReflasherEvent, - AGDeviceSamplingRateChangedInfoOnly, - IODeviceNameChanged, - SetDisplayNameFromIOModule, - IOMStateChanged, ///< This is used when IOM state is changed. - AudioCallback // VKamyshniy: param is AudioCallbackDataData* - }; - - WCMRAudioDeviceManagerClient () {} - virtual ~WCMRAudioDeviceManagerClient () {} - - // VKamyshniy: This is a structure to call the client's AudioDeviceManagerNotification - // every AudioCallback time - struct AudioCallbackData - { - const float *acdInputBuffer; - float *acdOutputBuffer; - size_t acdFrames; - int64_t acdSampleTime; - uint64_t acdCycleStartTimeNanos; - }; - - virtual void AudioDeviceManagerNotification (NotificationReason WCUNUSEDPARAM(reason), void *WCUNUSEDPARAM(pParam)) {} -}; - - -class WCMRAudioDevice : public WCRefManager -{ -public: - - enum ConnectionStates - { - DeviceAvailable, - DeviceDisconnected, - DeviceErrors - }; - - WCMRAudioDevice (WCMRAudioDeviceManager *pManager);///<Constructor - virtual ~WCMRAudioDevice ();///<Destructor - - virtual const std::string& DeviceName() const;///<Name? - virtual const std::vector<std::string>& InputChannels();///<Current Input Channel List? - note that this may change with change in sampling rate. - virtual const std::vector<std::string>& OutputChannels();///<Current Output Channel List? - note that this may change with change in sampling rate. - - virtual const std::vector<int>& SamplingRates();///<Supported Sampling Rate List? - virtual int CurrentSamplingRate(); ///<Current Sampling rate.? - virtual WTErr SetCurrentSamplingRate(int newRate);///<Change Current Sampling Rate : This is a requset, might not be successful at run time! - - virtual const std::vector<int>& BufferSizes();///<Supported Buffer Size List? - note that this may change with change in sampling rate. - virtual int CurrentBufferSize();///<Current Buffer Size.? - note that this may change with change in sampling rate. - virtual WTErr SetCurrentBufferSize (int newSize);///<Change Current Buffer Size : This is a requset, might not be successful at run time! - - virtual int CurrentBlockSize(); - - virtual ConnectionStates ConnectionStatus();///< Connection Status - device available, gone, disconnected - - virtual bool Active();///<Active status - mainly significant for ASIO, as certain ops can only be performed on active devices! - virtual WTErr SetActive (bool newState);///<Prepare/Activate device. - - virtual bool Streaming();///<Streaming Status? - virtual WTErr SetStreaming (bool newState);///<Start/Stop Streaming - should reconnect connections when streaming starts! - - virtual WTErr ResetDevice (); - - virtual bool IsProcessActive(); - - virtual WTErr DoIdle();///<Do Idle Processing - - virtual const std::vector<float>& InputLevels();///<Retrieve Input Levels (for VU display)? - - virtual const std::vector<float>& OutputLevels();///<Retrieve Output Levels (for VU display)? - - void GetMonitorInfo (int *pLeftChannel = NULL, int *pRightChannel = NULL, float *pGain = NULL);///<Retrieve current monitor channel pair and gain - optional, will not be available with AG - virtual WTErr SetMonitorChannels (int leftChannel, int rightChannel);///<Set monitor channels. - optional, will not be available with AG - virtual WTErr SetMonitorGain (float newGain);///<Set monitor gain. - optional, will not be available with AG - - virtual WTErr ShowConfigPanel (void *pParam);///< Show Control Panel - in case of ASIO this will work only with Active device! - virtual WTErr SendCustomCommand (int customCommand, void *pCommandParam); ///< Send a custom command to the audiodevice... - - virtual uint32_t GetLatency (bool isInput); ///Get latency. - - virtual WTErr UpdateDeviceInfo () = 0; - -protected: - WCMRAudioDeviceManager *m_pMyManager; ///< The manager who's managing this device, can be used for sending notifications! - - std::string m_DeviceName; ///< Name of the device. - std::vector<std::string> m_InputChannels; ///< List of input channel names. - std::vector<std::string> m_OutputChannels; ///< List of output channel names. - std::vector<int> m_SamplingRates; ///< List of available sampling rates. - std::vector<int> m_BufferSizes; ///< List of available buffer sizes. - - int m_CurrentSamplingRate; ///< Currently selected sampling rate. - int m_CurrentBufferSize; ///< Currently selected buffer size. - - ConnectionStates m_ConnectionStatus; ///< Status of device connection - bool m_IsActive; ///< Flag for teh active status. - bool m_IsStreaming; ///< Flag for streaming status. - std::vector<float> m_InputLevels; ///< List of input levels. - std::vector<float> m_OutputLevels; ///< List of output levels. - - int m_LeftMonitorChannel; ///< The device channel to use for monitoring left channel data. - int m_RightMonitorChannel; ///< The device channel to use for monitoring right channel data. - float m_MonitorGain; ///< Amount of gain to apply for monitoring signal. -}; - - -// This enum is for choosing filter for audio devices scan -typedef enum eAudioDeviceFilter -{ - eAllDevices = 0, // Choose all audio devices - eInputOnlyDevices, // Choose only input audio devices - eOutputOnlyDevices, // Choose only output audio devices - eFullDuplexDevices, // Choose audio devices that have both input and output channels on the same device - eMatchedDuplexDevices, // Match(aggregate) audio devices that have both input and output channels but are considered different audio devices (For mac) - eAudioDeviceFilterNum // Number of enums -} eAudioDeviceFilter; - - -class WCMRAudioDeviceManager : public WCRefManager -{ -public://< Public functions for the class. - - WCMRAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter); ///< constructor - virtual ~WCMRAudioDeviceManager(void); ///< Destructor - - //interfaces - WCMRAudioDevice* InitNewCurrentDevice(const std::string & deviceName); - void DestroyCurrentDevice(); - const DeviceInfoVec DeviceInfoList () const; - WTErr GetDeviceInfoByName(const std::string & nameToMatch, DeviceInfo & devInfo) const; - WTErr GetDeviceSampleRates(const std::string & nameToMatch, std::vector<int>& sampleRates) const; - WTErr GetDeviceBufferSizes(const std::string & nameToMatch, std::vector<int>& bufferSizes) const; - - //virtual void EnableVerboseLogging(bool /*bEnable*/, const std::string& /*logFilePath*/) { }; - - //notify backend - void NotifyClient (WCMRAudioDeviceManagerClient::NotificationReason forReason, void *pParam = NULL); - -protected: - - mutable wvNS::wvThread::ThreadMutex m_AudioDeviceInfoVecMutex; // mutex to lock device info list - DeviceInfoVec m_DeviceInfoVec; - - eAudioDeviceFilter m_eAudioDeviceFilter; - WCMRAudioDevice* m_CurrentDevice; - -private: - // override in derived classes - // made private to avoid pure virtual function call - virtual WCMRAudioDevice* initNewCurrentDeviceImpl(const std::string & deviceName) = 0; - virtual void destroyCurrentDeviceImpl() = 0; - virtual WTErr getDeviceSampleRatesImpl(const std::string & deviceName, std::vector<int>& sampleRates) const = 0; - virtual WTErr getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& bufferSizes) const = 0; - virtual WTErr generateDeviceListImpl() = 0; - virtual WTErr updateDeviceListImpl() = 0; - - WCMRAudioDeviceManagerClient *m_pTheClient; ///< The device manager's client, used to send notifications. -}; - -#endif //#ifndef __WCMRAudioDeviceManager_h_ diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp deleted file mode 100644 index 2a9a9ba19f..0000000000 --- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp +++ /dev/null @@ -1,3140 +0,0 @@ -//---------------------------------------------------------------------------------- -// -// Copyright (c) 2008 Waves Audio Ltd. All rights reserved. -// -//! \file WCMRCoreAudioDeviceManager.cpp -//! -//! WCMRCoreAudioDeviceManager and related class declarations -//! -//---------------------------------------------------------------------------------*/ -#include "WCMRCoreAudioDeviceManager.h" -#include <CoreServices/CoreServices.h> -#include "MiscUtils/safe_delete.h" -#include <sstream> -#include <syslog.h> - -// This flag is turned to 1, but it does not work with aggregated devices. -// due to problems with aggregated devices this flag is not functional there -#define ENABLE_DEVICE_CHANGE_LISTNER 1 - -#define PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS 10 -#define PROPERTY_CHANGE_TIMEOUT_SECONDS 5 -#define USE_IOCYCLE_TIMES 1 ///< Set this to 0 to use individual thread cpu measurement - -using namespace wvNS; -///< Supported Sample rates -static const double gAllSampleRates[] = -{ - 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0, -1 /* negative terminated list */ -}; - - -///< Default Supported Buffer Sizes. -static const int gAllBufferSizes[] = -{ - 32, 64, 96, 128, 192, 256, 512, 1024, 2048, -1 /* negative terminated list */ -}; - - -///< The default SR. -static const int DEFAULT_SR = 44100; -///< The default buffer size. -static const int DEFAULT_BUFFERSIZE = 1024; - -static const int NONE_DEVICE_ID = -1; - -///< Number of stalls to wait before notifying user... -static const int NUM_STALLS_FOR_NOTIFICATION = 2 * 50; // 2*50 corresponds to 2 * 50 x 42 ms idle timer - about 4 seconds. -static const int CHANGE_CHECK_COUNTER_PERIOD = 100; // 120 corresponds to 120 x 42 ms idle timer - about 4 seconds. - -#define AUHAL_OUTPUT_ELEMENT 0 -#define AUHAL_INPUT_ELEMENT 1 - -#include <sys/sysctl.h> - -static int getProcessorCount() -{ - int count = 1; - size_t size = sizeof(count); - - if (sysctlbyname("hw.ncpu", &count, &size, NULL, 0)) - return 1; - - //if something did not work, let's revert to a safe value... - if (count == 0) - count = 1; - - return count; -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::WCMRCoreAudioDevice -// -//! Constructor for the audio device. Opens the PA device and gets information about the device. -//! such as determining supported sampling rates, buffer sizes, and channel counts. -//! -//! \param *pManager : The audio device manager that's managing this device. -//! \param deviceID : The port audio device ID. -//! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true. -//! -//! \return Nothing. -//! -//********************************************************************************************** -WCMRCoreAudioDevice::WCMRCoreAudioDevice (WCMRCoreAudioDeviceManager *pManager, AudioDeviceID deviceID, bool useMultithreading, bool bNocopy) - : WCMRNativeAudioDevice (pManager, useMultithreading, bNocopy) - , m_SampleCountAtLastIdle (0) - , m_StalledSampleCounter(0) - , m_SampleCounter(0) - , m_BufferSizeChangeRequested (0) - , m_BufferSizeChangeReported (0) - , m_ResetRequested (0) - , m_ResetReported (0) - , m_ResyncRequested (0) - , m_ResyncReported (0) - , m_SRChangeRequested (0) - , m_SRChangeReported (0) - , m_ChangeCheckCounter(0) - , m_IOProcThreadPort (0) - , m_DropsDetected(0) - , m_DropsReported(0) - , m_IgnoreThisDrop(true) - , m_LastCPULog(0) -#if WV_USE_TONE_GEN - , m_pToneData(0) - , m_ToneDataSamples (0) - , m_NextSampleToUse (0) -#endif //WV_USE_TONE_GEN -{ - AUTO_FUNC_DEBUG; - UInt32 propSize = 0; - OSStatus err = kAudioHardwareNoError; - - //Update device info... - m_DeviceID = deviceID; - - m_CurrentSamplingRate = DEFAULT_SR; - m_CurrentBufferSize = DEFAULT_BUFFERSIZE; - m_StopRequested = true; - m_pInputData = NULL; - - m_CPUCount = getProcessorCount(); - m_LastCPULog = wvThread::now() - 10 * wvThread::ktdOneSecond; - - - - /* - @constant kAudioDevicePropertyNominalSampleRate - A Float64 that indicates the current nominal sample rate of the AudioDevice. - */ - Float64 currentNominalRate; - propSize = sizeof (currentNominalRate); - err = kAudioHardwareNoError; - if (AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, ¤tNominalRate) != kAudioHardwareNoError) - err = AudioDeviceGetProperty(m_DeviceID, 0, 1, kAudioDevicePropertyNominalSampleRate, &propSize, ¤tNominalRate); - - if (err == kAudioHardwareNoError) - m_CurrentSamplingRate = (int)currentNominalRate; - - /* - @constant kAudioDevicePropertyBufferFrameSize - A UInt32 whose value indicates the number of frames in the IO buffers. - */ - - UInt32 bufferSize; - propSize = sizeof (bufferSize); - err = kAudioHardwareNoError; - if (AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyBufferFrameSize, &propSize, &bufferSize) != kAudioHardwareNoError) - err = AudioDeviceGetProperty(m_DeviceID, 0, 1, kAudioDevicePropertyBufferFrameSize, &propSize, &bufferSize); - - if (err == kAudioHardwareNoError) - m_CurrentBufferSize = (int)bufferSize; - - - UpdateDeviceInfo(); - - //should use a valid current SR... - if (m_SamplingRates.size()) - { - //see if the current sr is present in the sr list, if not, use the first one! - std::vector<int>::iterator intIter = find(m_SamplingRates.begin(), m_SamplingRates.end(), m_CurrentSamplingRate); - if (intIter == m_SamplingRates.end()) - { - //not found... use the first one - m_CurrentSamplingRate = m_SamplingRates[0]; - } - } - - //should use a valid current buffer size - if (m_BufferSizes.size()) - { - //see if the current sr is present in the buffersize list, if not, use the first one! - std::vector<int>::iterator intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), m_CurrentBufferSize); - if (intIter == m_BufferSizes.end()) - { - //not found... use the first one - m_CurrentBufferSize = m_BufferSizes[0]; - } - } - - //build our input/output level lists - for (unsigned int currentChannel = 0; currentChannel < m_InputChannels.size(); currentChannel++) - { - m_InputLevels.push_back (0.0); - } - - //build our input/output level lists - for (unsigned int currentChannel = 0; currentChannel < m_OutputChannels.size(); currentChannel++) - { - m_OutputLevels.push_back (0.0); - } - -} - - - -//********************************************************************************************** -// WCMRCoreAudioDevice::~WCMRCoreAudioDevice -// -//! Destructor for the audio device. The base release all the connections that were created, if -//! they have not been already destroyed! Here we simply stop streaming, and close device -//! handles if necessary. -//! -//! \param none -//! -//! \return Nothing. -//! -//********************************************************************************************** -WCMRCoreAudioDevice::~WCMRCoreAudioDevice () -{ - AUTO_FUNC_DEBUG; - - try - { - //If device is streaming, need to stop it! - if (Streaming()) - { - SetStreaming (false); - } - - //If device is active (meaning stream is open) we need to close it. - if (Active()) - { - SetActive (false); - } - - } - catch (...) - { - //destructors should absorb exceptions, no harm in logging though!! - DEBUG_MSG ("Exception during destructor"); - } - -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::UpdateDeviceInfo -// -//! Updates Device Information about channels, sampling rates, buffer sizes. -//! -//! \return WTErr. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::UpdateDeviceInfo () -{ - AUTO_FUNC_DEBUG; - - WTErr retVal = eNoErr; - - // Some devices change the ID during restart - WTErr errId = UpdateDeviceId(); - - // Update all devices parts regardless of errors - WTErr errName = UpdateDeviceName(); - WTErr errIn = UpdateDeviceInputs(); - WTErr errOut = UpdateDeviceOutputs(); - WTErr errSR = eNoErr; - WTErr errBS = eNoErr; - - errSR = UpdateDeviceSampleRates(); - errBS = UpdateDeviceBufferSizes(); - - if(errId != eNoErr || errName != eNoErr || errIn != eNoErr || errOut != eNoErr || errSR != eNoErr || errBS != eNoErr) - { - retVal = eCoreAudioFailed; - } - - return retVal; -} - - -WTErr WCMRCoreAudioDevice::UpdateDeviceId() -{ - //Get device count... - UInt32 propSize = 0; - WTErr retVal = eNoErr; - OSStatus osErr = AudioHardwareGetPropertyInfo (kAudioHardwarePropertyDevices, &propSize, NULL); - ASSERT_ERROR(osErr, "AudioHardwareGetProperty 1"); - if (WUIsError(osErr)) - throw osErr; - - size_t numDevices = propSize / sizeof (AudioDeviceID); - AudioDeviceID* deviceIDs = new AudioDeviceID[numDevices]; - - //retrieve the device IDs - propSize = numDevices * sizeof (AudioDeviceID); - osErr = AudioHardwareGetProperty (kAudioHardwarePropertyDevices, &propSize, deviceIDs); - ASSERT_ERROR(osErr, "Error while getting audio devices: AudioHardwareGetProperty 2"); - if (WUIsError(osErr)) - throw osErr; - - //now add the ones that are not there... - for (size_t deviceIndex = 0; deviceIndex < numDevices; deviceIndex++) - { - DeviceInfo* pDevInfo = 0; - - //Get device name and create new DeviceInfo entry - //Get property name size. - osErr = AudioDeviceGetPropertyInfo(deviceIDs[deviceIndex], 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL); - if (osErr == kAudioHardwareNoError) - { - //Get property: name. - char* deviceName = new char[propSize]; - osErr = AudioDeviceGetProperty(deviceIDs[deviceIndex], 0, 0, kAudioDevicePropertyDeviceName, &propSize, deviceName); - if (osErr == kAudioHardwareNoError) - { - if ( (m_DeviceName == deviceName) && - (m_DeviceID != deviceIDs[deviceIndex]) ) { - - m_DeviceID = deviceIDs[deviceIndex]; - - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Current device has changed it's id."); - } - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device name. Device ID: " << m_DeviceID); - } - - delete [] deviceName; - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device name prop Info. Device ID: " << m_DeviceID); - } - } - - delete [] deviceIDs; - return retVal; -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::UpdateDeviceName -// -//! Updates Device name. -//! -//! Use 'kAudioDevicePropertyDeviceName' -//! -//! 1. Get property name size. -//! 2. Get property: name. -//! -//! \return WTErr. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::UpdateDeviceName() -{ - AUTO_FUNC_DEBUG; - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - UInt32 propSize = 0; - - // Initiate name to unknown. - m_DeviceName = "Unknown"; - - //! 1. Get property name size. - err = AudioDeviceGetPropertyInfo(m_DeviceID, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL); - if (err == kAudioHardwareNoError) - { - //! 2. Get property: name. - char* deviceName = new char[propSize]; - err = AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyDeviceName, &propSize, deviceName); - if (err == kAudioHardwareNoError) - { - m_DeviceName = deviceName; - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device name. Device ID: " << m_DeviceID); - } - - delete [] deviceName; - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device name property size. Device ID: " << m_DeviceID); - } - - return retVal; -} - -//********************************************************************************************** -// WCMRCoreAudioDevice::UpdateDeviceInputs -// -//! Updates Device Inputs. -//! -//! Use 'kAudioDevicePropertyStreamConfiguration' -//! This property returns the stream configuration of the device in an -//! AudioBufferList (with the buffer pointers set to NULL) which describes the -//! list of streams and the number of channels in each stream. This corresponds -//! to what will be passed into the IOProc. -//! -//! 1. Get property cannels input size. -//! 2. Get property: cannels input. -//! 3. Update input channels -//! -//! \return WTErr. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::UpdateDeviceInputs() -{ - AUTO_FUNC_DEBUG; - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - UInt32 propSize = 0; - int maxInputChannels = 0; - - // 1. Get property cannels input size. - err = AudioDeviceGetPropertyInfo (m_DeviceID, 0, 1/* Input */, kAudioDevicePropertyStreamConfiguration, &propSize, NULL); - if (err == kAudioHardwareNoError) - { - //! 2. Get property: cannels input. - - // Allocate size according to the property size. Note that this is a variable sized struct... - AudioBufferList *pStreamBuffers = (AudioBufferList *)malloc(propSize); - - if (pStreamBuffers) - { - memset (pStreamBuffers, 0, propSize); - - // Get the Input channels - err = AudioDeviceGetProperty (m_DeviceID, 0, true/* Input */, kAudioDevicePropertyStreamConfiguration, &propSize, pStreamBuffers); - if (err == kAudioHardwareNoError) - { - // Calculate the number of input channels - for (UInt32 streamIndex = 0; streamIndex < pStreamBuffers->mNumberBuffers; streamIndex++) - { - maxInputChannels += pStreamBuffers->mBuffers[streamIndex].mNumberChannels; - } - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device Input channels. Device Name: " << m_DeviceName.c_str()); - } - - free (pStreamBuffers); - } - else - { - retVal = eMemOutOfMemory; - DEBUG_MSG("Faild to allocate memory. Device Name: " << m_DeviceName.c_str()); - } - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device Input channels property size. Device Name: " << m_DeviceName.c_str()); - } - - // Update input channels - m_InputChannels.clear(); - - for (int channel = 0; channel < maxInputChannels; channel++) - { - CFStringRef cfName; - std::stringstream chNameStream; - UInt32 nameSize = 0; - OSStatus error = kAudioHardwareNoError; - - error = AudioDeviceGetPropertyInfo (m_DeviceID, - channel + 1, - true /* Input */, - kAudioDevicePropertyChannelNameCFString, - &nameSize, - NULL); - - if (error == kAudioHardwareNoError) - { - error = AudioDeviceGetProperty (m_DeviceID, - channel + 1, - true /* Input */, - kAudioDevicePropertyChannelNameCFString, - &nameSize, - &cfName); - } - - bool decoded = false; - char* cstr_name = 0; - if (error == kAudioHardwareNoError) - { - CFIndex length = CFStringGetLength(cfName); - CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); - cstr_name = new char[maxSize]; - decoded = CFStringGetCString(cfName, cstr_name, maxSize, kCFStringEncodingUTF8); - } - - chNameStream << (channel+1) << " - "; - - if (cstr_name && decoded && (0 != std::strlen(cstr_name) ) ) { - chNameStream << cstr_name; - } - else - { - chNameStream << "Input " << (channel+1); - } - - m_InputChannels.push_back (chNameStream.str()); - - delete [] cstr_name; - } - - return retVal; -} - -//********************************************************************************************** -// WCMRCoreAudioDevice::UpdateDeviceOutputs -// -//! Updates Device Outputs. -//! -//! Use 'kAudioDevicePropertyStreamConfiguration' -//! This property returns the stream configuration of the device in an -//! AudioBufferList (with the buffer pointers set to NULL) which describes the -//! list of streams and the number of channels in each stream. This corresponds -//! to what will be passed into the IOProc. -//! -//! 1. Get property cannels output size. -//! 2. Get property: cannels output. -//! 3. Update output channels -//! -//! \return Nothing. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::UpdateDeviceOutputs() -{ - AUTO_FUNC_DEBUG; - - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - UInt32 propSize = 0; - int maxOutputChannels = 0; - - //! 1. Get property cannels output size. - err = AudioDeviceGetPropertyInfo (m_DeviceID, 0, 0/* Output */, kAudioDevicePropertyStreamConfiguration, &propSize, NULL); - if (err == kAudioHardwareNoError) - { - //! 2. Get property: cannels output. - - // Allocate size according to the property size. Note that this is a variable sized struct... - AudioBufferList *pStreamBuffers = (AudioBufferList *)malloc(propSize); - if (pStreamBuffers) - { - memset (pStreamBuffers, 0, propSize); - - // Get the Output channels - err = AudioDeviceGetProperty (m_DeviceID, 0, 0/* Output */, kAudioDevicePropertyStreamConfiguration, &propSize, pStreamBuffers); - if (err == kAudioHardwareNoError) - { - // Calculate the number of output channels - for (UInt32 streamIndex = 0; streamIndex < pStreamBuffers->mNumberBuffers; streamIndex++) - { - maxOutputChannels += pStreamBuffers->mBuffers[streamIndex].mNumberChannels; - } - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device Output channels. Device Name: " << m_DeviceName.c_str()); - } - free (pStreamBuffers); - } - else - { - retVal = eMemOutOfMemory; - DEBUG_MSG("Faild to allocate memory. Device Name: " << m_DeviceName.c_str()); - } - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device Output channels property size. Device Name: " << m_DeviceName.c_str()); - } - - // Update output channels - m_OutputChannels.clear(); - for (int channel = 0; channel < maxOutputChannels; channel++) - { - CFStringRef cfName; - std::stringstream chNameStream; - UInt32 nameSize = 0; - OSStatus error = kAudioHardwareNoError; - - error = AudioDeviceGetPropertyInfo (m_DeviceID, - channel + 1, - false /* Output */, - kAudioDevicePropertyChannelNameCFString, - &nameSize, - NULL); - - if (error == kAudioHardwareNoError) - { - error = AudioDeviceGetProperty (m_DeviceID, - channel + 1, - false /* Output */, - kAudioDevicePropertyChannelNameCFString, - &nameSize, - &cfName); - } - - bool decoded = false; - char* cstr_name = 0; - if (error == kAudioHardwareNoError ) - { - CFIndex length = CFStringGetLength(cfName); - CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); - cstr_name = new char[maxSize]; - decoded = CFStringGetCString(cfName, cstr_name, maxSize, kCFStringEncodingUTF8); - } - - chNameStream << (channel+1) << " - "; - - if (cstr_name && decoded && (0 != std::strlen(cstr_name) ) ) { - chNameStream << cstr_name; - } - else - { - chNameStream << "Output " << (channel+1); - } - - m_OutputChannels.push_back (chNameStream.str()); - - delete [] cstr_name; - } - - return retVal; -} - -//********************************************************************************************** -// WCMRCoreAudioDevice::UpdateDeviceSampleRates -// -//! Updates Device Sample rates. -//! -//! Use 'kAudioDevicePropertyAvailableNominalSampleRates' -//! -//! 1. Get sample rate property size. -//! 2. Get property: sample rates. -//! 3. Update sample rates -//! -//! \return Nothing. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::UpdateDeviceSampleRates() -{ - AUTO_FUNC_DEBUG; - - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - UInt32 propSize = 0; - - m_SamplingRates.clear(); - - //! 1. Get sample rate property size. - err = AudioDeviceGetPropertyInfo(m_DeviceID, 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, NULL); - if (err == kAudioHardwareNoError) - { - //! 2. Get property: cannels output. - - // Allocate size accrding to the number of audio values - int numRates = propSize / sizeof(AudioValueRange); - AudioValueRange* supportedRates = new AudioValueRange[numRates]; - - // Get sampling rates from Audio device - err = AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, supportedRates); - if (err == kAudioHardwareNoError) - { - //! 3. Update sample rates - - // now iterate through our standard SRs - for(int ourSR=0; gAllSampleRates[ourSR] > 0; ourSR++) - { - //check to see if our SR is in the supported rates... - for (int deviceSR = 0; deviceSR < numRates; deviceSR++) - { - if ((supportedRates[deviceSR].mMinimum <= gAllSampleRates[ourSR]) && - (supportedRates[deviceSR].mMaximum >= gAllSampleRates[ourSR])) - { - m_SamplingRates.push_back ((int)gAllSampleRates[ourSR]); - break; - } - } - } - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device Sample rates. Device Name: " << m_DeviceName.c_str()); - } - - delete [] supportedRates; - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device Sample rates property size. Device Name: " << m_DeviceName.c_str()); - } - - return retVal; -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::UpdateDeviceBufferSizes_Simple -// -// Use kAudioDevicePropertyBufferFrameSizeRange -// -// in case of 'eMatchedDuplexDevices' and a matching device exists return common device name -// in all other cases retur base class function implementation -// -// 1. Get buffer size range -// 2. Run on all ranges and add them to the list -// -// \return error code -// -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::UpdateDeviceBufferSizes () -{ - AUTO_FUNC_DEBUG; - - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - UInt32 propSize = 0; - - // Clear buffer sizes - m_BufferSizes.clear(); - - // 1. Get buffer size range - AudioValueRange bufferSizesRange; - propSize = sizeof (AudioValueRange); - err = AudioDeviceGetProperty (m_DeviceID, 0, 0, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &bufferSizesRange); - if(err == kAudioHardwareNoError) - { - // 2. Run on all ranges and add them to the list - for(int bsize=0; gAllBufferSizes[bsize] > 0; bsize++) - { - if ((bufferSizesRange.mMinimum <= gAllBufferSizes[bsize]) && (bufferSizesRange.mMaximum >= gAllBufferSizes[bsize])) - { - m_BufferSizes.push_back (gAllBufferSizes[bsize]); - } - } - - //if we didn't get a single hit, let's simply add the min. and the max... - if (m_BufferSizes.empty()) - { - m_BufferSizes.push_back ((int)bufferSizesRange.mMinimum); - m_BufferSizes.push_back ((int)bufferSizesRange.mMaximum); - } - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device buffer sizes range. Device Name: " << m_DeviceName.c_str()); - } - - return retVal; -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::DeviceName -// -//! in case of 'eMatchedDuplexDevices' and a matching device exists return common device name -//! in all other cases retur base class function implementation -//! -//! \param none -//! -//! \return current device name -//! -//********************************************************************************************** -const std::string& WCMRCoreAudioDevice::DeviceName() const -{ - return WCMRAudioDevice::DeviceName(); -} - -//********************************************************************************************** -// WCMRCoreAudioDevice::InputChannels -// -//! return base class function implementation -//! -//! \param none -//! -//! \return base class function implementation -//! -//********************************************************************************************** -const std::vector<std::string>& WCMRCoreAudioDevice::InputChannels() -{ - return WCMRAudioDevice::InputChannels(); -} - -//********************************************************************************************** -// WCMRCoreAudioDevice::OutputChannels -// -//! in case of 'eMatchedDuplexDevices' return matching device output channel if there is one -//! in all other cases retur base class function implementation -//! -//! \param none -//! -//! \return list of output channels of current device -//! -//********************************************************************************************** -const std::vector<std::string>& WCMRCoreAudioDevice::OutputChannels() -{ - return WCMRAudioDevice::OutputChannels(); -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::SamplingRates -// -//! in case of 'eMatchedDuplexDevices' and a matching device exists return common sample rate -//! in all other cases retur base class function implementation -//! -//! \param none -//! -//! \return current sample rate -//! -//********************************************************************************************** -const std::vector<int>& WCMRCoreAudioDevice::SamplingRates() -{ - return WCMRAudioDevice::SamplingRates(); -} - -//********************************************************************************************** -// WCMRCoreAudioDevice::CurrentSamplingRate -// -//! The device's current sampling rate. This may be overridden, if the device needs to -//! query the driver for the current rate. -//! -//! \param none -//! -//! \return The device's current sampling rate. -1 on error. -//! -//********************************************************************************************** -int WCMRCoreAudioDevice::CurrentSamplingRate () -{ - AUTO_FUNC_DEBUG; - //ToDo: Perhaps for ASIO devices that are active, we should retrive the SR from the device... - UInt32 propSize = 0; - OSStatus err = kAudioHardwareNoError; - - Float64 currentNominalRate; - propSize = sizeof (currentNominalRate); - err = kAudioHardwareNoError; - if (AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, ¤tNominalRate) != kAudioHardwareNoError) - err = AudioDeviceGetProperty(m_DeviceID, 0, 1, kAudioDevicePropertyNominalSampleRate, &propSize, ¤tNominalRate); - - if (err == kAudioHardwareNoError) - m_CurrentSamplingRate = (int)currentNominalRate; - else - { - DEBUG_MSG("Unable to get sampling rate!"); - } - - return (m_CurrentSamplingRate); -} - - - - -//********************************************************************************************** -// WCMRCoreAudioDevice::SetCurrentSamplingRate -// -//! Change the sampling rate to be used by the device. -//! -//! \param newRate : The rate to use (samples per sec). -//! -//! \return eNoErr always. The derived classes may return error codes. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::SetCurrentSamplingRate (int newRate) -{ - AUTO_FUNC_DEBUG; - std::vector<int>::iterator intIter; - WTErr retVal = eNoErr; - - //changes the status. - int oldRate = CurrentSamplingRate(); - bool oldActive = Active(); - - //no change, nothing to do - if (oldRate == newRate) - goto Exit; - - //see if this is one of our supported rates... - intIter = find(m_SamplingRates.begin(), m_SamplingRates.end(), newRate); - if (intIter == m_SamplingRates.end()) - { - //Can't change, perhaps use an "invalid param" type of error - retVal = eCommandLineParameter; - goto Exit; - } - - if (Streaming()) - { - //Can't change, perhaps use an "in use" type of error - retVal = eGenericErr; - goto Exit; - } - - if (oldActive) - { - //Deactivate it for the change... - SetActive (false); - } - - retVal = SetAndCheckCurrentSamplingRate (newRate); - if(retVal == eNoErr) - { - retVal = UpdateDeviceInfo (); - } - - //reactivate it. - if (oldActive) - { - retVal = SetActive (true); - } - -Exit: - - return (retVal); - -} - -//********************************************************************************************** -// WCMRCoreAudioDevice::SetAndCheckCurrentSamplingRate -// -//! Change the sampling rate to be used by the device. -//! -//! \param newRate : The rate to use (samples per sec). -//! -//! \return eNoErr always. The derived classes may return error codes. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::SetAndCheckCurrentSamplingRate (int newRate) -{ - AUTO_FUNC_DEBUG; - std::vector<int>::iterator intIter; - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - UInt32 propSize = 0; - - // 1. Set new sampling rate - Float64 newNominalRate = newRate; - propSize = sizeof (Float64); - err = AudioDeviceSetProperty(m_DeviceID, NULL, 0, 0, kAudioDevicePropertyNominalSampleRate, propSize, &newNominalRate); - - if (err != kAudioHardwareNoError) - { - retVal = eCoreAudioFailed; - DEBUG_MSG ("Unable to set SR! Device name: " << m_DeviceName.c_str()); - } - else - { - // 2. wait for the SR to actually change... - - // Set total time out time - int tryAgain = ((PROPERTY_CHANGE_TIMEOUT_SECONDS * 1000) / PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS) ; - int actualWait = 0; - Float64 actualSamplingRate = 0.0; - - // Run as ling as time out is not finished - while (tryAgain) - { - // Get current sampling rate - err = AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &actualSamplingRate); - if (err == kAudioHardwareNoError) - { - if (actualSamplingRate == newNominalRate) - { - //success, let's get out! - break; - } - } - else - { - //error reading rate, but let's not complain too much! - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Could not read Sampling Rate for verification."); - DEBUG_MSG ("Unable to get SR. Device name: " << m_DeviceName.c_str()); - } - - // oh well...there's always another millisecond... - wvThread::sleep_milliseconds (PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS); - tryAgain--; - actualWait++; - } - - // If sample rate actually changed - if (tryAgain != 0) - { - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Changed the Sampling Rate."); - - // Update member with new rate - m_CurrentSamplingRate = newRate; - - char debugMsg[128]; - snprintf (debugMsg, sizeof(debugMsg), "Actual Wait for SR Change was %d milliseconds", actualWait * PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS); - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)debugMsg); - } - // If sample rate did not change after time out - else - { - // Check if current device sample rate is supported - bool found = false; - for(int i = 0; gAllSampleRates[i] > 0; i++) - { - if (fabs(gAllSampleRates[i] - actualSamplingRate) < 0.01) { - found = true; - } - } - - if (found) { - // Update member with last read value - m_CurrentSamplingRate = static_cast<int>(actualSamplingRate); - - char debugMsg[128]; - snprintf (debugMsg, sizeof(debugMsg), "Unable to change SR, even after waiting for %d milliseconds", actualWait * PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS); - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)debugMsg); - - float sample_rate_update = actualSamplingRate; - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::SamplingRateChanged, (void *)&sample_rate_update); - } else { - retVal = eGenericErr; - } - } - } - - return (retVal); -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::BufferSizes -// -//! in case of 'eMatchedDuplexDevices' and a matching device exists return common buffer sizes -//! in all other cases retur base class function implementation -//! -//! \param none -//! -//! \return current sample rate -//! -//********************************************************************************************** -const std::vector<int>& WCMRCoreAudioDevice::BufferSizes() -{ - return WCMRAudioDevice::BufferSizes(); -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::CurrentBufferSize -// -//! The device's current buffer size in use. This may be overridden, if the device needs to -//! query the driver for the current size. -//! -//! \param none -//! -//! \return The device's current buffer size. 0 on error. -//! -//********************************************************************************************** -int WCMRCoreAudioDevice::CurrentBufferSize () -{ - AUTO_FUNC_DEBUG; - - return (m_CurrentBufferSize); -} - - - -//********************************************************************************************** -// WCMRCoreAudioDevice::SetCurrentBufferSize -// -//! Change the buffer size to be used by the device. This will most likely be overridden, -//! the base class simply updates the member variable. -//! -//! \param newSize : The buffer size to use (in sample-frames) -//! -//! \return eNoErr always. The derived classes may return error codes. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::SetCurrentBufferSize (int newSize) -{ - AUTO_FUNC_DEBUG; - WTErr retVal = eNoErr; - std::vector<int>::iterator intIter; - - //changes the status. - int oldSize = CurrentBufferSize(); - bool oldActive = Active(); - - //same size, nothing to do. - if (oldSize == newSize) - goto Exit; - - if (Streaming()) - { - //Can't change, perhaps use an "in use" type of error - retVal = eGenericErr; - goto Exit; - } - - if (oldActive) - { - //Deactivate it for the change... - SetActive (false); - } - - // when audio device is inactive it is safe to set a working buffer size according to new buffer size - // if 'newSize' is not a valid buffer size, another valid buffer size will be set - retVal = SetWorkingBufferSize(newSize); - if(retVal != eNoErr) - { - DEBUG_MSG("Unable to set a working buffer size. Device Name: " << DeviceName().c_str()); - goto Exit; - } - - //reactivate it. - if (oldActive) - { - retVal = SetActive (true); - if(retVal != eNoErr) - { - DEBUG_MSG("Unable to activate device. Device Name: " << DeviceName().c_str()); - goto Exit; - } - } - -Exit: - - return (retVal); -} - -WTErr WCMRCoreAudioDevice::SetWorkingBufferSize(int newSize) -{ - AUTO_FUNC_DEBUG; - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - - // 1. Set new buffer size - err = SetBufferSizesByIO(newSize); - - // If there's no error it means this buffer size is supported - if(err == kAudioHardwareNoError) - { - m_CurrentBufferSize = newSize; - } - // If there was an error it means that this buffer size was not supported - else - { - // In case the new buffer size could not be set, set another working buffer size - - // Run on all buffer sizes: - - // Try setting buffer sizes that are bigger then selected buffer size first, - // Since bigger buffer sizes usually work safer - for(std::vector<int>::const_iterator iter = m_BufferSizes.begin();iter != m_BufferSizes.end();++iter) - { - int nCurBS = *iter; - - if(nCurBS > newSize) - { - // Try setting current buffer size - err = SetBufferSizesByIO(nCurBS); - - // in case buffer size is valid - if(err == kAudioHardwareNoError) - { - // Set current buffer size - m_CurrentBufferSize = nCurBS; - break; - } - } - } - - // If bigger buffer sizes failed, go to smaller buffer sizes - if(err != kAudioHardwareNoError) - { - for(std::vector<int>::const_iterator iter = m_BufferSizes.begin();iter != m_BufferSizes.end();++iter) - { - int nCurBS = *iter; - - if(nCurBS < newSize) - { - // Try setting current buffer size - err = SetBufferSizesByIO(*iter); - - // in case buffer size is valid - if(err == kAudioHardwareNoError) - { - // Set current buffer size - m_CurrentBufferSize = *iter; - break; - } - } - } - } - - // Check if a valid buffer size was found - if(err == kAudioHardwareNoError) - { - // Notify that a different sample rate is set - char debugMsg[256]; - snprintf (debugMsg, sizeof(debugMsg), "Could not set buffer size: %d, Set buffer size to: %d.", newSize, m_CurrentBufferSize); - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)debugMsg); - } - // if there was no buffer size that could be set - else - { - // Set the parameter buffer size by default, set a debug message - m_CurrentBufferSize = newSize; - DEBUG_MSG("Unable to set any buffer size. Device Name: " << m_DeviceName.c_str()); - } - } - - return retVal; -} - -OSStatus WCMRCoreAudioDevice::SetBufferSizesByIO(int newSize) -{ - OSStatus err = kAudioHardwareNoError; - - // 1. Set new buffer size - UInt32 bufferSize = (UInt32)newSize; - UInt32 propSize = sizeof (UInt32); - - // Set new buffer size to input - if (!m_InputChannels.empty()) - { - err = AudioDeviceSetProperty(m_DeviceID, NULL, 0, 1, kAudioDevicePropertyBufferFrameSize, propSize, &bufferSize); - } - else - { - err = AudioDeviceSetProperty(m_DeviceID, NULL, 0, 0, kAudioDevicePropertyBufferFrameSize, propSize, &bufferSize); - } - - return err; -} - -//********************************************************************************************** -// WCMRCoreAudioDevice::ConnectionStatus -// -//! Retrieves the device's current connection status. This will most likely be overridden, -//! in case some driver communication is required to query the status. -//! -//! \param none -//! -//! \return A ConnectionStates value. -//! -//********************************************************************************************** -WCMRCoreAudioDevice::ConnectionStates WCMRCoreAudioDevice::ConnectionStatus () -{ - AUTO_FUNC_DEBUG; - //ToDo: May want to do something more to extract the actual status! - return (m_ConnectionStatus); - -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::EnableAudioUnitIO -// -//! Sets up the AUHAL for IO, allowing changes to the devices to be used by the AudioUnit. -//! -//! \param none -//! -//! \return eNoErr on success, an error code on failure. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::EnableAudioUnitIO() -{ - AUTO_FUNC_DEBUG; - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - - UInt32 enableIO = 1; - if (!m_InputChannels.empty()) - { - /////////////// - //ENABLE IO (INPUT) - //You must enable the Audio Unit (AUHAL) for input - - //Enable input on the AUHAL - err = AudioUnitSetProperty(m_AUHALAudioUnit, - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, - AUHAL_INPUT_ELEMENT, - &enableIO, sizeof(enableIO)); - - if (err) - { - DEBUG_MSG("Couldn't Enable IO on input scope of input element, error = " << err); - retVal = eGenericErr; - goto Exit; - } - } - - //disable Output on the AUHAL if there's no output - if (m_OutputChannels.empty()) - enableIO = 0; - else - enableIO = 1; - - err = AudioUnitSetProperty(m_AUHALAudioUnit, - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, - AUHAL_OUTPUT_ELEMENT, - &enableIO, sizeof(enableIO)); - - if (err) - { - DEBUG_MSG("Couldn't Enable/Disable IO on output scope of output element, error = " << err); - retVal = eGenericErr; - goto Exit; - } - -Exit: - return retVal; -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::EnableListeners -// -//! Sets up listeners to listen for Audio Device property changes, so that app can be notified. -//! -//! \param none -//! -//! \return eNoErr on success, an error code on failure. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::EnableListeners() -{ - AUTO_FUNC_DEBUG; - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - - //listner for SR change... - err = AudioDeviceAddPropertyListener(m_DeviceID, 0, 0, kAudioDevicePropertyNominalSampleRate, - StaticPropertyChangeProc, this); - - if (err) - { - DEBUG_MSG("Couldn't Setup SR Property Listner, error = " << err); - retVal = eGenericErr; - goto Exit; - } - -#if ENABLE_DEVICE_CHANGE_LISTNER - { - //listner for device change... - - err = AudioDeviceAddPropertyListener (m_DeviceID, - kAudioPropertyWildcardChannel, - true, - kAudioDevicePropertyDeviceHasChanged, - StaticPropertyChangeProc, - this); - - if (err) - { - DEBUG_MSG("Couldn't Setup device change Property Listner, error = " << err); - retVal = eGenericErr; - goto Exit; - } - } -#endif //ENABLE_DEVICE_CHANGE_LISTNER - - //listner for dropouts... - err = AudioDeviceAddPropertyListener(m_DeviceID, 0, 0, kAudioDeviceProcessorOverload, - StaticPropertyChangeProc, this); - - if (err) - { - DEBUG_MSG("Couldn't Setup Processor Overload Property Listner, error = " << err); - retVal = eGenericErr; - goto Exit; - } - - -Exit: - return retVal; -} - - - -//********************************************************************************************** -// WCMRCoreAudioDevice::DisableListeners -// -//! Undoes the work done by EnableListeners -//! -//! \param none -//! -//! \return eNoErr on success, an error code on failure. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::DisableListeners() -{ - AUTO_FUNC_DEBUG; - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - - //listner for SR change... - err = AudioDeviceRemovePropertyListener(m_DeviceID, 0, 0, kAudioDevicePropertyNominalSampleRate, - StaticPropertyChangeProc); - - if (err) - { - DEBUG_MSG("Couldn't Cleanup SR Property Listner, error = " << err); - //not sure if we need to report this... - } - -#if ENABLE_DEVICE_CHANGE_LISTNER - { - err = AudioDeviceRemovePropertyListener (m_DeviceID, - kAudioPropertyWildcardChannel, - true/* Input */, - kAudioDevicePropertyDeviceHasChanged, - StaticPropertyChangeProc); - - if (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 - - err = AudioDeviceRemovePropertyListener(m_DeviceID, 0, 0, kAudioDeviceProcessorOverload, - StaticPropertyChangeProc); - - if (err) - { - DEBUG_MSG("Couldn't Cleanup device change Property Listner, error = " << err); - //not sure if we need to report this... - } - - - return retVal; -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::StaticPropertyChangeProc -// -//! The property change function called (as a result of EnableListeners) when device properties change. -//! It calls upon the non-static PropertyChangeProc to do the work. -//! -//! \param inDevice : The audio device in question. -//! \param inChannel : The channel on which the property has change. -//! \param isInput : If the change is for Input. -//! \param inPropertyID : The property that has changed. -//! \param inClientData: What was passed when listener was enabled, in our case teh WCMRCoreAudioDevice object. -//! -//! \return 0 always. -//! -//********************************************************************************************** -OSStatus WCMRCoreAudioDevice::StaticPropertyChangeProc (AudioDeviceID /*inDevice*/, UInt32 /*inChannel*/, Boolean /*isInput*/, - AudioDevicePropertyID inPropertyID, void *inClientData) -{ - if (inClientData) - { - WCMRCoreAudioDevice* pCoreDevice = (WCMRCoreAudioDevice *)inClientData; - pCoreDevice->PropertyChangeProc (inPropertyID); - } - - return 0; -} - - - -//********************************************************************************************** -// WCMRCoreAudioDevice::PropertyChangeProc -// -//! The non-static property change proc. Gets called when properties change. Since this gets called -//! on an arbitrary thread, we simply update the request counters and return. -//! -//! \param none -//! -//! \return nothing. -//! -//********************************************************************************************** -void WCMRCoreAudioDevice::PropertyChangeProc (AudioDevicePropertyID inPropertyID) -{ - switch (inPropertyID) - { - case kAudioDevicePropertyNominalSampleRate: - m_SRChangeRequested++; - break; -#if ENABLE_DEVICE_CHANGE_LISTNER - 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; - } -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::SetupAUHAL -// -//! Sets up the AUHAL AudioUnit for device IO. -//! -//! \param none -//! -//! \return eNoErr on success, an error code on failure. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::SetupAUHAL() -{ - AUTO_FUNC_DEBUG; - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - UInt32 propSize = 0; - Component comp; - ComponentDescription desc; - AudioStreamBasicDescription streamFormatToUse, auhalStreamFormat; - - //There are several different types of Audio Units. - //Some audio units serve as Outputs, Mixers, or DSP - //units. See AUComponent.h for listing - desc.componentType = kAudioUnitType_Output; - - //Every Component has a subType, which will give a clearer picture - //of what this components function will be. - desc.componentSubType = kAudioUnitSubType_HALOutput; - - //all Audio Units in AUComponent.h must use - //"kAudioUnitManufacturer_Apple" as the Manufacturer - desc.componentManufacturer = kAudioUnitManufacturer_Apple; - desc.componentFlags = 0; - desc.componentFlagsMask = 0; - - //Finds a component that meets the desc spec's - comp = FindNextComponent(NULL, &desc); - if (comp == NULL) - { - DEBUG_MSG("Couldn't find AUHAL Component"); - retVal = eGenericErr; - goto Exit; - } - - //gains access to the services provided by the component - OpenAComponent(comp, &m_AUHALAudioUnit); - - - retVal = EnableAudioUnitIO(); - if (retVal != eNoErr) - goto Exit; - - //Now setup the device to use by the audio unit... - - //input - if (!m_InputChannels.empty()) - { - err = AudioUnitSetProperty(m_AUHALAudioUnit, kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, AUHAL_INPUT_ELEMENT, - &m_DeviceID, sizeof(m_DeviceID)); - - if (err) - { - DEBUG_MSG("Couldn't Set the audio device property for Input Element Global scope, error = " << err); - retVal = eGenericErr; - goto Exit; - } - } - - //output - if (!m_OutputChannels.empty()) - { - err = AudioUnitSetProperty(m_AUHALAudioUnit, kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, AUHAL_OUTPUT_ELEMENT, - &m_DeviceID, sizeof(m_DeviceID)); - - if (err) - { - DEBUG_MSG("Couldn't Set the audio device property for Output Element Global scope, error = " << err); - retVal = eGenericErr; - goto Exit; - } - } - - //also set Sample Rate... - { - retVal = SetAndCheckCurrentSamplingRate(m_CurrentSamplingRate); - if(retVal != eNoErr) - { - DEBUG_MSG ("Unable to set SR, error = " << err); - goto Exit; - } - } - - //now set the buffer size... - { - err = SetWorkingBufferSize(m_CurrentBufferSize); - if (err) - { - DEBUG_MSG("Couldn't Set the buffer size property, error = " << err); - //we don't really quit here..., just keep going even if this does not work, - //the AUHAL is supposed to take care of this by way of slicing... - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Could not set buffer size."); - - } - } - - //convertor quality - { - UInt32 quality = kAudioConverterQuality_Max; - propSize = sizeof (quality); - err = AudioUnitSetProperty(m_AUHALAudioUnit, - kAudioUnitProperty_RenderQuality, kAudioUnitScope_Global, - AUHAL_OUTPUT_ELEMENT, - &quality, sizeof (quality)); - - if (err != kAudioHardwareNoError) - { - DEBUG_MSG ("Unable to set Convertor Quality, error = " << err); - retVal = eGenericErr; - goto Exit; - } - } - - memset (&auhalStreamFormat, 0, sizeof (auhalStreamFormat)); - propSize = sizeof (auhalStreamFormat); - err = AudioUnitGetProperty(m_AUHALAudioUnit, - kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, - AUHAL_INPUT_ELEMENT, - &auhalStreamFormat, &propSize); - if (err != kAudioHardwareNoError) - { - DEBUG_MSG ("Unable to get Input format, error = " << err); - retVal = eGenericErr; - goto Exit; - } - - if (auhalStreamFormat.mSampleRate != (Float64)m_CurrentSamplingRate) - { - TRACE_MSG ("AUHAL's Input SR differs from expected SR, expected = " << m_CurrentSamplingRate << ", AUHAL's = " << (UInt32)auhalStreamFormat.mSampleRate); - } - - //format, and slice size... - memset (&streamFormatToUse, 0, sizeof (streamFormatToUse)); - streamFormatToUse.mFormatID = kAudioFormatLinearPCM; - streamFormatToUse.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; - streamFormatToUse.mFramesPerPacket = 1; - streamFormatToUse.mBitsPerChannel = sizeof (float) * 8; - streamFormatToUse.mSampleRate = auhalStreamFormat.mSampleRate; - - if (!m_InputChannels.empty()) - { - streamFormatToUse.mChannelsPerFrame = m_InputChannels.size(); - streamFormatToUse.mBytesPerFrame = sizeof (float)*streamFormatToUse.mChannelsPerFrame; - streamFormatToUse.mBytesPerPacket = streamFormatToUse.mBytesPerFrame; - propSize = sizeof (streamFormatToUse); - err = AudioUnitSetProperty(m_AUHALAudioUnit, - kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, - AUHAL_INPUT_ELEMENT, - &streamFormatToUse, sizeof (streamFormatToUse)); - - if (err != kAudioHardwareNoError) - { - DEBUG_MSG ("Unable to set Input format, error = " << err); - retVal = eGenericErr; - goto Exit; - } - - UInt32 bufferSize = m_CurrentBufferSize; - err = AudioUnitSetProperty(m_AUHALAudioUnit, - kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, - AUHAL_INPUT_ELEMENT, - &bufferSize, sizeof (bufferSize)); - - if (err != kAudioHardwareNoError) - { - DEBUG_MSG ("Unable to set Input frames, error = " << err); - retVal = eGenericErr; - goto Exit; - } - - } - - if (!m_OutputChannels.empty()) - { - err = AudioUnitGetProperty(m_AUHALAudioUnit, - kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, - AUHAL_OUTPUT_ELEMENT, - &auhalStreamFormat, &propSize); - if (err != kAudioHardwareNoError) - { - DEBUG_MSG ("Unable to get Output format, error = " << err); - retVal = eGenericErr; - goto Exit; - } - - if (auhalStreamFormat.mSampleRate != (Float64)m_CurrentSamplingRate) - { - TRACE_MSG ("AUHAL's Output SR differs from expected SR, expected = " << m_CurrentSamplingRate << ", AUHAL's = " << (UInt32)auhalStreamFormat.mSampleRate); - } - - - streamFormatToUse.mChannelsPerFrame = m_OutputChannels.size(); - streamFormatToUse.mBytesPerFrame = sizeof (float)*streamFormatToUse.mChannelsPerFrame; - streamFormatToUse.mBytesPerPacket = streamFormatToUse.mBytesPerFrame; - streamFormatToUse.mSampleRate = auhalStreamFormat.mSampleRate; - propSize = sizeof (streamFormatToUse); - err = AudioUnitSetProperty(m_AUHALAudioUnit, - kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, - AUHAL_OUTPUT_ELEMENT, - &streamFormatToUse, sizeof (streamFormatToUse)); - - if (err != kAudioHardwareNoError) - { - DEBUG_MSG ("Unable to set Output format, error = " << err); - retVal = eGenericErr; - goto Exit; - } - - UInt32 bufferSize = m_CurrentBufferSize; - err = AudioUnitSetProperty(m_AUHALAudioUnit, - kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Input, - AUHAL_OUTPUT_ELEMENT, - &bufferSize, sizeof (bufferSize)); - - if (err != kAudioHardwareNoError) - { - DEBUG_MSG ("Unable to set Output frames, error = " << err); - retVal = eGenericErr; - goto Exit; - } - - } - - //setup callback (IOProc) - { - AURenderCallbackStruct renderCallback; - memset (&renderCallback, 0, sizeof (renderCallback)); - propSize = sizeof (renderCallback); - renderCallback.inputProc = StaticAudioIOProc; - renderCallback.inputProcRefCon = this; - - err = AudioUnitSetProperty(m_AUHALAudioUnit, - (m_OutputChannels.empty() ? (AudioUnitPropertyID)kAudioOutputUnitProperty_SetInputCallback : (AudioUnitPropertyID)kAudioUnitProperty_SetRenderCallback), - kAudioUnitScope_Output, - m_OutputChannels.empty() ? AUHAL_INPUT_ELEMENT : AUHAL_OUTPUT_ELEMENT, - &renderCallback, sizeof (renderCallback)); - - if (err != kAudioHardwareNoError) - { - DEBUG_MSG ("Unable to set callback, error = " << err); - retVal = eGenericErr; - goto Exit; - } - } - - retVal = EnableListeners(); - if (retVal != eNoErr) - goto Exit; - - //initialize the audio-unit now! - err = AudioUnitInitialize(m_AUHALAudioUnit); - if (err != kAudioHardwareNoError) - { - DEBUG_MSG ("Unable to Initialize AudioUnit = " << err); - retVal = eGenericErr; - goto Exit; - } - -Exit: - if (retVal != eNoErr) - TearDownAUHAL(); - - return retVal; -} - - - -//********************************************************************************************** -// WCMRCoreAudioDevice::TearDownAUHAL -// -//! Undoes the work done by SetupAUHAL -//! -//! \param none -//! -//! \return eNoErr on success, an error code on failure. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::TearDownAUHAL() -{ - WTErr retVal = eNoErr; - - if (m_AUHALAudioUnit) - { - DisableListeners (); - AudioUnitUninitialize(m_AUHALAudioUnit); - CloseComponent(m_AUHALAudioUnit); - m_AUHALAudioUnit = NULL; - } - - return retVal; -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::SetActive -// -//! Sets the device's activation status. Essentially, opens or closes the PA device. -//! If it's an ASIO device it may result in buffer size change in some cases. -//! -//! \param newState : Should be true to activate, false to deactivate. This roughly corresponds -//! to opening and closing the device handle/stream/audio unit. -//! -//! \return eNoErr on success, an error code otherwise. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::SetActive (bool newState) -{ - AUTO_FUNC_DEBUG; - - WTErr retVal = eNoErr; - - if (Active() == newState) - goto Exit; - - - if (newState) - { - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Setting up AUHAL."); - retVal = SetupAUHAL(); - - if (retVal != eNoErr) - goto Exit; - - m_BufferSizeChangeRequested = 0; - m_BufferSizeChangeReported = 0; - m_ResetRequested = 0; - m_ResetReported = 0; - m_ResyncRequested = 0; - m_ResyncReported = 0; - m_SRChangeRequested = 0; - m_SRChangeReported = 0; - m_DropsDetected = 0; - m_DropsReported = 0; - m_IgnoreThisDrop = true; - } - else - { - if (Streaming()) - { - SetStreaming (false); - } - - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Tearing down AUHAL."); - retVal = TearDownAUHAL(); - if (retVal != eNoErr) - goto Exit; - - m_BufferSizeChangeRequested = 0; - m_BufferSizeChangeReported = 0; - m_ResetRequested = 0; - m_ResetReported = 0; - m_ResyncRequested = 0; - m_ResyncReported = 0; - m_SRChangeRequested = 0; - m_SRChangeReported = 0; - m_DropsDetected = 0; - m_DropsReported = 0; - m_IgnoreThisDrop = true; - - UpdateDeviceInfo(); - } - - m_IsActive = newState; - -Exit: - return (retVal); -} - - -#if WV_USE_TONE_GEN -//********************************************************************************************** -// WCMRCoreAudioDevice::SetupToneGenerator -// -//! Sets up the Tone generator - only if a file /tmp/tonegen.txt is present. If the file is -//! present, it reads the value in the file and uses that as the frequency for the tone. This -//! code attempts to create an array of samples that would constitute an integral number of -//! cycles - for the currently active sampling rate. If tonegen is active, then the input -//! from the audio device is ignored, instead a data is supplied from the tone generator's -//! array - for all channels. The array is in m_pToneData, the size of the array is in -//! m_ToneDataSamples, and m_NextSampleToUse holds the index in the array from where -//! the next sample is going to be taken. -//! -//! -//! \return : Nothing -//! -//********************************************************************************************** -void WCMRCoreAudioDevice::SetupToneGenerator () -{ - safe_delete_array(m_pToneData); - m_ToneDataSamples = 0; - - //if tonegen exists? - FILE *toneGenHandle = fopen ("/tmp/tonegen.txt", "r"); - if (toneGenHandle) - { - int toneFreq = 0; - fscanf(toneGenHandle, "%d", &toneFreq); - if ((toneFreq <= 0) || (toneFreq > (m_CurrentSamplingRate/2))) - { - toneFreq = 1000; - } - - - m_ToneDataSamples = m_CurrentSamplingRate / toneFreq; - int toneDataSamplesFrac = m_CurrentSamplingRate % m_ToneDataSamples; - int powerOfTen = 1; - while (toneDataSamplesFrac) - { - m_ToneDataSamples = (uint32_t)((pow(10, powerOfTen) * m_CurrentSamplingRate) / toneFreq); - toneDataSamplesFrac = m_CurrentSamplingRate % m_ToneDataSamples; - powerOfTen++; - } - - //allocate - m_pToneData = new float_t[m_ToneDataSamples]; - - //fill with a -6dB Sine Tone - uint32_t numSamplesLeft = m_ToneDataSamples; - float_t *pNextSample = m_pToneData; - double phase = 0; - double phaseIncrement = (M_PI * 2.0 * toneFreq ) / ((double)m_CurrentSamplingRate); - while (numSamplesLeft) - { - *pNextSample = (float_t)(0.5 * sin(phase)); - phase += phaseIncrement; - pNextSample++; - numSamplesLeft--; - } - - m_NextSampleToUse = 0; - - fclose(toneGenHandle); - } -} -#endif //WV_USE_TONE_GEN - - -//********************************************************************************************** -// WCMRCoreAudioDevice::SetStreaming -// -//! Sets the device's streaming status. Calls PA's Start/Stop stream routines. -//! -//! \param newState : Should be true to start streaming, false to stop streaming. This roughly -//! corresponds to calling Start/Stop on the lower level interface. -//! -//! \return eNoErr always, the derived classes may return appropriate error code. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::SetStreaming (bool newState) -{ - AUTO_FUNC_DEBUG; - WTErr retVal = eNoErr; - ComponentResult err = 0; - - if (Streaming () == newState) - goto Exit; - - if (newState) - { -#if WV_USE_TONE_GEN - SetupToneGenerator (); -#endif //WV_USE_TONE_GEN - - m_SampleCountAtLastIdle = 0; - m_StalledSampleCounter = 0; - m_SampleCounter = 0; - m_IOProcThreadPort = 0; - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Starting AUHAL."); - - // Prepare for streaming - tell Engine to do the initialization for process callback - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStartsStreaming); - - if (m_UseMultithreading) - { - //set thread constraints... - unsigned int periodAndConstraintUS = (unsigned int)((1000000.0 * m_CurrentBufferSize) / m_CurrentSamplingRate); - unsigned int computationUS = (unsigned int)(0.8 * periodAndConstraintUS); //assuming we may want to use up to 80% CPU - //ErrandManager().SetRealTimeConstraintsForAllThreads (periodAndConstraintUS, computationUS, periodAndConstraintUS); - } - - err = AudioOutputUnitStart (m_AUHALAudioUnit); - - m_StopRequested = false; - - if(err) - { - DEBUG_MSG( "Failed to start AudioUnit, err " << err ); - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Failed to start AudioUnit."); - retVal = eGenericErr; - goto Exit; - } - } - else - { - m_StopRequested = true; - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Stopping AUHAL."); - err = AudioOutputUnitStop (m_AUHALAudioUnit); - if (!err) - { - //if (!m_InputChannels.empty()); - { - err = AudioUnitReset (m_AUHALAudioUnit, kAudioUnitScope_Global, AUHAL_INPUT_ELEMENT); - } - //if (!m_OutputChannels.empty()); - { - err = AudioUnitReset (m_AUHALAudioUnit, kAudioUnitScope_Global, AUHAL_OUTPUT_ELEMENT); - } - } - - if(err) - { - DEBUG_MSG( "Failed to stop AudioUnit " << err ); - retVal = eGenericErr; - goto Exit; - } - m_IOProcThreadPort = 0; - } - - // After units restart, reset request for reset and SR change - m_SRChangeReported = m_SRChangeRequested; - m_ResetReported = m_ResetRequested; - - m_IsStreaming = newState; - -Exit: - return (retVal); -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::DoIdle -// -//! A place for doing idle time processing. The other derived classes will probably do something -//! meaningful. -//! -//! \param none -//! -//! \return eNoErr always. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::DoIdle () -{ - /* - if (m_BufferSizeChangeRequested != m_BufferSizeChangeReported) - { - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged); - m_BufferSizeChangeReported = m_BufferSizeChangeRequested; - } - - if (m_ResetRequested != m_ResetReported) - { - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset); - m_ResetReported = m_ResetRequested; - } - - - if (m_ResyncRequested != m_ResyncReported) - { - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestResync); - m_ResyncReported = m_ResyncRequested; - } - - if (m_SRChangeReported != m_SRChangeRequested) - { - m_SRChangeReported = m_SRChangeRequested; - int newSR = CurrentSamplingRate(); - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::SamplingRateChanged, (void *)newSR); - } - - if (m_DropsReported != m_DropsDetected) - { - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDroppedSamples); - m_DropsReported = m_DropsDetected; - } - - - //Perhaps add checks to make sure a stream counter is incrementing if - //stream is supposed to be streaming! - if (Streaming()) - { - //latch the value - int64_t currentSampleCount = m_SampleCounter; - if (m_SampleCountAtLastIdle == currentSampleCount) - m_StalledSampleCounter++; - else - { - m_SampleCountAtLastIdle = (int)currentSampleCount; - m_StalledSampleCounter = 0; - } - - if (m_StalledSampleCounter > NUM_STALLS_FOR_NOTIFICATION) - { - m_StalledSampleCounter = 0; - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStoppedStreaming, (void *)currentSampleCount); - } - }*/ - - - return (eNoErr); -} - - - - - -//********************************************************************************************** -// WCMRCoreAudioDevice::SetMonitorChannels -// -//! Used to set the channels to be used for monitoring. -//! -//! \param leftChannel : Left monitor channel index. -//! \param rightChannel : Right monitor channel index. -//! -//! \return eNoErr always, the derived classes may return appropriate errors. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::SetMonitorChannels (int leftChannel, int rightChannel) -{ - AUTO_FUNC_DEBUG; - //This will most likely be overridden, the base class simply - //changes the member. - m_LeftMonitorChannel = leftChannel; - m_RightMonitorChannel = rightChannel; - return (eNoErr); -} - - - -//********************************************************************************************** -// WCMRCoreAudioDevice::SetMonitorGain -// -//! Used to set monitor gain (or atten). -//! -//! \param newGain : The new gain or atten. value to use. Specified as a linear multiplier (not dB) -//! -//! \return eNoErr always, the derived classes may return appropriate errors. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::SetMonitorGain (float newGain) -{ - AUTO_FUNC_DEBUG; - //This will most likely be overridden, the base class simply - //changes the member. - - - m_MonitorGain = newGain; - return (eNoErr); -} - - - - -//********************************************************************************************** -// WCMRCoreAudioDevice::ShowConfigPanel -// -//! Used to show device specific config/control panel. Some interfaces may not support it. -//! Some interfaces may require the device to be active before it can display a panel. -//! -//! \param pParam : A device/interface specific parameter, should be the app window handle for ASIO. -//! -//! \return eNoErr always, the derived classes may return errors. -//! -//********************************************************************************************** -WTErr WCMRCoreAudioDevice::ShowConfigPanel (void */*pParam*/) -{ - AUTO_FUNC_DEBUG; - WTErr retVal = eNoErr; - - CFStringRef configAP; - UInt32 propSize = sizeof (configAP); - /* - @constant kAudioDevicePropertyConfigurationApplication - A CFString that contains the bundle ID for an application that provides a - GUI for configuring the AudioDevice. By default, the value of this property - is the bundle ID for Audio MIDI Setup. The caller is responsible for - releasing the returned CFObject. - */ - - if (AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyConfigurationApplication, &propSize, &configAP) == kAudioHardwareNoError) - { - // get the FSRef of the config app - FSRef theAppFSRef; - OSStatus theError = LSFindApplicationForInfo(kLSUnknownCreator, configAP, NULL, &theAppFSRef, NULL); - if (!theError) - { - LSOpenFSRef(&theAppFSRef, NULL); - } - else - { - // open default AudioMIDISetup if device app is not found - CFStringRef audiMidiSetupApp = CFStringCreateWithCString(kCFAllocatorDefault, "com.apple.audio.AudioMIDISetup", kCFStringEncodingMacRoman); - theError = LSFindApplicationForInfo(kLSUnknownCreator, audiMidiSetupApp, NULL, &theAppFSRef, NULL); - - if (!theError) - { - LSOpenFSRef(&theAppFSRef, NULL); - } - } - - CFRelease (configAP); - } - - return (retVal); -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::StaticAudioIOProc -// -//! The AudioIOProc that gets called when the AudioUnit is ready with recorded audio, and wants to get audio. -//! This one simply calls the non-static member. -//! -//! \param inRefCon : What was passed when setting up the Callback (in our case a pointer to teh WCMRCoreAudioDevice object). -//! \param ioActionFlags : What actios has to be taken. -//! \param inTimeStamp: When the data will be played back. -//! \param inBusNumber : The AU element. -//! \param inNumberFrames: Number af Audio frames that are requested. -//! \param ioData : Where the playback data is to be placed. -//! -//! \return 0 always -//! -//********************************************************************************************** -OSStatus WCMRCoreAudioDevice::StaticAudioIOProc(void *inRefCon, AudioUnitRenderActionFlags * ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList *ioData) -{ - WCMRCoreAudioDevice *pMyDevice = (WCMRCoreAudioDevice *)inRefCon; - if (pMyDevice) - return pMyDevice->AudioIOProc (ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); - else - return 0; -} - - - - -//********************************************************************************************** -// WCMRCoreAudioDevice::AudioIOProc -// -//! The non-static AudioIOProc that gets called when the AudioUnit is ready with recorded audio, and wants to get audio. -//! We retrieve the recorded audio, and then do our processing, to generate audio to be played back. -//! -//! \param ioActionFlags : What actios has to be taken. -//! \param inTimeStamp: When the data will be played back. -//! \param inBusNumber : The AU element. -//! \param inNumberFrames: Number af Audio frames that are requested. -//! \param ioData : Where the playback data is to be placed. -//! -//! \return 0 always -//! -//********************************************************************************************** -OSStatus WCMRCoreAudioDevice::AudioIOProc(AudioUnitRenderActionFlags * ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 /*inBusNumber*/, UInt32 inNumberFrames, - AudioBufferList *ioData) -{ - UInt64 theStartTime = AudioGetCurrentHostTime(); - - OSStatus retVal = 0; - - if (m_StopRequested) - 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) - return retVal; - - //Retrieve the input data... - if (!m_InputChannels.empty()) - { - 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; - 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? - if (m_OutputChannels.empty()) - AudioCallback (NULL, inNumberFrames, (int64_t)inTimeStamp->mSampleTime, theStartTime); - else if ((!m_OutputChannels.empty()) && (ioData->mBuffers[0].mNumberChannels == m_OutputChannels.size())) - AudioCallback ((float *)ioData->mBuffers[0].mData, inNumberFrames, (int64_t)inTimeStamp->mSampleTime, theStartTime); - - return retVal; -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::AudioCallback -// -//! Here's where the actual audio processing happens. We call upon all the active connections' -//! sinks to provide data to us which can be put/mixed in the output buffer! Also, we make the -//! input data available to any sources that may call upon us during this time! -//! -//! \param *pOutputBuffer : Points to a buffer to receive playback data. For Input only devices, this will be NULL -//! \param framesPerBuffer : Number of sample frames in input and output buffers. Number of channels, -//! which are interleaved, is fixed at Device Open (Active) time. In this implementation, -//! the number of channels are fixed to use the maximum available. -//! -//! \return true -//! -//********************************************************************************************** -int WCMRCoreAudioDevice::AudioCallback (float *pOutputBuffer, unsigned long framesPerBuffer, int64_t inSampleTime, uint64_t inCycleStartTime) -{ - struct WCMRAudioDeviceManagerClient::AudioCallbackData audioCallbackData = - { - m_pInputData, - pOutputBuffer, - framesPerBuffer, - inSampleTime, - AudioConvertHostTimeToNanos(inCycleStartTime) - }; - - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::AudioCallback, (void *)&audioCallbackData); - - m_SampleCounter += framesPerBuffer; - return m_StopRequested; -} - - -//********************************************************************************************** -// WCMRCoreAudioDevice::GetLatency -// -//! Get Latency for device. -//! -//! Use 'kAudioDevicePropertyLatency' and 'kAudioDevicePropertySafetyOffset' + GetStreamLatencies -//! -//! \param isInput : Return latency for the input if isInput is true, otherwise the output latency -//! wiil be returned. -//! \return Latency in samples. -//! -//********************************************************************************************** -uint32_t WCMRCoreAudioDevice::GetLatency(bool isInput) -{ - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - - UInt32 propSize = sizeof(UInt32); - UInt32 value1 = 0; - UInt32 value2 = 0; - - UInt32 latency = 0; - std::vector<int> streamLatencies; - - - err = AudioDeviceGetProperty(m_DeviceID, 0, isInput, kAudioDevicePropertyLatency, &propSize, &value1); - if (err != kAudioHardwareNoError) - { - DEBUG_MSG("GetLatency kAudioDevicePropertyLatency err = " << err); - } - - err = AudioDeviceGetProperty(m_DeviceID, 0, isInput, kAudioDevicePropertySafetyOffset, &propSize, &value2); - if (err != kAudioHardwareNoError) - { - DEBUG_MSG("GetLatency kAudioDevicePropertySafetyOffset err = " << err); - } - - latency = value1 + value2; - - err = GetStreamLatency(m_DeviceID, isInput, streamLatencies); - if (err == kAudioHardwareNoError) - { - for ( int i = 0; i < streamLatencies.size(); i++) { - latency += streamLatencies[i]; - } - } - - return latency; -} - -//********************************************************************************************** -// WCMRCoreAudioDevice::GetStreamLatency -// -//! Get stream latency for device. -//! -//! \param deviceID : The audio device ID. -//! -//! \param isInput : Return latency for the input if isInput is true, otherwise the output latency -//! wiil be returned. -//********************************************************************************************** -OSStatus WCMRCoreAudioDevice::GetStreamLatency(AudioDeviceID device, bool isInput, std::vector<int>& latencies) -{ - OSStatus err = kAudioHardwareNoError; - UInt32 outSize1, outSize2, outSize3; - Boolean outWritable; - - err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreams, &outSize1, &outWritable); - if (err == noErr) { - int stream_count = outSize1 / sizeof(UInt32); - AudioStreamID streamIDs[stream_count]; - AudioBufferList bufferList[stream_count]; - UInt32 streamLatency; - outSize2 = sizeof(UInt32); - - err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreams, &outSize1, streamIDs); - if (err != noErr) { - DEBUG_MSG("GetStreamLatencies kAudioDevicePropertyStreams err = " << err); - return err; - } - - err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize3, &outWritable); - if (err != noErr) { - DEBUG_MSG("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = " << err); - return err; - } - - for (int i = 0; i < stream_count; i++) { - err = AudioStreamGetProperty(streamIDs[i], 0, kAudioStreamPropertyLatency, &outSize2, &streamLatency); - if (err != noErr) { - DEBUG_MSG("GetStreamLatencies kAudioStreamPropertyLatency err = " << err); - return err; - } - err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize3, bufferList); - if (err != noErr) { - DEBUG_MSG("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = " << err); - return err; - } - latencies.push_back(streamLatency); - } - } - return err; -} - - -//********************************************************************************************** -// WCMRCoreAudioDeviceManager::WCMRCoreAudioDeviceManager -// -//! The constructuor, we initialize PA, and build the device list. -//! -//! \param *pTheClient : The manager's client object (which receives notifications). -//! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true. -//! -//! \return Nothing. -//! -//********************************************************************************************** -WCMRCoreAudioDeviceManager::WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, - eAudioDeviceFilter eCurAudioDeviceFilter, bool useMultithreading, bool bNocopy) - : WCMRAudioDeviceManager (pTheClient, eCurAudioDeviceFilter) - , m_UseMultithreading (useMultithreading) - , m_bNoCopyAudioBuffer(bNocopy) -{ - AUTO_FUNC_DEBUG; - - //first of all, tell HAL to use it's own run loop, not to wait for our runloop to do - //it's dirty work... - //Essentially, this makes the HAL on Snow Leopard behave like Leopard. - //It's not yet (as of October 2009 documented), but the following discussion - //has the information provided by Jeff Moore @ Apple: - // http://lists.apple.com/archives/coreaudio-api/2009/Oct/msg00214.html - // - // As per Jeff's suggestion, opened an Apple Bug on this - ID# 7364011 - - CFRunLoopRef nullRunLoop = 0; - OSStatus err = AudioHardwareSetProperty (kAudioHardwarePropertyRunLoop, sizeof(CFRunLoopRef), &nullRunLoop); - - if (err != kAudioHardwareNoError) - { - syslog (LOG_NOTICE, "Unable to set RunLoop for Audio Hardware"); - } - - //add a listener to find out when devices change... - AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, HardwarePropertyChangeCallback, this); - - //Always add the None device first... - m_NoneDevice = new WCMRNativeAudioNoneDevice(this); - - //prepare our initial list... - generateDeviceListImpl(); - - return; -} - - - -//********************************************************************************************** -// WCMRCoreAudioDeviceManager::~WCMRCoreAudioDeviceManager -// -//! It clears the device list, releasing each of the device. -//! -//! \param none -//! -//! \return Nothing. -//! -//********************************************************************************************** -WCMRCoreAudioDeviceManager::~WCMRCoreAudioDeviceManager() -{ - AUTO_FUNC_DEBUG; - - try - { - delete m_NoneDevice; - } - catch (...) - { - //destructors should absorb exceptions, no harm in logging though!! - DEBUG_MSG ("Exception during destructor"); - } - -} - - -WCMRAudioDevice* WCMRCoreAudioDeviceManager::initNewCurrentDeviceImpl(const std::string & deviceName) -{ - destroyCurrentDeviceImpl(); - - std::cout << "API::PortAudioDeviceManager::initNewCurrentDevice " << deviceName << std::endl; - if (deviceName == m_NoneDevice->DeviceName() ) - { - m_CurrentDevice = m_NoneDevice; - return m_CurrentDevice; - } - - DeviceInfo devInfo; - WTErr err = GetDeviceInfoByName(deviceName, devInfo); - - if (eNoErr == err) - { - try - { - std::cout << "API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName << std::endl; - TRACE_MSG ("API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName); - - m_CurrentDevice = new WCMRCoreAudioDevice (this, devInfo.m_DeviceId, m_UseMultithreading, m_bNoCopyAudioBuffer); - } - catch (...) - { - std::cout << "Unabled to create PA Device: " << devInfo.m_DeviceId << std::endl; - DEBUG_MSG ("Unabled to create PA Device: " << devInfo.m_DeviceId); - } - } - - return m_CurrentDevice; -} - - -void WCMRCoreAudioDeviceManager::destroyCurrentDeviceImpl() -{ - if (m_CurrentDevice != m_NoneDevice) - delete m_CurrentDevice; - - m_CurrentDevice = 0; -} - - -WTErr WCMRCoreAudioDeviceManager::getDeviceAvailableSampleRates(DeviceID deviceId, std::vector<int>& sampleRates) -{ - AUTO_FUNC_DEBUG; - - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - UInt32 propSize = 0; - - sampleRates.clear(); - - //! 1. Get sample rate property size. - err = AudioDeviceGetPropertyInfo(deviceId, 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, NULL); - if (err == kAudioHardwareNoError) - { - //! 2. Get property: cannels output. - - // Allocate size according to the number of audio values - int numRates = propSize / sizeof(AudioValueRange); - AudioValueRange* supportedRates = new AudioValueRange[numRates]; - - // Get sampling rates from Audio device - err = AudioDeviceGetProperty(deviceId, 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, supportedRates); - if (err == kAudioHardwareNoError) - { - //! 3. Update sample rates - - // now iterate through our standard SRs - for(int ourSR=0; gAllSampleRates[ourSR] > 0; ourSR++) - { - //check to see if our SR is in the supported rates... - for (int deviceSR = 0; deviceSR < numRates; deviceSR++) - { - if ((supportedRates[deviceSR].mMinimum <= gAllSampleRates[ourSR]) && - (supportedRates[deviceSR].mMaximum >= gAllSampleRates[ourSR])) - { - sampleRates.push_back ((int)gAllSampleRates[ourSR]); - break; - } - } - } - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device Sample rates. Device Name: " << m_DeviceName.c_str()); - } - - delete [] supportedRates; - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device Sample rates property size. Device Name: " << m_DeviceName.c_str()); - } - - return retVal; -} - - -WTErr WCMRCoreAudioDeviceManager::getDeviceMaxInputChannels(DeviceID deviceId, unsigned int& inputChannels) -{ - AUTO_FUNC_DEBUG; - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - UInt32 propSize = 0; - inputChannels = 0; - - // 1. Get property cannels input size. - err = AudioDeviceGetPropertyInfo (deviceId, 0, 1/* Input */, kAudioDevicePropertyStreamConfiguration, &propSize, NULL); - if (err == kAudioHardwareNoError) - { - //! 2. Get property: cannels input. - - // Allocate size according to the property size. Note that this is a variable sized struct... - AudioBufferList *pStreamBuffers = (AudioBufferList *)malloc(propSize); - - if (pStreamBuffers) - { - memset (pStreamBuffers, 0, propSize); - - // Get the Input channels - err = AudioDeviceGetProperty (deviceId, 0, 1/* Input */, kAudioDevicePropertyStreamConfiguration, &propSize, pStreamBuffers); - if (err == kAudioHardwareNoError) - { - // Calculate the number of input channels - for (UInt32 streamIndex = 0; streamIndex < pStreamBuffers->mNumberBuffers; streamIndex++) - { - inputChannels += pStreamBuffers->mBuffers[streamIndex].mNumberChannels; - } - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device Input channels. Device Name: " << m_DeviceName.c_str()); - } - - free (pStreamBuffers); - } - else - { - retVal = eMemOutOfMemory; - DEBUG_MSG("Faild to allocate memory. Device Name: " << m_DeviceName.c_str()); - } - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device Input channels property size. Device Name: " << m_DeviceName.c_str()); - } - - return retVal; -} - - -WTErr WCMRCoreAudioDeviceManager::getDeviceMaxOutputChannels(DeviceID deviceId, unsigned int& outputChannels) -{ - AUTO_FUNC_DEBUG; - - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - UInt32 propSize = 0; - outputChannels = 0; - - //! 1. Get property cannels output size. - err = AudioDeviceGetPropertyInfo (deviceId, 0, 0/* Output */, kAudioDevicePropertyStreamConfiguration, &propSize, NULL); - if (err == kAudioHardwareNoError) - { - //! 2. Get property: cannels output. - - // Allocate size according to the property size. Note that this is a variable sized struct... - AudioBufferList *pStreamBuffers = (AudioBufferList *)malloc(propSize); - if (pStreamBuffers) - { - memset (pStreamBuffers, 0, propSize); - - // Get the Output channels - err = AudioDeviceGetProperty (deviceId, 0, 0/* Output */, kAudioDevicePropertyStreamConfiguration, &propSize, pStreamBuffers); - if (err == kAudioHardwareNoError) - { - // Calculate the number of output channels - for (UInt32 streamIndex = 0; streamIndex < pStreamBuffers->mNumberBuffers; streamIndex++) - { - outputChannels += pStreamBuffers->mBuffers[streamIndex].mNumberChannels; - } - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device Output channels. Device Name: " << m_DeviceName.c_str()); - } - free (pStreamBuffers); - } - else - { - retVal = eMemOutOfMemory; - DEBUG_MSG("Faild to allocate memory. Device Name: " << m_DeviceName.c_str()); - } - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device Output channels property size. Device Name: " << m_DeviceName.c_str()); - } - - return retVal; -} - - -WTErr WCMRCoreAudioDeviceManager::generateDeviceListImpl() -{ - AUTO_FUNC_DEBUG; - - // lock the list first - wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex); - m_DeviceInfoVec.clear(); - - //First, get info from None device which is always present - if (m_NoneDevice) - { - DeviceInfo *pDevInfo = new DeviceInfo(NONE_DEVICE_ID, m_NoneDevice->DeviceName() ); - pDevInfo->m_AvailableSampleRates = m_NoneDevice->SamplingRates(); - m_DeviceInfoVec.push_back(pDevInfo); - } - - WTErr retVal = eNoErr; - OSStatus osErr = noErr; - AudioDeviceID* deviceIDs = 0; - - openlog("WCMRCoreAudioDeviceManager", LOG_PID | LOG_CONS, LOG_USER); - - try - { - //Get device count... - UInt32 propSize = 0; - osErr = AudioHardwareGetPropertyInfo (kAudioHardwarePropertyDevices, &propSize, NULL); - ASSERT_ERROR(osErr, "AudioHardwareGetProperty 1"); - if (WUIsError(osErr)) - throw osErr; - - size_t numDevices = propSize / sizeof (AudioDeviceID); - deviceIDs = new AudioDeviceID[numDevices]; - - //retrieve the device IDs - propSize = numDevices * sizeof (AudioDeviceID); - osErr = AudioHardwareGetProperty (kAudioHardwarePropertyDevices, &propSize, deviceIDs); - ASSERT_ERROR(osErr, "Error while getting audio devices: AudioHardwareGetProperty 2"); - if (WUIsError(osErr)) - throw osErr; - - //now add the ones that are not there... - for (size_t deviceIndex = 0; deviceIndex < numDevices; deviceIndex++) - { - DeviceInfo* pDevInfo = 0; - - //Get device name and create new DeviceInfo entry - //Get property name size. - osErr = AudioDeviceGetPropertyInfo(deviceIDs[deviceIndex], 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL); - if (osErr == kAudioHardwareNoError) - { - //Get property: name. - char* deviceName = new char[propSize]; - osErr = AudioDeviceGetProperty(deviceIDs[deviceIndex], 0, 0, kAudioDevicePropertyDeviceName, &propSize, deviceName); - if (osErr == kAudioHardwareNoError) - { - pDevInfo = new DeviceInfo(deviceIDs[deviceIndex], deviceName); - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device name. Device ID: " << m_DeviceID); - } - - delete [] deviceName; - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device name property size. Device ID: " << m_DeviceID); - } - - if (pDevInfo) - { - //Retrieve all the information we need for the device - WTErr wErr = eNoErr; - - //Get available sample rates for the device - std::vector<int> availableSampleRates; - wErr = getDeviceAvailableSampleRates(pDevInfo->m_DeviceId, availableSampleRates); - - if (wErr != eNoErr) - { - DEBUG_MSG ("Failed to get device available sample rates. Device ID: " << m_DeviceID); - delete pDevInfo; - continue; //proceed to the next device - } - - pDevInfo->m_AvailableSampleRates = availableSampleRates; - - //Get max input channels - uint32_t maxInputChannels; - wErr = getDeviceMaxInputChannels(pDevInfo->m_DeviceId, maxInputChannels); - - if (wErr != eNoErr) - { - DEBUG_MSG ("Failed to get device max input channels count. Device ID: " << m_DeviceID); - delete pDevInfo; - continue; //proceed to the next device - } - - pDevInfo->m_MaxInputChannels = maxInputChannels; - - //Get max output channels - uint32_t maxOutputChannels; - wErr = getDeviceMaxOutputChannels(pDevInfo->m_DeviceId, maxOutputChannels); - - if (wErr != eNoErr) - { - DEBUG_MSG ("Failed to get device max output channels count. Device ID: " << m_DeviceID); - delete pDevInfo; - continue; //proceed to the next device - } - - pDevInfo->m_MaxOutputChannels = maxOutputChannels; - - //Now check if this device is acceptable according to current input/output settings - bool bRejectDevice = false; - switch(m_eAudioDeviceFilter) - { - case eInputOnlyDevices: - if (pDevInfo->m_MaxInputChannels != 0) - { - m_DeviceInfoVec.push_back(pDevInfo); - } - else - { - // Delete unnecesarry device - bRejectDevice = true; - } - break; - case eOutputOnlyDevices: - if (pDevInfo->m_MaxOutputChannels != 0) - { - m_DeviceInfoVec.push_back(pDevInfo); - } - else - { - // Delete unnecesarry device - bRejectDevice = true; - } - break; - case eFullDuplexDevices: - if (pDevInfo->m_MaxInputChannels != 0 && pDevInfo->m_MaxOutputChannels != 0) - { - m_DeviceInfoVec.push_back(pDevInfo); - } - else - { - // Delete unnecesarry device - bRejectDevice = true; - } - break; - case eAllDevices: - default: - m_DeviceInfoVec.push_back(pDevInfo); - break; - } - - if(bRejectDevice) - { - syslog (LOG_NOTICE, "%s rejected, In Channels = %d, Out Channels = %d\n", - pDevInfo->m_DeviceName.c_str(), pDevInfo->m_MaxInputChannels, pDevInfo->m_MaxOutputChannels); - // In case of Input and Output both channels being Zero, we will release memory; since we created CoreAudioDevice but we are Not adding it in list. - delete pDevInfo; - } - } - } - - - //If no devices were found, that's not a good thing! - if (m_DeviceInfoVec.empty()) - { - DEBUG_MSG ("No matching CoreAudio devices were found\n"); - } - } - catch (...) - { - if (WUNoError(retVal)) - retVal = eCoreAudioFailed; - } - - delete[] deviceIDs; - closelog(); - - return retVal; -} - - -WTErr WCMRCoreAudioDeviceManager::updateDeviceListImpl() -{ - wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex); - WTErr err = generateDeviceListImpl(); - - if (eNoErr != err) - { - std::cout << "API::PortAudioDeviceManager::updateDeviceListImpl: Device list update error: "<< err << std::endl; - } - - if (m_CurrentDevice) - { - // if we have device initialized we should find out if this device is still connected - DeviceInfo devInfo; - WTErr deviceLookUpErr = GetDeviceInfoByName(m_CurrentDevice->DeviceName(), devInfo ); - - if (eNoErr != deviceLookUpErr) - { - NotifyClient (WCMRAudioDeviceManagerClient::IODeviceDisconnected); - return err; - } - - WCMRCoreAudioDevice* current_device = dynamic_cast<WCMRCoreAudioDevice*>(m_CurrentDevice); - - if ( current_device && - (current_device->DeviceID() != devInfo.m_DeviceId ) ) - { - NotifyClient (WCMRAudioDeviceManagerClient::RequestReset); - return err; - } - } - - NotifyClient (WCMRAudioDeviceManagerClient::DeviceListChanged); - - return err; -} - - -WTErr WCMRCoreAudioDeviceManager::getDeviceSampleRatesImpl(const std::string & deviceName, std::vector<int>& sampleRates) const -{ - AUTO_FUNC_DEBUG; - - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - UInt32 propSize = 0; - - sampleRates.clear(); - - //first check if the request has been made for None device - if (deviceName == m_NoneDevice->DeviceName() ) - { - sampleRates = m_NoneDevice->SamplingRates(); - return retVal; - } - - if (m_CurrentDevice && m_CurrentDevice->DeviceName () == deviceName) { - sampleRates.assign(m_CurrentDevice->SamplingRates().begin(), m_CurrentDevice->SamplingRates().end() ); - return retVal; - } - - DeviceInfo devInfo; - retVal = GetDeviceInfoByName(deviceName, devInfo); - - //! 1. Get sample rate property size. - err = AudioDeviceGetPropertyInfo(devInfo.m_DeviceId, 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, NULL); - - if (err == kAudioHardwareNoError) - { - //! 2. Get property: cannels output. - - // Allocate size accrding to the number of audio values - int numRates = propSize / sizeof(AudioValueRange); - AudioValueRange* supportedRates = new AudioValueRange[numRates]; - - // Get sampling rates from Audio device - err = AudioDeviceGetProperty(devInfo.m_DeviceId, 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, supportedRates); - - if (err == kAudioHardwareNoError) - { - //! 3. Update sample rates - - // now iterate through our standard SRs - for(int ourSR=0; gAllSampleRates[ourSR] > 0; ourSR++) - { - //check to see if our SR is in the supported rates... - for (int deviceSR = 0; deviceSR < numRates; deviceSR++) - { - if ((supportedRates[deviceSR].mMinimum <= gAllSampleRates[ourSR]) && - (supportedRates[deviceSR].mMaximum >= gAllSampleRates[ourSR])) - { - sampleRates.push_back ((int)gAllSampleRates[ourSR]); - break; - } - } - } - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device Sample rates. Device Name: " << m_DeviceName.c_str()); - } - - delete [] supportedRates; - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device Sample rates property size. Device Name: " << m_DeviceName.c_str()); - } - - devInfo.m_AvailableSampleRates.assign(sampleRates.begin(), sampleRates.end() ); - - return retVal; -} - - -WTErr WCMRCoreAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& bufferSizes) const -{ - AUTO_FUNC_DEBUG; - - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - UInt32 propSize = 0; - - bufferSizes.clear(); - - //first check if the request has been made for None device - if (deviceName == m_NoneDevice->DeviceName() ) - { - bufferSizes = m_NoneDevice->BufferSizes(); - return retVal; - } - - if (m_CurrentDevice && m_CurrentDevice->DeviceName () == deviceName) { - bufferSizes.assign(m_CurrentDevice->BufferSizes().begin(), m_CurrentDevice->BufferSizes().end() ); - return retVal; - } - - DeviceInfo devInfo; - retVal = GetDeviceInfoByName(deviceName, devInfo); - - if (eNoErr == retVal) - { - // 1. Get buffer size range - AudioValueRange bufferSizesRange; - propSize = sizeof (AudioValueRange); - err = AudioDeviceGetProperty (devInfo.m_DeviceId, 0, 0, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &bufferSizesRange); - if(err == kAudioHardwareNoError) - { - // 2. Run on all ranges and add them to the list - for(int bsize=0; gAllBufferSizes[bsize] > 0; bsize++) - { - if ((bufferSizesRange.mMinimum <= gAllBufferSizes[bsize]) && (bufferSizesRange.mMaximum >= gAllBufferSizes[bsize])) - { - bufferSizes.push_back (gAllBufferSizes[bsize]); - } - } - - //if we didn't get a single hit, let's simply add the min. and the max... - if (bufferSizes.empty()) - { - bufferSizes.push_back ((int)bufferSizesRange.mMinimum); - bufferSizes.push_back ((int)bufferSizesRange.mMaximum); - } - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device buffer sizes range. Device Name: " << m_DeviceName.c_str()); - } - } - else - { - retVal = eRMResNotFound; - std::cout << "API::PortAudioDeviceManager::GetBufferSizes: Device not found: "<< deviceName << std::endl; - } - - - return retVal; -} - - -OSStatus WCMRCoreAudioDeviceManager::HardwarePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* inClientData) -{ - switch (inPropertyID) - { - case kAudioHardwarePropertyDevices: - { - WCMRCoreAudioDeviceManager* pManager = (WCMRCoreAudioDeviceManager*)inClientData; - if (pManager) - pManager->updateDeviceListImpl(); - } - break; - - default: - break; - } - - return 0; -} diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.h b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.h deleted file mode 100644 index 0d92493b51..0000000000 --- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - Copyright (C) 2014 Waves Audio Ltd. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -//---------------------------------------------------------------------------------- -// -// -//! \file WCMRCoreAudioDeviceManager.h -//! -//! WCMRCoreAudioDeviceManager and related class declarations -//! -//---------------------------------------------------------------------------------*/ -#ifndef __WCMRCoreAudioDeviceManager_h_ - #define __WCMRCoreAudioDeviceManager_h_ - -#include "WCMRAudioDeviceManager.h" -#include "WCMRNativeAudio.h" -#include "Threads/WCThreadSafe.h" - -#include <AudioUnit/AudioUnit.h> -#include <AudioToolbox/AudioToolbox.h> - -#include <mach/mach.h> - -#include <CoreAudio/CoreAudio.h> - -//forward decl. -class WCMRCoreAudioDeviceManager; - -#define WV_USE_TONE_GEN 0 ///! Set this to 1 to use a tone generator for input. See description at SetupToneGenerator for details. - -// This enum is for choosing filter for audio devices scan -typedef enum eCABS_Method -{ - eCABS_Simple = 0, - eCABS_DestructiveCache, - eCABS_CacheOnDeviceSet, - eCABS_MethodNum // Must be last -} eCABS_Method; - -//! Manages a port audio device, providing information -//! about the device, and managing audio callbacks. -class WCMRCoreAudioDevice : public WCMRNativeAudioDevice -{ -public: - - WCMRCoreAudioDevice (WCMRCoreAudioDeviceManager *pManager, AudioDeviceID deviceID, bool useMultithreading = true, bool bNocopy = false);///<Constructor - virtual ~WCMRCoreAudioDevice ();///<Destructor - - virtual const std::string& DeviceName() const;///<Name? - virtual const std::vector<std::string>& InputChannels();///<Current Input Channel List? - note that this may change with change in sampling rate. - virtual const std::vector<std::string>& OutputChannels();///<Current Output Channel List? - note that this may change with change in sampling rate. - - - virtual const std::vector<int>& SamplingRates();///<Supported Sampling Rate List? - virtual int CurrentSamplingRate(); ///<Current Sampling rate.? - virtual WTErr SetCurrentSamplingRate(int newRate);///<Change Current Sampling Rate : This is a requset, might not be successful at run time! - - virtual const std::vector<int>& BufferSizes();///<Supported Buffer Size List? - note that this may change with change in sampling rate. - virtual int CurrentBufferSize();///<Current Buffer Size.? - note that this may change with change in sampling rate. - virtual WTErr SetCurrentBufferSize (int newSize);///<Change Current Buffer Size : This is a requset, might not be successful at run time! - - virtual ConnectionStates ConnectionStatus();///< Connection Status - device available, gone, disconnected - - virtual WTErr SetActive (bool newState);///<Prepare/Activate device. - virtual WTErr SetStreaming (bool newState);///<Start/Stop Streaming - should reconnect connections when streaming starts! - - virtual WTErr DoIdle();///<Do Idle Processing - - virtual WTErr SetMonitorChannels (int leftChannel, int rightChannel);///<Set monitor channels. - optional, will not be available with AG - virtual WTErr SetMonitorGain (float newGain);///<Set monitor gain. - optional, will not be available with AG - - virtual WTErr ShowConfigPanel (void *pParam);///< Show Control Panel - in case of ASIO this will work only with Active device! - - virtual int AudioCallback (float *pOutputBuffer, unsigned long framesPerBuffer, int64_t inSampleTime, uint64_t inCycleStartTime); - - AudioDeviceID DeviceID () {return m_DeviceID;} - - virtual uint32_t GetLatency (bool isInput); ///< Get latency. - virtual OSStatus GetStreamLatency(AudioDeviceID deviceID, bool isInput, std::vector<int>& latencies); - - -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. - int64_t m_SampleCounter; ///< The current running sample counter, updated by the audio callback. - int64_t m_SampleCountAtLastIdle; ///< What was the sample count last time we checked... - int m_StalledSampleCounter; ///< The number of idle calls with same sample count detected - int m_ChangeCheckCounter; ///< The number of idle calls passed since we checked the buffer size change. - - wvNS::wvThread::timestamp m_LastCPULog; ///< The time when the last CPU details log was sent as a notification. -// unsigned int m_IOCyclesTimesTaken[MAX_IOCYCLE_TIMES]; ///< This stores the times taken by each IOCycle, in host-time units. -// int m_CurrentIOCycle; ///< The location in m_IOCyclesTymesTaken array, where the next cycle's value will go. -// 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 - - - AudioUnit m_AUHALAudioUnit;///< The AUHAL AudioUnit - - int m_BufferSizeChangeRequested; - int m_BufferSizeChangeReported; - int m_ResetRequested; - int m_ResetReported; - int m_ResyncRequested; - int m_ResyncReported; - int m_SRChangeRequested; - int m_SRChangeReported; - - int m_DropsDetected; ///< Number of times audio drops have been detected so far. - int m_DropsReported; ///< Number of times audio drops have been reported so far to the client. - bool m_IgnoreThisDrop; ///< Allows disregarding the first drop - - thread_t m_IOProcThreadPort; ///< Thread handle to calculate CPU consumption. - int m_CPUCount; ///< Number of processors/core to normalize cpu consumption calculation. - -#if WV_USE_TONE_GEN - //The Tone Generator... - float_t *m_pToneData; - uint32_t m_ToneDataSamples; - uint32_t m_NextSampleToUse; -#endif //WV_USE_TONE_GEN - - WTErr UpdateDeviceInfo (); - WTErr UpdateDeviceId (); - WTErr UpdateDeviceName(); - WTErr UpdateDeviceInputs(); - WTErr UpdateDeviceOutputs(); - WTErr UpdateDeviceSampleRates(); - WTErr UpdateDeviceBufferSizes(); - WTErr SetWorkingBufferSize(int newSize); - OSStatus SetBufferSizesByIO(int newSize); - WTErr SetAndCheckCurrentSamplingRate (int newRate); - - WTErr EnableAudioUnitIO(); - WTErr virtual EnableListeners(); - WTErr virtual DisableListeners(); - WTErr SetupAUHAL(); - WTErr TearDownAUHAL(); - -#if WV_USE_TONE_GEN - void SetupToneGenerator (); -#endif //WV_USE_TONE_GEN - - static OSStatus StaticAudioIOProc(void *inRefCon, AudioUnitRenderActionFlags * ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList *ioData); - OSStatus AudioIOProc(AudioUnitRenderActionFlags * ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList *ioData); - - static OSStatus StaticPropertyChangeProc (AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, - AudioDevicePropertyID inPropertyID, void *inClientData); - void PropertyChangeProc (AudioDevicePropertyID inPropertyID); - -private: - -}; - - -//! WCMRCoreAudioDeviceManager -/*! The CoreAudio Device Manager class */ -class WCMRCoreAudioDeviceManager : public WCMRAudioDeviceManager -{ -public: - - WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter, - bool useMultithreading = true, bool bNocopy = false); ///< constructor - virtual ~WCMRCoreAudioDeviceManager(void); ///< Destructor - -protected: - static OSStatus HardwarePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* inClientData); - - virtual WCMRAudioDevice* initNewCurrentDeviceImpl(const std::string & deviceName); - virtual void destroyCurrentDeviceImpl(); - virtual WTErr generateDeviceListImpl(); - virtual WTErr updateDeviceListImpl(); - virtual WTErr getDeviceSampleRatesImpl(const std::string & deviceName, std::vector<int>& sampleRates) const; - virtual WTErr getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& bufferSizes) const; - - bool m_UseMultithreading; ///< Flag indicates whether to use multi-threading for audio processing. - bool m_bNoCopyAudioBuffer; - -private: - // helper functions for this class only - WTErr getDeviceAvailableSampleRates(DeviceID deviceId, std::vector<int>& sampleRates); - WTErr getDeviceMaxInputChannels(DeviceID deviceId, unsigned int& inputChannels); - WTErr getDeviceMaxOutputChannels(DeviceID deviceId, unsigned int& outputChannels); - - WCMRAudioDevice* m_NoneDevice; -}; - -#endif //#ifndef __WCMRCoreAudioDeviceManager_h_ diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.cpp b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.cpp deleted file mode 100644 index bf5e4fbb90..0000000000 --- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.cpp +++ /dev/null @@ -1,266 +0,0 @@ -//---------------------------------------------------------------------------------- -// -// Copyright (c) 2008 Waves Audio Ltd. All rights reserved. -// -//! \file WCMRNativeAudio.cpp -//! -//! WCMRNativeAudioConnection and related class defienitions -//! -//---------------------------------------------------------------------------------*/ -#if defined(__APPLE__) -#include <CoreAudio/CoreAudio.h> -#endif - -#include "WCMRNativeAudio.h" -#include "MiscUtils/pthread_utils.h" -#include "MiscUtils/safe_delete.h" -#include <iostream> -#include <sstream> -#include <boost/assign/list_of.hpp> - -#define NONE_DEVICE_NAME "None" -#define NONE_DEVICE_INPUT_NAMES "Input " -#define NONE_DEVICE_OUTPUT_NAMES "Output " - -//********************************************************************************************** -// WCMRNativeAudioNoneDevice::WCMRNativeAudioNoneDevice -// -//! Constructor for the dummy "None" device. This constructor simply adds supported SRs, -//! buffer sizes, and channels, so that it may look like a real native device to -//! the applications. -//! -//! \param pManager : The managing device manager - simply passed on to the base class. -//! -//! -//********************************************************************************************** -WCMRNativeAudioNoneDevice::WCMRNativeAudioNoneDevice (WCMRAudioDeviceManager *pManager) - : WCMRNativeAudioDevice (pManager, false /*useMultiThreading*/) -#ifndef PTW32_VERSION - , m_SilenceThread(0) -#endif -#if defined (PLATFORM_WINDOWS) - , _waitableTimerForUsleep (CreateWaitableTimer(NULL, TRUE, NULL)) -#endif -{ - mark_pthread_inactive (m_SilenceThread); - - m_DeviceName = NONE_DEVICE_NAME; - - m_SamplingRates = boost::assign::list_of (m_CurrentSamplingRate=44100)(48000)(88200)(96000)(176400)(192000); - - m_BufferSizes = boost::assign::list_of (32)(64)(128)(m_CurrentBufferSize=256)(512)(1024); - - for (int channel = 0; channel < __m_NumInputChannels; channel++) - { - std::stringstream name; - name << NONE_DEVICE_INPUT_NAMES; - name << (channel + 1); - m_InputChannels.push_back(name.str()); - } - - for (int channel = 0; channel < __m_NumOutputChannels; channel++) - { - std::stringstream name; - name << NONE_DEVICE_INPUT_NAMES; - name << (channel + 1); - m_OutputChannels.push_back(name.str()); - } - _m_inputBuffer = new float[__m_NumInputChannels * m_BufferSizes.back()]; - _m_outputBuffer = new float[__m_NumOutputChannels * m_BufferSizes.back()]; - m_CurrentBufferSize = m_BufferSizes.back(); -} - - -WCMRNativeAudioNoneDevice::~WCMRNativeAudioNoneDevice () -{ -#if defined (PLATFORM_WINDOWS) - if(_waitableTimerForUsleep) { - CloseHandle(_waitableTimerForUsleep); - } -#endif -} - -WTErr WCMRNativeAudioNoneDevice::SetActive (bool newState) -{ - //This will most likely be overridden, the base class simply - //changes the member. - if (Active() == newState) - { - return (eNoErr); - } - - if (Active() && Streaming()) - { - SetStreaming(false); - } - return WCMRAudioDevice::SetActive(newState); -} - -WTErr WCMRNativeAudioNoneDevice::SetCurrentBufferSize (int newSize) -{ - - //changes the status. - int oldSize = CurrentBufferSize(); - bool oldActive = Active(); - - //same size, nothing to do. - if (oldSize == newSize) - return eNoErr; - - //see if this is one of our supported rates... - std::vector<int>::iterator intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), newSize); - if (intIter == m_BufferSizes.end()) - { - //Can't change, perhaps use an "invalid param" type of error - return eCommandLineParameter; - } - - if (Streaming()) - { - //Can't change, perhaps use an "in use" type of error - return eGenericErr; - } - - - return WCMRAudioDevice::SetCurrentBufferSize(newSize); -} - - -WTErr WCMRNativeAudioNoneDevice::UpdateDeviceInfo () -{ - return eNoErr; -} - - -WTErr WCMRNativeAudioNoneDevice::SetStreaming (bool newState) -{ - if (Streaming() == newState) - { - return (eNoErr); - } - - WCMRAudioDevice::SetStreaming(newState); - - if (Streaming()) - { - if (is_pthread_active (m_SilenceThread)) - std::cerr << "\t\t\t\t\t !!!!!!!!!!!!!!! Warning: the inactive NONE-DEVICE was streaming!" << std::endl; - - pthread_attr_t attributes; - size_t stack_size = 100000; -#ifdef __APPLE__ - stack_size = (((stack_size - 1) / PTHREAD_STACK_MIN) + 1) * PTHREAD_STACK_MIN; -#endif - if (pthread_attr_init (&attributes)) { - std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_attr_init () failed!" << std::endl; - return eGenericErr; - } - - if (pthread_attr_setstacksize (&attributes, stack_size)) { - std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_attr_setstacksize () failed!" << std::endl; - return eGenericErr; - } - - if (pthread_create (&m_SilenceThread, &attributes, __SilenceThread, this)) { - mark_pthread_inactive (m_SilenceThread); - std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_create () failed!" << std::endl; - return eGenericErr; - } - } - else - { - if (!is_pthread_active (m_SilenceThread)) - { - std::cerr << "\t\t\t\t\t !!!!!!!!!!!!!!! Warning: the active NONE-DEVICE was NOT streaming!" << std::endl; - } - - while (is_pthread_active (m_SilenceThread)) - { - _usleep(1); //now wait for ended thread; - } - } - - return eNoErr; -} - -void WCMRNativeAudioNoneDevice::_SilenceThread() -{ -#if defined(PLATFORM_WINDOWS) - float* theInpBuffers[__m_NumInputChannels]; - for(int i = 0; i < __m_NumInputChannels; ++i) - { - theInpBuffers[i] = _m_inputBuffer + m_BufferSizes.back() * i; - } -#else - float* theInpBuffers = _m_inputBuffer; -#endif - - const size_t buffer_size = CurrentBufferSize(); - const uint64_t cyclePeriodNanos = (1000000000.0 * buffer_size) / CurrentSamplingRate(); - - struct WCMRAudioDeviceManagerClient::AudioCallbackData audioCallbackData = - { - (const float*)theInpBuffers, - _m_outputBuffer, - buffer_size, - 0, - 0 - }; - - audioCallbackData.acdCycleStartTimeNanos =__get_time_nanos(); - - // VERY ROUGH IMPLEMENTATION: - while(Streaming()) { - - uint64_t cycleEndTimeNanos = audioCallbackData.acdCycleStartTimeNanos + cyclePeriodNanos; - - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::AudioCallback, (void *)&audioCallbackData); - - audioCallbackData.acdSampleTime += buffer_size; - - int64_t timeToSleepUsecs = ((int64_t)cycleEndTimeNanos - (int64_t)__get_time_nanos())/1000; - - if (timeToSleepUsecs > 0) { - _usleep (timeToSleepUsecs); - } - audioCallbackData.acdCycleStartTimeNanos = cycleEndTimeNanos+1; - } - mark_pthread_inactive (m_SilenceThread); -} - -void* WCMRNativeAudioNoneDevice::__SilenceThread(void *This) -{ - ((WCMRNativeAudioNoneDevice*)This)->_SilenceThread(); - return 0; -} - -#if defined(PLATFORM_WINDOWS) -void WCMRNativeAudioNoneDevice::_usleep(uint64_t duration_usec) -{ - LARGE_INTEGER ft; - - ft.QuadPart = -(10*duration_usec); // Convert to 100 nanosecond interval, negative value indicates relative time - - SetWaitableTimer(_waitableTimerForUsleep, &ft, 0, NULL, NULL, 0); - WaitForSingleObject(_waitableTimerForUsleep, INFINITE); -} -#endif - -uint64_t -WCMRNativeAudioNoneDevice::__get_time_nanos () -{ -#ifdef __APPLE__ - // here we exploit the time counting API which is used by the WCMRCoreAudioDeviceManager. However, - // the API should be a part of WCMRCoreAudioDeviceManager to give a chance of being tied to the - // audio device transport timeß. - return AudioConvertHostTimeToNanos (AudioGetCurrentHostTime ()); - -#elif PLATFORM_WINDOWS - - LARGE_INTEGER Frequency, Count ; - - QueryPerformanceFrequency (&Frequency) ; - QueryPerformanceCounter (&Count); - return uint64_t ((Count.QuadPart * 1000000000.0 / Frequency.QuadPart)); -#endif -} diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.h b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.h deleted file mode 100644 index 238d36fd74..0000000000 --- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - Copyright (C) 2014 Waves Audio Ltd. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -//---------------------------------------------------------------------------------- -// -// -//! \file WCMRNativeAudio.h -//! -//! WCMRNativeAudio and related class declarations -//! -//---------------------------------------------------------------------------------*/ -#ifndef __WCMRNativeAudio_h_ - #define __WCMRNativeAudio_h_ - -#if defined(PLATFORM_WINDOWS) -#include "windows.h" -#endif -#include "pthread.h" -#include "WCRefManager.h" -#include "WCMRAudioDeviceManager.h" - -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9 -#include <unistd.h> -#endif - -class WCMRNativeAudioDevice; //forward - - - -class WCMRNativeAudioDevice : public WCMRAudioDevice -{ -public: - - WCMRNativeAudioDevice (WCMRAudioDeviceManager *pManager, bool useMultithreading = true, bool bNoCopy = false) : - WCMRAudioDevice (pManager) - , m_UseMultithreading (useMultithreading) - , m_bNoCopyAudioBuffer(bNoCopy) - {} - virtual ~WCMRNativeAudioDevice () {} - -protected: - bool m_UseMultithreading; - bool m_bNoCopyAudioBuffer; ///< This flag determines whether the audio callback performs a copy of audio, or the source/sink perform the copy. It should be true to let source/sink do the copies. - -}; - - -//! A dummy device to allow apps to choose "None" in case no real device connection is required. -class WCMRNativeAudioNoneDevice : public WCMRNativeAudioDevice -{ -public: - WCMRNativeAudioNoneDevice (WCMRAudioDeviceManager *pManager); - virtual ~WCMRNativeAudioNoneDevice (); - virtual WTErr SetActive (bool newState);///<Prepare/Activate device. - virtual WTErr SetStreaming (bool newState);///<Start/Stop Streaming - should reconnect connections when streaming starts! - virtual WTErr SetCurrentBufferSize (int newSize);///<Change Current Buffer Size : This is a requset, might not be successful at run time! - virtual WTErr UpdateDeviceInfo (); - -private: - - static void* __SilenceThread(void *This); - void _SilenceThread(); -#if defined(PLATFORM_WINDOWS) - void _usleep(uint64_t usec); -#else - inline void _usleep(uint64_t usec) { ::usleep(usec); } -#endif - static const size_t __m_NumInputChannels = 0; - static const size_t __m_NumOutputChannels = 0; - pthread_t m_SilenceThread; - float *_m_inputBuffer; - float *_m_outputBuffer; - static uint64_t __get_time_nanos (); -#if defined (PLATFORM_WINDOWS) - HANDLE _waitableTimerForUsleep; -#endif -}; - - -#endif //#ifndef __WCMRNativeAudio_h_ diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.cpp b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.cpp deleted file mode 100644 index 8e63887d37..0000000000 --- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.cpp +++ /dev/null @@ -1,1782 +0,0 @@ -//---------------------------------------------------------------------------------- -// -// Copyright (c) 2008 Waves Audio Ltd. All rights reserved. -// -//! \file WCMRPortAudioDeviceManager.cpp -//! -//! WCMRPortAudioDeviceManager and related class declarations -//! -//---------------------------------------------------------------------------------*/ -#include "WCMRPortAudioDeviceManager.h" -#include "MiscUtils/safe_delete.h" -#include "UMicroseconds.h" -#include <iostream> -#include <sstream> -#include <algorithm> -#include <list> -using namespace wvNS; -#include "IncludeWindows.h" -#include <mmsystem.h> -#include "pa_asio.h" -#include "asio.h" - -#define PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS 200 -#define DEVICE_INFO_UPDATE_SLEEP_TIME_MILLISECONDS 500 -#define PROPERTY_CHANGE_TIMEOUT_SECONDS 2 -#define PROPERTY_CHANGE_RETRIES 3 - -///< Supported Sample rates -static const double gAllSampleRates[] = - { - 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0, -1 /* negative terminated list */ - }; - - - -///< Default Supported Buffer Sizes. -static const int gAllBufferSizes[] = - { - 32, 64, 96, 128, 192, 256, 512, 1024, 2048 - }; - - -///< The default SR. -static const int DEFAULT_SR = 44100; -///< The default buffer size. -static const int DEFAULT_BUFFERSIZE = 128; - -static const int NONE_DEVICE_ID = -1; - -///< Number of stalls to wait before notifying user... -static const int NUM_STALLS_FOR_NOTIFICATION = 100; // 100 corresponds to 100 x 42 ms idle timer - about 4 seconds. -static const int CHANGE_CHECK_COUNTER_PERIOD = 100; // 120 corresponds to 120 x 42 ms idle timer - about 4 seconds. - -#define HUNDRED_NANO_TO_MILLI_CONSTANT 10000 -#define CONSUMPTION_CALCULATION_INTERVAL 500 // Milli Seconds - - -// This wrapper is used to adapt device DoIdle method as entry point for MS thread -DWORD WINAPI WCMRPortAudioDevice::__DoIdle__(LPVOID lpThreadParameter) -{ - WCMRPortAudioDevice* pDevice = (WCMRPortAudioDevice*)lpThreadParameter; - pDevice->DoIdle(); - return 0; -} - -//********************************************************************************************** -// WCMRPortAudioDevice::WCMRPortAudioDevice -// -//! Constructor for the audio device. Opens the PA device -//! and gets information about the device. -//! Starts the thread which will process requests to this device -//! such as determining supported sampling rates, buffer sizes, and channel counts. -//! -//! \param *pManager : The audio device manager that's managing this device. -//! \param deviceID : The port audio device ID. -//! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true. -//! -//! \return Nothing. -//! -//********************************************************************************************** -WCMRPortAudioDevice::WCMRPortAudioDevice (WCMRPortAudioDeviceManager *pManager, unsigned int deviceID, bool useMultithreading, bool bNoCopy) : - WCMRNativeAudioDevice (pManager, useMultithreading, bNoCopy) - , m_SampleCounter(0) - , m_BufferSizeChangeRequested (0) - , m_BufferSizeChangeReported (0) - , m_ResetRequested (0) - , m_ResetReported (0) - , m_ResyncRequested (0) - , m_ResyncReported (0) - , m_DropsDetected(0) - , m_DropsReported(0) - , m_IgnoreThisDrop(true) - , m_hDeviceProcessingThread(NULL) - , m_DeviceProcessingThreadID(0) - , m_hUpdateDeviceInfoRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_hUpdateDeviceInfoDone(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_hActivateRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_hActivationDone(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_hDeActivateRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_hDeActivationDone(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_hStartStreamingRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_hStartStreamingDone(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_hStopStreamingRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_hStopStreamingDone(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_hResetRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_hResetDone(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_hResetFromDevRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_hBufferSizeChangedEvent(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_hSampleRateChangedEvent(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_hExitIdleThread(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_hDeviceInitialized(CreateEvent(NULL, FALSE, FALSE, NULL)) - , m_lastErr(eNoErr) -{ - AUTO_FUNC_DEBUG; - - //Set initial device info... - m_DeviceID = deviceID; - m_PortAudioStream = NULL; - m_CurrentSamplingRate = DEFAULT_SR; - m_CurrentBufferSize = DEFAULT_BUFFERSIZE; - m_StopRequested = true; - m_pInputData = NULL; - - //initialize device processing thread - //the divice become alive and now is able to process requests - m_hDeviceProcessingThread = CreateThread( NULL, 0, __DoIdle__, (LPVOID)this, 0, &m_DeviceProcessingThreadID ); - - if (!m_hDeviceProcessingThread) - { - DEBUG_MSG("API::Device " << m_DeviceName << " cannot create processing thread"); - throw eGenericErr; - } - - WaitForSingleObject(m_hDeviceInitialized, INFINITE); - - if (ConnectionStatus() == DeviceErrors) - { - throw m_lastErr; - } -} - - -void WCMRPortAudioDevice::initDevice() -{ - // Initialize COM for this thread - std::cout << "API::Device " << m_DeviceID << " initializing COM" << std::endl; - - if (S_OK == CoInitialize(NULL) ) - { - // Initialize PA - Pa_Initialize(); - - updateDeviceInfo(); - - //should use a valid current SR... - if (m_SamplingRates.size()) - { - //see if the current sr is present in the sr list, if not, use the first one! - std::vector<int>::iterator intIter = find(m_SamplingRates.begin(), m_SamplingRates.end(), m_CurrentSamplingRate); - if (intIter == m_SamplingRates.end()) - { - //not found... use the first one - m_CurrentSamplingRate = m_SamplingRates[0]; - } - } - else - std::cout << "API::Device " << m_DeviceName << " Device does not support any sample rate of ours" << std::endl; - - //should use a valid current buffer size - if (m_BufferSizes.size()) - { - //see if the current sr is present in the buffersize list, if not, use the first one! - std::vector<int>::iterator intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), m_CurrentBufferSize); - if (intIter == m_BufferSizes.end()) - { - //not found... use the first one - m_CurrentBufferSize = m_BufferSizes[0]; - } - } - - //build our input/output level lists - for (unsigned int currentChannel = 0; currentChannel < m_InputChannels.size(); currentChannel++) - { - m_InputLevels.push_back (0.0); - } - - //build our input/output level lists - for (unsigned int currentChannel = 0; currentChannel < m_OutputChannels.size(); currentChannel++) - { - m_OutputLevels.push_back (0.0); - } - - std::cout << "API::Device " << m_DeviceName << " Device has been initialized" << std::endl; - m_ConnectionStatus = DeviceDisconnected; - m_lastErr = eNoErr; - } - else - { - /*Replace with debug trace*/std::cout << "API::Device " << m_DeviceName << " cannot initialize COM" << std::endl; - DEBUG_MSG("Device " << m_DeviceName << " cannot initialize COM"); - m_ConnectionStatus = DeviceErrors; - m_lastErr = eSomeThingNotInitailzed; - SetEvent(m_hExitIdleThread); - } - - SetEvent(m_hDeviceInitialized); -} - -void WCMRPortAudioDevice::terminateDevice() -{ - std::cout << "API::Device " << m_DeviceName << " Terminating DEVICE" << std::endl; - - //If device is streaming, need to stop it! - if (Streaming()) - { - stopStreaming(); - } - - //If device is active (meaning stream is open) we need to close it. - if (Active()) - { - deactivateDevice(); - } - - std::cout << "API::Device " << m_DeviceName << " Terminating PA" << std::endl; - - //Deinitialize PA - Pa_Terminate(); -} - - -//********************************************************************************************** -// WCMRPortAudioDevice::~WCMRPortAudioDevice -// -//! Destructor for the audio device. The base release all the connections that were created, if -//! they have not been already destroyed! Here we simply stop streaming, and close device -//! handles if necessary. -//! -//! \param none -//! -//! \return Nothing. -//! -//********************************************************************************************** -WCMRPortAudioDevice::~WCMRPortAudioDevice () -{ - AUTO_FUNC_DEBUG; - - std::cout << "API::Destroying Device Instance: " << DeviceName() << std::endl; - try - { - //Stop deviceprocessing thread - SignalObjectAndWait(m_hExitIdleThread, m_hDeviceProcessingThread, INFINITE, false); - - std::cout << "API::Device " << m_DeviceName << " Processing Thread is stopped" << std::endl; - - CloseHandle(m_hDeviceProcessingThread); - - //Now it's safe to free all event handlers - CloseHandle(m_hUpdateDeviceInfoRequestedEvent); - CloseHandle(m_hUpdateDeviceInfoDone); - CloseHandle(m_hActivateRequestedEvent); - CloseHandle(m_hActivationDone); - CloseHandle(m_hDeActivateRequestedEvent); - CloseHandle(m_hDeActivationDone); - CloseHandle(m_hStartStreamingRequestedEvent); - CloseHandle(m_hStartStreamingDone); - CloseHandle(m_hStopStreamingRequestedEvent); - CloseHandle(m_hStopStreamingDone); - CloseHandle(m_hResetRequestedEvent); - CloseHandle(m_hResetDone); - CloseHandle(m_hResetFromDevRequestedEvent); - CloseHandle(m_hBufferSizeChangedEvent); - CloseHandle(m_hSampleRateChangedEvent); - CloseHandle(m_hExitIdleThread); - CloseHandle(m_hDeviceInitialized); - } - catch (...) - { - //destructors should absorb exceptions, no harm in logging though!! - DEBUG_MSG ("Exception during destructor"); - } -} - - -WTErr WCMRPortAudioDevice::UpdateDeviceInfo () -{ - std::cout << "API::Device (ID:)" << m_DeviceID << " Updating device info" << std::endl; - - SignalObjectAndWait(m_hUpdateDeviceInfoRequestedEvent, m_hUpdateDeviceInfoDone, INFINITE, false); - - return eNoErr; -} - - -//********************************************************************************************** -// WCMRPortAudioDevice::updateDeviceInfo -// -//! Must be called be device processing thread -//! Updates Device Information about channels, sampling rates, buffer sizes. -//! -//! \return Nothing. -//! -//********************************************************************************************** -void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/) -{ - AUTO_FUNC_DEBUG; - - //get device info - const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID); - - //update name. - m_DeviceName = pDeviceInfo->name; - - //following parameters are needed opening test stream and for sample rates validation - PaStreamParameters inputParameters, outputParameters; - PaStreamParameters *pInS = NULL, *pOutS = NULL; - - inputParameters.device = m_DeviceID; - inputParameters.channelCount = pDeviceInfo->maxInputChannels; - inputParameters.sampleFormat = paFloat32 | paNonInterleaved; - inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ - inputParameters.hostApiSpecificStreamInfo = 0; - - if (inputParameters.channelCount) - pInS = &inputParameters; - - outputParameters.device = m_DeviceID; - outputParameters.channelCount = pDeviceInfo->maxOutputChannels; - outputParameters.sampleFormat = paFloat32; - outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ - outputParameters.hostApiSpecificStreamInfo = 0; - - if (outputParameters.channelCount) - pOutS = &outputParameters; - - //////////////////////////////////////////////////////////////////////////////////// - //update list of supported SRs... - m_SamplingRates.clear(); - - // now iterate through our standard SRs and check if they are supported by device - // store them for this device - for(int sr=0; gAllSampleRates[sr] > 0; sr++) - { - PaError err = Pa_IsFormatSupported(pInS, pOutS, gAllSampleRates[sr]); - if( err == paFormatIsSupported) - { - m_SamplingRates.push_back ((int)gAllSampleRates[sr]); - } - } - - /////////////////////////////////////////////////////////////////////////////////// - //update buffer sizes - m_BufferSizes.clear(); - bool useDefaultBuffers = true; - - // In ASIO Windows, the buffer size is set from the sound device manufacturer's control panel - long minSize, maxSize, preferredSize, granularity; - PaError err = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity); - - if (err == paNoError) - { - std::cout << "API::Device " << m_DeviceName << " Buffers: " << minSize << " " << maxSize << " " << preferredSize << std::endl; - - m_BufferSizes.push_back (preferredSize); - useDefaultBuffers = false; - } - else - { - std::cout << "API::Device" << m_DeviceName << " Preffered buffer size is not supported" << std::endl; - } - - if (useDefaultBuffers) - { - std::cout << "API::Device" << m_DeviceName << " Using default buffer sizes " <<std::endl; - for(int bsize=0; bsize < (sizeof(gAllBufferSizes)/sizeof(gAllBufferSizes[0])); bsize++) - m_BufferSizes.push_back (gAllBufferSizes[bsize]); - } - - ///////////////////////////////////////////////////////////////////////////////////////// - //update channels info - { - int maxInputChannels = pDeviceInfo->maxInputChannels; - int maxOutputChannels = pDeviceInfo->maxOutputChannels; - - //Update input channels - m_InputChannels.clear(); - for (int channel = 0; channel < maxInputChannels; channel++) - { - const char* channelName[32]; // 32 is max leth declared by PortAudio for this operation - std::stringstream chNameStream; - - PaError error = PaAsio_GetInputChannelName(m_DeviceID, channel, channelName); - - chNameStream << (channel+1) << " - "; - - if (error == paNoError) - { - chNameStream << *channelName; - } - else - { - chNameStream << "Input " << (channel+1); - } - - m_InputChannels.push_back (chNameStream.str()); - } - - - //Update output channels - m_OutputChannels.clear(); - for (int channel = 0; channel < maxOutputChannels; channel++) - { - const char* channelName[32]; // 32 is max leth declared by PortAudio for this operation - std::stringstream chNameStream; - - PaError error = PaAsio_GetOutputChannelName(m_DeviceID, channel, channelName); - - chNameStream << (channel+1) << " - "; - - if (error == paNoError) - { - chNameStream << *channelName; - } - else - { - chNameStream << "Output " << (channel+1); - } - - m_OutputChannels.push_back (chNameStream.str()); - } - } - - std::cout << "API::Device" << m_DeviceName << " Device info update has been finished" << std::endl; - - if (callerIsWaiting) - SetEvent(m_hUpdateDeviceInfoDone); -} - - -PaError WCMRPortAudioDevice::testStateValidness(int sampleRate, int bufferSize) -{ - PaError paErr = paNoError; - - //get device info - const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID); - - //following parameters are needed opening test stream and for sample rates validation - PaStreamParameters inputParameters, outputParameters; - PaStreamParameters *pInS = NULL, *pOutS = NULL; - - inputParameters.device = m_DeviceID; - inputParameters.channelCount = pDeviceInfo->maxInputChannels; - inputParameters.sampleFormat = paFloat32 | paNonInterleaved; - inputParameters.suggestedLatency = 0; - inputParameters.hostApiSpecificStreamInfo = 0; - - if (inputParameters.channelCount) - pInS = &inputParameters; - - outputParameters.device = m_DeviceID; - outputParameters.channelCount = pDeviceInfo->maxOutputChannels; - outputParameters.sampleFormat = paFloat32; - outputParameters.suggestedLatency = 0; - outputParameters.hostApiSpecificStreamInfo = 0; - - if (outputParameters.channelCount) - pOutS = &outputParameters; - - PaStream *portAudioStream = NULL; - - //sometimes devices change buffer size if sample rate changes - //it updates buffer size during stream opening - //we need to find out how device would behave with current sample rate - //try opening test stream to load device driver for current sample rate and buffer size - paErr = Pa_OpenStream (&portAudioStream, pInS, pOutS, sampleRate, bufferSize, paDitherOff, NULL, NULL); - - if (portAudioStream) - { - // close test stream - Pa_CloseStream (portAudioStream); - portAudioStream = NULL; - } - - return paErr; -} - - -//********************************************************************************************** -// WCMRPortAudioDevice::CurrentSamplingRate -// -//! The device's current sampling rate. This may be overridden, if the device needs to -//! query the driver for the current rate. -//! -//! \param none -//! -//! \return The device's current sampling rate. -1 on error. -//! -//********************************************************************************************** -int WCMRPortAudioDevice::CurrentSamplingRate () -{ - AUTO_FUNC_DEBUG; - //ToDo: Perhaps for ASIO devices that are active, we should retrive the SR from the device... - - return (m_CurrentSamplingRate); -} - - -WTErr WCMRPortAudioDevice::SetActive (bool newState) -{ - if (newState == true) - { - std::cout << "API::Device " << m_DeviceName << " Activation requested" << std::endl; - SignalObjectAndWait(m_hActivateRequestedEvent, m_hActivationDone, INFINITE, false); - } - else - { - std::cout << "API::Device " << m_DeviceName << " Deactivation requested" << std::endl; - SignalObjectAndWait(m_hDeActivateRequestedEvent, m_hDeActivationDone, INFINITE, false); - } - - if (newState == Active() ) - return eNoErr; - else - return eGenericErr; -} - - -WTErr WCMRPortAudioDevice::SetStreaming (bool newState) -{ - if (newState == true) - { - std::cout << "API::Device " << m_DeviceName << " Stream start requested" << std::endl; - SignalObjectAndWait(m_hStartStreamingRequestedEvent, m_hStartStreamingDone, INFINITE, false); - } - else - { - std::cout << "API::Device " << m_DeviceName << " Stream stop requested" << std::endl; - SignalObjectAndWait(m_hStopStreamingRequestedEvent, m_hStopStreamingDone, INFINITE, false); - } - - if (newState == Streaming() ) - return eNoErr; - else - return eGenericErr; -} - - -WTErr WCMRPortAudioDevice::ResetDevice() -{ - std::cout << "API::Device: " << m_DeviceName << " Reseting device" << std::endl; - - SignalObjectAndWait(m_hResetRequestedEvent, m_hResetDone, INFINITE, false); - - if (ConnectionStatus() == DeviceErrors) - { - return m_lastErr; - } - - return eNoErr; -} - - -//********************************************************************************************** -// WCMRPortAudioDevice::SetCurrentSamplingRate -// -//! Change the sampling rate to be used by the device. -//! -//! \param newRate : The rate to use (samples per sec). -//! -//! \return eNoErr always. The derived classes may return error codes. -//! -//********************************************************************************************** -WTErr WCMRPortAudioDevice::SetCurrentSamplingRate (int newRate) -{ - AUTO_FUNC_DEBUG; - std::vector<int>::iterator intIter; - WTErr retVal = eNoErr; - - //changes the status. - int oldRate = CurrentSamplingRate(); - bool oldActive = Active(); - - //no change, nothing to do - if (oldRate == newRate) - return (retVal); - - //see if this is one of our supported rates... - intIter = find(m_SamplingRates.begin(), m_SamplingRates.end(), newRate); - - if (intIter == m_SamplingRates.end()) - { - //Can't change, perhaps use an "invalid param" type of error - retVal = eCommandLineParameter; - return (retVal); - } - - if (Streaming()) - { - //Can't change, perhaps use an "in use" type of error - retVal = eGenericErr; - return (retVal); - } - - //make the change... - m_CurrentSamplingRate = newRate; - PaError paErr = PaAsio_SetStreamSampleRate (m_PortAudioStream, m_CurrentSamplingRate); - Pa_Sleep(PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS); // sleep some time to make sure the change has place - - if (paErr != paNoError) - { - std::cout << "Sample rate change failed: " << Pa_GetErrorText (paErr) << std::endl; - if (paErr == paUnanticipatedHostError) - std::cout << "Details: "<< Pa_GetLastHostErrorInfo ()->errorText << "; code: " << Pa_GetLastHostErrorInfo ()->errorCode << std::endl; - - retVal = eWrongObjectState; - } - - return (retVal); -} - - -//********************************************************************************************** -// WCMRPortAudioDevice::CurrentBufferSize -// -//! The device's current buffer size in use. This may be overridden, if the device needs to -//! query the driver for the current size. -//! -//! \param none -//! -//! \return The device's current buffer size. 0 on error. -//! -//********************************************************************************************** -int WCMRPortAudioDevice::CurrentBufferSize () -{ - return m_CurrentBufferSize; -} - - -//********************************************************************************************** -// WCMRPortAudioDevice::SetCurrentBufferSize -// -//! Change the buffer size to be used by the device. This will most likely be overridden, -//! the base class simply updates the member variable. -//! -//! \param newSize : The buffer size to use (in sample-frames) -//! -//! \return eNoErr always. The derived classes may return error codes. -//! -//********************************************************************************************** -WTErr WCMRPortAudioDevice::SetCurrentBufferSize (int newSize) -{ - AUTO_FUNC_DEBUG; - WTErr retVal = eNoErr; - std::vector<int>::iterator intIter; - - if (Streaming()) - { - //Can't change, perhaps use an "in use" type of error - retVal = eGenericErr; - return (retVal); - } - - // Buffer size for ASIO devices can be changed from the control panel only - // We have driver driven logi here - if (m_CurrentBufferSize != newSize ) - { - // we have only one aloved buffer size which is preffered by PA - // this is the only value which could be set - newSize = m_BufferSizes[0]; - int bufferSize = newSize; - // notify client to update buffer size - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize); - return retVal; - } - - return (retVal); -} - - -//********************************************************************************************** -// WCMRPortAudioDevice::ConnectionStatus -// -//! Retrieves the device's current connection status. This will most likely be overridden, -//! in case some driver communication is required to query the status. -//! -//! \param none -//! -//! \return A ConnectionStates value. -//! -//********************************************************************************************** -WCMRPortAudioDevice::ConnectionStates WCMRPortAudioDevice::ConnectionStatus () -{ - AUTO_FUNC_DEBUG; - //ToDo: May want to do something more to extract the actual status! - return (m_ConnectionStatus); - -} - - -//********************************************************************************************** -// WCMRPortAudioDevice::activateDevice -// -//! IS CALLED BY PROCESS THREAD -//! Sets the device into "active" state. Essentially, opens the PA device. -//! If it's an ASIO device it may result in buffer size change in some cases. -//! -//********************************************************************************************** -void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/) -{ - AUTO_FUNC_DEBUG; - - PaError paErr = paNoError; - - // if device is not active activate it - if (!Active() ) - { - PaStreamParameters inputParameters, outputParameters; - PaStreamParameters *pInS = NULL, *pOutS = NULL; - - const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID); - const PaHostApiInfo *pHostApiInfo = Pa_GetHostApiInfo(pDeviceInfo->hostApi); - - inputParameters.device = m_DeviceID; - inputParameters.channelCount = (int)m_InputChannels.size(); - inputParameters.sampleFormat = paFloat32 | paNonInterleaved; - inputParameters.suggestedLatency = Pa_GetDeviceInfo(m_DeviceID)->defaultLowInputLatency; - inputParameters.hostApiSpecificStreamInfo = 0; - - if (inputParameters.channelCount) - pInS = &inputParameters; - - outputParameters.device = m_DeviceID; - outputParameters.channelCount = (int)m_OutputChannels.size(); - outputParameters.sampleFormat = paFloat32; - outputParameters.suggestedLatency = Pa_GetDeviceInfo(m_DeviceID)->defaultLowOutputLatency; - outputParameters.hostApiSpecificStreamInfo = 0; - - if (outputParameters.channelCount) - pOutS = &outputParameters; - - std::cout << "API::Device " << m_DeviceName << " Opening device stream " << std::endl; - std::cout << "Sample rate: " << m_CurrentSamplingRate << " buffer size: " << m_CurrentBufferSize << std::endl; - paErr = Pa_OpenStream(&m_PortAudioStream, - pInS, - pOutS, - m_CurrentSamplingRate, - m_CurrentBufferSize, - paDitherOff, - WCMRPortAudioDevice::TheCallback, - this); - - if(paErr != paNoError) - { - std::cout << "Cannot open streamm with buffer: "<< m_CurrentBufferSize << " Error: " << Pa_GetErrorText (paErr) << std::endl; - - if (paErr == paUnanticipatedHostError) - std::cout << "Error details: "<< Pa_GetLastHostErrorInfo ()->errorText << "; code: " << Pa_GetLastHostErrorInfo ()->errorCode << std::endl; - } - - if(paErr == paNoError) - { - std::cout << "Stream has been opened! "<< std::endl; - - // check for possible changes - long minSize, maxSize, preferredSize, granularity; - PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity); - - std::cout << "Checked if buffer size changed "<< std::endl; - if (paErr == paNoError && m_CurrentBufferSize != preferredSize) - { - std::cout << "Buffer size has changed "<< std::endl; - m_CurrentBufferSize = preferredSize; - m_BufferSizes.clear(); - m_BufferSizes.push_back(preferredSize); - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&preferredSize); - } - - m_DropsDetected = 0; - m_DropsReported = 0; - m_IgnoreThisDrop = true; - - if (pHostApiInfo->type == paASIO) - { - m_BufferSizeChangeRequested = 0; - m_BufferSizeChangeReported = 0; - m_ResetRequested = 0; - m_ResetReported = 0; - m_ResyncRequested = 0; - m_ResyncReported = 0; - std::cout << "Installing new mesage hook "<< std::endl; - PaAsio_SetMessageHook (StaticASIOMessageHook, this); - } - m_IsActive = true; - m_ConnectionStatus = DeviceAvailable; - m_lastErr = eNoErr; - } - else - { - //failed, do not update device state - std::cout << "Failed to open pa stream: " << Pa_GetErrorText (paErr) << std::endl; - DEBUG_MSG( "Failed to open pa stream: " << Pa_GetErrorText (paErr) ); - m_ConnectionStatus = DeviceErrors; - m_lastErr = eAsioFailed; - } - - - } - - std::cout << "Activation is DONE "<< std::endl; - - if (callerIsWaiting) - SetEvent(m_hActivationDone); -} - - -//********************************************************************************************** -// WCMRPortAudioDevice::deactivateDevice -// -//! IS CALLED BY PROCESS THREAD -//! Sets the device into "inactive" state. Essentially, closes the PA device. -//! -//********************************************************************************************** -void WCMRPortAudioDevice::deactivateDevice (bool callerIsWaiting/*=false*/) -{ - AUTO_FUNC_DEBUG; - - PaError paErr = paNoError; - - if (Active() ) - { - if (Streaming()) - { - stopStreaming (); - } - - if (m_PortAudioStream) - { - //close the stream first - std::cout << "API::Device" << m_DeviceName << " Closing device stream" << std::endl; - paErr = Pa_CloseStream (m_PortAudioStream); - if(paErr == paNoError) - { - m_PortAudioStream = NULL; - m_DropsDetected = 0; - m_DropsReported = 0; - m_IgnoreThisDrop = true; - m_BufferSizeChangeRequested = 0; - m_BufferSizeChangeReported = 0; - m_ResetRequested = 0; - m_ResetReported = 0; - m_ResyncRequested = 0; - m_ResyncReported = 0; - PaAsio_SetMessageHook (NULL, NULL); - - //finaly set device state to "not active" - m_IsActive = false; - m_ConnectionStatus = DeviceDisconnected; - m_lastErr = eNoErr; - } - else - { - //failed, do not update device state - std::cout << "Failed to close pa stream stream " << Pa_GetErrorText (paErr) << std::endl; - DEBUG_MSG( "Failed to open pa stream stream " << Pa_GetErrorText (paErr) ); - m_ConnectionStatus = DeviceErrors; - m_lastErr = eAsioFailed; - } - } - } - - if (callerIsWaiting) - SetEvent(m_hDeActivationDone); -} - - -//********************************************************************************************** -// WCMRPortAudioDevice::startStreaming -// -//! Sets the devices into "streaming" state. Calls PA's Start stream routines. -//! This roughly corresponds to calling Start on the lower level interface. -//! -//********************************************************************************************** -void WCMRPortAudioDevice::startStreaming (bool callerIsWaiting/*=false*/) -{ - AUTO_FUNC_DEBUG; - - // proceed if the device is not streaming - if (!Streaming () ) - { - PaError paErr = paNoError; - m_StopRequested = false; - m_SampleCounter = 0; - - std::cout << "API::Device" << m_DeviceName << " Starting device stream" << std::endl; - - //get device info - const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID); - - unsigned int inChannelCount = pDeviceInfo->maxInputChannels; - unsigned int outChannelCount = pDeviceInfo->maxOutputChannels; - - // Prepare for streaming - tell Engine to do the initialization for process callback - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStartsStreaming); - - paErr = Pa_StartStream( m_PortAudioStream ); - - if(paErr == paNoError) - { - // if the stream was started successfully - m_IsStreaming = true; - std::cout << "API::Device" << m_DeviceName << " Device is streaming" << std::endl; - } - else - { - std::cout << "Failed to start PA stream: " << Pa_GetErrorText (paErr) << std::endl; - DEBUG_MSG( "Failed to start PA stream: " << Pa_GetErrorText (paErr) ); - m_lastErr = eGenericErr; - } - } - - if (callerIsWaiting) - SetEvent(m_hStartStreamingDone); -} - - -//********************************************************************************************** -// WCMRPortAudioDevice::stopStreaming -// -//! Sets the devices into "not streaming" state. Calls PA's Stop stream routines. -//! This roughly corresponds to calling Stop on the lower level interface. -//! -//********************************************************************************************** -void WCMRPortAudioDevice::stopStreaming (bool callerIsWaiting/*=false*/) -{ - AUTO_FUNC_DEBUG; - - // proceed if the device is streaming - if (Streaming () ) - { - PaError paErr = paNoError; - m_StopRequested = true; - - std::cout << "API::Device " << m_DeviceName << " Stopping device stream" << std::endl; - paErr = Pa_StopStream( m_PortAudioStream ); - - if(paErr == paNoError || paErr == paStreamIsStopped) - { - // if the stream was stopped successfully - m_IsStreaming = false; - m_pInputData = NULL; - } - else - { - std::cout << "Failed to stop PA stream normaly! Error:" << Pa_GetErrorText (paErr) << std::endl; - DEBUG_MSG( "Failed to stop PA stream normaly! Error:" << Pa_GetErrorText (paErr) ); - m_lastErr = eGenericErr; - } - } - - if (callerIsWaiting) - SetEvent(m_hStopStreamingDone); -} - - -//********************************************************************************************** -// WCMRPortAudioDevice::resetDevice -// -//! Resets the device, updates device info. Importnat: does PA reinitialization calling -//! Pa_terminate/Pa_initialize functions. -//! -//! \param none -//! -//! \return nothing -//! -//********************************************************************************************** -void WCMRPortAudioDevice::resetDevice (bool callerIsWaiting /*=false*/ ) -{ - PaError paErr = paNoError; - - // Keep device sates - bool wasStreaming = Streaming(); - bool wasActive = Active(); - - // Reset the device - stopStreaming(); - deactivateDevice(); - - // Cache device buffer size as it might be changed during reset - int oldBufferSize = m_CurrentBufferSize; - - // Now, validate the state and update device info if required - unsigned int retry = PROPERTY_CHANGE_RETRIES; - while (retry-- ) - { - // Reinitialize PA - Pa_Terminate(); - Pa_Initialize(); - - std::cout << "Updating device state... " << std::endl; - // update device info - updateDeviceInfo(); - - // take up buffers - long minSize, maxSize, preferredSize, granularity; - PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity); - - if (paErr != paNoError) - { - continue; - } - m_CurrentBufferSize = preferredSize; - - paErr = testStateValidness(m_CurrentSamplingRate, m_CurrentBufferSize); - if (paNoError == paErr) - { - std::cout << "Device state is valid" << std::endl; - break; - } - - std::cout << "Cannot start with current state: sr: " << m_CurrentSamplingRate << " bs:" << m_CurrentBufferSize \ - << "\nReason: " << Pa_GetErrorText (paErr) << std::endl; - if (paErr == paUnanticipatedHostError) - std::cout << "Details: "<< Pa_GetLastHostErrorInfo ()->errorText << "; code: " << Pa_GetLastHostErrorInfo ()->errorCode << std::endl; - - std::cout << "Will try again in " << DEVICE_INFO_UPDATE_SLEEP_TIME_MILLISECONDS << "msec" << std::endl; - - Pa_Sleep(DEVICE_INFO_UPDATE_SLEEP_TIME_MILLISECONDS); - } - - if (paErr == paNoError) - { - // Notify the Application about device setting changes - if (oldBufferSize != m_CurrentBufferSize) - { - std::cout << "API::Device" << m_DeviceName << " buffer size changed" << std::endl; - int bufferSize = m_CurrentBufferSize; - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize); - } - - // Activate the device if it was active before - if (wasActive) - activateDevice(); - - // Resume streaming if the device was streaming before - if(wasStreaming && m_lastErr == eNoErr && m_ConnectionStatus == DeviceAvailable) - { - // start streaming - startStreaming(); - } - } else { - m_ConnectionStatus = DeviceErrors; - m_lastErr = eWrongObjectState; - } - - if (callerIsWaiting) - SetEvent(m_hResetDone); -} - - -#ifdef PLATFORM_WINDOWS - -long WCMRPortAudioDevice::StaticASIOMessageHook (void *pRefCon, long selector, long value, void* message, double* opt) -{ - if (pRefCon) - { - return ((WCMRPortAudioDevice*)(pRefCon))->ASIOMessageHook (selector, value, message, opt); - } - else - return -1; -} - -long WCMRPortAudioDevice::ASIOMessageHook (long selector, long WCUNUSEDPARAM(value), void* WCUNUSEDPARAM(message), double* WCUNUSEDPARAM(opt)) -{ - switch(selector) - { - case kAsioResyncRequest: - m_ResyncRequested++; - std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioResyncRequest" << std::endl; - break; - - case kAsioLatenciesChanged: - m_BufferSizeChangeRequested++; - std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioLatenciesChanged" << std::endl; - if (m_ResetRequested == 0) { - m_ResetRequested++; - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset); - } - break; - - case kAsioBufferSizeChange: - m_BufferSizeChangeRequested++; - std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- m_BufferSizeChangeRequested" << std::endl; - if (m_ResetRequested == 0) { - m_ResetRequested++; - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset); - } - break; - - case kAsioResetRequest: - std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioResetRequest" << std::endl; - m_ResetRequested++; - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset); - break; - - case kAsioOverload: - m_DropsDetected++; - std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioOverload" << std::endl; - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::Dropout); - break; - } - return 0; -} - -#endif - - -//********************************************************************************************** -// WCMRPortAudioDevice::DoIdle -// -//! A place for doing idle time processing. The other derived classes will probably do something -//! meaningful. -//! -//! \param none -//! -//! \return eNoErr always. -//! -//********************************************************************************************** -WTErr WCMRPortAudioDevice::DoIdle () -{ - WTErr retVal = eNoErr; - - std::cout << "WCMRPortAudioDevice::DoIdle ()" << std::endl; - HANDLE hEvents[] = - { - m_hUpdateDeviceInfoRequestedEvent, - m_hActivateRequestedEvent, - m_hDeActivateRequestedEvent, - m_hStartStreamingRequestedEvent, - m_hStopStreamingRequestedEvent, - m_hBufferSizeChangedEvent, - m_hSampleRateChangedEvent, - m_hResetRequestedEvent, - m_hResetFromDevRequestedEvent, - m_hExitIdleThread - }; - - const size_t hEventsSize = sizeof(hEvents)/sizeof(hEvents[0]); - - initDevice(); - - for(;;) - { - DWORD result = WaitForMultipleObjects (hEventsSize, hEvents, FALSE, INFINITE); - result = result - WAIT_OBJECT_0; - - if ((result < 0) || (result >= hEventsSize)) { - std::cout << "\t\t\t\t\t\t\tWCMRPortAudioDevice::DoIdle () -> (result < 0) || (result >= hEventsSize):" << result << std::endl; - retVal = eGenericErr; - break; - } - - if (hEvents[result] == m_hExitIdleThread) { - std::cout << "\t\t\t\t\t\t\tWCMRPortAudioDevice::DoIdle () -> m_hExitIdleThread" << result << std::endl; - retVal = eNoErr; - break; - } - - if (hEvents[result] == m_hUpdateDeviceInfoRequestedEvent) { - std::cout << "\t\t\t\t\t\tupdate requested ..." << std::endl; - updateDeviceInfo(true); - } - - if (hEvents[result] == m_hActivateRequestedEvent) { - std::cout << "\t\t\t\t\t\tactivation requested ..." << std::endl; - activateDevice(true); - } - - if (hEvents[result] == m_hDeActivateRequestedEvent) { - std::cout << "\t\t\t\t\t\tdeactivation requested ..." << std::endl; - deactivateDevice(true); - } - - if (hEvents[result] == m_hStartStreamingRequestedEvent) { - std::cout << "\t\t\t\t\t\tStart stream requested ..." << std::endl; - startStreaming(true); - } - - if (hEvents[result] == m_hStopStreamingRequestedEvent) { - std::cout << "\t\t\t\t\t\tStop stream requested ..." << std::endl; - stopStreaming(true); - } - - if (hEvents[result] == m_hResetRequestedEvent) { - std::cout << "\t\t\t\t\t\treset requested ..." << std::endl; - resetDevice(true); - } - - if (hEvents[result] == m_hResetFromDevRequestedEvent) { - std::cout << "\t\t\t\t\t\treset requested from device..." << std::endl; - resetDevice(); - } - - if (hEvents[result] == m_hBufferSizeChangedEvent) { - std::cout << "\t\t\t\t\t\tbuffer size changed from device..." << std::endl; - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged); - } - - if (hEvents[result] == m_hSampleRateChangedEvent) { - std::cout << "\t\t\t\t\t\tsample rate changed from device..." << std::endl; - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::SamplingRateChanged); - } - } - - terminateDevice(); - - return retVal; -} - - -//********************************************************************************************** -// WCMRPortAudioDevice::SetMonitorChannels -// -//! Used to set the channels to be used for monitoring. -//! -//! \param leftChannel : Left monitor channel index. -//! \param rightChannel : Right monitor channel index. -//! -//! \return eNoErr always, the derived classes may return appropriate errors. -//! -//********************************************************************************************** -WTErr WCMRPortAudioDevice::SetMonitorChannels (int leftChannel, int rightChannel) -{ - AUTO_FUNC_DEBUG; - //This will most likely be overridden, the base class simply - //changes the member. - m_LeftMonitorChannel = leftChannel; - m_RightMonitorChannel = rightChannel; - return (eNoErr); -} - - - -//********************************************************************************************** -// WCMRPortAudioDevice::SetMonitorGain -// -//! Used to set monitor gain (or atten). -//! -//! \param newGain : The new gain or atten. value to use. Specified as a linear multiplier (not dB) -//! -//! \return eNoErr always, the derived classes may return appropriate errors. -//! -//********************************************************************************************** -WTErr WCMRPortAudioDevice::SetMonitorGain (float newGain) -{ - AUTO_FUNC_DEBUG; - //This will most likely be overridden, the base class simply - //changes the member. - - m_MonitorGain = newGain; - return (eNoErr); -} - - - - -//********************************************************************************************** -// WCMRPortAudioDevice::ShowConfigPanel -// -//! Used to show device specific config/control panel. Some interfaces may not support it. -//! Some interfaces may require the device to be active before it can display a panel. -//! -//! \param pParam : A device/interface specific parameter, should be the app window handle for ASIO. -//! -//! \return eNoErr always, the derived classes may return errors. -//! -//********************************************************************************************** -WTErr WCMRPortAudioDevice::ShowConfigPanel (void *pParam) -{ - AUTO_FUNC_DEBUG; - WTErr retVal = eNoErr; - - if (Active() && !m_ResetRequested ) - { -#ifdef PLATFORM_WINDOWS - if(Pa_GetHostApiInfo(Pa_GetDeviceInfo(m_DeviceID)->hostApi)->type == paASIO) - { - // stop and deactivate the device - bool wasStreaming = Streaming(); - SetActive(false); - - // show control panel for the device - if (PaAsio_ShowControlPanel (m_DeviceID, pParam) != paNoError) - retVal = eGenericErr; - - // restore previous state for the device - SetActive(true); - if (wasStreaming) - SetStreaming(true); - - - // reset device to pick up changes - if (!m_ResetRequested) { - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset); - } - } -#else - pParam = pParam; -#endif //_windows - } - - return (retVal); -} - - -//***************************************************************************************************** -// WCMRPortAudioDevice::TheCallback -// -//! The (static) Port Audio Callback function. This is a static member. It calls on the AudioCallback in the -//! WCMRPortAudioDevice to do the real work. -//! -//! \param pInputBuffer: pointer to input buffer. -//! \param pOutputBuffer: pointer to output buffer. -//! \param framesPerBuffer: number of sample frames per buffer. -//! \param pTimeInfo: time info for PaStream callback. -//! \param statusFlags: -//! \param pUserData: pointer to user data, in our case the WCMRPortAudioDevice object. -//! -//! \return true to stop streaming else returns false. -//****************************************************************************************************** -int WCMRPortAudioDevice::TheCallback (const void *pInputBuffer, void *pOutputBuffer, unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo* /*pTimeInfo*/, PaStreamCallbackFlags statusFlags, void *pUserData ) -{ - WCMRPortAudioDevice *pMyDevice = (WCMRPortAudioDevice *)pUserData; - if (pMyDevice) - return pMyDevice->AudioCallback ((float *)pInputBuffer, (float *)pOutputBuffer, framesPerBuffer, - (statusFlags & (paInputOverflow | paOutputUnderflow)) != 0); - else - return (true); - -} - - - -//********************************************************************************************** -// WCMRPortAudioDevice::AudoiCallback -// -//! Here's where the actual audio processing happens. We call upon all the active connections' -//! sinks to provide data to us which can be put/mixed in the output buffer! Also, we make the -//! input data available to any sources that may call upon us during this time! -//! -//! \param *pInputBuffer : Points to a buffer with recorded data. -//! \param *pOutputBuffer : Points to a buffer to receive playback data. -//! \param framesPerBuffer : Number of sample frames in input and output buffers. Number of channels, -//! which are interleaved, is fixed at Device Open (Active) time. In this implementation, -//! the number of channels are fixed to use the maximum available. -//! \param dropsDetected : True if dropouts were detected in input or output. Can be used to signal the GUI. -//! -//! \return true -//! -//********************************************************************************************** -int WCMRPortAudioDevice::AudioCallback( const float *pInputBuffer, float *pOutputBuffer, unsigned long framesPerBuffer, bool dropsDetected ) -{ - UMicroseconds theStartTime; - - // detect drops - if (dropsDetected) - { - if (m_IgnoreThisDrop) - m_IgnoreThisDrop = false; //We'll ignore once, just once! - else - m_DropsDetected++; - } - - m_pInputData = pInputBuffer; - - // VKamyshniy: Is this a right place to call the client???: - struct WCMRAudioDeviceManagerClient::AudioCallbackData audioCallbackData = - { - m_pInputData, - pOutputBuffer, - framesPerBuffer, - m_SampleCounter, - theStartTime.MicroSeconds()*1000 - }; - - m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::AudioCallback, (void *)&audioCallbackData ); - - //Don't try to access after this call returns! - m_pInputData = NULL; - - m_SampleCounter += framesPerBuffer; - - return m_StopRequested; -} - - - - -//********************************************************************************************** -// WCMRPortAudioDeviceManager::WCMRPortAudioDeviceManager -// -//! The constructuor, we initialize PA, and build the device list. -//! -//! \param *pTheClient : The manager's client object (which receives notifications). -//! \param interfaceType : The PortAudio interface type to use for this manager - acts as a filter. -//! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true. -//! -//! \return Nothing. -//! -//********************************************************************************************** -WCMRPortAudioDeviceManager::WCMRPortAudioDeviceManager (WCMRAudioDeviceManagerClient *pTheClient, - eAudioDeviceFilter eCurAudioDeviceFilter, bool useMultithreading, bool bNocopy) - : WCMRAudioDeviceManager (pTheClient, eCurAudioDeviceFilter) - , m_NoneDevice(0) - , m_UseMultithreading(useMultithreading) - , m_bNoCopyAudioBuffer(bNocopy) -{ - AUTO_FUNC_DEBUG; - std::cout << "API::PortAudioDeviceManager::PA Device manager constructor" << std::endl; - - //Always create the None device first... - m_NoneDevice = new WCMRNativeAudioNoneDevice(this); - - WTErr err = generateDeviceListImpl(); - - if (eNoErr != err) - throw err; - - timeBeginPeriod (1); -} - - -//********************************************************************************************** -// WCMRPortAudioDeviceManager::~WCMRPortAudioDeviceManager -// -//! It clears the device list, releasing each of the device. -//! -//! \param none -//! -//! \return Nothing. -//! -//********************************************************************************************** -WCMRPortAudioDeviceManager::~WCMRPortAudioDeviceManager() -{ - AUTO_FUNC_DEBUG; - - std::cout << "API::Destroying PortAudioDeviceManager " << std::endl; - - try - { - delete m_NoneDevice; - } - catch (...) - { - //destructors should absorb exceptions, no harm in logging though!! - DEBUG_MSG ("Exception during destructor"); - } - - timeEndPeriod (1); -} - - -WCMRAudioDevice* WCMRPortAudioDeviceManager::initNewCurrentDeviceImpl(const std::string & deviceName) -{ - destroyCurrentDeviceImpl(); - - std::cout << "API::PortAudioDeviceManager::initNewCurrentDevice " << deviceName << std::endl; - if (deviceName == m_NoneDevice->DeviceName() ) - { - m_CurrentDevice = m_NoneDevice; - return m_CurrentDevice; - } - - DeviceInfo devInfo; - WTErr err = GetDeviceInfoByName(deviceName, devInfo); - - if (eNoErr == err) - { - try - { - std::cout << "API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName << std::endl; - TRACE_MSG ("API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName); - - m_CurrentDevice = new WCMRPortAudioDevice (this, devInfo.m_DeviceId, m_UseMultithreading, m_bNoCopyAudioBuffer); - } - catch (...) - { - std::cout << "Unabled to create PA Device: " << devInfo.m_DeviceId << std::endl; - DEBUG_MSG ("Unabled to create PA Device: " << devInfo.m_DeviceId); - } - } - - return m_CurrentDevice; -} - - -void WCMRPortAudioDeviceManager::destroyCurrentDeviceImpl() -{ - if (m_CurrentDevice != m_NoneDevice) - delete m_CurrentDevice; - - m_CurrentDevice = 0; -} - - -WTErr WCMRPortAudioDeviceManager::getDeviceAvailableSampleRates(DeviceID deviceId, std::vector<int>& sampleRates) -{ - WTErr retVal = eNoErr; - - sampleRates.clear(); - const PaDeviceInfo *pPaDeviceInfo = Pa_GetDeviceInfo(deviceId); - - //now find supported sample rates - //following parameters are needed for sample rates validation - PaStreamParameters inputParameters, outputParameters; - PaStreamParameters *pInS = NULL, *pOutS = NULL; - - inputParameters.device = deviceId; - inputParameters.channelCount = std::min<int>(2, pPaDeviceInfo->maxInputChannels); - inputParameters.sampleFormat = paFloat32 | paNonInterleaved; - inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ - inputParameters.hostApiSpecificStreamInfo = 0; - - if (inputParameters.channelCount) - pInS = &inputParameters; - - outputParameters.device = deviceId; - outputParameters.channelCount = std::min<int>(2, pPaDeviceInfo->maxOutputChannels); - outputParameters.sampleFormat = paFloat32; - outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ - outputParameters.hostApiSpecificStreamInfo = 0; - - if (outputParameters.channelCount) - pOutS = &outputParameters; - - for(int sr=0; gAllSampleRates[sr] > 0; sr++) - { - if( paFormatIsSupported == Pa_IsFormatSupported(pInS, pOutS, gAllSampleRates[sr]) ) - { - sampleRates.push_back ((int)gAllSampleRates[sr]); - } - } - - return retVal; -} - - -WTErr WCMRPortAudioDeviceManager::getDeviceAvailableBufferSizes(DeviceID deviceId, std::vector<int>& buffers) -{ - WTErr retVal = eNoErr; - - buffers.clear(); - - //make PA request to get actual device buffer sizes - long minSize, maxSize, preferredSize, granularity; - - PaError paErr = PaAsio_GetAvailableBufferSizes(deviceId, &minSize, &maxSize, &preferredSize, &granularity); - - //for Windows ASIO devices we always use prefferes buffer size ONLY - if (paNoError == paErr ) - { - buffers.push_back(preferredSize); - } - else - { - retVal = eAsioFailed; - std::cout << "API::PortAudioDeviceManager::GetBufferSizes: error: " << Pa_GetErrorText (paErr) << " getting buffer sizes for device: "<< deviceId << std::endl; - } - - return retVal; -} - - -WTErr WCMRPortAudioDeviceManager::generateDeviceListImpl() -{ - std::cout << "API::PortAudioDeviceManager::Generating device list" << std::endl; - - WTErr retVal = eNoErr; - - //Initialize PortAudio and ASIO first - PaError paErr = Pa_Initialize(); - - if (paErr != paNoError) - { - //ToDo: throw an exception here! - retVal = eSomeThingNotInitailzed; - return retVal; - } - - // lock DeviceInfoVec firts - wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex); - - if (m_NoneDevice) - { - DeviceInfo *pDevInfo = new DeviceInfo(NONE_DEVICE_ID, m_NoneDevice->DeviceName() ); - pDevInfo->m_AvailableSampleRates = m_NoneDevice->SamplingRates(); - m_DeviceInfoVec.push_back(pDevInfo); - } - - //Get device count... - int numDevices = Pa_GetDeviceCount(); - - //for each device, - for (int thisDeviceID = 0; thisDeviceID < numDevices; thisDeviceID++) - { - //if it's of the required type... - const PaDeviceInfo *pPaDeviceInfo = Pa_GetDeviceInfo(thisDeviceID); - - if (Pa_GetHostApiInfo(pPaDeviceInfo->hostApi)->type == paASIO) - { - //build a device object... - try - { - std::cout << "API::PortAudioDeviceManager::DeviceID: " << thisDeviceID << ", Device Name: " << pPaDeviceInfo->name << std::endl; - TRACE_MSG ("PA DeviceID: " << thisDeviceID << ", Device Name: " << pPaDeviceInfo->name); - - DeviceInfo *pDevInfo = new DeviceInfo(thisDeviceID, pPaDeviceInfo->name); - if (pDevInfo) - { - //Get available sample rates - std::vector<int> availableSampleRates; - WTErr wErr = WCMRPortAudioDeviceManager::getDeviceAvailableSampleRates(thisDeviceID, availableSampleRates); - - if (wErr != eNoErr) - { - DEBUG_MSG ("Failed to get device available sample rates. Device ID: " << m_DeviceID); - delete pDevInfo; - continue; //proceed to the next device - } - - pDevInfo->m_AvailableSampleRates = availableSampleRates; - pDevInfo->m_MaxInputChannels = pPaDeviceInfo->maxInputChannels; - pDevInfo->m_MaxOutputChannels = pPaDeviceInfo->maxOutputChannels; - - //Get available buffer sizes - std::vector<int> availableBuffers; - wErr = getDeviceAvailableBufferSizes(thisDeviceID, availableBuffers); - - if (wErr != eNoErr) - { - DEBUG_MSG ("Failed to get device available buffer sizes. Device ID: " << m_DeviceID); - delete pDevInfo; - continue; //proceed to the next device - } - - pDevInfo->m_AvailableBufferSizes = availableBuffers; - - //Now check if this device is acceptable according to current input/output settings - bool bRejectDevice = false; - switch(m_eAudioDeviceFilter) - { - case eInputOnlyDevices: - if (pDevInfo->m_MaxInputChannels != 0) - { - m_DeviceInfoVec.push_back(pDevInfo); - } - else - { - // Delete unnecesarry device - bRejectDevice = true; - } - break; - case eOutputOnlyDevices: - if (pDevInfo->m_MaxOutputChannels != 0) - { - m_DeviceInfoVec.push_back(pDevInfo); - } - else - { - // Delete unnecesarry device - bRejectDevice = true; - } - break; - case eFullDuplexDevices: - if (pDevInfo->m_MaxInputChannels != 0 && pDevInfo->m_MaxOutputChannels != 0) - { - m_DeviceInfoVec.push_back(pDevInfo); - } - else - { - // Delete unnecesarry device - bRejectDevice = true; - } - break; - case eAllDevices: - default: - m_DeviceInfoVec.push_back(pDevInfo); - break; - } - - if(bRejectDevice) - { - TRACE_MSG ("API::PortAudioDeviceManager::Device " << pDevInfo->m_DeviceName << "Rejected. \ - In Channels = " << pDevInfo->m_MaxInputChannels << "Out Channels = " <<pDevInfo->m_MaxOutputChannels ); - delete pDevInfo; - } - } - } - catch (...) - { - std::cout << "API::PortAudioDeviceManager::Unabled to create PA Device: " << std::endl; - DEBUG_MSG ("Unabled to create PA Device: " << thisDeviceID); - } - } - } - - //If no devices were found, that's not a good thing! - if (m_DeviceInfoVec.empty() ) - { - std::cout << "API::PortAudioDeviceManager::No matching PortAudio devices were found, total PA devices = " << numDevices << std::endl; - DEBUG_MSG ("No matching PortAudio devices were found, total PA devices = " << numDevices); - } - - //we don't need PA initialized right now - Pa_Terminate(); - - return retVal; -} - - -WTErr WCMRPortAudioDeviceManager::getDeviceSampleRatesImpl(const std::string & deviceName, std::vector<int>& sampleRates) const -{ - sampleRates.clear (); - - WTErr retVal = eNoErr; - - if (m_CurrentDevice && deviceName == m_CurrentDevice->DeviceName() ) - { - sampleRates=m_CurrentDevice->SamplingRates(); - return retVal; - } - - DeviceInfo devInfo; - retVal = GetDeviceInfoByName(deviceName, devInfo); - - if (eNoErr == retVal) - { - sampleRates=devInfo.m_AvailableSampleRates; - } - else - { - std::cout << "API::PortAudioDeviceManager::GetSampleRates: Device not found: "<< deviceName << std::endl; - } - - return retVal; -} - - -WTErr WCMRPortAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& buffers) const -{ - WTErr retVal = eNoErr; - - buffers.clear(); - - //first check if the request has been made for None device - if (deviceName == m_NoneDevice->DeviceName() ) - { - buffers=m_NoneDevice->BufferSizes(); - return retVal; - } - - if (m_CurrentDevice && deviceName == m_CurrentDevice->DeviceName() ) - { - buffers=m_CurrentDevice->BufferSizes(); - return retVal; - } - - DeviceInfo devInfo; - retVal = GetDeviceInfoByName(deviceName, devInfo); - - if (eNoErr == retVal) - { - std::cout << "API::PortAudioDeviceManager::GetBufferSizes: got buffer :"<< devInfo.m_AvailableBufferSizes.front() << std::endl; - buffers = devInfo.m_AvailableBufferSizes; - } - else - { - std::cout << "API::PortAudioDeviceManager::GetBufferSizes: Device not found: "<< deviceName << std::endl; - } - - return retVal; -} diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.h b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.h deleted file mode 100644 index c028d09511..0000000000 --- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - Copyright (C) 2014 Waves Audio Ltd. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -//---------------------------------------------------------------------------------- -// -// -//! \file WCMRPortAudioDeviceManager.h -//! -//! WCMRPortAudioDeviceManager and related class declarations -//! -//---------------------------------------------------------------------------------*/ -#ifndef __WCMRPortAudioDeviceManager_h_ - #define __WCMRPortAudioDeviceManager_h_ - -#include "WCMRAudioDeviceManager.h" -#include "WCMRNativeAudio.h" -#include "portaudio.h" - -//forward decl. -class WCMRPortAudioDeviceManager; - -//! Manages a port audio device, providing information -//! about the device, and managing audio callbacks. -class WCMRPortAudioDevice : public WCMRNativeAudioDevice -{ -public: - - WCMRPortAudioDevice (WCMRPortAudioDeviceManager *pManager, unsigned int deviceID, bool useMultiThreading = true, bool bNoCopy = false);///<Constructor - virtual ~WCMRPortAudioDevice ();///<Destructor - - virtual int CurrentSamplingRate(); ///<Current Sampling rate.? - virtual WTErr SetCurrentSamplingRate(int newRate);///<Change Current Sampling Rate : This is a requset, might not be successful at run time! - - virtual int CurrentBufferSize();///<Current Buffer Size.? - note that this may change with change in sampling rate. - virtual WTErr SetCurrentBufferSize (int newSize);///<Change Current Buffer Size : This is a requset, might not be successful at run time! - - virtual ConnectionStates ConnectionStatus();///< Connection Status - device available, gone, disconnected - - virtual WTErr SetActive (bool newState);///<Prepare/Activate device. - - virtual WTErr SetStreaming (bool newState);///<Start/Stop Streaming - should reconnect connections when streaming starts! - - virtual WTErr SetMonitorChannels (int leftChannel, int rightChannel);///<Set monitor channels. - optional, will not be available with AG - virtual WTErr SetMonitorGain (float newGain);///<Set monitor gain. - optional, will not be available with AG - - virtual WTErr ShowConfigPanel (void *pParam);///< Show Control Panel - in case of ASIO this will work only with Active device! - - virtual int AudioCallback (const float *pInputBuffer, float *pOutputBuffer, unsigned long framesPerBuffe, bool dropsDetectedr); - - virtual WTErr UpdateDeviceInfo (); - - virtual WTErr ResetDevice(); - -#ifdef PLATFORM_WINDOWS - static long StaticASIOMessageHook (void *pRefCon, long selector, long value, void* message, double* opt); - long ASIOMessageHook (long selector, long value, void* message, double* opt); -#endif //PLATFORM_WINDOWS - -protected: - static DWORD WINAPI __DoIdle__(LPVOID lpThreadParameter); - - // Methods which are executed by device processing thread - WTErr DoIdle();///<Do Idle Processing - void initDevice(); - void terminateDevice(); - void updateDeviceInfo(bool callerIsWaiting = false); - void activateDevice(bool callerIsWaiting = false); - void deactivateDevice(bool callerIsWaiting = false); - void startStreaming(bool callerIsWaiting = false); - void stopStreaming(bool callerIsWaiting = false); - void resetDevice (bool callerIsWaiting = false);///<Reset device - close and reopen stream, update device information! - - PaError testStateValidness(int sampleRate, int bufferSize); - /////////////////////////////////////////////////////////// - - static int TheCallback (const void *pInputBuffer, void *pOutputBuffer, unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo* /*pTimeInfo*/, PaStreamCallbackFlags /*statusFlags*/, void *pUserData ); - - unsigned int m_DeviceID; ///< The PA device id - PaStream* m_PortAudioStream; ///< Port audio stream, when the device is active! - bool m_StopRequested; ///< should be set to true when want to stop, set to false otherwise. - const float *m_pInputData; ///< This is what came in with the most recent callback. - int64_t m_SampleCounter; ///< The current running sample counter, updated by the audio callback. - int64_t m_SampleCountAtLastIdle; - - int m_DropsDetected; ///< Number of times audio drops have been detected so far. - int m_DropsReported; ///< Number of times audio drops have been reported so far to the client. - bool m_IgnoreThisDrop; ///< Allows disregarding the first drop - - int m_BufferSizeChangeRequested; - int m_BufferSizeChangeReported; - int m_ResetRequested; - int m_ResetReported; - int m_ResyncRequested; - int m_ResyncReported; - - HANDLE m_hDeviceProcessingThread; - DWORD m_DeviceProcessingThreadID; - - ///< Backend request events - HANDLE m_hResetRequestedEvent; - HANDLE m_hResetDone; - - HANDLE m_hUpdateDeviceInfoRequestedEvent; - HANDLE m_hUpdateDeviceInfoDone; - - HANDLE m_hActivateRequestedEvent; - HANDLE m_hActivationDone; - - HANDLE m_hDeActivateRequestedEvent; - HANDLE m_hDeActivationDone; - - HANDLE m_hStartStreamingRequestedEvent; - HANDLE m_hStartStreamingDone; - - HANDLE m_hStopStreamingRequestedEvent; - HANDLE m_hStopStreamingDone; - ///////////////////////// - - ///< Device request events - HANDLE m_hResetFromDevRequestedEvent; - HANDLE m_hBufferSizeChangedEvent; - HANDLE m_hSampleRateChangedEvent; - ///////////////////////////// - - ///< Sync events - HANDLE m_hDeviceInitialized; - HANDLE m_hExitIdleThread; - - //Should be set if the device connection status is "DeviceErrors" - WTErr m_lastErr; -}; - -//! WCMRPortAudioDeviceManager -/*! The PortAudio Device Manager class */ -class WCMRPortAudioDeviceManager : public WCMRAudioDeviceManager -{ -public: - WCMRPortAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter, - bool useMultithreading = true, bool bNocopy = false); ///< constructor - - virtual ~WCMRPortAudioDeviceManager(void); ///< destructor - -protected: - - virtual WCMRAudioDevice* initNewCurrentDeviceImpl(const std::string & deviceName); - virtual void destroyCurrentDeviceImpl(); - virtual WTErr generateDeviceListImpl(); // use this in derived class to fill device list - virtual WTErr updateDeviceListImpl() {return eNoErr; } // not supported - virtual WTErr getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& buffers) const; - virtual WTErr getDeviceSampleRatesImpl(const std::string & deviceName, std::vector<int>& sampleRates) const; - - bool m_UseMultithreading; ///< Flag indicates whether to use multi-threading for audio processing. - bool m_bNoCopyAudioBuffer; - -private: - // helper functions for this class only - WTErr getDeviceAvailableSampleRates(DeviceID deviceId, std::vector<int>& sampleRates); - WTErr getDeviceAvailableBufferSizes(DeviceID deviceId, std::vector<int>& buffers); - - WCMRAudioDevice* m_NoneDevice; -}; - -#endif //#ifndef __WCMRPortAudioDeviceManager_h_ |