1 //----------------------------------------------------------------------------------
3 // Copyright (c) 2008 Waves Audio Ltd. All rights reserved.
5 //! \file WCMRPortAudioDeviceManager.cpp
7 //! WCMRPortAudioDeviceManager and related class declarations
9 //---------------------------------------------------------------------------------*/
10 #include "WCMRPortAudioDeviceManager.h"
11 #include "MiscUtils/safe_delete.h"
12 #include "UMicroseconds.h"
16 #include "IncludeWindows.h"
21 ///< Supported Sample rates
22 static const double gAllSampleRates[] =
24 44100.0, 48000.0, 88200.0, 96000.0, -1 /* negative terminated list */
29 ///< Default Supported Buffer Sizes.
30 static const int gAllBufferSizes[] =
32 32, 64, 96, 128, 192, 256, 512, 1024, 2048
37 static const int DEFAULT_SR = 44100;
38 ///< The default buffer size.
39 static const int DEFAULT_BUFFERSIZE = 128;
41 static const int NONE_DEVICE_ID = -1;
43 ///< Number of stalls to wait before notifying user...
44 static const int NUM_STALLS_FOR_NOTIFICATION = 100; // 100 corresponds to 100 x 42 ms idle timer - about 4 seconds.
45 static const int CHANGE_CHECK_COUNTER_PERIOD = 100; // 120 corresponds to 120 x 42 ms idle timer - about 4 seconds.
47 #define HUNDRED_NANO_TO_MILLI_CONSTANT 10000
48 #define CONSUMPTION_CALCULATION_INTERVAL 500 // Milli Seconds
51 // This wrapper is used to adapt device DoIdle method as entry point for MS thread
52 DWORD WINAPI WCMRPortAudioDevice::__DoIdle__(LPVOID lpThreadParameter)
54 WCMRPortAudioDevice* pDevice = (WCMRPortAudioDevice*)lpThreadParameter;
59 //**********************************************************************************************
60 // WCMRPortAudioDevice::WCMRPortAudioDevice
62 //! Constructor for the audio device. Opens the PA device
63 //! and gets information about the device.
64 //! Starts the thread which will process requests to this device
65 //! such as determining supported sampling rates, buffer sizes, and channel counts.
67 //! \param *pManager : The audio device manager that's managing this device.
68 //! \param deviceID : The port audio device ID.
69 //! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true.
73 //**********************************************************************************************
74 WCMRPortAudioDevice::WCMRPortAudioDevice (WCMRPortAudioDeviceManager *pManager, unsigned int deviceID, bool useMultithreading, bool bNoCopy) :
75 WCMRNativeAudioDevice (pManager, useMultithreading, bNoCopy)
77 , m_BufferSizeChangeRequested (0)
78 , m_BufferSizeChangeReported (0)
79 , m_ResetRequested (0)
81 , m_ResyncRequested (0)
82 , m_ResyncReported (0)
85 , m_IgnoreThisDrop(true)
86 , m_hDeviceProcessingThread(NULL)
87 , m_DeviceProcessingThreadID(0)
88 , m_hUpdateDeviceInfoRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
89 , m_hUpdateDeviceInfoDone(CreateEvent(NULL, FALSE, FALSE, NULL))
90 , m_hActivateRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
91 , m_hActivationDone(CreateEvent(NULL, FALSE, FALSE, NULL))
92 , m_hDeActivateRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
93 , m_hDeActivationDone(CreateEvent(NULL, FALSE, FALSE, NULL))
94 , m_hStartStreamingRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
95 , m_hStartStreamingDone(CreateEvent(NULL, FALSE, FALSE, NULL))
96 , m_hStopStreamingRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
97 , m_hStopStreamingDone(CreateEvent(NULL, FALSE, FALSE, NULL))
98 , m_hResetRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
99 , m_hResetDone(CreateEvent(NULL, FALSE, FALSE, NULL))
100 , m_hResetFromDevRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
101 , m_hBufferSizeChangedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
102 , m_hSampleRateChangedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
103 , m_hExitIdleThread(CreateEvent(NULL, FALSE, FALSE, NULL))
104 , m_hDeviceInitialized(CreateEvent(NULL, FALSE, FALSE, NULL))
109 //Set initial device info...
110 m_DeviceID = deviceID;
111 m_PortAudioStream = NULL;
112 m_CurrentSamplingRate = DEFAULT_SR;
113 m_CurrentBufferSize = DEFAULT_BUFFERSIZE;
114 m_StopRequested = true;
117 //initialize device processing thread
118 //the divice become alive and now is able to process requests
119 m_hDeviceProcessingThread = CreateThread( NULL, 0, __DoIdle__, (LPVOID)this, 0, &m_DeviceProcessingThreadID );
121 if (!m_hDeviceProcessingThread)
123 DEBUG_MSG("API::Device " << m_DeviceName << " cannot create processing thread");
127 WaitForSingleObject(m_hDeviceInitialized, INFINITE);
129 if (ConnectionStatus() == DeviceErrors)
136 void WCMRPortAudioDevice::initDevice()
138 // Initialize COM for this thread
139 std::cout << "API::Device " << m_DeviceID << " initializing COM" << std::endl;
141 if (S_OK == CoInitialize(NULL) )
148 //should use a valid current SR...
149 if (m_SamplingRates.size())
151 //see if the current sr is present in the sr list, if not, use the first one!
152 std::vector<int>::iterator intIter = find(m_SamplingRates.begin(), m_SamplingRates.end(), m_CurrentSamplingRate);
153 if (intIter == m_SamplingRates.end())
155 //not found... use the first one
156 m_CurrentSamplingRate = m_SamplingRates[0];
160 std::cout << "API::Device " << m_DeviceName << " Device does not support any sample rate of ours" << std::endl;
162 //should use a valid current buffer size
163 if (m_BufferSizes.size())
165 //see if the current sr is present in the buffersize list, if not, use the first one!
166 std::vector<int>::iterator intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), m_CurrentBufferSize);
167 if (intIter == m_BufferSizes.end())
169 //not found... use the first one
170 m_CurrentBufferSize = m_BufferSizes[0];
174 //build our input/output level lists
175 for (unsigned int currentChannel = 0; currentChannel < m_InputChannels.size(); currentChannel++)
177 m_InputLevels.push_back (0.0);
180 //build our input/output level lists
181 for (unsigned int currentChannel = 0; currentChannel < m_OutputChannels.size(); currentChannel++)
183 m_OutputLevels.push_back (0.0);
186 std::cout << "API::Device " << m_DeviceName << " Device has been initialized" << std::endl;
187 m_ConnectionStatus = DeviceDisconnected;
192 /*Replace with debug trace*/std::cout << "API::Device " << m_DeviceName << " cannot initialize COM" << std::endl;
193 DEBUG_MSG("Device " << m_DeviceName << " cannot initialize COM");
194 m_ConnectionStatus = DeviceErrors;
195 m_lastErr = eSomeThingNotInitailzed;
196 SetEvent(m_hExitIdleThread);
199 SetEvent(m_hDeviceInitialized);
202 void WCMRPortAudioDevice::terminateDevice()
204 std::cout << "API::Device " << m_DeviceName << " Terminating DEVICE" << std::endl;
206 //If device is streaming, need to stop it!
212 //If device is active (meaning stream is open) we need to close it.
218 std::cout << "API::Device " << m_DeviceName << " Terminating PA" << std::endl;
225 //**********************************************************************************************
226 // WCMRPortAudioDevice::~WCMRPortAudioDevice
228 //! Destructor for the audio device. The base release all the connections that were created, if
229 //! they have not been already destroyed! Here we simply stop streaming, and close device
230 //! handles if necessary.
236 //**********************************************************************************************
237 WCMRPortAudioDevice::~WCMRPortAudioDevice ()
241 std::cout << "API::Destroying Device Instance: " << DeviceName() << std::endl;
244 //Stop deviceprocessing thread
245 SignalObjectAndWait(m_hExitIdleThread, m_hDeviceProcessingThread, INFINITE, false);
247 std::cout << "API::Device " << m_DeviceName << " Processing Thread is stopped" << std::endl;
249 CloseHandle(m_hDeviceProcessingThread);
251 //Now it's safe to free all event handlers
252 CloseHandle(m_hUpdateDeviceInfoRequestedEvent);
253 CloseHandle(m_hUpdateDeviceInfoDone);
254 CloseHandle(m_hActivateRequestedEvent);
255 CloseHandle(m_hActivationDone);
256 CloseHandle(m_hDeActivateRequestedEvent);
257 CloseHandle(m_hDeActivationDone);
258 CloseHandle(m_hStartStreamingRequestedEvent);
259 CloseHandle(m_hStartStreamingDone);
260 CloseHandle(m_hStopStreamingRequestedEvent);
261 CloseHandle(m_hStopStreamingDone);
262 CloseHandle(m_hResetRequestedEvent);
263 CloseHandle(m_hResetDone);
264 CloseHandle(m_hResetFromDevRequestedEvent);
265 CloseHandle(m_hBufferSizeChangedEvent);
266 CloseHandle(m_hSampleRateChangedEvent);
267 CloseHandle(m_hExitIdleThread);
268 CloseHandle(m_hDeviceInitialized);
272 //destructors should absorb exceptions, no harm in logging though!!
273 DEBUG_MSG ("Exception during destructor");
278 WTErr WCMRPortAudioDevice::UpdateDeviceInfo ()
280 std::cout << "API::Device (ID:)" << m_DeviceID << " Updating device info" << std::endl;
282 SignalObjectAndWait(m_hUpdateDeviceInfoRequestedEvent, m_hUpdateDeviceInfoDone, INFINITE, false);
288 //**********************************************************************************************
289 // WCMRPortAudioDevice::updateDeviceInfo
291 //! Must be called be device processing thread
292 //! Updates Device Information about channels, sampling rates, buffer sizes.
296 //**********************************************************************************************
297 void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/)
302 const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
305 m_DeviceName = pDeviceInfo->name;
307 std::cout << "API::Device " << m_DeviceName << " Getting device info " << std::endl;
309 //following parameters are needed opening test stream and for sample rates validation
310 PaStreamParameters inputParameters, outputParameters;
311 PaStreamParameters *pInS = NULL, *pOutS = NULL;
313 inputParameters.device = m_DeviceID;
314 inputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxInputChannels);
315 inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
316 inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
317 inputParameters.hostApiSpecificStreamInfo = 0;
319 if (inputParameters.channelCount)
320 pInS = &inputParameters;
322 outputParameters.device = m_DeviceID;
323 outputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxOutputChannels);
324 outputParameters.sampleFormat = paFloat32;
325 outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
326 outputParameters.hostApiSpecificStreamInfo = 0;
328 if (outputParameters.channelCount)
329 pOutS = &outputParameters;
331 std::cout << "API::Device" << m_DeviceName << " Updating sample rates " << std::endl;
332 ////////////////////////////////////////////////////////////////////////////////////
333 //update list of supported SRs...
334 m_SamplingRates.clear();
336 // now iterate through our standard SRs and check if they are supported by device
337 // store them for this device
338 for(int sr=0; gAllSampleRates[sr] > 0; sr++)
340 PaError err = Pa_IsFormatSupported(pInS, pOutS, gAllSampleRates[sr]);
341 if( err == paFormatIsSupported)
343 m_SamplingRates.push_back ((int)gAllSampleRates[sr]);
347 std::cout << "API::Device" << m_DeviceName << " Updating buffer sizes" << std::endl;
348 ///////////////////////////////////////////////////////////////////////////////////
349 //update buffer sizes
350 m_BufferSizes.clear();
351 bool useDefaultBuffers = true;
352 PaError paErr = paNoError;
354 //sometimes devices change buffer size if sample rate changes
355 //it updates buffer size during stream opening
356 //we need to find out how device would behave with current sample rate
357 //try opening test stream to load device driver for current sample rate and buffer size
358 //(skip this step if the device is Active)
361 if (paNoError != testStateValidness(m_CurrentSamplingRate, m_CurrentBufferSize) )
363 //buffer size did change
367 // test validness with current sample rate and device prefered buffer size
368 paErr = testStateValidness(m_CurrentSamplingRate, 0);
372 if (paErr == paNoError)
374 // In ASIO Windows, the buffer size is set from the sound device manufacturer's control panel
375 long minSize, maxSize, preferredSize, granularity;
376 paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
378 if (paErr == paNoError)
380 std::cout << "API::Device " << m_DeviceName << " Buffers: " << minSize << " " << maxSize << " " << preferredSize << std::endl;
382 m_BufferSizes.push_back (preferredSize);
383 useDefaultBuffers = false;
387 std::cout << "API::Device" << m_DeviceName << " Preffered buffer size is not supported" << std::endl;
392 std::cout << "API::Device" << m_DeviceName << " Device does not start with sample rate: "<< m_CurrentSamplingRate << " and default buffer size" << std::endl;
395 if (useDefaultBuffers)
397 std::cout << "API::Device" << m_DeviceName << " Using default buffer sizes " <<std::endl;
398 for(int bsize=0; bsize < (sizeof(gAllBufferSizes)/sizeof(gAllBufferSizes[0])); bsize++)
399 m_BufferSizes.push_back (gAllBufferSizes[bsize]);
402 /////////////////////////////////////////////////////////////////////////////////////////
403 //update channels info
405 int maxInputChannels = pDeviceInfo->maxInputChannels;
406 int maxOutputChannels = pDeviceInfo->maxOutputChannels;
408 //Update input channels
409 m_InputChannels.clear();
410 for (int channel = 0; channel < maxInputChannels; channel++)
412 std::stringstream chNameStream;
413 //A better implementation would be to retrieve the names from ASIO or CoreAudio interfaces
414 chNameStream << "Input " << (channel+1);
415 m_InputChannels.push_back (chNameStream.str());
419 //Update output channels
420 m_OutputChannels.clear();
421 for (int channel = 0; channel < maxOutputChannels; channel++)
423 std::stringstream chNameStream;
424 //A better implementation would be to retrieve the names from ASIO or CoreAudio interfaces
425 chNameStream << "Output " << (channel+1);
426 m_OutputChannels.push_back (chNameStream.str());
430 std::cout << "API::Device" << m_DeviceName << " Device info update has been finished" << std::endl;
433 SetEvent(m_hUpdateDeviceInfoDone);
437 PaError WCMRPortAudioDevice::testStateValidness(int sampleRate, int bufferSize)
439 PaError paErr = paNoError;
442 const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
444 //following parameters are needed opening test stream and for sample rates validation
445 PaStreamParameters inputParameters, outputParameters;
446 PaStreamParameters *pInS = NULL, *pOutS = NULL;
448 inputParameters.device = m_DeviceID;
449 inputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxInputChannels);
450 inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
451 inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
452 inputParameters.hostApiSpecificStreamInfo = 0;
454 if (inputParameters.channelCount)
455 pInS = &inputParameters;
457 outputParameters.device = m_DeviceID;
458 outputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxOutputChannels);
459 outputParameters.sampleFormat = paFloat32;
460 outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
461 outputParameters.hostApiSpecificStreamInfo = 0;
463 if (outputParameters.channelCount)
464 pOutS = &outputParameters;
466 PaStream *portAudioStream = NULL;
468 //sometimes devices change buffer size if sample rate changes
469 //it updates buffer size during stream opening
470 //we need to find out how device would behave with current sample rate
471 //try opening test stream to load device driver for current sample rate and buffer size
472 paErr = Pa_OpenStream (&portAudioStream, pInS, pOutS, m_CurrentSamplingRate, m_CurrentBufferSize, paDitherOff, NULL, NULL);
477 Pa_CloseStream (portAudioStream);
478 portAudioStream = NULL;
485 //**********************************************************************************************
486 // WCMRPortAudioDevice::CurrentSamplingRate
488 //! The device's current sampling rate. This may be overridden, if the device needs to
489 //! query the driver for the current rate.
493 //! \return The device's current sampling rate. -1 on error.
495 //**********************************************************************************************
496 int WCMRPortAudioDevice::CurrentSamplingRate ()
499 //ToDo: Perhaps for ASIO devices that are active, we should retrive the SR from the device...
501 return (m_CurrentSamplingRate);
505 WTErr WCMRPortAudioDevice::SetActive (bool newState)
507 if (newState == true)
509 std::cout << "API::Device " << m_DeviceName << " Activation requested" << std::endl;
510 SignalObjectAndWait(m_hActivateRequestedEvent, m_hActivationDone, INFINITE, false);
514 std::cout << "API::Device " << m_DeviceName << " Deactivation requested" << std::endl;
515 SignalObjectAndWait(m_hDeActivateRequestedEvent, m_hDeActivationDone, INFINITE, false);
518 if (newState == Active() )
525 WTErr WCMRPortAudioDevice::SetStreaming (bool newState)
527 if (newState == true)
529 std::cout << "API::Device " << m_DeviceName << " Stream start requested" << std::endl;
530 SignalObjectAndWait(m_hStartStreamingRequestedEvent, m_hStartStreamingDone, INFINITE, false);
534 std::cout << "API::Device " << m_DeviceName << " Stream stop requested" << std::endl;
535 SignalObjectAndWait(m_hStopStreamingRequestedEvent, m_hStopStreamingDone, INFINITE, false);
538 if (newState == Streaming() )
545 WTErr WCMRPortAudioDevice::ResetDevice()
547 std::cout << "API::Device: " << m_DeviceName << " Reseting device" << std::endl;
549 SignalObjectAndWait(m_hResetRequestedEvent, m_hResetDone, INFINITE, false);
551 if (ConnectionStatus() == DeviceErrors)
560 //**********************************************************************************************
561 // WCMRPortAudioDevice::SetCurrentSamplingRate
563 //! Change the sampling rate to be used by the device.
565 //! \param newRate : The rate to use (samples per sec).
567 //! \return eNoErr always. The derived classes may return error codes.
569 //**********************************************************************************************
570 WTErr WCMRPortAudioDevice::SetCurrentSamplingRate (int newRate)
573 std::vector<int>::iterator intIter;
574 WTErr retVal = eNoErr;
576 //changes the status.
577 int oldRate = CurrentSamplingRate();
578 bool oldActive = Active();
580 //no change, nothing to do
581 if (oldRate == newRate)
584 //see if this is one of our supported rates...
585 intIter = find(m_SamplingRates.begin(), m_SamplingRates.end(), newRate);
587 if (intIter == m_SamplingRates.end())
589 //Can't change, perhaps use an "invalid param" type of error
590 retVal = eCommandLineParameter;
596 //Can't change, perhaps use an "in use" type of error
597 retVal = eGenericErr;
603 //Deactivate it for the change...
608 m_CurrentSamplingRate = newRate;
610 // Before reactivating the device: opening stream we should try getting buffer size update from the device
611 // because for new sampling rate some devices may change buffer size as well
612 int oldBufferSize = m_CurrentBufferSize;
614 retVal = ResetDevice();
617 if (oldActive && retVal == eNoErr)
619 retVal = SetActive (true);
622 if (retVal != eNoErr)
624 //revert changes if the device was not activated
625 m_CurrentSamplingRate = oldRate;
626 m_CurrentBufferSize = oldBufferSize;
627 int bufferSize = m_CurrentBufferSize;
628 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
629 retVal = eCommandLineParameter;
636 //**********************************************************************************************
637 // WCMRPortAudioDevice::CurrentBufferSize
639 //! The device's current buffer size in use. This may be overridden, if the device needs to
640 //! query the driver for the current size.
644 //! \return The device's current buffer size. 0 on error.
646 //**********************************************************************************************
647 int WCMRPortAudioDevice::CurrentBufferSize ()
649 return m_CurrentBufferSize;
653 //**********************************************************************************************
654 // WCMRPortAudioDevice::SetCurrentBufferSize
656 //! Change the buffer size to be used by the device. This will most likely be overridden,
657 //! the base class simply updates the member variable.
659 //! \param newSize : The buffer size to use (in sample-frames)
661 //! \return eNoErr always. The derived classes may return error codes.
663 //**********************************************************************************************
664 WTErr WCMRPortAudioDevice::SetCurrentBufferSize (int newSize)
667 WTErr retVal = eNoErr;
668 std::vector<int>::iterator intIter;
670 //changes the status.
671 int oldSize = CurrentBufferSize();
672 bool oldActive = Active();
674 //same size, nothing to do.
675 if (oldSize == newSize)
678 //see if this is one of our supported rates...
679 intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), newSize);
680 if (intIter == m_BufferSizes.end())
682 //Can't change, perhaps use an "invalid param" type of error
683 retVal = eCommandLineParameter;
689 //Can't change, perhaps use an "in use" type of error
690 retVal = eGenericErr;
696 //Deactivate it for the change...
701 m_CurrentBufferSize = newSize;
706 retVal = SetActive (true);
713 //**********************************************************************************************
714 // WCMRPortAudioDevice::ConnectionStatus
716 //! Retrieves the device's current connection status. This will most likely be overridden,
717 //! in case some driver communication is required to query the status.
721 //! \return A ConnectionStates value.
723 //**********************************************************************************************
724 WCMRPortAudioDevice::ConnectionStates WCMRPortAudioDevice::ConnectionStatus ()
727 //ToDo: May want to do something more to extract the actual status!
728 return (m_ConnectionStatus);
733 //**********************************************************************************************
734 // WCMRPortAudioDevice::activateDevice
736 //! IS CALLED BY PROCESS THREAD
737 //! Sets the device into "active" state. Essentially, opens the PA device.
738 //! If it's an ASIO device it may result in buffer size change in some cases.
740 //**********************************************************************************************
741 void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
745 PaError paErr = paNoError;
747 // if device is not active activate it
750 PaStreamParameters inputParameters, outputParameters;
751 PaStreamParameters *pInS = NULL, *pOutS = NULL;
753 const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
754 const PaHostApiInfo *pHostApiInfo = Pa_GetHostApiInfo(pDeviceInfo->hostApi);
756 inputParameters.device = m_DeviceID;
757 inputParameters.channelCount = (int)m_InputChannels.size();
758 inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
759 inputParameters.suggestedLatency = Pa_GetDeviceInfo(m_DeviceID)->defaultLowInputLatency;
760 inputParameters.hostApiSpecificStreamInfo = 0;
762 if (inputParameters.channelCount)
763 pInS = &inputParameters;
765 outputParameters.device = m_DeviceID;
766 outputParameters.channelCount = (int)m_OutputChannels.size();
767 outputParameters.sampleFormat = paFloat32;
768 outputParameters.suggestedLatency = Pa_GetDeviceInfo(m_DeviceID)->defaultLowOutputLatency;
769 outputParameters.hostApiSpecificStreamInfo = 0;
771 if (outputParameters.channelCount)
772 pOutS = &outputParameters;
774 std::cout << "API::Device" << m_DeviceName << " Opening device stream " << std::endl;
775 std::cout << "Sample rate: " << m_CurrentSamplingRate << " buffer size: " << m_CurrentBufferSize << std::endl;
776 paErr = Pa_OpenStream(&m_PortAudioStream,
779 m_CurrentSamplingRate,
782 WCMRPortAudioDevice::TheCallback,
785 if(paErr == paNoError)
789 m_IgnoreThisDrop = true;
791 if (pHostApiInfo->type == paASIO)
793 m_BufferSizeChangeRequested = 0;
794 m_BufferSizeChangeReported = 0;
795 m_ResetRequested = 0;
797 m_ResyncRequested = 0;
798 m_ResyncReported = 0;
799 PaAsio_SetMessageHook (StaticASIOMessageHook, this);
802 m_ConnectionStatus = DeviceAvailable;
807 //failed, do not update device state
808 std::cout << "Failed to open pa stream stream " << paErr << std::endl;
809 DEBUG_MSG( "Failed to open pa stream stream " << paErr );
810 m_ConnectionStatus = DeviceErrors;
811 m_lastErr = eAsioFailed;
818 SetEvent(m_hActivationDone);
822 //**********************************************************************************************
823 // WCMRPortAudioDevice::deactivateDevice
825 //! IS CALLED BY PROCESS THREAD
826 //! Sets the device into "inactive" state. Essentially, closes the PA device.
828 //**********************************************************************************************
829 void WCMRPortAudioDevice::deactivateDevice (bool callerIsWaiting/*=false*/)
833 PaError paErr = paNoError;
842 if (m_PortAudioStream)
844 //close the stream first
845 std::cout << "API::Device" << m_DeviceName << " Closing device stream" << std::endl;
846 paErr = Pa_CloseStream (m_PortAudioStream);
847 if(paErr == paNoError)
849 m_PortAudioStream = NULL;
852 m_IgnoreThisDrop = true;
853 m_BufferSizeChangeRequested = 0;
854 m_BufferSizeChangeReported = 0;
855 m_ResetRequested = 0;
857 m_ResyncRequested = 0;
858 m_ResyncReported = 0;
859 PaAsio_SetMessageHook (NULL, NULL);
861 //finaly set device state to "not active"
863 m_ConnectionStatus = DeviceDisconnected;
868 //failed, do not update device state
869 std::cout << "Failed to close pa stream stream " << paErr << std::endl;
870 DEBUG_MSG( "Failed to open pa stream stream " << paErr );
871 m_ConnectionStatus = DeviceErrors;
872 m_lastErr = eAsioFailed;
878 SetEvent(m_hDeActivationDone);
882 //**********************************************************************************************
883 // WCMRPortAudioDevice::startStreaming
885 //! Sets the devices into "streaming" state. Calls PA's Start stream routines.
886 //! This roughly corresponds to calling Start on the lower level interface.
888 //**********************************************************************************************
889 void WCMRPortAudioDevice::startStreaming (bool callerIsWaiting/*=false*/)
893 // proceed if the device is not streaming
896 PaError paErr = paNoError;
897 m_StopRequested = false;
900 std::cout << "API::Device" << m_DeviceName << " Starting device stream" << std::endl;
901 paErr = Pa_StartStream( m_PortAudioStream );
903 if(paErr == paNoError)
905 // if the stream was started successfully
906 m_IsStreaming = true;
910 std::cout << "Failed to start PA stream: " << paErr << std::endl;
911 DEBUG_MSG( "Failed to start PA stream: " << paErr );
912 m_lastErr = eGenericErr;
917 SetEvent(m_hStartStreamingDone);
921 //**********************************************************************************************
922 // WCMRPortAudioDevice::stopStreaming
924 //! Sets the devices into "not streaming" state. Calls PA's Stop stream routines.
925 //! This roughly corresponds to calling Stop on the lower level interface.
927 //**********************************************************************************************
928 void WCMRPortAudioDevice::stopStreaming (bool callerIsWaiting/*=false*/)
932 // proceed if the device is streaming
935 PaError paErr = paNoError;
936 m_StopRequested = true;
938 std::cout << "API::Device " << m_DeviceName << " Stopping device stream" << std::endl;
939 paErr = Pa_StopStream( m_PortAudioStream );
941 if(paErr == paNoError)
943 // if the stream was stopped successfully
944 m_IsStreaming = false;
949 std::cout << "Failed to stop PA stream: " << paErr << std::endl;
950 DEBUG_MSG( "Failed to stop PA stream " << paErr );
951 m_lastErr = eGenericErr;
956 SetEvent(m_hStopStreamingDone);
960 //**********************************************************************************************
961 // WCMRPortAudioDevice::resetDevice
963 //! Resets the device, updates device info. Importnat: does PA reinitialization calling
964 //! Pa_terminate/Pa_initialize functions.
970 //**********************************************************************************************
971 void WCMRPortAudioDevice::resetDevice (bool callerIsWaiting /*=false*/ )
973 std::cout << "API::Device" << m_DeviceName << "Reseting device" << std::endl;
976 bool wasStreaming = Streaming();
977 bool wasActive = Active();
979 // Notify the Application about reset
980 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
992 // Cache device buffer size as it might be changed during reset
993 int oldBufferSize = m_CurrentBufferSize;
995 // In ASIO Windows, the buffer size is set from the sound device manufacturer's control panel
996 // Backend should always use preffered buffer size value in this case
997 long minSize, maxSize, preferredSize, granularity;
998 PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
1000 if (paErr == paNoError)
1002 m_CurrentBufferSize = preferredSize;
1006 // if we can't get device buffer sizes, use the first one among supported
1007 if (m_BufferSizes.size() != 0)
1008 m_CurrentBufferSize = m_BufferSizes.front();
1011 // Notify the Application about device setting changes
1012 if (oldBufferSize != m_CurrentBufferSize)
1014 std::cout << "API::Device" << m_DeviceName << " buffer size changed" << std::endl;
1015 int bufferSize = m_CurrentBufferSize;
1016 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
1019 // Activate the device if it was active before
1023 // Resume streaming if the device was streaming before
1026 // Notify the Application to prepare for the stream start
1027 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStartsStreaming);
1031 if (callerIsWaiting)
1032 SetEvent(m_hResetDone);
1038 long WCMRPortAudioDevice::StaticASIOMessageHook (void *pRefCon, long selector, long value, void* message, double* opt)
1042 return ((WCMRPortAudioDevice*)(pRefCon))->ASIOMessageHook (selector, value, message, opt);
1048 long WCMRPortAudioDevice::ASIOMessageHook (long selector, long WCUNUSEDPARAM(value), void* WCUNUSEDPARAM(message), double* WCUNUSEDPARAM(opt))
1052 case kAsioBufferSizeChange:
1053 m_BufferSizeChangeRequested++;
1054 std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- m_BufferSizeChangeRequested" << std::endl;
1055 SetEvent(m_hBufferSizeChangedEvent);
1058 case kAsioResetRequest:
1060 std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioResetRequest" << std::endl;
1061 SetEvent(m_hResetFromDevRequestedEvent);
1064 case kAsioResyncRequest:
1065 std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioResyncRequest" << std::endl;
1066 m_ResyncRequested++;
1069 case kAsioLatenciesChanged:
1070 std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioLatenciesChanged" << std::endl;
1071 SetEvent(m_hBufferSizeChangedEvent);
1072 m_BufferSizeChangeRequested++;
1076 std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioOverload" << std::endl;
1086 //**********************************************************************************************
1087 // WCMRPortAudioDevice::DoIdle
1089 //! A place for doing idle time processing. The other derived classes will probably do something
1094 //! \return eNoErr always.
1096 //**********************************************************************************************
1097 WTErr WCMRPortAudioDevice::DoIdle ()
1099 WTErr retVal = eNoErr;
1101 std::cout << "WCMRPortAudioDevice::DoIdle ()" << std::endl;
1104 m_hUpdateDeviceInfoRequestedEvent,
1105 m_hActivateRequestedEvent,
1106 m_hDeActivateRequestedEvent,
1107 m_hStartStreamingRequestedEvent,
1108 m_hStopStreamingRequestedEvent,
1109 m_hBufferSizeChangedEvent,
1110 m_hSampleRateChangedEvent,
1111 m_hResetRequestedEvent,
1112 m_hResetFromDevRequestedEvent,
1116 const size_t hEventsSize = sizeof(hEvents)/sizeof(hEvents[0]);
1122 DWORD result = WaitForMultipleObjects (hEventsSize, hEvents, FALSE, INFINITE);
1123 result = result - WAIT_OBJECT_0;
1125 if ((result < 0) || (result >= hEventsSize)) {
1126 std::cout << "\t\t\t\t\t\t\tWCMRPortAudioDevice::DoIdle () -> (result < 0) || (result >= hEventsSize):" << result << std::endl;
1127 retVal = eGenericErr;
1131 if (hEvents[result] == m_hExitIdleThread) {
1132 std::cout << "\t\t\t\t\t\t\tWCMRPortAudioDevice::DoIdle () -> m_hExitIdleThread" << result << std::endl;
1137 if (hEvents[result] == m_hUpdateDeviceInfoRequestedEvent) {
1138 std::cout << "\t\t\t\t\t\tupdate requested ..." << std::endl;
1139 updateDeviceInfo(true);
1142 if (hEvents[result] == m_hActivateRequestedEvent) {
1143 std::cout << "\t\t\t\t\t\tactivation requested ..." << std::endl;
1144 activateDevice(true);
1147 if (hEvents[result] == m_hDeActivateRequestedEvent) {
1148 std::cout << "\t\t\t\t\t\tdeactivation requested ..." << std::endl;
1149 deactivateDevice(true);
1152 if (hEvents[result] == m_hStartStreamingRequestedEvent) {
1153 std::cout << "\t\t\t\t\t\tStart stream requested ..." << std::endl;
1154 startStreaming(true);
1157 if (hEvents[result] == m_hStopStreamingRequestedEvent) {
1158 std::cout << "\t\t\t\t\t\tStop stream requested ..." << std::endl;
1159 stopStreaming(true);
1162 if (hEvents[result] == m_hResetRequestedEvent) {
1163 std::cout << "\t\t\t\t\t\treset requested ..." << std::endl;
1167 if (hEvents[result] == m_hResetFromDevRequestedEvent) {
1168 std::cout << "\t\t\t\t\t\treset requested from device..." << std::endl;
1172 if (hEvents[result] == m_hBufferSizeChangedEvent) {
1173 std::cout << "\t\t\t\t\t\tbuffer size changed from device..." << std::endl;
1174 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged);
1177 if (hEvents[result] == m_hSampleRateChangedEvent) {
1178 std::cout << "\t\t\t\t\t\tsample rate changed from device..." << std::endl;
1179 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::SamplingRateChanged);
1189 //**********************************************************************************************
1190 // WCMRPortAudioDevice::SetMonitorChannels
1192 //! Used to set the channels to be used for monitoring.
1194 //! \param leftChannel : Left monitor channel index.
1195 //! \param rightChannel : Right monitor channel index.
1197 //! \return eNoErr always, the derived classes may return appropriate errors.
1199 //**********************************************************************************************
1200 WTErr WCMRPortAudioDevice::SetMonitorChannels (int leftChannel, int rightChannel)
1203 //This will most likely be overridden, the base class simply
1204 //changes the member.
1205 m_LeftMonitorChannel = leftChannel;
1206 m_RightMonitorChannel = rightChannel;
1212 //**********************************************************************************************
1213 // WCMRPortAudioDevice::SetMonitorGain
1215 //! Used to set monitor gain (or atten).
1217 //! \param newGain : The new gain or atten. value to use. Specified as a linear multiplier (not dB)
1219 //! \return eNoErr always, the derived classes may return appropriate errors.
1221 //**********************************************************************************************
1222 WTErr WCMRPortAudioDevice::SetMonitorGain (float newGain)
1225 //This will most likely be overridden, the base class simply
1226 //changes the member.
1228 m_MonitorGain = newGain;
1235 //**********************************************************************************************
1236 // WCMRPortAudioDevice::ShowConfigPanel
1238 //! Used to show device specific config/control panel. Some interfaces may not support it.
1239 //! Some interfaces may require the device to be active before it can display a panel.
1241 //! \param pParam : A device/interface specific parameter, should be the app window handle for ASIO.
1243 //! \return eNoErr always, the derived classes may return errors.
1245 //**********************************************************************************************
1246 WTErr WCMRPortAudioDevice::ShowConfigPanel (void *pParam)
1249 WTErr retVal = eNoErr;
1254 if(Pa_GetHostApiInfo(Pa_GetDeviceInfo(m_DeviceID)->hostApi)->type == paASIO)
1256 // stop and deactivate the device
1257 bool wasStreaming = Streaming();
1259 // show control panel for the device
1260 if (PaAsio_ShowControlPanel (m_DeviceID, pParam) != paNoError)
1261 retVal = eGenericErr;
1262 // reset device to pick up changes
1264 // restore previous state for the device
1278 //*****************************************************************************************************
1279 // WCMRPortAudioDevice::TheCallback
1281 //! The (static) Port Audio Callback function. This is a static member. It calls on the AudioCallback in the
1282 //! WCMRPortAudioDevice to do the real work.
1284 //! \param pInputBuffer: pointer to input buffer.
1285 //! \param pOutputBuffer: pointer to output buffer.
1286 //! \param framesPerBuffer: number of sample frames per buffer.
1287 //! \param pTimeInfo: time info for PaStream callback.
1288 //! \param statusFlags:
1289 //! \param pUserData: pointer to user data, in our case the WCMRPortAudioDevice object.
1291 //! \return true to stop streaming else returns false.
1292 //******************************************************************************************************
1293 int WCMRPortAudioDevice::TheCallback (const void *pInputBuffer, void *pOutputBuffer, unsigned long framesPerBuffer,
1294 const PaStreamCallbackTimeInfo* /*pTimeInfo*/, PaStreamCallbackFlags statusFlags, void *pUserData )
1296 WCMRPortAudioDevice *pMyDevice = (WCMRPortAudioDevice *)pUserData;
1298 return pMyDevice->AudioCallback ((float *)pInputBuffer, (float *)pOutputBuffer, framesPerBuffer,
1299 (statusFlags & (paInputOverflow | paOutputUnderflow)) != 0);
1307 //**********************************************************************************************
1308 // WCMRPortAudioDevice::AudoiCallback
1310 //! Here's where the actual audio processing happens. We call upon all the active connections'
1311 //! sinks to provide data to us which can be put/mixed in the output buffer! Also, we make the
1312 //! input data available to any sources that may call upon us during this time!
1314 //! \param *pInputBuffer : Points to a buffer with recorded data.
1315 //! \param *pOutputBuffer : Points to a buffer to receive playback data.
1316 //! \param framesPerBuffer : Number of sample frames in input and output buffers. Number of channels,
1317 //! which are interleaved, is fixed at Device Open (Active) time. In this implementation,
1318 //! the number of channels are fixed to use the maximum available.
1319 //! \param dropsDetected : True if dropouts were detected in input or output. Can be used to signal the GUI.
1323 //**********************************************************************************************
1324 int WCMRPortAudioDevice::AudioCallback( const float *pInputBuffer, float *pOutputBuffer, unsigned long framesPerBuffer, bool dropsDetected )
1326 UMicroseconds theStartTime;
1331 if (m_IgnoreThisDrop)
1332 m_IgnoreThisDrop = false; //We'll ignore once, just once!
1337 m_pInputData = pInputBuffer;
1339 // VKamyshniy: Is this a right place to call the client???:
1340 struct WCMRAudioDeviceManagerClient::AudioCallbackData audioCallbackData =
1346 theStartTime.MicroSeconds()*1000
1349 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::AudioCallback, (void *)&audioCallbackData );
1351 //Don't try to access after this call returns!
1352 m_pInputData = NULL;
1354 m_SampleCounter += framesPerBuffer;
1356 return m_StopRequested;
1362 //**********************************************************************************************
1363 // WCMRPortAudioDeviceManager::WCMRPortAudioDeviceManager
1365 //! The constructuor, we initialize PA, and build the device list.
1367 //! \param *pTheClient : The manager's client object (which receives notifications).
1368 //! \param interfaceType : The PortAudio interface type to use for this manager - acts as a filter.
1369 //! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true.
1371 //! \return Nothing.
1373 //**********************************************************************************************
1374 WCMRPortAudioDeviceManager::WCMRPortAudioDeviceManager (WCMRAudioDeviceManagerClient *pTheClient,
1375 eAudioDeviceFilter eCurAudioDeviceFilter, bool useMultithreading, bool bNocopy)
1376 : WCMRAudioDeviceManager (pTheClient, eCurAudioDeviceFilter)
1378 , m_UseMultithreading(useMultithreading)
1379 , m_bNoCopyAudioBuffer(bNocopy)
1382 std::cout << "API::PortAudioDeviceManager::PA Device manager constructor" << std::endl;
1384 //Always create the None device first...
1385 m_NoneDevice = new WCMRNativeAudioNoneDevice(this);
1387 WTErr err = generateDeviceListImpl();
1392 timeBeginPeriod (1);
1396 //**********************************************************************************************
1397 // WCMRPortAudioDeviceManager::~WCMRPortAudioDeviceManager
1399 //! It clears the device list, releasing each of the device.
1403 //! \return Nothing.
1405 //**********************************************************************************************
1406 WCMRPortAudioDeviceManager::~WCMRPortAudioDeviceManager()
1410 std::cout << "API::Destroying PortAudioDeviceManager " << std::endl;
1414 delete m_NoneDevice;
1418 //destructors should absorb exceptions, no harm in logging though!!
1419 DEBUG_MSG ("Exception during destructor");
1426 WCMRAudioDevice* WCMRPortAudioDeviceManager::initNewCurrentDeviceImpl(const std::string & deviceName)
1428 destroyCurrentDeviceImpl();
1430 std::cout << "API::PortAudioDeviceManager::initNewCurrentDevice " << deviceName << std::endl;
1431 if (deviceName == m_NoneDevice->DeviceName() )
1433 m_CurrentDevice = m_NoneDevice;
1434 return m_CurrentDevice;
1438 WTErr err = GetDeviceInfoByName(deviceName, devInfo);
1444 std::cout << "API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName << std::endl;
1445 TRACE_MSG ("API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName);
1447 m_CurrentDevice = new WCMRPortAudioDevice (this, devInfo.m_DeviceId, m_UseMultithreading, m_bNoCopyAudioBuffer);
1451 std::cout << "Unabled to create PA Device: " << devInfo.m_DeviceId << std::endl;
1452 DEBUG_MSG ("Unabled to create PA Device: " << devInfo.m_DeviceId);
1456 return m_CurrentDevice;
1460 void WCMRPortAudioDeviceManager::destroyCurrentDeviceImpl()
1462 if (m_CurrentDevice != m_NoneDevice)
1463 delete m_CurrentDevice;
1465 m_CurrentDevice = 0;
1469 WTErr WCMRPortAudioDeviceManager::getDeviceAvailableSampleRates(DeviceID deviceId, std::vector<int>& sampleRates)
1471 sampleRates.clear();
1472 const PaDeviceInfo *pPaDeviceInfo = Pa_GetDeviceInfo(deviceId);
1474 //now find supported sample rates
1475 //following parameters are needed for sample rates validation
1476 PaStreamParameters inputParameters, outputParameters;
1477 PaStreamParameters *pInS = NULL, *pOutS = NULL;
1479 inputParameters.device = deviceId;
1480 inputParameters.channelCount = std::min<int>(2, pPaDeviceInfo->maxInputChannels);
1481 inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
1482 inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
1483 inputParameters.hostApiSpecificStreamInfo = 0;
1485 if (inputParameters.channelCount)
1486 pInS = &inputParameters;
1488 outputParameters.device = deviceId;
1489 outputParameters.channelCount = std::min<int>(2, pPaDeviceInfo->maxOutputChannels);
1490 outputParameters.sampleFormat = paFloat32;
1491 outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
1492 outputParameters.hostApiSpecificStreamInfo = 0;
1494 if (outputParameters.channelCount)
1495 pOutS = &outputParameters;
1497 for(int sr=0; gAllSampleRates[sr] > 0; sr++)
1499 if( paFormatIsSupported == Pa_IsFormatSupported(pInS, pOutS, gAllSampleRates[sr]) )
1501 sampleRates.push_back ((int)gAllSampleRates[sr]);
1507 WTErr WCMRPortAudioDeviceManager::generateDeviceListImpl()
1509 std::cout << "API::PortAudioDeviceManager::Generating device list" << std::endl;
1511 WTErr retVal = eNoErr;
1513 //Initialize PortAudio and ASIO first
1514 PaError paErr = Pa_Initialize();
1516 if (paErr != paNoError)
1518 //ToDo: throw an exception here!
1519 retVal = eSomeThingNotInitailzed;
1523 // lock DeviceInfoVec firts
1524 wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex);
1528 DeviceInfo *pDevInfo = new DeviceInfo(NONE_DEVICE_ID, m_NoneDevice->DeviceName() );
1529 pDevInfo->m_AvailableSampleRates = m_NoneDevice->SamplingRates();
1530 m_DeviceInfoVec.push_back(pDevInfo);
1533 //Get device count...
1534 int numDevices = Pa_GetDeviceCount();
1537 for (int thisDeviceID = 0; thisDeviceID < numDevices; thisDeviceID++)
1539 //if it's of the required type...
1540 const PaDeviceInfo *pPaDeviceInfo = Pa_GetDeviceInfo(thisDeviceID);
1542 if (Pa_GetHostApiInfo(pPaDeviceInfo->hostApi)->type == paASIO)
1544 //build a device object...
1547 std::cout << "API::PortAudioDeviceManager::DeviceID: " << thisDeviceID << ", Device Name: " << pPaDeviceInfo->name << std::endl;
1548 TRACE_MSG ("PA DeviceID: " << thisDeviceID << ", Device Name: " << pPaDeviceInfo->name);
1550 DeviceInfo *pDevInfo = new DeviceInfo(thisDeviceID, pPaDeviceInfo->name);
1553 std::vector<int> availableSampleRates;
1554 WTErr wErr = WCMRPortAudioDeviceManager::getDeviceAvailableSampleRates(thisDeviceID, availableSampleRates);
1558 DEBUG_MSG ("Failed to get device available sample rates. Device ID: " << m_DeviceID);
1560 continue; //proceed to the next device
1563 pDevInfo->m_AvailableSampleRates = availableSampleRates;
1564 pDevInfo->m_MaxInputChannels = pPaDeviceInfo->maxInputChannels;
1565 pDevInfo->m_MaxOutputChannels = pPaDeviceInfo->maxOutputChannels;
1567 //Now check if this device is acceptable according to current input/output settings
1568 bool bRejectDevice = false;
1569 switch(m_eAudioDeviceFilter)
1571 case eInputOnlyDevices:
1572 if (pDevInfo->m_MaxInputChannels != 0)
1574 m_DeviceInfoVec.push_back(pDevInfo);
1578 // Delete unnecesarry device
1579 bRejectDevice = true;
1582 case eOutputOnlyDevices:
1583 if (pDevInfo->m_MaxOutputChannels != 0)
1585 m_DeviceInfoVec.push_back(pDevInfo);
1589 // Delete unnecesarry device
1590 bRejectDevice = true;
1593 case eFullDuplexDevices:
1594 if (pDevInfo->m_MaxInputChannels != 0 && pDevInfo->m_MaxOutputChannels != 0)
1596 m_DeviceInfoVec.push_back(pDevInfo);
1600 // Delete unnecesarry device
1601 bRejectDevice = true;
1606 m_DeviceInfoVec.push_back(pDevInfo);
1612 TRACE_MSG ("API::PortAudioDeviceManager::Device " << pDevInfo->m_DeviceName << "Rejected. \
1613 In Channels = " << pDevInfo->m_MaxInputChannels << "Out Channels = " <<pDevInfo->m_MaxOutputChannels );
1620 std::cout << "API::PortAudioDeviceManager::Unabled to create PA Device: " << std::endl;
1621 DEBUG_MSG ("Unabled to create PA Device: " << thisDeviceID);
1626 //If no devices were found, that's not a good thing!
1627 if (m_DeviceInfoVec.empty() )
1629 std::cout << "API::PortAudioDeviceManager::No matching PortAudio devices were found, total PA devices = " << numDevices << std::endl;
1630 DEBUG_MSG ("No matching PortAudio devices were found, total PA devices = " << numDevices);
1633 //we don't need PA initialized right now
1640 WTErr WCMRPortAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& buffers) const
1642 WTErr retVal = eNoErr;
1643 std::cout << "API::PortAudioDeviceManager::GetBufferSizes: getting buffer size for device: "<< deviceName << std::endl;
1644 //first check if the request has been made for None device
1645 if (deviceName == m_NoneDevice->DeviceName() )
1647 buffers = m_NoneDevice->BufferSizes();
1651 //if we have current device initialized and it's PA device, reset it
1652 //this procedure will reset PA corrently and update info for all PA devices as well
1654 bool paLocalInit = false;
1655 WCMRPortAudioDevice* portaudioDevice = dynamic_cast<WCMRPortAudioDevice*>(m_CurrentDevice);
1656 if (portaudioDevice)
1658 portaudioDevice->ResetDevice();
1662 //initialize PA to get buffers for the device
1668 retVal = GetDeviceInfoByName(deviceName, devInfo);
1670 if (eNoErr == retVal)
1672 //make PA request to get actual device buffer sizes
1673 long minSize, maxSize, preferredSize, granularity;
1674 PaError paErr = PaAsio_GetAvailableBufferSizes(devInfo.m_DeviceId, &minSize, &maxSize, &preferredSize, &granularity);
1676 //for Windows ASIO devices we always use prefferes buffer size ONLY
1677 if (paNoError == paErr )
1679 buffers.push_back(preferredSize);
1683 retVal = eAsioFailed;
1684 std::cout << "API::PortAudioDeviceManager::GetBufferSizes: error: " << paErr << " getting buffer size fo device: "<< deviceName << std::endl;
1689 std::cout << "API::PortAudioDeviceManager::GetBufferSizes: Device not found: "<< deviceName << std::endl;
1692 //deinitialize PA now