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"
18 #include "IncludeWindows.h"
23 #define PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS 200
24 #define DEVICE_INFO_UPDATE_SLEEP_TIME_MILLISECONDS 500
25 #define PROPERTY_CHANGE_TIMEOUT_SECONDS 2
26 #define PROPERTY_CHANGE_RETRIES 3
28 ///< Supported Sample rates
29 static const double gAllSampleRates[] =
31 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0, -1 /* negative terminated list */
36 ///< Default Supported Buffer Sizes.
37 static const int gAllBufferSizes[] =
39 32, 64, 96, 128, 192, 256, 512, 1024, 2048
44 static const int DEFAULT_SR = 44100;
45 ///< The default buffer size.
46 static const int DEFAULT_BUFFERSIZE = 128;
48 static const int NONE_DEVICE_ID = -1;
50 ///< Number of stalls to wait before notifying user...
51 static const int NUM_STALLS_FOR_NOTIFICATION = 100; // 100 corresponds to 100 x 42 ms idle timer - about 4 seconds.
52 static const int CHANGE_CHECK_COUNTER_PERIOD = 100; // 120 corresponds to 120 x 42 ms idle timer - about 4 seconds.
54 #define HUNDRED_NANO_TO_MILLI_CONSTANT 10000
55 #define CONSUMPTION_CALCULATION_INTERVAL 500 // Milli Seconds
58 // This wrapper is used to adapt device DoIdle method as entry point for MS thread
59 DWORD WINAPI WCMRPortAudioDevice::__DoIdle__(LPVOID lpThreadParameter)
61 WCMRPortAudioDevice* pDevice = (WCMRPortAudioDevice*)lpThreadParameter;
66 //**********************************************************************************************
67 // WCMRPortAudioDevice::WCMRPortAudioDevice
69 //! Constructor for the audio device. Opens the PA device
70 //! and gets information about the device.
71 //! Starts the thread which will process requests to this device
72 //! such as determining supported sampling rates, buffer sizes, and channel counts.
74 //! \param *pManager : The audio device manager that's managing this device.
75 //! \param deviceID : The port audio device ID.
76 //! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true.
80 //**********************************************************************************************
81 WCMRPortAudioDevice::WCMRPortAudioDevice (WCMRPortAudioDeviceManager *pManager, unsigned int deviceID, bool useMultithreading, bool bNoCopy) :
82 WCMRNativeAudioDevice (pManager, useMultithreading, bNoCopy)
84 , m_BufferSizeChangeRequested (0)
85 , m_BufferSizeChangeReported (0)
86 , m_ResetRequested (0)
88 , m_ResyncRequested (0)
89 , m_ResyncReported (0)
92 , m_IgnoreThisDrop(true)
93 , m_hDeviceProcessingThread(NULL)
94 , m_DeviceProcessingThreadID(0)
95 , m_hUpdateDeviceInfoRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
96 , m_hUpdateDeviceInfoDone(CreateEvent(NULL, FALSE, FALSE, NULL))
97 , m_hActivateRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
98 , m_hActivationDone(CreateEvent(NULL, FALSE, FALSE, NULL))
99 , m_hDeActivateRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
100 , m_hDeActivationDone(CreateEvent(NULL, FALSE, FALSE, NULL))
101 , m_hStartStreamingRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
102 , m_hStartStreamingDone(CreateEvent(NULL, FALSE, FALSE, NULL))
103 , m_hStopStreamingRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
104 , m_hStopStreamingDone(CreateEvent(NULL, FALSE, FALSE, NULL))
105 , m_hResetRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
106 , m_hResetDone(CreateEvent(NULL, FALSE, FALSE, NULL))
107 , m_hResetFromDevRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
108 , m_hBufferSizeChangedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
109 , m_hSampleRateChangedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
110 , m_hExitIdleThread(CreateEvent(NULL, FALSE, FALSE, NULL))
111 , m_hDeviceInitialized(CreateEvent(NULL, FALSE, FALSE, NULL))
116 //Set initial device info...
117 m_DeviceID = deviceID;
118 m_PortAudioStream = NULL;
119 m_CurrentSamplingRate = DEFAULT_SR;
120 m_CurrentBufferSize = DEFAULT_BUFFERSIZE;
121 m_StopRequested = true;
124 //initialize device processing thread
125 //the divice become alive and now is able to process requests
126 m_hDeviceProcessingThread = CreateThread( NULL, 0, __DoIdle__, (LPVOID)this, 0, &m_DeviceProcessingThreadID );
128 if (!m_hDeviceProcessingThread)
130 DEBUG_MSG("API::Device " << m_DeviceName << " cannot create processing thread");
134 WaitForSingleObject(m_hDeviceInitialized, INFINITE);
136 if (ConnectionStatus() == DeviceErrors)
143 void WCMRPortAudioDevice::initDevice()
145 // Initialize COM for this thread
146 std::cout << "API::Device " << m_DeviceID << " initializing COM" << std::endl;
148 if (S_OK == CoInitialize(NULL) )
155 //should use a valid current SR...
156 if (m_SamplingRates.size())
158 //see if the current sr is present in the sr list, if not, use the first one!
159 std::vector<int>::iterator intIter = find(m_SamplingRates.begin(), m_SamplingRates.end(), m_CurrentSamplingRate);
160 if (intIter == m_SamplingRates.end())
162 //not found... use the first one
163 m_CurrentSamplingRate = m_SamplingRates[0];
167 std::cout << "API::Device " << m_DeviceName << " Device does not support any sample rate of ours" << std::endl;
169 //should use a valid current buffer size
170 if (m_BufferSizes.size())
172 //see if the current sr is present in the buffersize list, if not, use the first one!
173 std::vector<int>::iterator intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), m_CurrentBufferSize);
174 if (intIter == m_BufferSizes.end())
176 //not found... use the first one
177 m_CurrentBufferSize = m_BufferSizes[0];
181 //build our input/output level lists
182 for (unsigned int currentChannel = 0; currentChannel < m_InputChannels.size(); currentChannel++)
184 m_InputLevels.push_back (0.0);
187 //build our input/output level lists
188 for (unsigned int currentChannel = 0; currentChannel < m_OutputChannels.size(); currentChannel++)
190 m_OutputLevels.push_back (0.0);
193 std::cout << "API::Device " << m_DeviceName << " Device has been initialized" << std::endl;
194 m_ConnectionStatus = DeviceDisconnected;
199 /*Replace with debug trace*/std::cout << "API::Device " << m_DeviceName << " cannot initialize COM" << std::endl;
200 DEBUG_MSG("Device " << m_DeviceName << " cannot initialize COM");
201 m_ConnectionStatus = DeviceErrors;
202 m_lastErr = eSomeThingNotInitailzed;
203 SetEvent(m_hExitIdleThread);
206 SetEvent(m_hDeviceInitialized);
209 void WCMRPortAudioDevice::terminateDevice()
211 std::cout << "API::Device " << m_DeviceName << " Terminating DEVICE" << std::endl;
213 //If device is streaming, need to stop it!
219 //If device is active (meaning stream is open) we need to close it.
225 std::cout << "API::Device " << m_DeviceName << " Terminating PA" << std::endl;
232 //**********************************************************************************************
233 // WCMRPortAudioDevice::~WCMRPortAudioDevice
235 //! Destructor for the audio device. The base release all the connections that were created, if
236 //! they have not been already destroyed! Here we simply stop streaming, and close device
237 //! handles if necessary.
243 //**********************************************************************************************
244 WCMRPortAudioDevice::~WCMRPortAudioDevice ()
248 std::cout << "API::Destroying Device Instance: " << DeviceName() << std::endl;
251 //Stop deviceprocessing thread
252 SignalObjectAndWait(m_hExitIdleThread, m_hDeviceProcessingThread, INFINITE, false);
254 std::cout << "API::Device " << m_DeviceName << " Processing Thread is stopped" << std::endl;
256 CloseHandle(m_hDeviceProcessingThread);
258 //Now it's safe to free all event handlers
259 CloseHandle(m_hUpdateDeviceInfoRequestedEvent);
260 CloseHandle(m_hUpdateDeviceInfoDone);
261 CloseHandle(m_hActivateRequestedEvent);
262 CloseHandle(m_hActivationDone);
263 CloseHandle(m_hDeActivateRequestedEvent);
264 CloseHandle(m_hDeActivationDone);
265 CloseHandle(m_hStartStreamingRequestedEvent);
266 CloseHandle(m_hStartStreamingDone);
267 CloseHandle(m_hStopStreamingRequestedEvent);
268 CloseHandle(m_hStopStreamingDone);
269 CloseHandle(m_hResetRequestedEvent);
270 CloseHandle(m_hResetDone);
271 CloseHandle(m_hResetFromDevRequestedEvent);
272 CloseHandle(m_hBufferSizeChangedEvent);
273 CloseHandle(m_hSampleRateChangedEvent);
274 CloseHandle(m_hExitIdleThread);
275 CloseHandle(m_hDeviceInitialized);
279 //destructors should absorb exceptions, no harm in logging though!!
280 DEBUG_MSG ("Exception during destructor");
285 WTErr WCMRPortAudioDevice::UpdateDeviceInfo ()
287 std::cout << "API::Device (ID:)" << m_DeviceID << " Updating device info" << std::endl;
289 SignalObjectAndWait(m_hUpdateDeviceInfoRequestedEvent, m_hUpdateDeviceInfoDone, INFINITE, false);
295 //**********************************************************************************************
296 // WCMRPortAudioDevice::updateDeviceInfo
298 //! Must be called be device processing thread
299 //! Updates Device Information about channels, sampling rates, buffer sizes.
303 //**********************************************************************************************
304 void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/)
309 const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
312 m_DeviceName = pDeviceInfo->name;
314 //following parameters are needed opening test stream and for sample rates validation
315 PaStreamParameters inputParameters, outputParameters;
316 PaStreamParameters *pInS = NULL, *pOutS = NULL;
318 inputParameters.device = m_DeviceID;
319 inputParameters.channelCount = pDeviceInfo->maxInputChannels;
320 inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
321 inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
322 inputParameters.hostApiSpecificStreamInfo = 0;
324 if (inputParameters.channelCount)
325 pInS = &inputParameters;
327 outputParameters.device = m_DeviceID;
328 outputParameters.channelCount = pDeviceInfo->maxOutputChannels;
329 outputParameters.sampleFormat = paFloat32;
330 outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
331 outputParameters.hostApiSpecificStreamInfo = 0;
333 if (outputParameters.channelCount)
334 pOutS = &outputParameters;
336 ////////////////////////////////////////////////////////////////////////////////////
337 //update list of supported SRs...
338 m_SamplingRates.clear();
340 // now iterate through our standard SRs and check if they are supported by device
341 // store them for this device
342 for(int sr=0; gAllSampleRates[sr] > 0; sr++)
344 PaError err = Pa_IsFormatSupported(pInS, pOutS, gAllSampleRates[sr]);
345 if( err == paFormatIsSupported)
347 m_SamplingRates.push_back ((int)gAllSampleRates[sr]);
351 ///////////////////////////////////////////////////////////////////////////////////
352 //update buffer sizes
353 m_BufferSizes.clear();
354 bool useDefaultBuffers = true;
356 // In ASIO Windows, the buffer size is set from the sound device manufacturer's control panel
357 long minSize, maxSize, preferredSize, granularity;
358 PaError err = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
360 if (err == paNoError)
362 std::cout << "API::Device " << m_DeviceName << " Buffers: " << minSize << " " << maxSize << " " << preferredSize << std::endl;
364 m_BufferSizes.push_back (preferredSize);
365 useDefaultBuffers = false;
369 std::cout << "API::Device" << m_DeviceName << " Preffered buffer size is not supported" << std::endl;
372 if (useDefaultBuffers)
374 std::cout << "API::Device" << m_DeviceName << " Using default buffer sizes " <<std::endl;
375 for(int bsize=0; bsize < (sizeof(gAllBufferSizes)/sizeof(gAllBufferSizes[0])); bsize++)
376 m_BufferSizes.push_back (gAllBufferSizes[bsize]);
379 /////////////////////////////////////////////////////////////////////////////////////////
380 //update channels info
382 int maxInputChannels = pDeviceInfo->maxInputChannels;
383 int maxOutputChannels = pDeviceInfo->maxOutputChannels;
385 //Update input channels
386 m_InputChannels.clear();
387 for (int channel = 0; channel < maxInputChannels; channel++)
389 const char* channelName[32]; // 32 is max leth declared by PortAudio for this operation
390 std::stringstream chNameStream;
392 PaError error = PaAsio_GetInputChannelName(m_DeviceID, channel, channelName);
394 chNameStream << (channel+1) << " - ";
396 if (error == paNoError)
398 chNameStream << *channelName;
402 chNameStream << "Input " << (channel+1);
405 m_InputChannels.push_back (chNameStream.str());
409 //Update output channels
410 m_OutputChannels.clear();
411 for (int channel = 0; channel < maxOutputChannels; channel++)
413 const char* channelName[32]; // 32 is max leth declared by PortAudio for this operation
414 std::stringstream chNameStream;
416 PaError error = PaAsio_GetOutputChannelName(m_DeviceID, channel, channelName);
418 chNameStream << (channel+1) << " - ";
420 if (error == paNoError)
422 chNameStream << *channelName;
426 chNameStream << "Output " << (channel+1);
429 m_OutputChannels.push_back (chNameStream.str());
433 std::cout << "API::Device" << m_DeviceName << " Device info update has been finished" << std::endl;
436 SetEvent(m_hUpdateDeviceInfoDone);
440 PaError WCMRPortAudioDevice::testStateValidness(int sampleRate, int bufferSize)
442 PaError paErr = paNoError;
445 const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
447 //following parameters are needed opening test stream and for sample rates validation
448 PaStreamParameters inputParameters, outputParameters;
449 PaStreamParameters *pInS = NULL, *pOutS = NULL;
451 inputParameters.device = m_DeviceID;
452 inputParameters.channelCount = pDeviceInfo->maxInputChannels;
453 inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
454 inputParameters.suggestedLatency = 0;
455 inputParameters.hostApiSpecificStreamInfo = 0;
457 if (inputParameters.channelCount)
458 pInS = &inputParameters;
460 outputParameters.device = m_DeviceID;
461 outputParameters.channelCount = pDeviceInfo->maxOutputChannels;
462 outputParameters.sampleFormat = paFloat32;
463 outputParameters.suggestedLatency = 0;
464 outputParameters.hostApiSpecificStreamInfo = 0;
466 if (outputParameters.channelCount)
467 pOutS = &outputParameters;
469 PaStream *portAudioStream = NULL;
471 //sometimes devices change buffer size if sample rate changes
472 //it updates buffer size during stream opening
473 //we need to find out how device would behave with current sample rate
474 //try opening test stream to load device driver for current sample rate and buffer size
475 paErr = Pa_OpenStream (&portAudioStream, pInS, pOutS, sampleRate, bufferSize, paDitherOff, NULL, NULL);
480 Pa_CloseStream (portAudioStream);
481 portAudioStream = NULL;
488 //**********************************************************************************************
489 // WCMRPortAudioDevice::CurrentSamplingRate
491 //! The device's current sampling rate. This may be overridden, if the device needs to
492 //! query the driver for the current rate.
496 //! \return The device's current sampling rate. -1 on error.
498 //**********************************************************************************************
499 int WCMRPortAudioDevice::CurrentSamplingRate ()
502 //ToDo: Perhaps for ASIO devices that are active, we should retrive the SR from the device...
504 return (m_CurrentSamplingRate);
508 WTErr WCMRPortAudioDevice::SetActive (bool newState)
510 if (newState == true)
512 std::cout << "API::Device " << m_DeviceName << " Activation requested" << std::endl;
513 SignalObjectAndWait(m_hActivateRequestedEvent, m_hActivationDone, INFINITE, false);
517 std::cout << "API::Device " << m_DeviceName << " Deactivation requested" << std::endl;
518 SignalObjectAndWait(m_hDeActivateRequestedEvent, m_hDeActivationDone, INFINITE, false);
521 if (newState == Active() )
528 WTErr WCMRPortAudioDevice::SetStreaming (bool newState)
530 if (newState == true)
532 std::cout << "API::Device " << m_DeviceName << " Stream start requested" << std::endl;
533 SignalObjectAndWait(m_hStartStreamingRequestedEvent, m_hStartStreamingDone, INFINITE, false);
537 std::cout << "API::Device " << m_DeviceName << " Stream stop requested" << std::endl;
538 SignalObjectAndWait(m_hStopStreamingRequestedEvent, m_hStopStreamingDone, INFINITE, false);
541 if (newState == Streaming() )
548 WTErr WCMRPortAudioDevice::ResetDevice()
550 std::cout << "API::Device: " << m_DeviceName << " Reseting device" << std::endl;
552 SignalObjectAndWait(m_hResetRequestedEvent, m_hResetDone, INFINITE, false);
554 if (ConnectionStatus() == DeviceErrors)
563 //**********************************************************************************************
564 // WCMRPortAudioDevice::SetCurrentSamplingRate
566 //! Change the sampling rate to be used by the device.
568 //! \param newRate : The rate to use (samples per sec).
570 //! \return eNoErr always. The derived classes may return error codes.
572 //**********************************************************************************************
573 WTErr WCMRPortAudioDevice::SetCurrentSamplingRate (int newRate)
576 std::vector<int>::iterator intIter;
577 WTErr retVal = eNoErr;
579 //changes the status.
580 int oldRate = CurrentSamplingRate();
581 bool oldActive = Active();
583 //no change, nothing to do
584 if (oldRate == newRate)
587 //see if this is one of our supported rates...
588 intIter = find(m_SamplingRates.begin(), m_SamplingRates.end(), newRate);
590 if (intIter == m_SamplingRates.end())
592 //Can't change, perhaps use an "invalid param" type of error
593 retVal = eCommandLineParameter;
599 //Can't change, perhaps use an "in use" type of error
600 retVal = eGenericErr;
605 m_CurrentSamplingRate = newRate;
606 PaError paErr = PaAsio_SetStreamSampleRate (m_PortAudioStream, m_CurrentSamplingRate);
607 Pa_Sleep(PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS); // sleep some time to make sure the change has place
609 if (paErr != paNoError)
611 std::cout << "Sample rate change failed: " << Pa_GetErrorText (paErr) << std::endl;
612 if (paErr == paUnanticipatedHostError)
613 std::cout << "Details: "<< Pa_GetLastHostErrorInfo ()->errorText << "; code: " << Pa_GetLastHostErrorInfo ()->errorCode << std::endl;
615 retVal = eWrongObjectState;
622 //**********************************************************************************************
623 // WCMRPortAudioDevice::CurrentBufferSize
625 //! The device's current buffer size in use. This may be overridden, if the device needs to
626 //! query the driver for the current size.
630 //! \return The device's current buffer size. 0 on error.
632 //**********************************************************************************************
633 int WCMRPortAudioDevice::CurrentBufferSize ()
635 return m_CurrentBufferSize;
639 //**********************************************************************************************
640 // WCMRPortAudioDevice::SetCurrentBufferSize
642 //! Change the buffer size to be used by the device. This will most likely be overridden,
643 //! the base class simply updates the member variable.
645 //! \param newSize : The buffer size to use (in sample-frames)
647 //! \return eNoErr always. The derived classes may return error codes.
649 //**********************************************************************************************
650 WTErr WCMRPortAudioDevice::SetCurrentBufferSize (int newSize)
653 WTErr retVal = eNoErr;
654 std::vector<int>::iterator intIter;
658 //Can't change, perhaps use an "in use" type of error
659 retVal = eGenericErr;
663 // Buffer size for ASIO devices can be changed from the control panel only
664 // We have driver driven logi here
665 if (m_CurrentBufferSize != newSize )
667 // we have only one aloved buffer size which is preffered by PA
668 // this is the only value which could be set
669 newSize = m_BufferSizes[0];
670 int bufferSize = newSize;
671 // notify client to update buffer size
672 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
680 //**********************************************************************************************
681 // WCMRPortAudioDevice::ConnectionStatus
683 //! Retrieves the device's current connection status. This will most likely be overridden,
684 //! in case some driver communication is required to query the status.
688 //! \return A ConnectionStates value.
690 //**********************************************************************************************
691 WCMRPortAudioDevice::ConnectionStates WCMRPortAudioDevice::ConnectionStatus ()
694 //ToDo: May want to do something more to extract the actual status!
695 return (m_ConnectionStatus);
700 //**********************************************************************************************
701 // WCMRPortAudioDevice::activateDevice
703 //! IS CALLED BY PROCESS THREAD
704 //! Sets the device into "active" state. Essentially, opens the PA device.
705 //! If it's an ASIO device it may result in buffer size change in some cases.
707 //**********************************************************************************************
708 void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
712 PaError paErr = paNoError;
714 // if device is not active activate it
717 PaStreamParameters inputParameters, outputParameters;
718 PaStreamParameters *pInS = NULL, *pOutS = NULL;
720 const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
721 const PaHostApiInfo *pHostApiInfo = Pa_GetHostApiInfo(pDeviceInfo->hostApi);
723 inputParameters.device = m_DeviceID;
724 inputParameters.channelCount = (int)m_InputChannels.size();
725 inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
726 inputParameters.suggestedLatency = Pa_GetDeviceInfo(m_DeviceID)->defaultLowInputLatency;
727 inputParameters.hostApiSpecificStreamInfo = 0;
729 if (inputParameters.channelCount)
730 pInS = &inputParameters;
732 outputParameters.device = m_DeviceID;
733 outputParameters.channelCount = (int)m_OutputChannels.size();
734 outputParameters.sampleFormat = paFloat32;
735 outputParameters.suggestedLatency = Pa_GetDeviceInfo(m_DeviceID)->defaultLowOutputLatency;
736 outputParameters.hostApiSpecificStreamInfo = 0;
738 if (outputParameters.channelCount)
739 pOutS = &outputParameters;
741 std::cout << "API::Device " << m_DeviceName << " Opening device stream " << std::endl;
742 std::cout << "Sample rate: " << m_CurrentSamplingRate << " buffer size: " << m_CurrentBufferSize << std::endl;
743 paErr = Pa_OpenStream(&m_PortAudioStream,
746 m_CurrentSamplingRate,
749 WCMRPortAudioDevice::TheCallback,
752 if(paErr != paNoError)
754 std::cout << "Cannot open streamm with buffer: "<< m_CurrentBufferSize << " Error: " << Pa_GetErrorText (paErr) << std::endl;
756 if (paErr == paUnanticipatedHostError)
757 std::cout << "Error details: "<< Pa_GetLastHostErrorInfo ()->errorText << "; code: " << Pa_GetLastHostErrorInfo ()->errorCode << std::endl;
760 if(paErr == paNoError)
762 std::cout << "Stream has been opened! "<< std::endl;
764 // check for possible changes
765 long minSize, maxSize, preferredSize, granularity;
766 PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
768 std::cout << "Checked if buffer size changed "<< std::endl;
769 if (paErr == paNoError && m_CurrentBufferSize != preferredSize)
771 std::cout << "Buffer size has changed "<< std::endl;
772 m_CurrentBufferSize = preferredSize;
773 m_BufferSizes.clear();
774 m_BufferSizes.push_back(preferredSize);
775 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&preferredSize);
780 m_IgnoreThisDrop = true;
782 if (pHostApiInfo->type == paASIO)
784 m_BufferSizeChangeRequested = 0;
785 m_BufferSizeChangeReported = 0;
786 m_ResetRequested = 0;
788 m_ResyncRequested = 0;
789 m_ResyncReported = 0;
790 std::cout << "Installing new mesage hook "<< std::endl;
791 PaAsio_SetMessageHook (StaticASIOMessageHook, this);
794 m_ConnectionStatus = DeviceAvailable;
799 //failed, do not update device state
800 std::cout << "Failed to open pa stream: " << Pa_GetErrorText (paErr) << std::endl;
801 DEBUG_MSG( "Failed to open pa stream: " << Pa_GetErrorText (paErr) );
802 m_ConnectionStatus = DeviceErrors;
803 m_lastErr = eAsioFailed;
809 std::cout << "Activation is DONE "<< std::endl;
812 SetEvent(m_hActivationDone);
816 //**********************************************************************************************
817 // WCMRPortAudioDevice::deactivateDevice
819 //! IS CALLED BY PROCESS THREAD
820 //! Sets the device into "inactive" state. Essentially, closes the PA device.
822 //**********************************************************************************************
823 void WCMRPortAudioDevice::deactivateDevice (bool callerIsWaiting/*=false*/)
827 PaError paErr = paNoError;
836 if (m_PortAudioStream)
838 //close the stream first
839 std::cout << "API::Device" << m_DeviceName << " Closing device stream" << std::endl;
840 paErr = Pa_CloseStream (m_PortAudioStream);
841 if(paErr == paNoError)
843 m_PortAudioStream = NULL;
846 m_IgnoreThisDrop = true;
847 m_BufferSizeChangeRequested = 0;
848 m_BufferSizeChangeReported = 0;
849 m_ResetRequested = 0;
851 m_ResyncRequested = 0;
852 m_ResyncReported = 0;
853 PaAsio_SetMessageHook (NULL, NULL);
855 //finaly set device state to "not active"
857 m_ConnectionStatus = DeviceDisconnected;
862 //failed, do not update device state
863 std::cout << "Failed to close pa stream stream " << Pa_GetErrorText (paErr) << std::endl;
864 DEBUG_MSG( "Failed to open pa stream stream " << Pa_GetErrorText (paErr) );
865 m_ConnectionStatus = DeviceErrors;
866 m_lastErr = eAsioFailed;
872 SetEvent(m_hDeActivationDone);
876 //**********************************************************************************************
877 // WCMRPortAudioDevice::startStreaming
879 //! Sets the devices into "streaming" state. Calls PA's Start stream routines.
880 //! This roughly corresponds to calling Start on the lower level interface.
882 //**********************************************************************************************
883 void WCMRPortAudioDevice::startStreaming (bool callerIsWaiting/*=false*/)
887 // proceed if the device is not streaming
890 PaError paErr = paNoError;
891 m_StopRequested = false;
894 std::cout << "API::Device" << m_DeviceName << " Starting device stream" << std::endl;
897 const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
899 unsigned int inChannelCount = pDeviceInfo->maxInputChannels;
900 unsigned int outChannelCount = pDeviceInfo->maxOutputChannels;
902 // Prepare for streaming - tell Engine to do the initialization for process callback
903 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStartsStreaming);
905 paErr = Pa_StartStream( m_PortAudioStream );
907 if(paErr == paNoError)
909 // if the stream was started successfully
910 m_IsStreaming = true;
911 std::cout << "API::Device" << m_DeviceName << " Device is streaming" << std::endl;
915 std::cout << "Failed to start PA stream: " << Pa_GetErrorText (paErr) << std::endl;
916 DEBUG_MSG( "Failed to start PA stream: " << Pa_GetErrorText (paErr) );
917 m_lastErr = eGenericErr;
922 SetEvent(m_hStartStreamingDone);
926 //**********************************************************************************************
927 // WCMRPortAudioDevice::stopStreaming
929 //! Sets the devices into "not streaming" state. Calls PA's Stop stream routines.
930 //! This roughly corresponds to calling Stop on the lower level interface.
932 //**********************************************************************************************
933 void WCMRPortAudioDevice::stopStreaming (bool callerIsWaiting/*=false*/)
937 // proceed if the device is streaming
940 PaError paErr = paNoError;
941 m_StopRequested = true;
943 std::cout << "API::Device " << m_DeviceName << " Stopping device stream" << std::endl;
944 paErr = Pa_StopStream( m_PortAudioStream );
946 if(paErr == paNoError || paErr == paStreamIsStopped)
948 // if the stream was stopped successfully
949 m_IsStreaming = false;
954 std::cout << "Failed to stop PA stream normaly! Error:" << Pa_GetErrorText (paErr) << std::endl;
955 DEBUG_MSG( "Failed to stop PA stream normaly! Error:" << Pa_GetErrorText (paErr) );
956 m_lastErr = eGenericErr;
961 SetEvent(m_hStopStreamingDone);
965 //**********************************************************************************************
966 // WCMRPortAudioDevice::resetDevice
968 //! Resets the device, updates device info. Importnat: does PA reinitialization calling
969 //! Pa_terminate/Pa_initialize functions.
975 //**********************************************************************************************
976 void WCMRPortAudioDevice::resetDevice (bool callerIsWaiting /*=false*/ )
978 PaError paErr = paNoError;
981 bool wasStreaming = Streaming();
982 bool wasActive = Active();
988 // Cache device buffer size as it might be changed during reset
989 int oldBufferSize = m_CurrentBufferSize;
991 // Now, validate the state and update device info if required
992 unsigned int retry = PROPERTY_CHANGE_RETRIES;
999 std::cout << "Updating device state... " << std::endl;
1000 // update device info
1004 long minSize, maxSize, preferredSize, granularity;
1005 PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
1007 if (paErr != paNoError)
1011 m_CurrentBufferSize = preferredSize;
1013 paErr = testStateValidness(m_CurrentSamplingRate, m_CurrentBufferSize);
1014 if (paNoError == paErr)
1016 std::cout << "Device state is valid" << std::endl;
1020 std::cout << "Cannot start with current state: sr: " << m_CurrentSamplingRate << " bs:" << m_CurrentBufferSize \
1021 << "\nReason: " << Pa_GetErrorText (paErr) << std::endl;
1022 if (paErr == paUnanticipatedHostError)
1023 std::cout << "Details: "<< Pa_GetLastHostErrorInfo ()->errorText << "; code: " << Pa_GetLastHostErrorInfo ()->errorCode << std::endl;
1025 std::cout << "Will try again in " << DEVICE_INFO_UPDATE_SLEEP_TIME_MILLISECONDS << "msec" << std::endl;
1027 Pa_Sleep(DEVICE_INFO_UPDATE_SLEEP_TIME_MILLISECONDS);
1030 if (paErr == paNoError)
1032 // Notify the Application about device setting changes
1033 if (oldBufferSize != m_CurrentBufferSize)
1035 std::cout << "API::Device" << m_DeviceName << " buffer size changed" << std::endl;
1036 int bufferSize = m_CurrentBufferSize;
1037 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
1040 // Activate the device if it was active before
1044 // Resume streaming if the device was streaming before
1045 if(wasStreaming && m_lastErr == eNoErr && m_ConnectionStatus == DeviceAvailable)
1051 m_ConnectionStatus = DeviceErrors;
1052 m_lastErr = eWrongObjectState;
1055 if (callerIsWaiting)
1056 SetEvent(m_hResetDone);
1060 #ifdef PLATFORM_WINDOWS
1062 long WCMRPortAudioDevice::StaticASIOMessageHook (void *pRefCon, long selector, long value, void* message, double* opt)
1066 return ((WCMRPortAudioDevice*)(pRefCon))->ASIOMessageHook (selector, value, message, opt);
1072 long WCMRPortAudioDevice::ASIOMessageHook (long selector, long WCUNUSEDPARAM(value), void* WCUNUSEDPARAM(message), double* WCUNUSEDPARAM(opt))
1076 case kAsioResyncRequest:
1077 m_ResyncRequested++;
1078 std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioResyncRequest" << std::endl;
1081 case kAsioLatenciesChanged:
1082 m_BufferSizeChangeRequested++;
1083 std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioLatenciesChanged" << std::endl;
1084 if (m_ResetRequested == 0) {
1086 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
1090 case kAsioBufferSizeChange:
1091 m_BufferSizeChangeRequested++;
1092 std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- m_BufferSizeChangeRequested" << std::endl;
1093 if (m_ResetRequested == 0) {
1095 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
1099 case kAsioResetRequest:
1100 std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioResetRequest" << std::endl;
1102 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
1107 std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioOverload" << std::endl;
1108 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::Dropout);
1117 //**********************************************************************************************
1118 // WCMRPortAudioDevice::DoIdle
1120 //! A place for doing idle time processing. The other derived classes will probably do something
1125 //! \return eNoErr always.
1127 //**********************************************************************************************
1128 WTErr WCMRPortAudioDevice::DoIdle ()
1130 WTErr retVal = eNoErr;
1132 std::cout << "WCMRPortAudioDevice::DoIdle ()" << std::endl;
1135 m_hUpdateDeviceInfoRequestedEvent,
1136 m_hActivateRequestedEvent,
1137 m_hDeActivateRequestedEvent,
1138 m_hStartStreamingRequestedEvent,
1139 m_hStopStreamingRequestedEvent,
1140 m_hBufferSizeChangedEvent,
1141 m_hSampleRateChangedEvent,
1142 m_hResetRequestedEvent,
1143 m_hResetFromDevRequestedEvent,
1147 const size_t hEventsSize = sizeof(hEvents)/sizeof(hEvents[0]);
1153 DWORD result = WaitForMultipleObjects (hEventsSize, hEvents, FALSE, INFINITE);
1154 result = result - WAIT_OBJECT_0;
1156 if ((result < 0) || (result >= hEventsSize)) {
1157 std::cout << "\t\t\t\t\t\t\tWCMRPortAudioDevice::DoIdle () -> (result < 0) || (result >= hEventsSize):" << result << std::endl;
1158 retVal = eGenericErr;
1162 if (hEvents[result] == m_hExitIdleThread) {
1163 std::cout << "\t\t\t\t\t\t\tWCMRPortAudioDevice::DoIdle () -> m_hExitIdleThread" << result << std::endl;
1168 if (hEvents[result] == m_hUpdateDeviceInfoRequestedEvent) {
1169 std::cout << "\t\t\t\t\t\tupdate requested ..." << std::endl;
1170 updateDeviceInfo(true);
1173 if (hEvents[result] == m_hActivateRequestedEvent) {
1174 std::cout << "\t\t\t\t\t\tactivation requested ..." << std::endl;
1175 activateDevice(true);
1178 if (hEvents[result] == m_hDeActivateRequestedEvent) {
1179 std::cout << "\t\t\t\t\t\tdeactivation requested ..." << std::endl;
1180 deactivateDevice(true);
1183 if (hEvents[result] == m_hStartStreamingRequestedEvent) {
1184 std::cout << "\t\t\t\t\t\tStart stream requested ..." << std::endl;
1185 startStreaming(true);
1188 if (hEvents[result] == m_hStopStreamingRequestedEvent) {
1189 std::cout << "\t\t\t\t\t\tStop stream requested ..." << std::endl;
1190 stopStreaming(true);
1193 if (hEvents[result] == m_hResetRequestedEvent) {
1194 std::cout << "\t\t\t\t\t\treset requested ..." << std::endl;
1198 if (hEvents[result] == m_hResetFromDevRequestedEvent) {
1199 std::cout << "\t\t\t\t\t\treset requested from device..." << std::endl;
1203 if (hEvents[result] == m_hBufferSizeChangedEvent) {
1204 std::cout << "\t\t\t\t\t\tbuffer size changed from device..." << std::endl;
1205 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged);
1208 if (hEvents[result] == m_hSampleRateChangedEvent) {
1209 std::cout << "\t\t\t\t\t\tsample rate changed from device..." << std::endl;
1210 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::SamplingRateChanged);
1220 //**********************************************************************************************
1221 // WCMRPortAudioDevice::SetMonitorChannels
1223 //! Used to set the channels to be used for monitoring.
1225 //! \param leftChannel : Left monitor channel index.
1226 //! \param rightChannel : Right monitor channel index.
1228 //! \return eNoErr always, the derived classes may return appropriate errors.
1230 //**********************************************************************************************
1231 WTErr WCMRPortAudioDevice::SetMonitorChannels (int leftChannel, int rightChannel)
1234 //This will most likely be overridden, the base class simply
1235 //changes the member.
1236 m_LeftMonitorChannel = leftChannel;
1237 m_RightMonitorChannel = rightChannel;
1243 //**********************************************************************************************
1244 // WCMRPortAudioDevice::SetMonitorGain
1246 //! Used to set monitor gain (or atten).
1248 //! \param newGain : The new gain or atten. value to use. Specified as a linear multiplier (not dB)
1250 //! \return eNoErr always, the derived classes may return appropriate errors.
1252 //**********************************************************************************************
1253 WTErr WCMRPortAudioDevice::SetMonitorGain (float newGain)
1256 //This will most likely be overridden, the base class simply
1257 //changes the member.
1259 m_MonitorGain = newGain;
1266 //**********************************************************************************************
1267 // WCMRPortAudioDevice::ShowConfigPanel
1269 //! Used to show device specific config/control panel. Some interfaces may not support it.
1270 //! Some interfaces may require the device to be active before it can display a panel.
1272 //! \param pParam : A device/interface specific parameter, should be the app window handle for ASIO.
1274 //! \return eNoErr always, the derived classes may return errors.
1276 //**********************************************************************************************
1277 WTErr WCMRPortAudioDevice::ShowConfigPanel (void *pParam)
1280 WTErr retVal = eNoErr;
1282 if (Active() && !m_ResetRequested )
1284 #ifdef PLATFORM_WINDOWS
1285 if(Pa_GetHostApiInfo(Pa_GetDeviceInfo(m_DeviceID)->hostApi)->type == paASIO)
1287 // stop and deactivate the device
1288 bool wasStreaming = Streaming();
1291 // show control panel for the device
1292 if (PaAsio_ShowControlPanel (m_DeviceID, pParam) != paNoError)
1293 retVal = eGenericErr;
1295 // restore previous state for the device
1301 // reset device to pick up changes
1302 if (!m_ResetRequested) {
1303 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
1315 //*****************************************************************************************************
1316 // WCMRPortAudioDevice::TheCallback
1318 //! The (static) Port Audio Callback function. This is a static member. It calls on the AudioCallback in the
1319 //! WCMRPortAudioDevice to do the real work.
1321 //! \param pInputBuffer: pointer to input buffer.
1322 //! \param pOutputBuffer: pointer to output buffer.
1323 //! \param framesPerBuffer: number of sample frames per buffer.
1324 //! \param pTimeInfo: time info for PaStream callback.
1325 //! \param statusFlags:
1326 //! \param pUserData: pointer to user data, in our case the WCMRPortAudioDevice object.
1328 //! \return true to stop streaming else returns false.
1329 //******************************************************************************************************
1330 int WCMRPortAudioDevice::TheCallback (const void *pInputBuffer, void *pOutputBuffer, unsigned long framesPerBuffer,
1331 const PaStreamCallbackTimeInfo* /*pTimeInfo*/, PaStreamCallbackFlags statusFlags, void *pUserData )
1333 WCMRPortAudioDevice *pMyDevice = (WCMRPortAudioDevice *)pUserData;
1335 return pMyDevice->AudioCallback ((float *)pInputBuffer, (float *)pOutputBuffer, framesPerBuffer,
1336 (statusFlags & (paInputOverflow | paOutputUnderflow)) != 0);
1344 //**********************************************************************************************
1345 // WCMRPortAudioDevice::AudoiCallback
1347 //! Here's where the actual audio processing happens. We call upon all the active connections'
1348 //! sinks to provide data to us which can be put/mixed in the output buffer! Also, we make the
1349 //! input data available to any sources that may call upon us during this time!
1351 //! \param *pInputBuffer : Points to a buffer with recorded data.
1352 //! \param *pOutputBuffer : Points to a buffer to receive playback data.
1353 //! \param framesPerBuffer : Number of sample frames in input and output buffers. Number of channels,
1354 //! which are interleaved, is fixed at Device Open (Active) time. In this implementation,
1355 //! the number of channels are fixed to use the maximum available.
1356 //! \param dropsDetected : True if dropouts were detected in input or output. Can be used to signal the GUI.
1360 //**********************************************************************************************
1361 int WCMRPortAudioDevice::AudioCallback( const float *pInputBuffer, float *pOutputBuffer, unsigned long framesPerBuffer, bool dropsDetected )
1363 UMicroseconds theStartTime;
1368 if (m_IgnoreThisDrop)
1369 m_IgnoreThisDrop = false; //We'll ignore once, just once!
1374 m_pInputData = pInputBuffer;
1376 // VKamyshniy: Is this a right place to call the client???:
1377 struct WCMRAudioDeviceManagerClient::AudioCallbackData audioCallbackData =
1383 theStartTime.MicroSeconds()*1000
1386 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::AudioCallback, (void *)&audioCallbackData );
1388 //Don't try to access after this call returns!
1389 m_pInputData = NULL;
1391 m_SampleCounter += framesPerBuffer;
1393 return m_StopRequested;
1399 //**********************************************************************************************
1400 // WCMRPortAudioDeviceManager::WCMRPortAudioDeviceManager
1402 //! The constructuor, we initialize PA, and build the device list.
1404 //! \param *pTheClient : The manager's client object (which receives notifications).
1405 //! \param interfaceType : The PortAudio interface type to use for this manager - acts as a filter.
1406 //! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true.
1408 //! \return Nothing.
1410 //**********************************************************************************************
1411 WCMRPortAudioDeviceManager::WCMRPortAudioDeviceManager (WCMRAudioDeviceManagerClient *pTheClient,
1412 eAudioDeviceFilter eCurAudioDeviceFilter, bool useMultithreading, bool bNocopy)
1413 : WCMRAudioDeviceManager (pTheClient, eCurAudioDeviceFilter)
1415 , m_UseMultithreading(useMultithreading)
1416 , m_bNoCopyAudioBuffer(bNocopy)
1419 std::cout << "API::PortAudioDeviceManager::PA Device manager constructor" << std::endl;
1421 //Always create the None device first...
1422 m_NoneDevice = new WCMRNativeAudioNoneDevice(this);
1424 WTErr err = generateDeviceListImpl();
1429 timeBeginPeriod (1);
1433 //**********************************************************************************************
1434 // WCMRPortAudioDeviceManager::~WCMRPortAudioDeviceManager
1436 //! It clears the device list, releasing each of the device.
1440 //! \return Nothing.
1442 //**********************************************************************************************
1443 WCMRPortAudioDeviceManager::~WCMRPortAudioDeviceManager()
1447 std::cout << "API::Destroying PortAudioDeviceManager " << std::endl;
1451 delete m_NoneDevice;
1455 //destructors should absorb exceptions, no harm in logging though!!
1456 DEBUG_MSG ("Exception during destructor");
1463 WCMRAudioDevice* WCMRPortAudioDeviceManager::initNewCurrentDeviceImpl(const std::string & deviceName)
1465 destroyCurrentDeviceImpl();
1467 std::cout << "API::PortAudioDeviceManager::initNewCurrentDevice " << deviceName << std::endl;
1468 if (deviceName == m_NoneDevice->DeviceName() )
1470 m_CurrentDevice = m_NoneDevice;
1471 return m_CurrentDevice;
1475 WTErr err = GetDeviceInfoByName(deviceName, devInfo);
1481 std::cout << "API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName << std::endl;
1482 TRACE_MSG ("API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName);
1484 m_CurrentDevice = new WCMRPortAudioDevice (this, devInfo.m_DeviceId, m_UseMultithreading, m_bNoCopyAudioBuffer);
1488 std::cout << "Unabled to create PA Device: " << devInfo.m_DeviceId << std::endl;
1489 DEBUG_MSG ("Unabled to create PA Device: " << devInfo.m_DeviceId);
1493 return m_CurrentDevice;
1497 void WCMRPortAudioDeviceManager::destroyCurrentDeviceImpl()
1499 if (m_CurrentDevice != m_NoneDevice)
1500 delete m_CurrentDevice;
1502 m_CurrentDevice = 0;
1506 WTErr WCMRPortAudioDeviceManager::getDeviceAvailableSampleRates(DeviceID deviceId, std::vector<int>& sampleRates)
1508 WTErr retVal = eNoErr;
1510 sampleRates.clear();
1511 const PaDeviceInfo *pPaDeviceInfo = Pa_GetDeviceInfo(deviceId);
1513 //now find supported sample rates
1514 //following parameters are needed for sample rates validation
1515 PaStreamParameters inputParameters, outputParameters;
1516 PaStreamParameters *pInS = NULL, *pOutS = NULL;
1518 inputParameters.device = deviceId;
1519 inputParameters.channelCount = std::min<int>(2, pPaDeviceInfo->maxInputChannels);
1520 inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
1521 inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
1522 inputParameters.hostApiSpecificStreamInfo = 0;
1524 if (inputParameters.channelCount)
1525 pInS = &inputParameters;
1527 outputParameters.device = deviceId;
1528 outputParameters.channelCount = std::min<int>(2, pPaDeviceInfo->maxOutputChannels);
1529 outputParameters.sampleFormat = paFloat32;
1530 outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
1531 outputParameters.hostApiSpecificStreamInfo = 0;
1533 if (outputParameters.channelCount)
1534 pOutS = &outputParameters;
1536 for(int sr=0; gAllSampleRates[sr] > 0; sr++)
1538 if( paFormatIsSupported == Pa_IsFormatSupported(pInS, pOutS, gAllSampleRates[sr]) )
1540 sampleRates.push_back ((int)gAllSampleRates[sr]);
1548 WTErr WCMRPortAudioDeviceManager::getDeviceAvailableBufferSizes(DeviceID deviceId, std::vector<int>& buffers)
1550 WTErr retVal = eNoErr;
1554 //make PA request to get actual device buffer sizes
1555 long minSize, maxSize, preferredSize, granularity;
1557 PaError paErr = PaAsio_GetAvailableBufferSizes(deviceId, &minSize, &maxSize, &preferredSize, &granularity);
1559 //for Windows ASIO devices we always use prefferes buffer size ONLY
1560 if (paNoError == paErr )
1562 buffers.push_back(preferredSize);
1566 retVal = eAsioFailed;
1567 std::cout << "API::PortAudioDeviceManager::GetBufferSizes: error: " << Pa_GetErrorText (paErr) << " getting buffer sizes for device: "<< deviceId << std::endl;
1574 WTErr WCMRPortAudioDeviceManager::generateDeviceListImpl()
1576 std::cout << "API::PortAudioDeviceManager::Generating device list" << std::endl;
1578 WTErr retVal = eNoErr;
1580 //Initialize PortAudio and ASIO first
1581 PaError paErr = Pa_Initialize();
1583 if (paErr != paNoError)
1585 //ToDo: throw an exception here!
1586 retVal = eSomeThingNotInitailzed;
1590 // lock DeviceInfoVec firts
1591 wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex);
1595 DeviceInfo *pDevInfo = new DeviceInfo(NONE_DEVICE_ID, m_NoneDevice->DeviceName() );
1596 pDevInfo->m_AvailableSampleRates = m_NoneDevice->SamplingRates();
1597 m_DeviceInfoVec.push_back(pDevInfo);
1600 //Get device count...
1601 int numDevices = Pa_GetDeviceCount();
1604 for (int thisDeviceID = 0; thisDeviceID < numDevices; thisDeviceID++)
1606 //if it's of the required type...
1607 const PaDeviceInfo *pPaDeviceInfo = Pa_GetDeviceInfo(thisDeviceID);
1609 if (Pa_GetHostApiInfo(pPaDeviceInfo->hostApi)->type == paASIO)
1611 //build a device object...
1614 std::cout << "API::PortAudioDeviceManager::DeviceID: " << thisDeviceID << ", Device Name: " << pPaDeviceInfo->name << std::endl;
1615 TRACE_MSG ("PA DeviceID: " << thisDeviceID << ", Device Name: " << pPaDeviceInfo->name);
1617 DeviceInfo *pDevInfo = new DeviceInfo(thisDeviceID, pPaDeviceInfo->name);
1620 //Get available sample rates
1621 std::vector<int> availableSampleRates;
1622 WTErr wErr = WCMRPortAudioDeviceManager::getDeviceAvailableSampleRates(thisDeviceID, availableSampleRates);
1626 DEBUG_MSG ("Failed to get device available sample rates. Device ID: " << m_DeviceID);
1628 continue; //proceed to the next device
1631 pDevInfo->m_AvailableSampleRates = availableSampleRates;
1632 pDevInfo->m_MaxInputChannels = pPaDeviceInfo->maxInputChannels;
1633 pDevInfo->m_MaxOutputChannels = pPaDeviceInfo->maxOutputChannels;
1635 //Get available buffer sizes
1636 std::vector<int> availableBuffers;
1637 wErr = getDeviceAvailableBufferSizes(thisDeviceID, availableBuffers);
1641 DEBUG_MSG ("Failed to get device available buffer sizes. Device ID: " << m_DeviceID);
1643 continue; //proceed to the next device
1646 pDevInfo->m_AvailableBufferSizes = availableBuffers;
1648 //Now check if this device is acceptable according to current input/output settings
1649 bool bRejectDevice = false;
1650 switch(m_eAudioDeviceFilter)
1652 case eInputOnlyDevices:
1653 if (pDevInfo->m_MaxInputChannels != 0)
1655 m_DeviceInfoVec.push_back(pDevInfo);
1659 // Delete unnecesarry device
1660 bRejectDevice = true;
1663 case eOutputOnlyDevices:
1664 if (pDevInfo->m_MaxOutputChannels != 0)
1666 m_DeviceInfoVec.push_back(pDevInfo);
1670 // Delete unnecesarry device
1671 bRejectDevice = true;
1674 case eFullDuplexDevices:
1675 if (pDevInfo->m_MaxInputChannels != 0 && pDevInfo->m_MaxOutputChannels != 0)
1677 m_DeviceInfoVec.push_back(pDevInfo);
1681 // Delete unnecesarry device
1682 bRejectDevice = true;
1687 m_DeviceInfoVec.push_back(pDevInfo);
1693 TRACE_MSG ("API::PortAudioDeviceManager::Device " << pDevInfo->m_DeviceName << "Rejected. \
1694 In Channels = " << pDevInfo->m_MaxInputChannels << "Out Channels = " <<pDevInfo->m_MaxOutputChannels );
1701 std::cout << "API::PortAudioDeviceManager::Unabled to create PA Device: " << std::endl;
1702 DEBUG_MSG ("Unabled to create PA Device: " << thisDeviceID);
1707 //If no devices were found, that's not a good thing!
1708 if (m_DeviceInfoVec.empty() )
1710 std::cout << "API::PortAudioDeviceManager::No matching PortAudio devices were found, total PA devices = " << numDevices << std::endl;
1711 DEBUG_MSG ("No matching PortAudio devices were found, total PA devices = " << numDevices);
1714 //we don't need PA initialized right now
1721 WTErr WCMRPortAudioDeviceManager::getDeviceSampleRatesImpl(const std::string & deviceName, std::vector<int>& sampleRates) const
1723 sampleRates.clear ();
1725 WTErr retVal = eNoErr;
1727 if (m_CurrentDevice && deviceName == m_CurrentDevice->DeviceName() )
1729 sampleRates=m_CurrentDevice->SamplingRates();
1734 retVal = GetDeviceInfoByName(deviceName, devInfo);
1736 if (eNoErr == retVal)
1738 sampleRates=devInfo.m_AvailableSampleRates;
1742 std::cout << "API::PortAudioDeviceManager::GetSampleRates: Device not found: "<< deviceName << std::endl;
1749 WTErr WCMRPortAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& buffers) const
1751 WTErr retVal = eNoErr;
1755 //first check if the request has been made for None device
1756 if (deviceName == m_NoneDevice->DeviceName() )
1758 buffers=m_NoneDevice->BufferSizes();
1762 if (m_CurrentDevice && deviceName == m_CurrentDevice->DeviceName() )
1764 buffers=m_CurrentDevice->BufferSizes();
1769 retVal = GetDeviceInfoByName(deviceName, devInfo);
1771 if (eNoErr == retVal)
1773 std::cout << "API::PortAudioDeviceManager::GetBufferSizes: got buffer :"<< devInfo.m_AvailableBufferSizes.front() << std::endl;
1774 buffers = devInfo.m_AvailableBufferSizes;
1778 std::cout << "API::PortAudioDeviceManager::GetBufferSizes: Device not found: "<< deviceName << std::endl;