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"
17 #include "IncludeWindows.h"
22 ///< Supported Sample rates
23 static const double gAllSampleRates[] =
25 44100.0, 48000.0, 88200.0, 96000.0, -1 /* negative terminated list */
30 ///< Default Supported Buffer Sizes.
31 static const int gAllBufferSizes[] =
33 32, 64, 96, 128, 192, 256, 512, 1024, 2048
38 static const int DEFAULT_SR = 44100;
39 ///< The default buffer size.
40 static const int DEFAULT_BUFFERSIZE = 128;
42 static const int NONE_DEVICE_ID = -1;
44 ///< Number of stalls to wait before notifying user...
45 static const int NUM_STALLS_FOR_NOTIFICATION = 100; // 100 corresponds to 100 x 42 ms idle timer - about 4 seconds.
46 static const int CHANGE_CHECK_COUNTER_PERIOD = 100; // 120 corresponds to 120 x 42 ms idle timer - about 4 seconds.
48 #define HUNDRED_NANO_TO_MILLI_CONSTANT 10000
49 #define CONSUMPTION_CALCULATION_INTERVAL 500 // Milli Seconds
52 // This wrapper is used to adapt device DoIdle method as entry point for MS thread
53 DWORD WINAPI WCMRPortAudioDevice::__DoIdle__(LPVOID lpThreadParameter)
55 WCMRPortAudioDevice* pDevice = (WCMRPortAudioDevice*)lpThreadParameter;
60 //**********************************************************************************************
61 // WCMRPortAudioDevice::WCMRPortAudioDevice
63 //! Constructor for the audio device. Opens the PA device
64 //! and gets information about the device.
65 //! Starts the thread which will process requests to this device
66 //! such as determining supported sampling rates, buffer sizes, and channel counts.
68 //! \param *pManager : The audio device manager that's managing this device.
69 //! \param deviceID : The port audio device ID.
70 //! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true.
74 //**********************************************************************************************
75 WCMRPortAudioDevice::WCMRPortAudioDevice (WCMRPortAudioDeviceManager *pManager, unsigned int deviceID, bool useMultithreading, bool bNoCopy) :
76 WCMRNativeAudioDevice (pManager, useMultithreading, bNoCopy)
78 , m_BufferSizeChangeRequested (0)
79 , m_BufferSizeChangeReported (0)
80 , m_ResetRequested (0)
82 , m_ResyncRequested (0)
83 , m_ResyncReported (0)
86 , m_IgnoreThisDrop(true)
87 , m_hDeviceProcessingThread(NULL)
88 , m_DeviceProcessingThreadID(0)
89 , m_hUpdateDeviceInfoRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
90 , m_hUpdateDeviceInfoDone(CreateEvent(NULL, FALSE, FALSE, NULL))
91 , m_hActivateRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
92 , m_hActivationDone(CreateEvent(NULL, FALSE, FALSE, NULL))
93 , m_hDeActivateRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
94 , m_hDeActivationDone(CreateEvent(NULL, FALSE, FALSE, NULL))
95 , m_hStartStreamingRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
96 , m_hStartStreamingDone(CreateEvent(NULL, FALSE, FALSE, NULL))
97 , m_hStopStreamingRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
98 , m_hStopStreamingDone(CreateEvent(NULL, FALSE, FALSE, NULL))
99 , m_hResetRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
100 , m_hResetDone(CreateEvent(NULL, FALSE, FALSE, NULL))
101 , m_hResetFromDevRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
102 , m_hBufferSizeChangedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
103 , m_hSampleRateChangedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
104 , m_hExitIdleThread(CreateEvent(NULL, FALSE, FALSE, NULL))
105 , m_hDeviceInitialized(CreateEvent(NULL, FALSE, FALSE, NULL))
110 //Set initial device info...
111 m_DeviceID = deviceID;
112 m_PortAudioStream = NULL;
113 m_CurrentSamplingRate = DEFAULT_SR;
114 m_CurrentBufferSize = DEFAULT_BUFFERSIZE;
115 m_StopRequested = true;
118 //initialize device processing thread
119 //the divice become alive and now is able to process requests
120 m_hDeviceProcessingThread = CreateThread( NULL, 0, __DoIdle__, (LPVOID)this, 0, &m_DeviceProcessingThreadID );
122 if (!m_hDeviceProcessingThread)
124 DEBUG_MSG("API::Device " << m_DeviceName << " cannot create processing thread");
128 WaitForSingleObject(m_hDeviceInitialized, INFINITE);
130 if (ConnectionStatus() == DeviceErrors)
137 void WCMRPortAudioDevice::initDevice()
139 // Initialize COM for this thread
140 std::cout << "API::Device " << m_DeviceID << " initializing COM" << std::endl;
142 if (S_OK == CoInitialize(NULL) )
149 //should use a valid current SR...
150 if (m_SamplingRates.size())
152 //see if the current sr is present in the sr list, if not, use the first one!
153 std::vector<int>::iterator intIter = find(m_SamplingRates.begin(), m_SamplingRates.end(), m_CurrentSamplingRate);
154 if (intIter == m_SamplingRates.end())
156 //not found... use the first one
157 m_CurrentSamplingRate = m_SamplingRates[0];
161 std::cout << "API::Device " << m_DeviceName << " Device does not support any sample rate of ours" << std::endl;
163 //should use a valid current buffer size
164 if (m_BufferSizes.size())
166 //see if the current sr is present in the buffersize list, if not, use the first one!
167 std::vector<int>::iterator intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), m_CurrentBufferSize);
168 if (intIter == m_BufferSizes.end())
170 //not found... use the first one
171 m_CurrentBufferSize = m_BufferSizes[0];
175 //build our input/output level lists
176 for (unsigned int currentChannel = 0; currentChannel < m_InputChannels.size(); currentChannel++)
178 m_InputLevels.push_back (0.0);
181 //build our input/output level lists
182 for (unsigned int currentChannel = 0; currentChannel < m_OutputChannels.size(); currentChannel++)
184 m_OutputLevels.push_back (0.0);
187 std::cout << "API::Device " << m_DeviceName << " Device has been initialized" << std::endl;
188 m_ConnectionStatus = DeviceDisconnected;
193 /*Replace with debug trace*/std::cout << "API::Device " << m_DeviceName << " cannot initialize COM" << std::endl;
194 DEBUG_MSG("Device " << m_DeviceName << " cannot initialize COM");
195 m_ConnectionStatus = DeviceErrors;
196 m_lastErr = eSomeThingNotInitailzed;
197 SetEvent(m_hExitIdleThread);
200 SetEvent(m_hDeviceInitialized);
203 void WCMRPortAudioDevice::terminateDevice()
205 std::cout << "API::Device " << m_DeviceName << " Terminating DEVICE" << std::endl;
207 //If device is streaming, need to stop it!
213 //If device is active (meaning stream is open) we need to close it.
219 std::cout << "API::Device " << m_DeviceName << " Terminating PA" << std::endl;
226 //**********************************************************************************************
227 // WCMRPortAudioDevice::~WCMRPortAudioDevice
229 //! Destructor for the audio device. The base release all the connections that were created, if
230 //! they have not been already destroyed! Here we simply stop streaming, and close device
231 //! handles if necessary.
237 //**********************************************************************************************
238 WCMRPortAudioDevice::~WCMRPortAudioDevice ()
242 std::cout << "API::Destroying Device Instance: " << DeviceName() << std::endl;
245 //Stop deviceprocessing thread
246 SignalObjectAndWait(m_hExitIdleThread, m_hDeviceProcessingThread, INFINITE, false);
248 std::cout << "API::Device " << m_DeviceName << " Processing Thread is stopped" << std::endl;
250 CloseHandle(m_hDeviceProcessingThread);
252 //Now it's safe to free all event handlers
253 CloseHandle(m_hUpdateDeviceInfoRequestedEvent);
254 CloseHandle(m_hUpdateDeviceInfoDone);
255 CloseHandle(m_hActivateRequestedEvent);
256 CloseHandle(m_hActivationDone);
257 CloseHandle(m_hDeActivateRequestedEvent);
258 CloseHandle(m_hDeActivationDone);
259 CloseHandle(m_hStartStreamingRequestedEvent);
260 CloseHandle(m_hStartStreamingDone);
261 CloseHandle(m_hStopStreamingRequestedEvent);
262 CloseHandle(m_hStopStreamingDone);
263 CloseHandle(m_hResetRequestedEvent);
264 CloseHandle(m_hResetDone);
265 CloseHandle(m_hResetFromDevRequestedEvent);
266 CloseHandle(m_hBufferSizeChangedEvent);
267 CloseHandle(m_hSampleRateChangedEvent);
268 CloseHandle(m_hExitIdleThread);
269 CloseHandle(m_hDeviceInitialized);
273 //destructors should absorb exceptions, no harm in logging though!!
274 DEBUG_MSG ("Exception during destructor");
279 WTErr WCMRPortAudioDevice::UpdateDeviceInfo ()
281 std::cout << "API::Device (ID:)" << m_DeviceID << " Updating device info" << std::endl;
283 SignalObjectAndWait(m_hUpdateDeviceInfoRequestedEvent, m_hUpdateDeviceInfoDone, INFINITE, false);
289 //**********************************************************************************************
290 // WCMRPortAudioDevice::updateDeviceInfo
292 //! Must be called be device processing thread
293 //! Updates Device Information about channels, sampling rates, buffer sizes.
297 //**********************************************************************************************
298 void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/)
303 const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
306 m_DeviceName = pDeviceInfo->name;
308 std::cout << "API::Device " << m_DeviceName << " Getting device info " << std::endl;
310 //following parameters are needed opening test stream and for sample rates validation
311 PaStreamParameters inputParameters, outputParameters;
312 PaStreamParameters *pInS = NULL, *pOutS = NULL;
314 inputParameters.device = m_DeviceID;
315 inputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxInputChannels);
316 inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
317 inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
318 inputParameters.hostApiSpecificStreamInfo = 0;
320 if (inputParameters.channelCount)
321 pInS = &inputParameters;
323 outputParameters.device = m_DeviceID;
324 outputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxOutputChannels);
325 outputParameters.sampleFormat = paFloat32;
326 outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
327 outputParameters.hostApiSpecificStreamInfo = 0;
329 if (outputParameters.channelCount)
330 pOutS = &outputParameters;
332 std::cout << "API::Device" << m_DeviceName << " Updating sample rates " << std::endl;
333 ////////////////////////////////////////////////////////////////////////////////////
334 //update list of supported SRs...
335 m_SamplingRates.clear();
337 // now iterate through our standard SRs and check if they are supported by device
338 // store them for this device
339 for(int sr=0; gAllSampleRates[sr] > 0; sr++)
341 PaError err = Pa_IsFormatSupported(pInS, pOutS, gAllSampleRates[sr]);
342 if( err == paFormatIsSupported)
344 m_SamplingRates.push_back ((int)gAllSampleRates[sr]);
348 std::cout << "API::Device" << m_DeviceName << " Updating buffer sizes" << std::endl;
349 ///////////////////////////////////////////////////////////////////////////////////
350 //update buffer sizes
351 m_BufferSizes.clear();
352 bool useDefaultBuffers = true;
353 PaError paErr = paNoError;
355 //sometimes devices change buffer size if sample rate changes
356 //it updates buffer size during stream opening
357 //we need to find out how device would behave with current sample rate
358 //try opening test stream to load device driver for current sample rate and buffer size
359 //(skip this step if the device is Active)
362 if (paNoError != testStateValidness(m_CurrentSamplingRate, m_CurrentBufferSize) )
364 //buffer size did change
368 // test validness with current sample rate and device prefered buffer size
369 paErr = testStateValidness(m_CurrentSamplingRate, 0);
373 if (paErr == paNoError)
375 // In ASIO Windows, the buffer size is set from the sound device manufacturer's control panel
376 long minSize, maxSize, preferredSize, granularity;
377 paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
379 if (paErr == paNoError)
381 std::cout << "API::Device " << m_DeviceName << " Buffers: " << minSize << " " << maxSize << " " << preferredSize << std::endl;
383 m_BufferSizes.push_back (preferredSize);
384 useDefaultBuffers = false;
388 std::cout << "API::Device" << m_DeviceName << " Preffered buffer size is not supported" << std::endl;
393 std::cout << "API::Device" << m_DeviceName << " Device does not start with sample rate: "<< m_CurrentSamplingRate << " and default buffer size" << std::endl;
396 if (useDefaultBuffers)
398 std::cout << "API::Device" << m_DeviceName << " Using default buffer sizes " <<std::endl;
399 for(int bsize=0; bsize < (sizeof(gAllBufferSizes)/sizeof(gAllBufferSizes[0])); bsize++)
400 m_BufferSizes.push_back (gAllBufferSizes[bsize]);
403 /////////////////////////////////////////////////////////////////////////////////////////
404 //update channels info
406 int maxInputChannels = pDeviceInfo->maxInputChannels;
407 int maxOutputChannels = pDeviceInfo->maxOutputChannels;
409 //Update input channels
410 m_InputChannels.clear();
411 for (int channel = 0; channel < maxInputChannels; channel++)
413 std::stringstream chNameStream;
414 //A better implementation would be to retrieve the names from ASIO or CoreAudio interfaces
415 chNameStream << "Input " << (channel+1);
416 m_InputChannels.push_back (chNameStream.str());
420 //Update output channels
421 m_OutputChannels.clear();
422 for (int channel = 0; channel < maxOutputChannels; channel++)
424 std::stringstream chNameStream;
425 //A better implementation would be to retrieve the names from ASIO or CoreAudio interfaces
426 chNameStream << "Output " << (channel+1);
427 m_OutputChannels.push_back (chNameStream.str());
431 std::cout << "API::Device" << m_DeviceName << " Device info update has been finished" << std::endl;
434 SetEvent(m_hUpdateDeviceInfoDone);
438 PaError WCMRPortAudioDevice::testStateValidness(int sampleRate, int bufferSize)
440 PaError paErr = paNoError;
443 const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
445 //following parameters are needed opening test stream and for sample rates validation
446 PaStreamParameters inputParameters, outputParameters;
447 PaStreamParameters *pInS = NULL, *pOutS = NULL;
449 inputParameters.device = m_DeviceID;
450 inputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxInputChannels);
451 inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
452 inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
453 inputParameters.hostApiSpecificStreamInfo = 0;
455 if (inputParameters.channelCount)
456 pInS = &inputParameters;
458 outputParameters.device = m_DeviceID;
459 outputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxOutputChannels);
460 outputParameters.sampleFormat = paFloat32;
461 outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
462 outputParameters.hostApiSpecificStreamInfo = 0;
464 if (outputParameters.channelCount)
465 pOutS = &outputParameters;
467 PaStream *portAudioStream = NULL;
469 //sometimes devices change buffer size if sample rate changes
470 //it updates buffer size during stream opening
471 //we need to find out how device would behave with current sample rate
472 //try opening test stream to load device driver for current sample rate and buffer size
473 paErr = Pa_OpenStream (&portAudioStream, pInS, pOutS, m_CurrentSamplingRate, m_CurrentBufferSize, paDitherOff, NULL, NULL);
478 Pa_CloseStream (portAudioStream);
479 portAudioStream = NULL;
486 //**********************************************************************************************
487 // WCMRPortAudioDevice::CurrentSamplingRate
489 //! The device's current sampling rate. This may be overridden, if the device needs to
490 //! query the driver for the current rate.
494 //! \return The device's current sampling rate. -1 on error.
496 //**********************************************************************************************
497 int WCMRPortAudioDevice::CurrentSamplingRate ()
500 //ToDo: Perhaps for ASIO devices that are active, we should retrive the SR from the device...
502 return (m_CurrentSamplingRate);
506 WTErr WCMRPortAudioDevice::SetActive (bool newState)
508 if (newState == true)
510 std::cout << "API::Device " << m_DeviceName << " Activation requested" << std::endl;
511 SignalObjectAndWait(m_hActivateRequestedEvent, m_hActivationDone, INFINITE, false);
515 std::cout << "API::Device " << m_DeviceName << " Deactivation requested" << std::endl;
516 SignalObjectAndWait(m_hDeActivateRequestedEvent, m_hDeActivationDone, INFINITE, false);
519 if (newState == Active() )
526 WTErr WCMRPortAudioDevice::SetStreaming (bool newState)
528 if (newState == true)
530 std::cout << "API::Device " << m_DeviceName << " Stream start requested" << std::endl;
531 SignalObjectAndWait(m_hStartStreamingRequestedEvent, m_hStartStreamingDone, INFINITE, false);
535 std::cout << "API::Device " << m_DeviceName << " Stream stop requested" << std::endl;
536 SignalObjectAndWait(m_hStopStreamingRequestedEvent, m_hStopStreamingDone, INFINITE, false);
539 if (newState == Streaming() )
546 WTErr WCMRPortAudioDevice::ResetDevice()
548 std::cout << "API::Device: " << m_DeviceName << " Reseting device" << std::endl;
550 SignalObjectAndWait(m_hResetRequestedEvent, m_hResetDone, INFINITE, false);
552 if (ConnectionStatus() == DeviceErrors)
561 //**********************************************************************************************
562 // WCMRPortAudioDevice::SetCurrentSamplingRate
564 //! Change the sampling rate to be used by the device.
566 //! \param newRate : The rate to use (samples per sec).
568 //! \return eNoErr always. The derived classes may return error codes.
570 //**********************************************************************************************
571 WTErr WCMRPortAudioDevice::SetCurrentSamplingRate (int newRate)
574 std::vector<int>::iterator intIter;
575 WTErr retVal = eNoErr;
577 //changes the status.
578 int oldRate = CurrentSamplingRate();
579 bool oldActive = Active();
581 //no change, nothing to do
582 if (oldRate == newRate)
585 //see if this is one of our supported rates...
586 intIter = find(m_SamplingRates.begin(), m_SamplingRates.end(), newRate);
588 if (intIter == m_SamplingRates.end())
590 //Can't change, perhaps use an "invalid param" type of error
591 retVal = eCommandLineParameter;
597 //Can't change, perhaps use an "in use" type of error
598 retVal = eGenericErr;
604 //Deactivate it for the change...
609 m_CurrentSamplingRate = newRate;
611 // Before reactivating the device: opening stream we should try getting buffer size update from the device
612 // because for new sampling rate some devices may change buffer size as well
613 int oldBufferSize = m_CurrentBufferSize;
615 retVal = ResetDevice();
618 if (oldActive && retVal == eNoErr)
620 retVal = SetActive (true);
623 if (retVal != eNoErr)
625 //revert changes if the device was not activated
626 m_CurrentSamplingRate = oldRate;
627 m_CurrentBufferSize = oldBufferSize;
628 int bufferSize = m_CurrentBufferSize;
629 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
630 retVal = eCommandLineParameter;
637 //**********************************************************************************************
638 // WCMRPortAudioDevice::CurrentBufferSize
640 //! The device's current buffer size in use. This may be overridden, if the device needs to
641 //! query the driver for the current size.
645 //! \return The device's current buffer size. 0 on error.
647 //**********************************************************************************************
648 int WCMRPortAudioDevice::CurrentBufferSize ()
650 return m_CurrentBufferSize;
654 //**********************************************************************************************
655 // WCMRPortAudioDevice::SetCurrentBufferSize
657 //! Change the buffer size to be used by the device. This will most likely be overridden,
658 //! the base class simply updates the member variable.
660 //! \param newSize : The buffer size to use (in sample-frames)
662 //! \return eNoErr always. The derived classes may return error codes.
664 //**********************************************************************************************
665 WTErr WCMRPortAudioDevice::SetCurrentBufferSize (int newSize)
668 WTErr retVal = eNoErr;
669 std::vector<int>::iterator intIter;
671 //changes the status.
672 int oldSize = CurrentBufferSize();
673 bool oldActive = Active();
675 //same size, nothing to do.
676 if (oldSize == newSize)
679 //see if this is one of our supported rates...
680 intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), newSize);
681 if (intIter == m_BufferSizes.end())
683 //Can't change, perhaps use an "invalid param" type of error
684 retVal = eCommandLineParameter;
690 //Can't change, perhaps use an "in use" type of error
691 retVal = eGenericErr;
697 //Deactivate it for the change...
702 m_CurrentBufferSize = newSize;
707 retVal = SetActive (true);
714 //**********************************************************************************************
715 // WCMRPortAudioDevice::ConnectionStatus
717 //! Retrieves the device's current connection status. This will most likely be overridden,
718 //! in case some driver communication is required to query the status.
722 //! \return A ConnectionStates value.
724 //**********************************************************************************************
725 WCMRPortAudioDevice::ConnectionStates WCMRPortAudioDevice::ConnectionStatus ()
728 //ToDo: May want to do something more to extract the actual status!
729 return (m_ConnectionStatus);
734 //**********************************************************************************************
735 // WCMRPortAudioDevice::activateDevice
737 //! IS CALLED BY PROCESS THREAD
738 //! Sets the device into "active" state. Essentially, opens the PA device.
739 //! If it's an ASIO device it may result in buffer size change in some cases.
741 //**********************************************************************************************
742 void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
746 PaError paErr = paNoError;
748 // if device is not active activate it
751 PaStreamParameters inputParameters, outputParameters;
752 PaStreamParameters *pInS = NULL, *pOutS = NULL;
754 const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
755 const PaHostApiInfo *pHostApiInfo = Pa_GetHostApiInfo(pDeviceInfo->hostApi);
757 inputParameters.device = m_DeviceID;
758 inputParameters.channelCount = (int)m_InputChannels.size();
759 inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
760 inputParameters.suggestedLatency = Pa_GetDeviceInfo(m_DeviceID)->defaultLowInputLatency;
761 inputParameters.hostApiSpecificStreamInfo = 0;
763 if (inputParameters.channelCount)
764 pInS = &inputParameters;
766 outputParameters.device = m_DeviceID;
767 outputParameters.channelCount = (int)m_OutputChannels.size();
768 outputParameters.sampleFormat = paFloat32;
769 outputParameters.suggestedLatency = Pa_GetDeviceInfo(m_DeviceID)->defaultLowOutputLatency;
770 outputParameters.hostApiSpecificStreamInfo = 0;
772 if (outputParameters.channelCount)
773 pOutS = &outputParameters;
775 std::cout << "API::Device" << m_DeviceName << " Opening device stream " << std::endl;
776 std::cout << "Sample rate: " << m_CurrentSamplingRate << " buffer size: " << m_CurrentBufferSize << std::endl;
777 paErr = Pa_OpenStream(&m_PortAudioStream,
780 m_CurrentSamplingRate,
783 WCMRPortAudioDevice::TheCallback,
786 if(paErr == paNoError)
790 m_IgnoreThisDrop = true;
792 if (pHostApiInfo->type == paASIO)
794 m_BufferSizeChangeRequested = 0;
795 m_BufferSizeChangeReported = 0;
796 m_ResetRequested = 0;
798 m_ResyncRequested = 0;
799 m_ResyncReported = 0;
800 PaAsio_SetMessageHook (StaticASIOMessageHook, this);
803 m_ConnectionStatus = DeviceAvailable;
808 //failed, do not update device state
809 std::cout << "Failed to open pa stream stream " << paErr << std::endl;
810 DEBUG_MSG( "Failed to open pa stream stream " << paErr );
811 m_ConnectionStatus = DeviceErrors;
812 m_lastErr = eAsioFailed;
819 SetEvent(m_hActivationDone);
823 //**********************************************************************************************
824 // WCMRPortAudioDevice::deactivateDevice
826 //! IS CALLED BY PROCESS THREAD
827 //! Sets the device into "inactive" state. Essentially, closes the PA device.
829 //**********************************************************************************************
830 void WCMRPortAudioDevice::deactivateDevice (bool callerIsWaiting/*=false*/)
834 PaError paErr = paNoError;
843 if (m_PortAudioStream)
845 //close the stream first
846 std::cout << "API::Device" << m_DeviceName << " Closing device stream" << std::endl;
847 paErr = Pa_CloseStream (m_PortAudioStream);
848 if(paErr == paNoError)
850 m_PortAudioStream = NULL;
853 m_IgnoreThisDrop = true;
854 m_BufferSizeChangeRequested = 0;
855 m_BufferSizeChangeReported = 0;
856 m_ResetRequested = 0;
858 m_ResyncRequested = 0;
859 m_ResyncReported = 0;
860 PaAsio_SetMessageHook (NULL, NULL);
862 //finaly set device state to "not active"
864 m_ConnectionStatus = DeviceDisconnected;
869 //failed, do not update device state
870 std::cout << "Failed to close pa stream stream " << paErr << std::endl;
871 DEBUG_MSG( "Failed to open pa stream stream " << paErr );
872 m_ConnectionStatus = DeviceErrors;
873 m_lastErr = eAsioFailed;
879 SetEvent(m_hDeActivationDone);
883 //**********************************************************************************************
884 // WCMRPortAudioDevice::startStreaming
886 //! Sets the devices into "streaming" state. Calls PA's Start stream routines.
887 //! This roughly corresponds to calling Start on the lower level interface.
889 //**********************************************************************************************
890 void WCMRPortAudioDevice::startStreaming (bool callerIsWaiting/*=false*/)
894 // proceed if the device is not streaming
897 PaError paErr = paNoError;
898 m_StopRequested = false;
901 std::cout << "API::Device" << m_DeviceName << " Starting device stream" << std::endl;
902 paErr = Pa_StartStream( m_PortAudioStream );
904 if(paErr == paNoError)
906 // if the stream was started successfully
907 m_IsStreaming = true;
911 std::cout << "Failed to start PA stream: " << paErr << std::endl;
912 DEBUG_MSG( "Failed to start PA stream: " << paErr );
913 m_lastErr = eGenericErr;
918 SetEvent(m_hStartStreamingDone);
922 //**********************************************************************************************
923 // WCMRPortAudioDevice::stopStreaming
925 //! Sets the devices into "not streaming" state. Calls PA's Stop stream routines.
926 //! This roughly corresponds to calling Stop on the lower level interface.
928 //**********************************************************************************************
929 void WCMRPortAudioDevice::stopStreaming (bool callerIsWaiting/*=false*/)
933 // proceed if the device is streaming
936 PaError paErr = paNoError;
937 m_StopRequested = true;
939 std::cout << "API::Device " << m_DeviceName << " Stopping device stream" << std::endl;
940 paErr = Pa_StopStream( m_PortAudioStream );
942 if(paErr == paNoError)
944 // if the stream was stopped successfully
945 m_IsStreaming = false;
950 std::cout << "Failed to stop PA stream: " << paErr << std::endl;
951 DEBUG_MSG( "Failed to stop PA stream " << paErr );
952 m_lastErr = eGenericErr;
957 SetEvent(m_hStopStreamingDone);
961 //**********************************************************************************************
962 // WCMRPortAudioDevice::resetDevice
964 //! Resets the device, updates device info. Importnat: does PA reinitialization calling
965 //! Pa_terminate/Pa_initialize functions.
971 //**********************************************************************************************
972 void WCMRPortAudioDevice::resetDevice (bool callerIsWaiting /*=false*/ )
974 std::cout << "API::Device" << m_DeviceName << "Reseting device" << std::endl;
977 bool wasStreaming = Streaming();
978 bool wasActive = Active();
980 // Notify the Application about reset
981 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
993 // Cache device buffer size as it might be changed during reset
994 int oldBufferSize = m_CurrentBufferSize;
996 // In ASIO Windows, the buffer size is set from the sound device manufacturer's control panel
997 // Backend should always use preffered buffer size value in this case
998 long minSize, maxSize, preferredSize, granularity;
999 PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
1001 if (paErr == paNoError)
1003 m_CurrentBufferSize = preferredSize;
1007 // if we can't get device buffer sizes, use the first one among supported
1008 if (m_BufferSizes.size() != 0)
1009 m_CurrentBufferSize = m_BufferSizes.front();
1012 // Notify the Application about device setting changes
1013 if (oldBufferSize != m_CurrentBufferSize)
1015 std::cout << "API::Device" << m_DeviceName << " buffer size changed" << std::endl;
1016 int bufferSize = m_CurrentBufferSize;
1017 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
1020 // Activate the device if it was active before
1024 // Resume streaming if the device was streaming before
1027 // Notify the Application to prepare for the stream start
1028 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStartsStreaming);
1032 if (callerIsWaiting)
1033 SetEvent(m_hResetDone);
1037 #ifdef PLATFORM_WINDOWS
1039 long WCMRPortAudioDevice::StaticASIOMessageHook (void *pRefCon, long selector, long value, void* message, double* opt)
1043 return ((WCMRPortAudioDevice*)(pRefCon))->ASIOMessageHook (selector, value, message, opt);
1049 long WCMRPortAudioDevice::ASIOMessageHook (long selector, long WCUNUSEDPARAM(value), void* WCUNUSEDPARAM(message), double* WCUNUSEDPARAM(opt))
1053 case kAsioBufferSizeChange:
1054 m_BufferSizeChangeRequested++;
1055 std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- m_BufferSizeChangeRequested" << std::endl;
1056 SetEvent(m_hBufferSizeChangedEvent);
1059 case kAsioResetRequest:
1061 std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioResetRequest" << std::endl;
1062 SetEvent(m_hResetFromDevRequestedEvent);
1065 case kAsioResyncRequest:
1066 std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioResyncRequest" << std::endl;
1067 m_ResyncRequested++;
1070 case kAsioLatenciesChanged:
1071 std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioLatenciesChanged" << std::endl;
1072 SetEvent(m_hBufferSizeChangedEvent);
1073 m_BufferSizeChangeRequested++;
1077 std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioOverload" << std::endl;
1087 //**********************************************************************************************
1088 // WCMRPortAudioDevice::DoIdle
1090 //! A place for doing idle time processing. The other derived classes will probably do something
1095 //! \return eNoErr always.
1097 //**********************************************************************************************
1098 WTErr WCMRPortAudioDevice::DoIdle ()
1100 WTErr retVal = eNoErr;
1102 std::cout << "WCMRPortAudioDevice::DoIdle ()" << std::endl;
1105 m_hUpdateDeviceInfoRequestedEvent,
1106 m_hActivateRequestedEvent,
1107 m_hDeActivateRequestedEvent,
1108 m_hStartStreamingRequestedEvent,
1109 m_hStopStreamingRequestedEvent,
1110 m_hBufferSizeChangedEvent,
1111 m_hSampleRateChangedEvent,
1112 m_hResetRequestedEvent,
1113 m_hResetFromDevRequestedEvent,
1117 const size_t hEventsSize = sizeof(hEvents)/sizeof(hEvents[0]);
1123 DWORD result = WaitForMultipleObjects (hEventsSize, hEvents, FALSE, INFINITE);
1124 result = result - WAIT_OBJECT_0;
1126 if ((result < 0) || (result >= hEventsSize)) {
1127 std::cout << "\t\t\t\t\t\t\tWCMRPortAudioDevice::DoIdle () -> (result < 0) || (result >= hEventsSize):" << result << std::endl;
1128 retVal = eGenericErr;
1132 if (hEvents[result] == m_hExitIdleThread) {
1133 std::cout << "\t\t\t\t\t\t\tWCMRPortAudioDevice::DoIdle () -> m_hExitIdleThread" << result << std::endl;
1138 if (hEvents[result] == m_hUpdateDeviceInfoRequestedEvent) {
1139 std::cout << "\t\t\t\t\t\tupdate requested ..." << std::endl;
1140 updateDeviceInfo(true);
1143 if (hEvents[result] == m_hActivateRequestedEvent) {
1144 std::cout << "\t\t\t\t\t\tactivation requested ..." << std::endl;
1145 activateDevice(true);
1148 if (hEvents[result] == m_hDeActivateRequestedEvent) {
1149 std::cout << "\t\t\t\t\t\tdeactivation requested ..." << std::endl;
1150 deactivateDevice(true);
1153 if (hEvents[result] == m_hStartStreamingRequestedEvent) {
1154 std::cout << "\t\t\t\t\t\tStart stream requested ..." << std::endl;
1155 startStreaming(true);
1158 if (hEvents[result] == m_hStopStreamingRequestedEvent) {
1159 std::cout << "\t\t\t\t\t\tStop stream requested ..." << std::endl;
1160 stopStreaming(true);
1163 if (hEvents[result] == m_hResetRequestedEvent) {
1164 std::cout << "\t\t\t\t\t\treset requested ..." << std::endl;
1168 if (hEvents[result] == m_hResetFromDevRequestedEvent) {
1169 std::cout << "\t\t\t\t\t\treset requested from device..." << std::endl;
1173 if (hEvents[result] == m_hBufferSizeChangedEvent) {
1174 std::cout << "\t\t\t\t\t\tbuffer size changed from device..." << std::endl;
1175 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged);
1178 if (hEvents[result] == m_hSampleRateChangedEvent) {
1179 std::cout << "\t\t\t\t\t\tsample rate changed from device..." << std::endl;
1180 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::SamplingRateChanged);
1190 //**********************************************************************************************
1191 // WCMRPortAudioDevice::SetMonitorChannels
1193 //! Used to set the channels to be used for monitoring.
1195 //! \param leftChannel : Left monitor channel index.
1196 //! \param rightChannel : Right monitor channel index.
1198 //! \return eNoErr always, the derived classes may return appropriate errors.
1200 //**********************************************************************************************
1201 WTErr WCMRPortAudioDevice::SetMonitorChannels (int leftChannel, int rightChannel)
1204 //This will most likely be overridden, the base class simply
1205 //changes the member.
1206 m_LeftMonitorChannel = leftChannel;
1207 m_RightMonitorChannel = rightChannel;
1213 //**********************************************************************************************
1214 // WCMRPortAudioDevice::SetMonitorGain
1216 //! Used to set monitor gain (or atten).
1218 //! \param newGain : The new gain or atten. value to use. Specified as a linear multiplier (not dB)
1220 //! \return eNoErr always, the derived classes may return appropriate errors.
1222 //**********************************************************************************************
1223 WTErr WCMRPortAudioDevice::SetMonitorGain (float newGain)
1226 //This will most likely be overridden, the base class simply
1227 //changes the member.
1229 m_MonitorGain = newGain;
1236 //**********************************************************************************************
1237 // WCMRPortAudioDevice::ShowConfigPanel
1239 //! Used to show device specific config/control panel. Some interfaces may not support it.
1240 //! Some interfaces may require the device to be active before it can display a panel.
1242 //! \param pParam : A device/interface specific parameter, should be the app window handle for ASIO.
1244 //! \return eNoErr always, the derived classes may return errors.
1246 //**********************************************************************************************
1247 WTErr WCMRPortAudioDevice::ShowConfigPanel (void *pParam)
1250 WTErr retVal = eNoErr;
1254 #ifdef PLATFORM_WINDOWS
1255 if(Pa_GetHostApiInfo(Pa_GetDeviceInfo(m_DeviceID)->hostApi)->type == paASIO)
1257 // stop and deactivate the device
1258 bool wasStreaming = Streaming();
1260 // show control panel for the device
1261 if (PaAsio_ShowControlPanel (m_DeviceID, pParam) != paNoError)
1262 retVal = eGenericErr;
1263 // reset device to pick up changes
1265 // restore previous state for the device
1279 //*****************************************************************************************************
1280 // WCMRPortAudioDevice::TheCallback
1282 //! The (static) Port Audio Callback function. This is a static member. It calls on the AudioCallback in the
1283 //! WCMRPortAudioDevice to do the real work.
1285 //! \param pInputBuffer: pointer to input buffer.
1286 //! \param pOutputBuffer: pointer to output buffer.
1287 //! \param framesPerBuffer: number of sample frames per buffer.
1288 //! \param pTimeInfo: time info for PaStream callback.
1289 //! \param statusFlags:
1290 //! \param pUserData: pointer to user data, in our case the WCMRPortAudioDevice object.
1292 //! \return true to stop streaming else returns false.
1293 //******************************************************************************************************
1294 int WCMRPortAudioDevice::TheCallback (const void *pInputBuffer, void *pOutputBuffer, unsigned long framesPerBuffer,
1295 const PaStreamCallbackTimeInfo* /*pTimeInfo*/, PaStreamCallbackFlags statusFlags, void *pUserData )
1297 WCMRPortAudioDevice *pMyDevice = (WCMRPortAudioDevice *)pUserData;
1299 return pMyDevice->AudioCallback ((float *)pInputBuffer, (float *)pOutputBuffer, framesPerBuffer,
1300 (statusFlags & (paInputOverflow | paOutputUnderflow)) != 0);
1308 //**********************************************************************************************
1309 // WCMRPortAudioDevice::AudoiCallback
1311 //! Here's where the actual audio processing happens. We call upon all the active connections'
1312 //! sinks to provide data to us which can be put/mixed in the output buffer! Also, we make the
1313 //! input data available to any sources that may call upon us during this time!
1315 //! \param *pInputBuffer : Points to a buffer with recorded data.
1316 //! \param *pOutputBuffer : Points to a buffer to receive playback data.
1317 //! \param framesPerBuffer : Number of sample frames in input and output buffers. Number of channels,
1318 //! which are interleaved, is fixed at Device Open (Active) time. In this implementation,
1319 //! the number of channels are fixed to use the maximum available.
1320 //! \param dropsDetected : True if dropouts were detected in input or output. Can be used to signal the GUI.
1324 //**********************************************************************************************
1325 int WCMRPortAudioDevice::AudioCallback( const float *pInputBuffer, float *pOutputBuffer, unsigned long framesPerBuffer, bool dropsDetected )
1327 UMicroseconds theStartTime;
1332 if (m_IgnoreThisDrop)
1333 m_IgnoreThisDrop = false; //We'll ignore once, just once!
1338 m_pInputData = pInputBuffer;
1340 // VKamyshniy: Is this a right place to call the client???:
1341 struct WCMRAudioDeviceManagerClient::AudioCallbackData audioCallbackData =
1347 theStartTime.MicroSeconds()*1000
1350 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::AudioCallback, (void *)&audioCallbackData );
1352 //Don't try to access after this call returns!
1353 m_pInputData = NULL;
1355 m_SampleCounter += framesPerBuffer;
1357 return m_StopRequested;
1363 //**********************************************************************************************
1364 // WCMRPortAudioDeviceManager::WCMRPortAudioDeviceManager
1366 //! The constructuor, we initialize PA, and build the device list.
1368 //! \param *pTheClient : The manager's client object (which receives notifications).
1369 //! \param interfaceType : The PortAudio interface type to use for this manager - acts as a filter.
1370 //! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true.
1372 //! \return Nothing.
1374 //**********************************************************************************************
1375 WCMRPortAudioDeviceManager::WCMRPortAudioDeviceManager (WCMRAudioDeviceManagerClient *pTheClient,
1376 eAudioDeviceFilter eCurAudioDeviceFilter, bool useMultithreading, bool bNocopy)
1377 : WCMRAudioDeviceManager (pTheClient, eCurAudioDeviceFilter)
1379 , m_UseMultithreading(useMultithreading)
1380 , m_bNoCopyAudioBuffer(bNocopy)
1383 std::cout << "API::PortAudioDeviceManager::PA Device manager constructor" << std::endl;
1385 //Always create the None device first...
1386 m_NoneDevice = new WCMRNativeAudioNoneDevice(this);
1388 WTErr err = generateDeviceListImpl();
1393 timeBeginPeriod (1);
1397 //**********************************************************************************************
1398 // WCMRPortAudioDeviceManager::~WCMRPortAudioDeviceManager
1400 //! It clears the device list, releasing each of the device.
1404 //! \return Nothing.
1406 //**********************************************************************************************
1407 WCMRPortAudioDeviceManager::~WCMRPortAudioDeviceManager()
1411 std::cout << "API::Destroying PortAudioDeviceManager " << std::endl;
1415 delete m_NoneDevice;
1419 //destructors should absorb exceptions, no harm in logging though!!
1420 DEBUG_MSG ("Exception during destructor");
1427 WCMRAudioDevice* WCMRPortAudioDeviceManager::initNewCurrentDeviceImpl(const std::string & deviceName)
1429 destroyCurrentDeviceImpl();
1431 std::cout << "API::PortAudioDeviceManager::initNewCurrentDevice " << deviceName << std::endl;
1432 if (deviceName == m_NoneDevice->DeviceName() )
1434 m_CurrentDevice = m_NoneDevice;
1435 return m_CurrentDevice;
1439 WTErr err = GetDeviceInfoByName(deviceName, devInfo);
1445 std::cout << "API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName << std::endl;
1446 TRACE_MSG ("API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName);
1448 m_CurrentDevice = new WCMRPortAudioDevice (this, devInfo.m_DeviceId, m_UseMultithreading, m_bNoCopyAudioBuffer);
1452 std::cout << "Unabled to create PA Device: " << devInfo.m_DeviceId << std::endl;
1453 DEBUG_MSG ("Unabled to create PA Device: " << devInfo.m_DeviceId);
1457 return m_CurrentDevice;
1461 void WCMRPortAudioDeviceManager::destroyCurrentDeviceImpl()
1463 if (m_CurrentDevice != m_NoneDevice)
1464 delete m_CurrentDevice;
1466 m_CurrentDevice = 0;
1470 WTErr WCMRPortAudioDeviceManager::getDeviceAvailableSampleRates(DeviceID deviceId, std::vector<int>& sampleRates)
1472 sampleRates.clear();
1473 const PaDeviceInfo *pPaDeviceInfo = Pa_GetDeviceInfo(deviceId);
1475 //now find supported sample rates
1476 //following parameters are needed for sample rates validation
1477 PaStreamParameters inputParameters, outputParameters;
1478 PaStreamParameters *pInS = NULL, *pOutS = NULL;
1480 inputParameters.device = deviceId;
1481 inputParameters.channelCount = std::min<int>(2, pPaDeviceInfo->maxInputChannels);
1482 inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
1483 inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
1484 inputParameters.hostApiSpecificStreamInfo = 0;
1486 if (inputParameters.channelCount)
1487 pInS = &inputParameters;
1489 outputParameters.device = deviceId;
1490 outputParameters.channelCount = std::min<int>(2, pPaDeviceInfo->maxOutputChannels);
1491 outputParameters.sampleFormat = paFloat32;
1492 outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
1493 outputParameters.hostApiSpecificStreamInfo = 0;
1495 if (outputParameters.channelCount)
1496 pOutS = &outputParameters;
1498 for(int sr=0; gAllSampleRates[sr] > 0; sr++)
1500 if( paFormatIsSupported == Pa_IsFormatSupported(pInS, pOutS, gAllSampleRates[sr]) )
1502 sampleRates.push_back ((int)gAllSampleRates[sr]);
1508 WTErr WCMRPortAudioDeviceManager::generateDeviceListImpl()
1510 std::cout << "API::PortAudioDeviceManager::Generating device list" << std::endl;
1512 WTErr retVal = eNoErr;
1514 //Initialize PortAudio and ASIO first
1515 PaError paErr = Pa_Initialize();
1517 if (paErr != paNoError)
1519 //ToDo: throw an exception here!
1520 retVal = eSomeThingNotInitailzed;
1524 // lock DeviceInfoVec firts
1525 wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex);
1529 DeviceInfo *pDevInfo = new DeviceInfo(NONE_DEVICE_ID, m_NoneDevice->DeviceName() );
1530 pDevInfo->m_AvailableSampleRates = m_NoneDevice->SamplingRates();
1531 m_DeviceInfoVec.push_back(pDevInfo);
1534 //Get device count...
1535 int numDevices = Pa_GetDeviceCount();
1538 for (int thisDeviceID = 0; thisDeviceID < numDevices; thisDeviceID++)
1540 //if it's of the required type...
1541 const PaDeviceInfo *pPaDeviceInfo = Pa_GetDeviceInfo(thisDeviceID);
1543 if (Pa_GetHostApiInfo(pPaDeviceInfo->hostApi)->type == paASIO)
1545 //build a device object...
1548 std::cout << "API::PortAudioDeviceManager::DeviceID: " << thisDeviceID << ", Device Name: " << pPaDeviceInfo->name << std::endl;
1549 TRACE_MSG ("PA DeviceID: " << thisDeviceID << ", Device Name: " << pPaDeviceInfo->name);
1551 DeviceInfo *pDevInfo = new DeviceInfo(thisDeviceID, pPaDeviceInfo->name);
1554 std::vector<int> availableSampleRates;
1555 WTErr wErr = WCMRPortAudioDeviceManager::getDeviceAvailableSampleRates(thisDeviceID, availableSampleRates);
1559 DEBUG_MSG ("Failed to get device available sample rates. Device ID: " << m_DeviceID);
1561 continue; //proceed to the next device
1564 pDevInfo->m_AvailableSampleRates = availableSampleRates;
1565 pDevInfo->m_MaxInputChannels = pPaDeviceInfo->maxInputChannels;
1566 pDevInfo->m_MaxOutputChannels = pPaDeviceInfo->maxOutputChannels;
1568 //Now check if this device is acceptable according to current input/output settings
1569 bool bRejectDevice = false;
1570 switch(m_eAudioDeviceFilter)
1572 case eInputOnlyDevices:
1573 if (pDevInfo->m_MaxInputChannels != 0)
1575 m_DeviceInfoVec.push_back(pDevInfo);
1579 // Delete unnecesarry device
1580 bRejectDevice = true;
1583 case eOutputOnlyDevices:
1584 if (pDevInfo->m_MaxOutputChannels != 0)
1586 m_DeviceInfoVec.push_back(pDevInfo);
1590 // Delete unnecesarry device
1591 bRejectDevice = true;
1594 case eFullDuplexDevices:
1595 if (pDevInfo->m_MaxInputChannels != 0 && pDevInfo->m_MaxOutputChannels != 0)
1597 m_DeviceInfoVec.push_back(pDevInfo);
1601 // Delete unnecesarry device
1602 bRejectDevice = true;
1607 m_DeviceInfoVec.push_back(pDevInfo);
1613 TRACE_MSG ("API::PortAudioDeviceManager::Device " << pDevInfo->m_DeviceName << "Rejected. \
1614 In Channels = " << pDevInfo->m_MaxInputChannels << "Out Channels = " <<pDevInfo->m_MaxOutputChannels );
1621 std::cout << "API::PortAudioDeviceManager::Unabled to create PA Device: " << std::endl;
1622 DEBUG_MSG ("Unabled to create PA Device: " << thisDeviceID);
1627 //If no devices were found, that's not a good thing!
1628 if (m_DeviceInfoVec.empty() )
1630 std::cout << "API::PortAudioDeviceManager::No matching PortAudio devices were found, total PA devices = " << numDevices << std::endl;
1631 DEBUG_MSG ("No matching PortAudio devices were found, total PA devices = " << numDevices);
1634 //we don't need PA initialized right now
1641 WTErr WCMRPortAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& buffers) const
1643 WTErr retVal = eNoErr;
1644 std::cout << "API::PortAudioDeviceManager::GetBufferSizes: getting buffer size for device: "<< deviceName << std::endl;
1645 //first check if the request has been made for None device
1646 if (deviceName == m_NoneDevice->DeviceName() )
1648 buffers = m_NoneDevice->BufferSizes();
1652 //if we have current device initialized and it's PA device, reset it
1653 //this procedure will reset PA corrently and update info for all PA devices as well
1655 bool paLocalInit = false;
1656 WCMRPortAudioDevice* portaudioDevice = dynamic_cast<WCMRPortAudioDevice*>(m_CurrentDevice);
1657 if (portaudioDevice)
1659 portaudioDevice->ResetDevice();
1663 //initialize PA to get buffers for the device
1669 retVal = GetDeviceInfoByName(deviceName, devInfo);
1671 if (eNoErr == retVal)
1673 //make PA request to get actual device buffer sizes
1674 long minSize, maxSize, preferredSize, granularity;
1675 PaError paErr = PaAsio_GetAvailableBufferSizes(devInfo.m_DeviceId, &minSize, &maxSize, &preferredSize, &granularity);
1677 //for Windows ASIO devices we always use prefferes buffer size ONLY
1678 if (paNoError == paErr )
1680 buffers.push_back(preferredSize);
1684 retVal = eAsioFailed;
1685 std::cout << "API::PortAudioDeviceManager::GetBufferSizes: error: " << paErr << " getting buffer size fo device: "<< deviceName << std::endl;
1690 std::cout << "API::PortAudioDeviceManager::GetBufferSizes: Device not found: "<< deviceName << std::endl;
1693 //deinitialize PA now