add correct copyright statements to all files in Waves backend except those derived...
[ardour.git] / libs / backends / wavesaudio / wavesapi / devicemanager / WCMRCoreAudioDeviceManager.cpp
index b66d2519cab7e155f3f2535fd488ceac5bb276f4..5c1ceac63efd90add3c0530d80c15e24c8f8d4a3 100644 (file)
@@ -1,23 +1,6 @@
-/*
-    Copyright (C) 2013 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.
-
-*/
 //----------------------------------------------------------------------------------
 //
+// Copyright (c) 2008 Waves Audio Ltd. All rights reserved.
 //
 //! \file   WCMRCoreAudioDeviceManager.cpp
 //!
@@ -42,7 +25,7 @@ using namespace wvNS;
 ///< Supported Sample rates
 static const double gAllSampleRates[] =
 {
-    44100.0, 48000.0, 88200.0, 96000.0, -1 /* negative terminated  list */
+    44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0, -1 /* negative terminated  list */
 };
 
 
@@ -58,6 +41,8 @@ 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 = 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.
@@ -166,7 +151,7 @@ WCMRCoreAudioDevice::WCMRCoreAudioDevice (WCMRCoreAudioDeviceManager *pManager,
         m_CurrentBufferSize = (int)bufferSize;
     
     
-    UpdateDeviceInfo(true /*updateSRSupported*/, true /* updateBufferSizes */);
+    UpdateDeviceInfo();
 
     //should use a valid current SR...
     if (m_SamplingRates.size())
@@ -252,14 +237,11 @@ WCMRCoreAudioDevice::~WCMRCoreAudioDevice ()
 // WCMRCoreAudioDevice::UpdateDeviceInfo 
 //
 //! Updates Device Information about channels, sampling rates, buffer sizes.
-//!
-//! \param updateSRSupported : Is Sampling Rate support needs to be updated.
-//! \param updateBufferSizes : Is buffer size support needs to be updated.
 //! 
 //! \return WTErr.
 //! 
 //**********************************************************************************************
-WTErr WCMRCoreAudioDevice::UpdateDeviceInfo (bool updateSRSupported, bool updateBufferSizes)
+WTErr WCMRCoreAudioDevice::UpdateDeviceInfo ()
 {
     AUTO_FUNC_DEBUG;
     
@@ -272,17 +254,8 @@ WTErr WCMRCoreAudioDevice::UpdateDeviceInfo (bool updateSRSupported, bool update
     WTErr errSR =   eNoErr; 
     WTErr errBS =   eNoErr; 
     
-    if (updateSRSupported)
-    {
-        errSR = UpdateDeviceSampleRates();      
-    }
-    
-    //update SR list... This is done conditionally, because some devices may not like
-    //changing the SR later on, just to check on things.
-    if (updateBufferSizes)
-    {
-        errBS = UpdateDeviceBufferSizes();
-    }
+    errSR = UpdateDeviceSampleRates();
+    errBS = UpdateDeviceBufferSizes();
 
     if(errName != eNoErr || errIn != eNoErr || errOut != eNoErr || errSR != eNoErr || errBS != eNoErr)
     {
@@ -383,7 +356,7 @@ WTErr WCMRCoreAudioDevice::UpdateDeviceInputs()
             memset (pStreamBuffers, 0, propSize);
         
             // Get the Input channels
-            err = AudioDeviceGetProperty (m_DeviceID, 0, 1/* Input */, kAudioDevicePropertyStreamConfiguration, &propSize, pStreamBuffers);
+            err = AudioDeviceGetProperty (m_DeviceID, 0, true/* Input */, kAudioDevicePropertyStreamConfiguration, &propSize, pStreamBuffers);
             if (err == kAudioHardwareNoError)
             {
                 // Calculate the number of input channels
@@ -414,12 +387,54 @@ WTErr WCMRCoreAudioDevice::UpdateDeviceInputs()
     
     // Update input channels
     m_InputChannels.clear();
+    
     for (int channel = 0; channel < maxInputChannels; channel++)
     {
+        CFStringRef cfName;
         std::stringstream chNameStream;
-        //A better implementation would be to retrieve the names from ASIO or CoreAudio interfaces
-        chNameStream << "Input " << (channel+1);
+        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;
@@ -497,10 +512,51 @@ WTErr WCMRCoreAudioDevice::UpdateDeviceOutputs()
     m_OutputChannels.clear();
     for (int channel = 0; channel < maxOutputChannels; channel++)
     {
+        CFStringRef cfName;
         std::stringstream chNameStream;
-        //A better implementation would be to retrieve the names from ASIO or CoreAudio interfaces
-        chNameStream << "Output " << (channel+1);
+        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;
@@ -786,7 +842,7 @@ WTErr WCMRCoreAudioDevice::SetCurrentSamplingRate (int newRate)
     retVal = SetAndCheckCurrentSamplingRate (newRate);
     if(retVal == eNoErr)
     {
-        retVal = UpdateDeviceInfo (false/*updateSRSupported*/, true/*updateBufferSizes*/);
+        retVal = UpdateDeviceInfo ();
     }
 
     //reactivate it.    
@@ -1205,12 +1261,17 @@ WTErr WCMRCoreAudioDevice::EnableListeners()
         goto Exit;
     }
 
-#if ENABLE_DEVICE_CHANGE_LISTNER    
+#if ENABLE_DEVICE_CHANGE_LISTNER
     {
         //listner for device change...
-        err = AudioDeviceAddPropertyListener(m_DeviceID, 0, 0, kAudioDevicePropertyDeviceHasChanged,
-                                             StaticPropertyChangeProc, this);
         
+        err = AudioDeviceAddPropertyListener (m_DeviceID,
+                                              kAudioPropertyWildcardChannel,
+                                              true,
+                                              kAudioDevicePropertyDeviceHasChanged,
+                                              StaticPropertyChangeProc,
+                                              this);
+                
         if (err)
         {
             DEBUG_MSG("Couldn't Setup device change Property Listner, error = " << err);
@@ -1266,14 +1327,18 @@ WTErr WCMRCoreAudioDevice::DisableListeners()
 
 #if ENABLE_DEVICE_CHANGE_LISTNER    
     {
-        err = AudioDeviceRemovePropertyListener(m_DeviceID, 0, 0, kAudioDevicePropertyDeviceHasChanged,
-                                                StaticPropertyChangeProc);
-            
+        err = AudioDeviceRemovePropertyListener (m_DeviceID,
+                                                 kAudioPropertyWildcardChannel,
+                                                 true/* Input */,
+                                                 kAudioDevicePropertyDeviceHasChanged,
+                                                 StaticPropertyChangeProc);
+        
         if (err)
         {
-            DEBUG_MSG("Couldn't Cleanup device change Property Listner, error = " << err);
+            DEBUG_MSG("Couldn't Cleanup device input stream change Property Listner, error = " << err);
             //not sure if we need to report this...
         }
+        
     }
 #endif //ENABLE_DEVICE_CHANGE_LISTNER   
 
@@ -1342,15 +1407,19 @@ void WCMRCoreAudioDevice::PropertyChangeProc (AudioDevicePropertyID inPropertyID
     case kAudioDevicePropertyDeviceHasChanged:
         {
             m_ResetRequested++;
+            m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
         }
         break;
 #endif //ENABLE_DEVICE_CHANGE_LISTNER   
     case kAudioDeviceProcessorOverload:
+        {
         if (m_IgnoreThisDrop)
             m_IgnoreThisDrop = false; //We'll ignore once, just once!
         else
             m_DropsDetected++;
+            m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::Dropout );
         break;
+        }
     default:
         break;
     }
@@ -1616,35 +1685,7 @@ WTErr WCMRCoreAudioDevice::SetupAUHAL()
     retVal = EnableListeners();
     if (retVal != eNoErr)
         goto Exit;
-
-    //also prepare the buffer list for input...
-    if (!m_InputChannels.empty())
-    {
-        
-        //now setup the buffer list.
-        memset (&m_InputAudioBufferList, 0, sizeof (m_InputAudioBufferList));
-        m_InputAudioBufferList.mNumberBuffers = 1;
-        m_InputAudioBufferList.mBuffers[0].mNumberChannels = m_InputChannels.size();
-        m_InputAudioBufferList.mBuffers[0].mDataByteSize = m_InputAudioBufferList.mBuffers[0].mNumberChannels *
-            m_CurrentBufferSize * sizeof(float);
-        //allocate the data buffer...
-        try
-        {
-            m_pInputData = new float[m_InputAudioBufferList.mBuffers[0].mNumberChannels * m_CurrentBufferSize];
-        }
-        catch (...)
-        {
-            retVal = eMemNewFailed;
-            goto Exit;
-        }
-        
-        m_InputAudioBufferList.mBuffers[0].mData = m_pInputData;
-        
-        //zero it out...
-        memset (m_InputAudioBufferList.mBuffers[0].mData, 0, m_InputAudioBufferList.mBuffers[0].mDataByteSize);
     
-    }
-
     //initialize the audio-unit now!
     err = AudioUnitInitialize(m_AUHALAudioUnit);
     if (err != kAudioHardwareNoError)
@@ -1684,8 +1725,6 @@ WTErr WCMRCoreAudioDevice::TearDownAUHAL()
         CloseComponent(m_AUHALAudioUnit);
         m_AUHALAudioUnit = NULL;
     }
-    
-    safe_delete_array(m_pInputData);
 
     return retVal;
 }
@@ -1716,7 +1755,6 @@ WTErr WCMRCoreAudioDevice::SetActive (bool newState)
 
     if (newState)
     {
-        
         m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Setting up AUHAL.");
         retVal = SetupAUHAL();
 
@@ -1759,7 +1797,7 @@ WTErr WCMRCoreAudioDevice::SetActive (bool newState)
         m_DropsReported = 0;
         m_IgnoreThisDrop = true;
 
-        UpdateDeviceInfo(true /*updateSRSupported */, true /* updateBufferSizes#*/);
+        UpdateDeviceInfo();
 
     }
     
@@ -1864,7 +1902,6 @@ WTErr WCMRCoreAudioDevice::SetStreaming (bool newState)
         SetupToneGenerator ();
 #endif //WV_USE_TONE_GEN
 
-        m_StopRequested = false;
         m_SampleCountAtLastIdle = 0;
         m_StalledSampleCounter = 0;
         m_SampleCounter = 0;
@@ -1881,6 +1918,8 @@ WTErr WCMRCoreAudioDevice::SetStreaming (bool newState)
         
         err = AudioOutputUnitStart (m_AUHALAudioUnit);
         
+        m_StopRequested = false;
+        
         if(err)
         {
             DEBUG_MSG( "Failed to start AudioUnit, err " << err );
@@ -1895,11 +1934,11 @@ WTErr WCMRCoreAudioDevice::SetStreaming (bool newState)
         err = AudioOutputUnitStop (m_AUHALAudioUnit);
         if (!err)
         {
-            if (!m_InputChannels.empty());
+            //if (!m_InputChannels.empty());
             {
                 err = AudioUnitReset (m_AUHALAudioUnit, kAudioUnitScope_Global, AUHAL_INPUT_ELEMENT);
             }
-            if (!m_OutputChannels.empty());
+            //if (!m_OutputChannels.empty());
             {
                 err = AudioUnitReset (m_AUHALAudioUnit, kAudioUnitScope_Global, AUHAL_OUTPUT_ELEMENT);
             }
@@ -1938,6 +1977,7 @@ Exit:
 //**********************************************************************************************
 WTErr WCMRCoreAudioDevice::DoIdle ()
 {
+    /*
     if (m_BufferSizeChangeRequested != m_BufferSizeChangeReported)
     {
         m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged);
@@ -1990,7 +2030,7 @@ WTErr WCMRCoreAudioDevice::DoIdle ()
             m_StalledSampleCounter = 0;
             m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStoppedStreaming, (void *)currentSampleCount);
         }
-    }
+    }*/
 
     
     return (eNoErr);
@@ -2082,6 +2122,18 @@ WTErr WCMRCoreAudioDevice::ShowConfigPanel (void */*pParam*/)
         {
             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);
     }
     
@@ -2143,19 +2195,38 @@ OSStatus WCMRCoreAudioDevice::AudioIOProc(AudioUnitRenderActionFlags *  ioAction
     OSStatus retVal = 0;
     
     if (m_StopRequested)
-        goto Exit;
+        return retVal;
 
     if (m_IOProcThreadPort == 0)
         m_IOProcThreadPort = mach_thread_self ();
     
     //cannot really deal with it unless the number of frames are the same as our buffer size!
     if (inNumberFrames != (UInt32)m_CurrentBufferSize)
-        goto Exit;
+        return retVal;
     
     //Retrieve the input data...
     if (!m_InputChannels.empty())
     {
-        retVal = AudioUnitRender(m_AUHALAudioUnit, ioActionFlags, inTimeStamp, AUHAL_INPUT_ELEMENT, inNumberFrames, &m_InputAudioBufferList);
+        UInt32 expectedDataSize = m_InputChannels.size() * m_CurrentBufferSize * sizeof(float);
+        AudioBufferList inputAudioBufferList;
+        inputAudioBufferList.mNumberBuffers = 1;
+        inputAudioBufferList.mBuffers[0].mNumberChannels = m_InputChannels.size();
+        inputAudioBufferList.mBuffers[0].mDataByteSize = expectedDataSize;
+        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?
@@ -2164,7 +2235,6 @@ OSStatus WCMRCoreAudioDevice::AudioIOProc(AudioUnitRenderActionFlags *  ioAction
     else if ((!m_OutputChannels.empty()) && (ioData->mBuffers[0].mNumberChannels == m_OutputChannels.size()))
         AudioCallback ((float *)ioData->mBuffers[0].mData, inNumberFrames, (uint32_t)inTimeStamp->mSampleTime, theStartTime);
     
-Exit:   
     return retVal;
 }
 
@@ -2317,14 +2387,10 @@ OSStatus WCMRCoreAudioDevice::GetStreamLatency(AudioDeviceID device, bool isInpu
 //! \return Nothing.
 //! 
 //**********************************************************************************************
-WCMRCoreAudioDeviceManager::WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter 
-                                                       , bool useMultithreading, eCABS_Method eCABS_method, bool bNocopy) 
-  : WCMRAudioDeviceManager (pTheClient, eCurAudioDeviceFilter
-      )
-  , m_UpdateDeviceListRequested(0)
-  , m_UpdateDeviceListProcessed(0)
+WCMRCoreAudioDeviceManager::WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient,
+                            eAudioDeviceFilter eCurAudioDeviceFilter, bool useMultithreading, bool bNocopy)
+  : WCMRAudioDeviceManager (pTheClient, eCurAudioDeviceFilter)
   , m_UseMultithreading (useMultithreading)
-  , m_eCABS_Method(eCABS_method)
   , m_bNoCopyAudioBuffer(bNocopy)
 {
     AUTO_FUNC_DEBUG;
@@ -2347,13 +2413,13 @@ WCMRCoreAudioDeviceManager::WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerCli
     }
 
     //add a listener to find out when devices change...
-    AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, StaticPropertyChangeProc, this);
-
+    AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, HardwarePropertyChangeCallback, this);
+    
     //Always add the None device first...
-    m_Devices.push_back (new WCMRNativeAudioNoneDevice(this));
+    m_NoneDevice = new WCMRNativeAudioNoneDevice(this);
 
     //prepare our initial list...
-    UpdateDeviceList_Private();
+    generateDeviceListImpl();
 
     return;
 }
@@ -2376,25 +2442,7 @@ WCMRCoreAudioDeviceManager::~WCMRCoreAudioDeviceManager()
 
     try
     {
-        AudioHardwareRemovePropertyListener (kAudioHardwarePropertyDevices, StaticPropertyChangeProc);
-
-        //Note: We purposely release the device list here, instead of
-        //depending on the superclass to do it, as by the time the superclass'
-        //destructor executes, we will have called Pa_Terminate()!
-    
-        //Need to call release on our devices, and erase them from list
-        std::vector<WCMRAudioDevice*>::iterator deviceIter;
-        while (m_Devices.size())
-        {
-            WCMRAudioDevice *pDeviceToRelease = m_Devices.back();
-            m_Devices.pop_back();
-
-            SAFE_RELEASE (pDeviceToRelease);
-        }
-    
-        
-        //The derived classes may want to do additional de-int!
-
+        delete m_NoneDevice;
     }
     catch (...)
     {
@@ -2405,313 +2453,595 @@ WCMRCoreAudioDeviceManager::~WCMRCoreAudioDeviceManager()
 }
 
 
-//**********************************************************************************************
-// WCMRCoreAudioDeviceManager::StaticPropertyChangeProc
-//
-//! The property change listener for the Audio Device Manager. It calls upon (non-static) PropertyChangeProc
-//!     to do the actual work.
-//!
-//! \param iPropertyID : the property that has changed.
-//! \param inClientData : What was supplied at init time.
-//! 
-//! \return if parameters are incorrect, or the value returned by PropertyChangeProc.
-//! 
-//**********************************************************************************************
-OSStatus WCMRCoreAudioDeviceManager::StaticPropertyChangeProc (AudioHardwarePropertyID inPropertyID, void* inClientData)
+WCMRAudioDevice* WCMRCoreAudioDeviceManager::initNewCurrentDeviceImpl(const std::string & deviceName)
 {
-    WCMRCoreAudioDeviceManager *pMyManager = (WCMRCoreAudioDeviceManager *)inClientData;
-    
-    if (pMyManager)
-        return pMyManager->PropertyChangeProc (inPropertyID);
-
-    return 0;
+    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;
 }
 
 
-
-//**********************************************************************************************
-// WCMRCoreAudioDeviceManager::PropertyChangeProc
-//
-//! The property change listener for the Audio Device Manager. Currently we only listen for the
-//!     device list change (device arrival/removal, and accordingly cause an update to the device list.
-//!     Note that the actual update happens from the DoIdle() call to prevent multi-threading related issues.
-//!
-//! \param 
-//! 
-//! \return Nothing.
-//! 
-//**********************************************************************************************
-OSStatus WCMRCoreAudioDeviceManager::PropertyChangeProc (AudioHardwarePropertyID inPropertyID)
+void WCMRCoreAudioDeviceManager::destroyCurrentDeviceImpl()
 {
-    OSStatus retVal = 0;
-    switch (inPropertyID)
+    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)
     {
-    case kAudioHardwarePropertyDevices:
-        m_UpdateDeviceListRequested++;
-        break;
-    default:
-        break;
+        //! 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;
 }
-
-//**********************************************************************************************
-// WCMRCoreAudioDeviceManager::remove_pattern
-//
-//! remove a substring from a given string
-//!
-//! \param original_str - original string
-//! \param pattern_str - pattern to find
-//! \param return_str - the return string - without the pattern substring
-//! 
-//! \return Nothing.
-//! 
-//**********************************************************************************************
-void WCMRCoreAudioDeviceManager::remove_pattern(const std::string& original_str, const std::string& pattern_str, std::string& return_str)
-{
-    char *orig_c_str = new char[original_str.size() + 1];
-    char* strSavePtr;
-    strcpy(orig_c_str, original_str.c_str());
-    char *p_splited_orig_str = strtok_r(orig_c_str," ", &strSavePtr);
     
-    std::ostringstream stream_str;
-    while (p_splited_orig_str != 0) 
+    
+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
     {
-        int cmp_res = strcmp(p_splited_orig_str, pattern_str.c_str()); // might need Ignore case ( stricmp OR strcasecmp)
-        if ( cmp_res != 0)
-            stream_str << p_splited_orig_str << " ";
-        p_splited_orig_str = strtok_r(NULL," ", &strSavePtr);
+        retVal = eCoreAudioFailed;
+        DEBUG_MSG("Failed to get device Input channels property size. Device Name: " << m_DeviceName.c_str());
     }
-    delete[] orig_c_str;
-    return_str = stream_str.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;
 
-//**********************************************************************************************
-// WCMRCoreAudioDeviceManager::UpdateDeviceList_Private
-//
-//! Updates the list of devices maintained by the manager. If devices have gone away, they are removed
-//!     if new devices have been connected, they are added to the list.
-//!
-//! \param none
-//! 
-//! \return eNoErr on success, an error code on failure.
-//! 
-//**********************************************************************************************
-WTErr WCMRCoreAudioDeviceManager::UpdateDeviceList_Private()
+    //! 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;
-    size_t reportedDeviceIndex = 0;
     
     openlog("WCMRCoreAudioDeviceManager", LOG_PID | LOG_CONS, LOG_USER);
-
-    try 
-    {
-    
-        // Define 2 vectors for input and output - only for eMatchedDuplexDevices case
-        WCMRAudioDeviceList adOnlyIn;
-        WCMRAudioDeviceList adOnlyOut;
     
+    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;
-    
-        //first go through our list of devices, remove the ones that are no longer present...
-        std::vector<WCMRAudioDevice*>::iterator deviceIter;
-        for (deviceIter = m_Devices.begin(); deviceIter != m_Devices.end(); /*This is purposefully blank*/)
+        
+        //now add the ones that are not there...
+        for (size_t deviceIndex = 0; deviceIndex < numDevices; deviceIndex++)
         {
-            WCMRCoreAudioDevice *pDeviceToWorkUpon = dynamic_cast<WCMRCoreAudioDevice *>(*deviceIter);
-
-            //it's possible that the device is actually not a core audio device - perhaps a none device...
-            if (!pDeviceToWorkUpon)
-            {
-                deviceIter++;
-                continue;
-            }
-
-            AudioDeviceID myDeviceID = pDeviceToWorkUpon->DeviceID();
-            bool deviceFound = false;
-            for (reportedDeviceIndex = 0; reportedDeviceIndex < numDevices; reportedDeviceIndex++)
+            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)
             {
-                if (myDeviceID == deviceIDs[reportedDeviceIndex])
+                //Get property: name.
+                char* deviceName = new char[propSize];
+                osErr = AudioDeviceGetProperty(deviceIDs[deviceIndex], 0, 0, kAudioDevicePropertyDeviceName, &propSize, deviceName);
+                if (osErr == kAudioHardwareNoError)
                 {
-                    deviceFound = true;
-                    break;
+                    pDevInfo = new DeviceInfo(deviceIDs[deviceIndex], deviceName);
                 }
-            }
-        
-            if (!deviceFound)
-            {
-                //it's no longer there, need to remove it!
-                WCMRAudioDevice *pTheDeviceToErase = *deviceIter;
-                deviceIter = m_Devices.erase (deviceIter);
-                if (pTheDeviceToErase->Active())
+                else
                 {
-                    NotifyClient (WCMRAudioDeviceManagerClient::DeviceConnectionLost);
+                    retVal = eCoreAudioFailed;
+                    DEBUG_MSG("Failed to get device name. Device ID: " << m_DeviceID);
                 }
-                SAFE_RELEASE (pTheDeviceToErase);
+                
+                delete [] deviceName;
             }
             else
-                deviceIter++;
-        }
-
-        //now add the ones that are not there...
-        for (reportedDeviceIndex = 0; reportedDeviceIndex < numDevices; reportedDeviceIndex++)
-        {
-            bool deviceFound = false;
-            for (deviceIter = m_Devices.begin(); deviceIter != m_Devices.end(); deviceIter++)
             {
-                WCMRCoreAudioDevice *pDeviceToWorkUpon = dynamic_cast<WCMRCoreAudioDevice *>(*deviceIter);
-                //it's possible that the device is actually not a core audio device - perhaps a none device...
-                if (!pDeviceToWorkUpon)
-                    continue;
-
-                if (pDeviceToWorkUpon->DeviceID() == deviceIDs[reportedDeviceIndex])
-                {
-                    deviceFound = true;
-                    break;
-                }
+                retVal = eCoreAudioFailed;
+                DEBUG_MSG("Failed to get device name property size. Device ID: " << m_DeviceID);
             }
-        
-            if (!deviceFound)
+            
+            if (pDevInfo)
             {
-                //add it to our list...
-                //build a device object...
-                WCMRCoreAudioDevice *pNewDevice = new WCMRCoreAudioDevice (this, deviceIDs[reportedDeviceIndex], m_UseMultithreading, m_bNoCopyAudioBuffer);
-                bool bDeleteNewDevice = true;
+                //Retrieve all the information we need for the device
+                WTErr wErr = eNoErr;
                 
-                if (pNewDevice)
+                //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)
                 {
-
-                    // Don't delete the new device by default, since most cases use it
-                    bDeleteNewDevice = false;
-                    
-                    // Insert the new device to the device list according to its enum
-                    switch(m_eAudioDeviceFilter)
-                    {
                     case eInputOnlyDevices:
-                        if ((int) pNewDevice->InputChannels().size() != 0)
+                        if (pDevInfo->m_MaxInputChannels != 0)
                         {
-                            m_Devices.push_back (pNewDevice);
+                            m_DeviceInfoVec.push_back(pDevInfo);
                         }
                         else
                         {
                             // Delete unnecesarry device
-                            bDeleteNewDevice = true;
+                            bRejectDevice = true;
                         }
                         break;
                     case eOutputOnlyDevices:
-                        if ((int) pNewDevice->OutputChannels().size() != 0)
+                        if (pDevInfo->m_MaxOutputChannels != 0)
                         {
-                            m_Devices.push_back (pNewDevice);
+                            m_DeviceInfoVec.push_back(pDevInfo);
                         }
                         else
                         {
                             // Delete unnecesarry device
-                            bDeleteNewDevice = true;
+                            bRejectDevice = true;
                         }
                         break;
                     case eFullDuplexDevices:
-                        if ((int) pNewDevice->InputChannels().size() != 0 && (int) pNewDevice->OutputChannels().size() != 0)
+                        if (pDevInfo->m_MaxInputChannels != 0 && pDevInfo->m_MaxOutputChannels != 0)
                         {
-                            m_Devices.push_back (pNewDevice);
+                            m_DeviceInfoVec.push_back(pDevInfo);
                         }
                         else
                         {
                             // Delete unnecesarry device
-                            bDeleteNewDevice = true;
+                            bRejectDevice = true;
                         }
                         break;
                     case eAllDevices:
                     default:
-                        m_Devices.push_back (pNewDevice);
+                        m_DeviceInfoVec.push_back(pDevInfo);
                         break;
-                    }
                 }
                 
-                if(bDeleteNewDevice)
+                if(bRejectDevice)
                 {
                     syslog (LOG_NOTICE, "%s rejected, In Channels = %d, Out Channels = %d\n",
-                            pNewDevice->DeviceName().c_str(), (int) pNewDevice->InputChannels().size(),
-                            (int) pNewDevice->OutputChannels().size());
+                            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.
-                    SAFE_RELEASE(pNewDevice);
+                    delete pDevInfo;
                 }
             }
         }
-    
-
+        
+        
         //If no devices were found, that's not a good thing!
-        if (m_Devices.empty())
+        if (m_DeviceInfoVec.empty())
         {
             DEBUG_MSG ("No matching CoreAudio devices were found\n");
-        }
-    
-
-        m_UpdateDeviceListRequested = m_UpdateDeviceListProcessed = 0;
-    
+        }        
     }
     catch (...)
     {
         if (WUNoError(retVal))
             retVal = eCoreAudioFailed;
     }
-
-    safe_delete_array(deviceIDs);
+    
+    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;
+        return err;
+    }
+    
+    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;
+        }
+    }
+    
+    NotifyClient (WCMRAudioDeviceManagerClient::DeviceListChanged);
+    
+    return err;
+}
+
 
-//**********************************************************************************************
-// WCMRCoreAudioDeviceManager::DoIdle
-//
-//! Used for idle time processing. This calls each device's DoIdle so that it can perform it's own idle processing.
-//!     Also, if a device list change is detected, it updates the device list.
-//!
-//! \param none
-//! 
-//! \return noErr if no devices have returned an error. An error code if any of the devices returned error.
-//! 
-//**********************************************************************************************
-WTErr WCMRCoreAudioDeviceManager::DoIdle()
+WTErr WCMRCoreAudioDeviceManager::getDeviceSampleRatesImpl(const std::string & deviceName, std::vector<int>& sampleRates) const
 {
-    //WTErr retVal = eNoErr;
+    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
     {
-        //wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
+        retVal = eCoreAudioFailed;
+        DEBUG_MSG("Failed to get device Sample rates property size. Device Name: " << m_DeviceName.c_str());
+    }
 
-        //If there's something specific to CoreAudio manager idle handling do it here...
-        if (m_UpdateDeviceListRequested != m_UpdateDeviceListProcessed)
+    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)
         {
-            m_UpdateDeviceListProcessed = m_UpdateDeviceListRequested;
-            UpdateDeviceList_Private();
-            NotifyClient (WCMRAudioDeviceManagerClient::DeviceListChanged);
+            // 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;
+       }
 
-    //Note that the superclass is going to call all the devices' DoIdle() anyway...
-    return (WCMRAudioDeviceManager::DoIdle());
+    
+    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;
+}