update wavesaudio backend, now supports Windows (ASIO) as well as OS X (CoreAudio)
[ardour.git] / libs / backends / wavesaudio / wavesapi / devicemanager / WCMRPortAudioDeviceManager.cpp
1 //----------------------------------------------------------------------------------
2 //
3 // Copyright (c) 2008 Waves Audio Ltd. All rights reserved.
4 //
5 //! \file       WCMRPortAudioDeviceManager.cpp
6 //!
7 //! WCMRPortAudioDeviceManager and related class declarations
8 //!
9 //---------------------------------------------------------------------------------*/
10 #include "WCMRPortAudioDeviceManager.h"
11 #include "MiscUtils/safe_delete.h"
12 #include "UMicroseconds.h"
13 #include <sstream>
14 #include <algorithm>
15 using namespace wvNS;
16 #include "IncludeWindows.h"
17 #include <MMSystem.h>
18 #include "pa_asio.h"
19 #include "asio.h"
20
21 ///< Supported Sample rates                                                                                                  
22 static const double gAllSampleRates[] =
23         {
24                 44100.0, 48000.0, 88200.0, 96000.0, -1 /* negative terminated  list */
25         };
26
27
28
29 ///< Default Supported Buffer Sizes.
30 static const int gAllBufferSizes[] =
31         {
32                 32, 64, 96, 128, 192, 256, 512, 1024, 2048
33         };
34         
35
36 ///< The default SR.
37 static const int DEFAULT_SR = 44100;
38 ///< The default buffer size.
39 static const int DEFAULT_BUFFERSIZE = 128;
40
41 static const int NONE_DEVICE_ID = -1;
42
43 ///< Number of stalls to wait before notifying user...
44 static const int NUM_STALLS_FOR_NOTIFICATION = 100; // 100 corresponds to 100 x 42 ms idle timer - about 4 seconds.
45 static const int CHANGE_CHECK_COUNTER_PERIOD = 100; // 120 corresponds to 120 x 42 ms idle timer - about 4 seconds.
46         
47 #define HUNDRED_NANO_TO_MILLI_CONSTANT 10000
48 #define CONSUMPTION_CALCULATION_INTERVAL 500 // Milli Seconds
49
50
51 // This wrapper is used to adapt device DoIdle method as entry point for MS thread
52 DWORD WINAPI WCMRPortAudioDevice::__DoIdle__(LPVOID lpThreadParameter)
53 {
54         WCMRPortAudioDevice* pDevice = (WCMRPortAudioDevice*)lpThreadParameter;
55         pDevice->DoIdle();
56         return 0;
57 }
58
59 //**********************************************************************************************
60 // WCMRPortAudioDevice::WCMRPortAudioDevice 
61 //
62 //! Constructor for the audio device. Opens the PA device
63 //! and gets information about the device.
64 //! Starts the thread which will process requests to this device
65 //!     such as determining supported sampling rates, buffer sizes, and channel counts.
66 //!
67 //! \param *pManager    : The audio device manager that's managing this device.
68 //! \param deviceID             : The port audio device ID.
69 //! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true.
70 //! 
71 //! \return Nothing.
72 //! 
73 //**********************************************************************************************
74 WCMRPortAudioDevice::WCMRPortAudioDevice (WCMRPortAudioDeviceManager *pManager, unsigned int deviceID, bool useMultithreading, bool bNoCopy) :
75         WCMRNativeAudioDevice (pManager, useMultithreading, bNoCopy)
76         , m_SampleCounter(0)
77         , m_BufferSizeChangeRequested (0)
78         , m_BufferSizeChangeReported (0)
79         , m_ResetRequested (0)
80         , m_ResetReported (0)
81         , m_ResyncRequested (0)
82         , m_ResyncReported (0)
83         , m_DropsDetected(0)
84         , m_DropsReported(0)
85         , m_IgnoreThisDrop(true)
86         , m_hDeviceProcessingThread(NULL)
87         , m_DeviceProcessingThreadID(0)
88         , m_hUpdateDeviceInfoRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
89         , m_hUpdateDeviceInfoDone(CreateEvent(NULL, FALSE, FALSE, NULL))
90         , m_hActivateRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
91         , m_hActivationDone(CreateEvent(NULL, FALSE, FALSE, NULL))
92         , m_hDeActivateRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
93         , m_hDeActivationDone(CreateEvent(NULL, FALSE, FALSE, NULL))
94         , m_hStartStreamingRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
95         , m_hStartStreamingDone(CreateEvent(NULL, FALSE, FALSE, NULL))
96         , m_hStopStreamingRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
97         , m_hStopStreamingDone(CreateEvent(NULL, FALSE, FALSE, NULL))
98         , m_hResetRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
99         , m_hResetDone(CreateEvent(NULL, FALSE, FALSE, NULL))
100         , m_hResetFromDevRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
101         , m_hBufferSizeChangedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
102         , m_hSampleRateChangedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
103         , m_hExitIdleThread(CreateEvent(NULL, FALSE, FALSE, NULL))
104         , m_hDeviceInitialized(CreateEvent(NULL, FALSE, FALSE, NULL))
105         , m_lastErr(eNoErr)
106 {
107     AUTO_FUNC_DEBUG;
108
109         //Set initial device info...
110         m_DeviceID = deviceID;
111         m_PortAudioStream = NULL;
112         m_CurrentSamplingRate = DEFAULT_SR;
113         m_CurrentBufferSize = DEFAULT_BUFFERSIZE;
114         m_StopRequested = true;
115         m_pInputData = NULL;
116
117         //initialize device processing thread
118         //the divice become alive and now is able to process requests
119         m_hDeviceProcessingThread = CreateThread( NULL, 0, __DoIdle__, (LPVOID)this, 0, &m_DeviceProcessingThreadID );
120
121         if (!m_hDeviceProcessingThread)
122         {
123                 DEBUG_MSG("API::Device " << m_DeviceName << " cannot create processing thread");
124                 throw eGenericErr;
125         }
126
127         WaitForSingleObject(m_hDeviceInitialized, INFINITE);
128
129         if (ConnectionStatus() == DeviceErrors)
130         {
131                 throw m_lastErr;
132         }
133 }
134
135
136 void WCMRPortAudioDevice::initDevice()
137 {
138         // Initialize COM for this thread
139         std::cout << "API::Device " << m_DeviceID << " initializing COM" << std::endl;
140
141         if (S_OK == CoInitialize(NULL) )
142         {
143                 // Initialize PA
144                 Pa_Initialize();
145
146                 updateDeviceInfo();
147
148                 //should use a valid current SR...
149                 if (m_SamplingRates.size())
150                 {
151                         //see if the current sr is present in the sr list, if not, use the first one!
152                         std::vector<int>::iterator intIter = find(m_SamplingRates.begin(), m_SamplingRates.end(), m_CurrentSamplingRate);
153                         if (intIter == m_SamplingRates.end())
154                         {
155                                 //not found... use the first one
156                                 m_CurrentSamplingRate = m_SamplingRates[0];
157                         }
158                 }
159                 else
160                         std::cout << "API::Device " << m_DeviceName << " Device does not support any sample rate of ours" << std::endl;
161         
162                 //should use a valid current buffer size
163                 if (m_BufferSizes.size())
164                 {
165                         //see if the current sr is present in the buffersize list, if not, use the first one!
166                         std::vector<int>::iterator intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), m_CurrentBufferSize);
167                         if (intIter == m_BufferSizes.end())
168                         {
169                                 //not found... use the first one
170                                 m_CurrentBufferSize = m_BufferSizes[0];
171                         }
172                 }
173         
174                 //build our input/output level lists
175                 for (unsigned int currentChannel = 0; currentChannel < m_InputChannels.size(); currentChannel++)
176                 {
177                         m_InputLevels.push_back (0.0);
178                 }
179
180                 //build our input/output level lists
181                 for (unsigned int currentChannel = 0; currentChannel < m_OutputChannels.size(); currentChannel++)
182                 {
183                         m_OutputLevels.push_back (0.0);
184                 }
185
186                 std::cout << "API::Device " << m_DeviceName << " Device has been initialized" << std::endl;
187                 m_ConnectionStatus = DeviceDisconnected;
188                 m_lastErr = eNoErr;
189         }
190         else
191         {
192                 /*Replace with debug trace*/std::cout << "API::Device " << m_DeviceName << " cannot initialize COM" << std::endl;
193                 DEBUG_MSG("Device " << m_DeviceName << " cannot initialize COM");
194                 m_ConnectionStatus = DeviceErrors;
195                 m_lastErr = eSomeThingNotInitailzed;
196                 SetEvent(m_hExitIdleThread);
197         }
198
199         SetEvent(m_hDeviceInitialized);
200 }
201
202 void WCMRPortAudioDevice::terminateDevice()
203 {
204         std::cout << "API::Device " << m_DeviceName << " Terminating DEVICE" << std::endl;
205
206         //If device is streaming, need to stop it!
207         if (Streaming())
208         {
209                 stopStreaming();
210         }
211                 
212         //If device is active (meaning stream is open) we need to close it.
213         if (Active())
214         {
215                 deactivateDevice();
216         }
217
218         std::cout << "API::Device " << m_DeviceName << " Terminating PA" << std::endl;
219
220         //Deinitialize PA
221         Pa_Terminate();
222 }
223
224
225 //**********************************************************************************************
226 // WCMRPortAudioDevice::~WCMRPortAudioDevice 
227 //
228 //! Destructor for the audio device. The base release all the connections that were created, if
229 //!             they have not been already destroyed! Here we simply stop streaming, and close device
230 //!             handles if necessary.
231 //!
232 //! \param none
233 //! 
234 //! \return Nothing.
235 //! 
236 //**********************************************************************************************
237 WCMRPortAudioDevice::~WCMRPortAudioDevice ()
238 {
239     AUTO_FUNC_DEBUG;
240
241         std::cout << "API::Destroying Device Instance: " << DeviceName() << std::endl;
242         try
243         {
244                 //Stop deviceprocessing thread
245                 SignalObjectAndWait(m_hExitIdleThread, m_hDeviceProcessingThread, INFINITE, false);
246
247                 std::cout << "API::Device " << m_DeviceName << " Processing Thread is stopped" << std::endl;
248
249                 CloseHandle(m_hDeviceProcessingThread);
250
251                 //Now it's safe to free all event handlers
252                 CloseHandle(m_hUpdateDeviceInfoRequestedEvent);
253                 CloseHandle(m_hUpdateDeviceInfoDone);
254                 CloseHandle(m_hActivateRequestedEvent);
255                 CloseHandle(m_hActivationDone);
256                 CloseHandle(m_hDeActivateRequestedEvent);
257                 CloseHandle(m_hDeActivationDone);
258                 CloseHandle(m_hStartStreamingRequestedEvent);
259                 CloseHandle(m_hStartStreamingDone);
260                 CloseHandle(m_hStopStreamingRequestedEvent);
261                 CloseHandle(m_hStopStreamingDone);
262                 CloseHandle(m_hResetRequestedEvent);
263                 CloseHandle(m_hResetDone);
264                 CloseHandle(m_hResetFromDevRequestedEvent);
265                 CloseHandle(m_hBufferSizeChangedEvent);
266                 CloseHandle(m_hSampleRateChangedEvent);
267                 CloseHandle(m_hExitIdleThread);
268                 CloseHandle(m_hDeviceInitialized);
269         }
270         catch (...)
271         {
272                 //destructors should absorb exceptions, no harm in logging though!!
273                 DEBUG_MSG ("Exception during destructor");
274         }
275 }
276
277
278 WTErr WCMRPortAudioDevice::UpdateDeviceInfo ()
279 {
280         std::cout << "API::Device (ID:)" << m_DeviceID << " Updating device info" << std::endl;
281         
282         SignalObjectAndWait(m_hUpdateDeviceInfoRequestedEvent, m_hUpdateDeviceInfoDone, INFINITE, false);
283
284         return eNoErr;
285 }
286
287
288 //**********************************************************************************************
289 // WCMRPortAudioDevice::updateDeviceInfo 
290 //
291 //! Must be called be device processing thread
292 //! Updates Device Information about channels, sampling rates, buffer sizes.
293 //!
294 //! \return Nothing.
295 //! 
296 //**********************************************************************************************
297 void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/)
298 {
299     AUTO_FUNC_DEBUG;
300
301         //get device info
302         const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
303         
304         //update name.
305         m_DeviceName = pDeviceInfo->name;
306
307         std::cout << "API::Device " << m_DeviceName << " Getting device info " << std::endl;
308
309         //following parameters are needed opening test stream and for sample rates validation
310         PaStreamParameters inputParameters, outputParameters;
311         PaStreamParameters *pInS = NULL, *pOutS = NULL;
312
313         inputParameters.device = m_DeviceID;
314         inputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxInputChannels);
315         inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
316         inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
317         inputParameters.hostApiSpecificStreamInfo = 0;
318
319         if (inputParameters.channelCount)
320                 pInS = &inputParameters;
321
322         outputParameters.device = m_DeviceID;
323         outputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxOutputChannels);
324         outputParameters.sampleFormat = paFloat32;
325         outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
326         outputParameters.hostApiSpecificStreamInfo = 0;
327
328         if (outputParameters.channelCount)
329                 pOutS = &outputParameters;
330
331         std::cout << "API::Device" << m_DeviceName << " Updating sample rates " << std::endl;
332         ////////////////////////////////////////////////////////////////////////////////////
333         //update list of supported SRs...
334         m_SamplingRates.clear();
335                 
336         // now iterate through our standard SRs and check if they are supported by device
337         // store them for this device
338         for(int sr=0; gAllSampleRates[sr] > 0; sr++)
339         {
340                 PaError err = Pa_IsFormatSupported(pInS, pOutS, gAllSampleRates[sr]);
341                 if( err == paFormatIsSupported)
342                 {
343                         m_SamplingRates.push_back ((int)gAllSampleRates[sr]);
344                 }
345         }
346
347         std::cout << "API::Device" << m_DeviceName << " Updating buffer sizes" << std::endl;
348         ///////////////////////////////////////////////////////////////////////////////////
349         //update buffer sizes
350         m_BufferSizes.clear();
351         bool useDefaultBuffers = true;
352         PaError paErr = paNoError;
353
354         //sometimes devices change buffer size if sample rate changes
355         //it updates buffer size during stream opening
356         //we need to find out how device would behave with current sample rate
357         //try opening test stream to load device driver for current sample rate and buffer size
358         //(skip this step if the device is Active)
359         if ( !Active() )
360         {
361                 if (paNoError != testStateValidness(m_CurrentSamplingRate, m_CurrentBufferSize) )
362                 {
363                         //buffer size did change
364                         Pa_Terminate();
365                         Pa_Initialize();
366
367                         // test validness with current sample rate and device prefered buffer size
368                         paErr = testStateValidness(m_CurrentSamplingRate, 0);
369                 }
370         }
371
372         if (paErr == paNoError)
373         {
374                 // In ASIO Windows, the buffer size is set from the sound device manufacturer's control panel 
375                 long minSize, maxSize, preferredSize, granularity;
376                 paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
377         
378                 if (paErr == paNoError)
379                 {
380                         std::cout << "API::Device " << m_DeviceName << " Buffers: " << minSize << " " << maxSize << " " << preferredSize << std::endl;
381                         
382                         m_BufferSizes.push_back (preferredSize);
383                         useDefaultBuffers = false;
384                 }
385                 else
386                 {
387                         std::cout << "API::Device" << m_DeviceName << " Preffered buffer size is not supported" << std::endl;
388                 }
389         }
390         else
391         {
392                 std::cout << "API::Device" << m_DeviceName << " Device does not start with sample rate: "<< m_CurrentSamplingRate << " and default buffer size" << std::endl;
393         }
394
395         if (useDefaultBuffers)
396         {
397                 std::cout << "API::Device" << m_DeviceName << " Using default buffer sizes " <<std::endl;
398                 for(int bsize=0; bsize < (sizeof(gAllBufferSizes)/sizeof(gAllBufferSizes[0])); bsize++)
399                         m_BufferSizes.push_back (gAllBufferSizes[bsize]);
400         }
401
402         /////////////////////////////////////////////////////////////////////////////////////////
403         //update channels info
404         {
405                 int maxInputChannels = pDeviceInfo->maxInputChannels;
406                 int maxOutputChannels = pDeviceInfo->maxOutputChannels;
407
408                 //Update input channels
409                 m_InputChannels.clear();
410                 for (int channel = 0; channel < maxInputChannels; channel++)
411                 {
412                         std::stringstream chNameStream;
413                         //A better implementation would be to retrieve the names from ASIO or CoreAudio interfaces
414                         chNameStream << "Input " << (channel+1);
415                         m_InputChannels.push_back (chNameStream.str());
416                 }
417         
418         
419                 //Update output channels
420                 m_OutputChannels.clear();
421                 for (int channel = 0; channel < maxOutputChannels; channel++)
422                 {
423                         std::stringstream chNameStream;
424                         //A better implementation would be to retrieve the names from ASIO or CoreAudio interfaces
425                         chNameStream << "Output " << (channel+1);
426                         m_OutputChannels.push_back (chNameStream.str());
427                 }
428         }
429
430         std::cout << "API::Device" << m_DeviceName << " Device info update has been finished" << std::endl;
431
432         if (callerIsWaiting)
433                 SetEvent(m_hUpdateDeviceInfoDone);
434 }
435
436
437 PaError WCMRPortAudioDevice::testStateValidness(int sampleRate, int bufferSize)
438 {
439         PaError paErr = paNoError;
440
441         //get device info
442         const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
443
444         //following parameters are needed opening test stream and for sample rates validation
445         PaStreamParameters inputParameters, outputParameters;
446         PaStreamParameters *pInS = NULL, *pOutS = NULL;
447
448         inputParameters.device = m_DeviceID;
449         inputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxInputChannels);
450         inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
451         inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
452         inputParameters.hostApiSpecificStreamInfo = 0;
453
454         if (inputParameters.channelCount)
455                 pInS = &inputParameters;
456
457         outputParameters.device = m_DeviceID;
458         outputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxOutputChannels);
459         outputParameters.sampleFormat = paFloat32;
460         outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
461         outputParameters.hostApiSpecificStreamInfo = 0;
462
463         if (outputParameters.channelCount)
464                 pOutS = &outputParameters;
465
466         PaStream *portAudioStream = NULL;
467                 
468         //sometimes devices change buffer size if sample rate changes
469         //it updates buffer size during stream opening
470         //we need to find out how device would behave with current sample rate
471         //try opening test stream to load device driver for current sample rate and buffer size
472         paErr = Pa_OpenStream (&portAudioStream, pInS, pOutS, m_CurrentSamplingRate, m_CurrentBufferSize, paDitherOff, NULL, NULL);
473         
474         if (portAudioStream)
475         {
476                 // close test stream
477                 Pa_CloseStream (portAudioStream);
478                 portAudioStream = NULL;
479         }
480
481         return paErr;
482 }
483
484
485 //**********************************************************************************************
486 // WCMRPortAudioDevice::CurrentSamplingRate 
487 //
488 //! The device's current sampling rate. This may be overridden, if the device needs to 
489 //!             query the driver for the current rate.
490 //!
491 //! \param none
492 //! 
493 //! \return The device's current sampling rate. -1 on error.
494 //! 
495 //**********************************************************************************************
496 int WCMRPortAudioDevice::CurrentSamplingRate ()
497 {
498     AUTO_FUNC_DEBUG;
499         //ToDo: Perhaps for ASIO devices that are active, we should retrive the SR from the device...
500         
501         return (m_CurrentSamplingRate);
502 }
503
504
505 WTErr WCMRPortAudioDevice::SetActive (bool newState)
506 {
507         if (newState == true)
508         {
509                 std::cout << "API::Device " << m_DeviceName << " Activation requested" << std::endl;
510                 SignalObjectAndWait(m_hActivateRequestedEvent, m_hActivationDone, INFINITE, false);
511         }
512         else
513         {
514                 std::cout << "API::Device " << m_DeviceName << " Deactivation requested" << std::endl;
515                 SignalObjectAndWait(m_hDeActivateRequestedEvent, m_hDeActivationDone, INFINITE, false);
516         }
517
518         if (newState == Active() )
519                 return eNoErr;
520         else
521                 return eGenericErr;
522 }
523
524
525 WTErr WCMRPortAudioDevice::SetStreaming (bool newState)
526 {
527         if (newState == true)
528         {
529                 std::cout << "API::Device " << m_DeviceName << " Stream start requested" << std::endl;
530                 SignalObjectAndWait(m_hStartStreamingRequestedEvent, m_hStartStreamingDone, INFINITE, false);
531         }
532         else
533         {
534                 std::cout << "API::Device " << m_DeviceName << " Stream stop requested" << std::endl;
535                 SignalObjectAndWait(m_hStopStreamingRequestedEvent, m_hStopStreamingDone, INFINITE, false);
536         }
537
538         if (newState == Streaming() )
539                 return eNoErr;
540         else
541                 return eGenericErr;
542 }
543
544
545 WTErr WCMRPortAudioDevice::ResetDevice()
546 {
547         std::cout << "API::Device: " << m_DeviceName << " Reseting device" << std::endl;
548         
549         SignalObjectAndWait(m_hResetRequestedEvent, m_hResetDone, INFINITE, false);
550
551         if (ConnectionStatus() == DeviceErrors)
552         {
553                 return m_lastErr;
554         }
555
556         return eNoErr;
557 }
558
559
560 //**********************************************************************************************
561 // WCMRPortAudioDevice::SetCurrentSamplingRate 
562 //
563 //! Change the sampling rate to be used by the device. 
564 //!
565 //! \param newRate : The rate to use (samples per sec).
566 //! 
567 //! \return eNoErr always. The derived classes may return error codes.
568 //! 
569 //**********************************************************************************************
570 WTErr WCMRPortAudioDevice::SetCurrentSamplingRate (int newRate)
571 {
572     AUTO_FUNC_DEBUG;
573         std::vector<int>::iterator intIter;
574         WTErr retVal = eNoErr;
575
576         //changes the status.
577         int oldRate = CurrentSamplingRate();
578         bool oldActive = Active();
579         
580         //no change, nothing to do
581         if (oldRate == newRate)
582                 return (retVal);
583
584         //see if this is one of our supported rates...
585         intIter = find(m_SamplingRates.begin(), m_SamplingRates.end(), newRate);
586
587         if (intIter == m_SamplingRates.end())
588         {
589                 //Can't change, perhaps use an "invalid param" type of error
590                 retVal = eCommandLineParameter;
591                 return (retVal);
592         }
593         
594         if (Streaming())
595         {
596                 //Can't change, perhaps use an "in use" type of error
597                 retVal = eGenericErr;
598                 return (retVal);
599         }
600         
601         if (oldActive)
602         {
603                 //Deactivate it for the change...
604                 SetActive (false);
605         }
606         
607         //make the change...
608         m_CurrentSamplingRate = newRate;
609
610         // Before reactivating the device: opening stream we should try getting buffer size update from the device
611         // because for new sampling rate some devices may change buffer size as well
612         int oldBufferSize = m_CurrentBufferSize;
613         
614         retVal = ResetDevice();
615
616         //reactivate it.        
617         if (oldActive && retVal == eNoErr)
618         {
619                 retVal = SetActive (true);
620         }
621
622         if (retVal != eNoErr)
623         {
624                 //revert changes if the device was not activated
625                 m_CurrentSamplingRate = oldRate;
626                 m_CurrentBufferSize = oldBufferSize;
627                 int bufferSize = m_CurrentBufferSize;
628                 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
629                 retVal = eCommandLineParameter;
630         }
631         
632         return (retVal);
633 }
634
635
636 //**********************************************************************************************
637 // WCMRPortAudioDevice::CurrentBufferSize
638 //
639 //! The device's current buffer size in use. This may be overridden, if the device needs to 
640 //!             query the driver for the current size.
641 //!
642 //! \param none
643 //! 
644 //! \return The device's current buffer size. 0 on error.
645 //! 
646 //**********************************************************************************************
647 int WCMRPortAudioDevice::CurrentBufferSize ()
648 {
649         return m_CurrentBufferSize;
650 }
651
652
653 //**********************************************************************************************
654 // WCMRPortAudioDevice::SetCurrentBufferSize
655 //
656 //! Change the buffer size to be used by the device. This will most likely be overridden, 
657 //!             the base class simply updates the member variable.
658 //!
659 //! \param newSize : The buffer size to use (in sample-frames)
660 //! 
661 //! \return eNoErr always. The derived classes may return error codes.
662 //! 
663 //**********************************************************************************************
664 WTErr WCMRPortAudioDevice::SetCurrentBufferSize (int newSize)
665 {
666     AUTO_FUNC_DEBUG;
667         WTErr retVal = eNoErr;
668         std::vector<int>::iterator intIter;
669
670         //changes the status.
671         int oldSize = CurrentBufferSize();
672         bool oldActive = Active();
673
674         //same size, nothing to do.
675         if (oldSize == newSize)
676                 return (retVal);
677         
678         //see if this is one of our supported rates...
679         intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), newSize);
680         if (intIter == m_BufferSizes.end())
681         {
682                 //Can't change, perhaps use an "invalid param" type of error
683                 retVal = eCommandLineParameter;
684                 return (retVal);
685         }
686         
687         if (Streaming())
688         {
689                 //Can't change, perhaps use an "in use" type of error
690                 retVal = eGenericErr;
691                 return (retVal);
692         }
693         
694         if (oldActive)
695         {
696                 //Deactivate it for the change...
697                 SetActive (false);
698         }
699         
700         //make the change...
701         m_CurrentBufferSize = newSize;
702
703         //reactivate it.        
704         if (oldActive)
705         {
706                 retVal = SetActive (true);
707         }
708
709         return (retVal);
710 }
711
712
713 //**********************************************************************************************
714 // WCMRPortAudioDevice::ConnectionStatus 
715 //
716 //! Retrieves the device's current connection status. This will most likely be overridden,
717 //!             in case some driver communication is required to query the status.
718 //!
719 //! \param none
720 //! 
721 //! \return A ConnectionStates value.
722 //! 
723 //**********************************************************************************************
724 WCMRPortAudioDevice::ConnectionStates WCMRPortAudioDevice::ConnectionStatus ()
725 {
726     AUTO_FUNC_DEBUG;
727         //ToDo: May want to do something more to extract the actual status!
728         return (m_ConnectionStatus);
729         
730 }
731
732
733 //**********************************************************************************************
734 // WCMRPortAudioDevice::activateDevice
735 //
736 //!     IS CALLED BY PROCESS THREAD
737 //! Sets the device into "active" state. Essentially, opens the PA device. 
738 //!             If it's an ASIO device it may result in buffer size change in some cases.
739 //!
740 //**********************************************************************************************
741 void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
742 {
743         AUTO_FUNC_DEBUG;
744
745         PaError paErr = paNoError;
746         
747         // if device is not active activate it
748         if (!Active() )
749         {
750                 PaStreamParameters inputParameters, outputParameters;
751                 PaStreamParameters *pInS = NULL, *pOutS = NULL;
752
753                 const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
754                 const PaHostApiInfo *pHostApiInfo = Pa_GetHostApiInfo(pDeviceInfo->hostApi);
755
756                 inputParameters.device = m_DeviceID;
757                 inputParameters.channelCount = (int)m_InputChannels.size();
758                 inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
759                 inputParameters.suggestedLatency = Pa_GetDeviceInfo(m_DeviceID)->defaultLowInputLatency;
760                 inputParameters.hostApiSpecificStreamInfo = 0;
761
762                 if (inputParameters.channelCount)
763                         pInS = &inputParameters;
764
765                 outputParameters.device = m_DeviceID;
766                 outputParameters.channelCount = (int)m_OutputChannels.size();
767                 outputParameters.sampleFormat = paFloat32;
768                 outputParameters.suggestedLatency = Pa_GetDeviceInfo(m_DeviceID)->defaultLowOutputLatency;
769                 outputParameters.hostApiSpecificStreamInfo = 0;
770
771                 if (outputParameters.channelCount)
772                         pOutS = &outputParameters;
773                 
774                 std::cout << "API::Device" << m_DeviceName << " Opening device stream " << std::endl;
775                 std::cout << "Sample rate: " << m_CurrentSamplingRate << " buffer size: " << m_CurrentBufferSize << std::endl;
776                 paErr = Pa_OpenStream(&m_PortAudioStream, 
777                                                           pInS,
778                                                           pOutS,
779                                                           m_CurrentSamplingRate,
780                                                           m_CurrentBufferSize,
781                                                           paDitherOff,
782                                                           WCMRPortAudioDevice::TheCallback,
783                                                           this);
784
785                 if(paErr == paNoError)
786                 {
787                         m_DropsDetected = 0;
788                         m_DropsReported = 0;
789                         m_IgnoreThisDrop = true;
790
791                         if (pHostApiInfo->type == paASIO)
792                         {
793                                 m_BufferSizeChangeRequested = 0;
794                                 m_BufferSizeChangeReported = 0;
795                                 m_ResetRequested = 0;
796                                 m_ResetReported = 0;
797                                 m_ResyncRequested = 0;
798                                 m_ResyncReported = 0;
799                                 PaAsio_SetMessageHook (StaticASIOMessageHook, this);
800                         }
801                         m_IsActive = true;
802                         m_ConnectionStatus = DeviceAvailable;
803                         m_lastErr = eNoErr;
804                 }
805                 else
806                 {
807                         //failed, do not update device state
808                         std::cout << "Failed to open pa stream stream " << paErr << std::endl;
809                         DEBUG_MSG( "Failed to open pa stream stream " << paErr );
810                         m_ConnectionStatus = DeviceErrors;
811                         m_lastErr = eAsioFailed;
812                 }
813
814         
815         }
816
817         if (callerIsWaiting)
818                 SetEvent(m_hActivationDone);
819 }
820
821
822 //**********************************************************************************************
823 // WCMRPortAudioDevice::deactivateDevice
824 //
825 //!     IS CALLED BY PROCESS THREAD
826 //! Sets the device into "inactive" state. Essentially, closes the PA device. 
827 //!
828 //**********************************************************************************************
829 void WCMRPortAudioDevice::deactivateDevice (bool callerIsWaiting/*=false*/)
830 {
831     AUTO_FUNC_DEBUG;
832
833         PaError paErr = paNoError;
834         
835         if (Active() )
836         {
837                 if (Streaming())
838                 {
839                         stopStreaming ();
840                 }
841                 
842                 if (m_PortAudioStream)
843                 {
844                         //close the stream first
845                         std::cout << "API::Device" << m_DeviceName << " Closing device stream" << std::endl;
846                         paErr = Pa_CloseStream (m_PortAudioStream);
847                         if(paErr == paNoError)
848                         {
849                                 m_PortAudioStream = NULL;
850                                 m_DropsDetected = 0;
851                                 m_DropsReported = 0;
852                                 m_IgnoreThisDrop = true;
853                                 m_BufferSizeChangeRequested = 0;
854                                 m_BufferSizeChangeReported = 0;
855                                 m_ResetRequested = 0;
856                                 m_ResetReported = 0;
857                                 m_ResyncRequested = 0;
858                                 m_ResyncReported = 0;
859                                 PaAsio_SetMessageHook (NULL, NULL);
860
861                                 //finaly set device state to "not active"
862                                 m_IsActive = false;
863                                 m_ConnectionStatus = DeviceDisconnected;
864                                 m_lastErr = eNoErr;
865                         }
866                         else
867                         {
868                                 //failed, do not update device state
869                                 std::cout << "Failed to close pa stream stream " << paErr << std::endl;
870                                 DEBUG_MSG( "Failed to open pa stream stream " << paErr );
871                                 m_ConnectionStatus = DeviceErrors;
872                                 m_lastErr = eAsioFailed;
873                         }
874                 }
875         }
876
877         if (callerIsWaiting)
878                 SetEvent(m_hDeActivationDone);
879 }
880
881
882 //**********************************************************************************************
883 // WCMRPortAudioDevice::startStreaming
884 //
885 //! Sets the devices into "streaming" state. Calls PA's Start stream routines.
886 //! This roughly corresponds to calling Start on the lower level interface.
887 //! 
888 //**********************************************************************************************
889 void WCMRPortAudioDevice::startStreaming (bool callerIsWaiting/*=false*/)
890 {
891     AUTO_FUNC_DEBUG;
892
893         // proceed if the device is not streaming
894         if (!Streaming () )
895         {
896                 PaError paErr = paNoError;
897                 m_StopRequested = false;
898                 m_SampleCounter = 0;
899
900                 std::cout << "API::Device" << m_DeviceName << " Starting device stream" << std::endl;
901                 paErr = Pa_StartStream( m_PortAudioStream );
902
903                 if(paErr == paNoError)
904                 {
905                         // if the stream was started successfully
906                         m_IsStreaming = true;
907                 }
908                 else
909                 {
910                         std::cout << "Failed to start PA stream: " << paErr << std::endl;
911                         DEBUG_MSG( "Failed to start PA stream: " << paErr );
912                         m_lastErr = eGenericErr;
913                 }
914         }
915                 
916         if (callerIsWaiting)
917                 SetEvent(m_hStartStreamingDone);
918 }
919
920
921 //**********************************************************************************************
922 // WCMRPortAudioDevice::stopStreaming
923 //
924 //! Sets the devices into "not streaming" state. Calls PA's Stop stream routines.
925 //! This roughly corresponds to calling Stop on the lower level interface.
926 //! 
927 //**********************************************************************************************
928 void WCMRPortAudioDevice::stopStreaming (bool callerIsWaiting/*=false*/)
929 {
930     AUTO_FUNC_DEBUG;
931
932         // proceed if the device is streaming
933         if (Streaming () )
934         {
935                 PaError paErr = paNoError;
936                 m_StopRequested = true;
937
938                 std::cout << "API::Device " << m_DeviceName << " Stopping device stream" << std::endl;
939                 paErr = Pa_StopStream( m_PortAudioStream );
940
941                 if(paErr == paNoError)
942                 {
943                         // if the stream was stopped successfully
944                         m_IsStreaming = false;
945                         m_pInputData = NULL;
946                 }
947                 else
948                 {
949                         std::cout << "Failed to stop PA stream: " << paErr << std::endl;
950                         DEBUG_MSG( "Failed to stop PA stream " << paErr );
951                         m_lastErr = eGenericErr;
952                 }
953         }
954
955         if (callerIsWaiting)
956                 SetEvent(m_hStopStreamingDone);
957 }
958
959
960 //**********************************************************************************************
961 // WCMRPortAudioDevice::resetDevice 
962 //
963 //! Resets the device, updates device info. Importnat: does PA reinitialization calling
964 //! Pa_terminate/Pa_initialize functions.
965 //!
966 //! \param none
967 //! 
968 //! \return nothing
969 //! 
970 //**********************************************************************************************
971 void WCMRPortAudioDevice::resetDevice (bool callerIsWaiting /*=false*/ )
972 {
973         std::cout << "API::Device" << m_DeviceName << "Reseting device" << std::endl;
974
975         // Keep device sates
976         bool wasStreaming = Streaming();
977         bool wasActive = Active();
978
979         // Notify the Application about reset
980         m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
981
982         // Reset the device
983         stopStreaming();
984         deactivateDevice();
985
986         // Reinitialize PA
987         Pa_Terminate();
988         Pa_Initialize();
989
990         updateDeviceInfo();
991
992         // Cache device buffer size as it might be changed during reset
993         int oldBufferSize = m_CurrentBufferSize;
994
995         // In ASIO Windows, the buffer size is set from the sound device manufacturer's control panel
996         // Backend should always use preffered buffer size value in this case
997         long minSize, maxSize, preferredSize, granularity;
998         PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
999
1000         if (paErr == paNoError)
1001         {
1002                 m_CurrentBufferSize = preferredSize;
1003         }
1004         else
1005         {
1006                 // if we can't get device buffer sizes, use the first one among supported
1007                 if (m_BufferSizes.size() != 0)
1008                         m_CurrentBufferSize = m_BufferSizes.front();
1009         }
1010
1011         // Notify the Application about device setting changes
1012         if (oldBufferSize != m_CurrentBufferSize)
1013         {
1014                 std::cout << "API::Device" << m_DeviceName << " buffer size changed" << std::endl;
1015                 int bufferSize = m_CurrentBufferSize;
1016                 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
1017         }
1018
1019         // Activate the device if it was active before
1020         if (wasActive)
1021                 activateDevice();
1022
1023         // Resume streaming if the device was streaming before
1024         if(wasStreaming)
1025         {
1026                 // Notify the Application to prepare for the stream start
1027                 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStartsStreaming);
1028                 startStreaming();
1029         }
1030
1031         if (callerIsWaiting)
1032                 SetEvent(m_hResetDone);
1033 }
1034
1035
1036 #ifdef _WINDOWS
1037
1038 long WCMRPortAudioDevice::StaticASIOMessageHook (void *pRefCon, long selector, long value, void* message, double* opt)
1039 {
1040         if (pRefCon)
1041         {
1042                 return ((WCMRPortAudioDevice*)(pRefCon))->ASIOMessageHook (selector, value, message, opt);
1043         }
1044         else
1045                 return -1;
1046 }
1047
1048 long WCMRPortAudioDevice::ASIOMessageHook (long selector, long WCUNUSEDPARAM(value), void* WCUNUSEDPARAM(message), double* WCUNUSEDPARAM(opt))
1049 {
1050         switch(selector)
1051         {
1052                 case kAsioBufferSizeChange:
1053                         m_BufferSizeChangeRequested++;
1054                         std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- m_BufferSizeChangeRequested" << std::endl;
1055                         SetEvent(m_hBufferSizeChangedEvent);
1056                         break;
1057
1058                 case kAsioResetRequest:
1059                         m_ResetRequested++;
1060                         std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioResetRequest" << std::endl;
1061                         SetEvent(m_hResetFromDevRequestedEvent);
1062                         break;
1063
1064                 case kAsioResyncRequest:
1065                         std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioResyncRequest" << std::endl;
1066                         m_ResyncRequested++;
1067                         break;
1068
1069                 case kAsioLatenciesChanged:
1070                         std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioLatenciesChanged" << std::endl;
1071                         SetEvent(m_hBufferSizeChangedEvent);
1072                         m_BufferSizeChangeRequested++;
1073                         break;
1074
1075         case kAsioOverload:
1076                         std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioOverload" << std::endl;
1077             m_DropsDetected++;
1078             break;
1079         }
1080         return 0;
1081 }
1082
1083 #endif
1084
1085
1086 //**********************************************************************************************
1087 // WCMRPortAudioDevice::DoIdle 
1088 //
1089 //! A place for doing idle time processing. The other derived classes will probably do something
1090 //!             meaningful.
1091 //!
1092 //! \param none
1093 //! 
1094 //! \return eNoErr always.
1095 //! 
1096 //**********************************************************************************************
1097 WTErr WCMRPortAudioDevice::DoIdle ()
1098 {
1099         WTErr retVal = eNoErr;
1100
1101         std::cout << "WCMRPortAudioDevice::DoIdle ()" << std::endl;
1102         HANDLE hEvents[] = 
1103         {
1104                 m_hUpdateDeviceInfoRequestedEvent,
1105                 m_hActivateRequestedEvent,
1106                 m_hDeActivateRequestedEvent,
1107                 m_hStartStreamingRequestedEvent,
1108                 m_hStopStreamingRequestedEvent,
1109                 m_hBufferSizeChangedEvent,
1110                 m_hSampleRateChangedEvent,
1111                 m_hResetRequestedEvent,
1112                 m_hResetFromDevRequestedEvent,
1113                 m_hExitIdleThread
1114         };
1115
1116         const size_t hEventsSize = sizeof(hEvents)/sizeof(hEvents[0]);
1117         
1118         initDevice();
1119
1120         for(;;)
1121         {
1122                 DWORD result = WaitForMultipleObjects (hEventsSize, hEvents, FALSE, INFINITE);
1123                 result = result - WAIT_OBJECT_0;
1124
1125                 if ((result < 0) || (result >= hEventsSize)) {
1126                         std::cout << "\t\t\t\t\t\t\tWCMRPortAudioDevice::DoIdle () -> (result < 0) || (result >= hEventsSize):" << result << std::endl;
1127                         retVal = eGenericErr;
1128                         break;
1129                 }
1130
1131                 if (hEvents[result] == m_hExitIdleThread) {
1132                         std::cout << "\t\t\t\t\t\t\tWCMRPortAudioDevice::DoIdle () -> m_hExitIdleThread" << result << std::endl;
1133                         retVal = eNoErr;
1134                         break;
1135                 }
1136
1137                 if (hEvents[result] == m_hUpdateDeviceInfoRequestedEvent) {
1138                         std::cout << "\t\t\t\t\t\tupdate requested ..." << std::endl;
1139                         updateDeviceInfo(true);
1140                 }
1141
1142                 if (hEvents[result] == m_hActivateRequestedEvent) {
1143                         std::cout << "\t\t\t\t\t\tactivation requested ..." << std::endl;
1144                         activateDevice(true);
1145                 }
1146
1147                 if (hEvents[result] == m_hDeActivateRequestedEvent) {
1148                         std::cout << "\t\t\t\t\t\tdeactivation requested ..." << std::endl;
1149                         deactivateDevice(true);
1150                 }
1151
1152                 if (hEvents[result] == m_hStartStreamingRequestedEvent) {
1153                         std::cout << "\t\t\t\t\t\tStart stream requested ..." << std::endl;
1154                         startStreaming(true);
1155                 }
1156
1157                 if (hEvents[result] == m_hStopStreamingRequestedEvent) {
1158                         std::cout << "\t\t\t\t\t\tStop stream requested ..." << std::endl;
1159                         stopStreaming(true);
1160                 }
1161
1162                 if (hEvents[result] == m_hResetRequestedEvent) {
1163                         std::cout << "\t\t\t\t\t\treset requested ..." << std::endl;
1164                         resetDevice(true);
1165                 }
1166
1167                 if (hEvents[result] == m_hResetFromDevRequestedEvent) {
1168                         std::cout << "\t\t\t\t\t\treset requested from device..." << std::endl;
1169                         resetDevice();
1170                 }
1171
1172                 if (hEvents[result] == m_hBufferSizeChangedEvent) {
1173                         std::cout << "\t\t\t\t\t\tbuffer size changed from device..." << std::endl;
1174                         m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged);
1175                 }
1176
1177                 if (hEvents[result] == m_hSampleRateChangedEvent) {
1178                         std::cout << "\t\t\t\t\t\tsample rate changed from device..." << std::endl;
1179                         m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::SamplingRateChanged);
1180                 }
1181         }
1182
1183         terminateDevice();
1184
1185         return retVal;
1186 }
1187
1188
1189 //**********************************************************************************************
1190 // WCMRPortAudioDevice::SetMonitorChannels 
1191 //
1192 //! Used to set the channels to be used for monitoring.
1193 //!
1194 //! \param leftChannel : Left monitor channel index.
1195 //! \param rightChannel : Right monitor channel index.
1196 //! 
1197 //! \return eNoErr always, the derived classes may return appropriate errors.
1198 //! 
1199 //**********************************************************************************************
1200 WTErr WCMRPortAudioDevice::SetMonitorChannels (int leftChannel, int rightChannel)
1201 {
1202     AUTO_FUNC_DEBUG;
1203         //This will most likely be overridden, the base class simply
1204         //changes the member.
1205         m_LeftMonitorChannel = leftChannel;
1206         m_RightMonitorChannel = rightChannel;
1207         return (eNoErr);
1208 }
1209
1210
1211
1212 //**********************************************************************************************
1213 // WCMRPortAudioDevice::SetMonitorGain 
1214 //
1215 //! Used to set monitor gain (or atten).
1216 //!
1217 //! \param newGain : The new gain or atten. value to use. Specified as a linear multiplier (not dB) 
1218 //! 
1219 //! \return eNoErr always, the derived classes may return appropriate errors.
1220 //! 
1221 //**********************************************************************************************
1222 WTErr WCMRPortAudioDevice::SetMonitorGain (float newGain)
1223 {
1224     AUTO_FUNC_DEBUG;
1225         //This will most likely be overridden, the base class simply
1226         //changes the member.
1227         
1228         m_MonitorGain = newGain;
1229         return (eNoErr);
1230 }
1231
1232
1233
1234
1235 //**********************************************************************************************
1236 // WCMRPortAudioDevice::ShowConfigPanel 
1237 //
1238 //! Used to show device specific config/control panel. Some interfaces may not support it.
1239 //!             Some interfaces may require the device to be active before it can display a panel.
1240 //!
1241 //! \param pParam : A device/interface specific parameter, should be the app window handle for ASIO.
1242 //! 
1243 //! \return eNoErr always, the derived classes may return errors.
1244 //! 
1245 //**********************************************************************************************
1246 WTErr WCMRPortAudioDevice::ShowConfigPanel (void *pParam)
1247 {
1248     AUTO_FUNC_DEBUG;
1249         WTErr retVal = eNoErr;
1250         
1251         if (Active())
1252         {
1253 #ifdef _WINDOWS
1254                 if(Pa_GetHostApiInfo(Pa_GetDeviceInfo(m_DeviceID)->hostApi)->type == paASIO)
1255                 {
1256                         // stop and deactivate the device
1257                         bool wasStreaming = Streaming();
1258                         SetActive(false);
1259                         // show control panel for the device
1260                         if (PaAsio_ShowControlPanel (m_DeviceID, pParam) != paNoError)
1261                                 retVal = eGenericErr;
1262                         // reset device to pick up changes
1263                         ResetDevice();
1264                         // restore previous state for the device
1265                         SetActive(true);
1266                         if (wasStreaming)
1267                                 SetStreaming(true);
1268                 }
1269 #else
1270         pParam = pParam;
1271 #endif //_windows               
1272         }
1273         
1274         return (retVal);
1275 }
1276
1277
1278 //*****************************************************************************************************
1279 // WCMRPortAudioDevice::TheCallback
1280 //
1281 //! The (static) Port Audio Callback function. This is a static member. It calls on the AudioCallback in the 
1282 //!             WCMRPortAudioDevice to do the real work.
1283 //!
1284 //! \param pInputBuffer: pointer to input buffer.
1285 //! \param pOutputBuffer: pointer to output buffer.
1286 //! \param framesPerBuffer: number of sample frames per buffer.
1287 //! \param pTimeInfo: time info for PaStream callback.
1288 //! \param statusFlags:
1289 //! \param pUserData: pointer to user data, in our case the WCMRPortAudioDevice object.
1290 //! 
1291 //! \return true to stop streaming else returns false.
1292 //******************************************************************************************************
1293 int WCMRPortAudioDevice::TheCallback (const void *pInputBuffer, void *pOutputBuffer, unsigned long framesPerBuffer, 
1294         const PaStreamCallbackTimeInfo* /*pTimeInfo*/, PaStreamCallbackFlags statusFlags, void *pUserData )
1295 {
1296         WCMRPortAudioDevice *pMyDevice = (WCMRPortAudioDevice *)pUserData;
1297         if (pMyDevice)
1298                 return pMyDevice->AudioCallback ((float *)pInputBuffer, (float *)pOutputBuffer, framesPerBuffer,
1299                         (statusFlags & (paInputOverflow | paOutputUnderflow)) != 0);
1300         else
1301                 return (true);
1302                         
1303 }
1304
1305
1306
1307 //**********************************************************************************************
1308 // WCMRPortAudioDevice::AudoiCallback 
1309 //
1310 //! Here's where the actual audio processing happens. We call upon all the active connections' 
1311 //!             sinks to provide data to us which can be put/mixed in the output buffer! Also, we make the 
1312 //!             input data available to any sources     that may call upon us during this time!
1313 //!
1314 //! \param *pInputBuffer : Points to a buffer with recorded data.
1315 //! \param *pOutputBuffer : Points to a buffer to receive playback data.
1316 //! \param framesPerBuffer : Number of sample frames in input and output buffers. Number of channels,
1317 //!             which are interleaved, is fixed at Device Open (Active) time. In this implementation,
1318 //!             the number of channels are fixed to use the maximum available.
1319 //!     \param dropsDetected : True if dropouts were detected in input or output. Can be used to signal the GUI.
1320 //! 
1321 //! \return true
1322 //! 
1323 //**********************************************************************************************
1324 int WCMRPortAudioDevice::AudioCallback( const float *pInputBuffer, float *pOutputBuffer, unsigned long framesPerBuffer, bool dropsDetected )
1325 {
1326         UMicroseconds theStartTime;
1327
1328     // detect drops
1329         if (dropsDetected)
1330         {
1331                 if (m_IgnoreThisDrop)
1332                         m_IgnoreThisDrop = false; //We'll ignore once, just once!
1333                 else
1334                         m_DropsDetected++;
1335         }
1336
1337         m_pInputData = pInputBuffer;
1338
1339     // VKamyshniy: Is this a right place to call the client???:
1340     struct WCMRAudioDeviceManagerClient::AudioCallbackData audioCallbackData =
1341     {
1342         m_pInputData,
1343         pOutputBuffer,
1344         framesPerBuffer,
1345                 m_SampleCounter,
1346                 theStartTime.MicroSeconds()*1000
1347     };
1348     
1349     m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::AudioCallback, (void *)&audioCallbackData );
1350
1351         //Don't try to  access after this call returns!
1352         m_pInputData = NULL;
1353
1354         m_SampleCounter += framesPerBuffer;     
1355
1356         return m_StopRequested;
1357 }
1358
1359
1360
1361
1362 //**********************************************************************************************
1363 // WCMRPortAudioDeviceManager::WCMRPortAudioDeviceManager
1364 //
1365 //! The constructuor, we initialize PA, and build the device list.
1366 //!
1367 //! \param *pTheClient : The manager's client object (which receives notifications).
1368 //! \param interfaceType : The PortAudio interface type to use for this manager - acts as a filter.
1369 //! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true.
1370 //! 
1371 //! \return Nothing.
1372 //! 
1373 //**********************************************************************************************
1374 WCMRPortAudioDeviceManager::WCMRPortAudioDeviceManager (WCMRAudioDeviceManagerClient *pTheClient, 
1375                                                                                                                 eAudioDeviceFilter eCurAudioDeviceFilter, bool useMultithreading, bool bNocopy)
1376         : WCMRAudioDeviceManager (pTheClient, eCurAudioDeviceFilter)
1377         , m_NoneDevice(0)
1378         , m_UseMultithreading(useMultithreading)
1379         , m_bNoCopyAudioBuffer(bNocopy)
1380 {
1381     AUTO_FUNC_DEBUG;
1382         std::cout << "API::PortAudioDeviceManager::PA Device manager constructor" << std::endl;
1383         
1384         //Always create the None device first...
1385         m_NoneDevice = new WCMRNativeAudioNoneDevice(this);
1386
1387         WTErr err = generateDeviceListImpl();
1388
1389         if (eNoErr != err)
1390                 throw err;
1391
1392         timeBeginPeriod (1);
1393 }
1394
1395
1396 //**********************************************************************************************
1397 // WCMRPortAudioDeviceManager::~WCMRPortAudioDeviceManager
1398 //
1399 //! It clears the device list, releasing each of the device.
1400 //!
1401 //! \param none
1402 //! 
1403 //! \return Nothing.
1404 //! 
1405 //**********************************************************************************************
1406 WCMRPortAudioDeviceManager::~WCMRPortAudioDeviceManager()
1407 {
1408     AUTO_FUNC_DEBUG;
1409         
1410         std::cout << "API::Destroying PortAudioDeviceManager " << std::endl;
1411
1412         try
1413         {
1414                 delete m_NoneDevice;
1415         }
1416         catch (...)
1417         {
1418                 //destructors should absorb exceptions, no harm in logging though!!
1419                 DEBUG_MSG ("Exception during destructor");
1420         }
1421
1422         timeEndPeriod (1);
1423 }
1424
1425
1426 WCMRAudioDevice* WCMRPortAudioDeviceManager::initNewCurrentDeviceImpl(const std::string & deviceName)
1427 {
1428     destroyCurrentDeviceImpl();
1429     
1430         std::cout << "API::PortAudioDeviceManager::initNewCurrentDevice " << deviceName << std::endl;
1431         if (deviceName == m_NoneDevice->DeviceName() )
1432         {
1433                 m_CurrentDevice = m_NoneDevice;
1434                 return m_CurrentDevice;
1435         }
1436
1437         DeviceInfo devInfo;
1438         WTErr err = GetDeviceInfoByName(deviceName, devInfo);
1439
1440         if (eNoErr == err)
1441         {
1442                 try
1443                 {
1444                         std::cout << "API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName << std::endl;
1445                         TRACE_MSG ("API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName);
1446                 
1447                         m_CurrentDevice = new WCMRPortAudioDevice (this, devInfo.m_DeviceId, m_UseMultithreading, m_bNoCopyAudioBuffer);
1448                 }
1449                 catch (...)
1450                 {
1451                         std::cout << "Unabled to create PA Device: " << devInfo.m_DeviceId << std::endl;
1452                         DEBUG_MSG ("Unabled to create PA Device: " << devInfo.m_DeviceId);
1453                 }
1454         }
1455
1456         return m_CurrentDevice;
1457 }
1458
1459
1460 void WCMRPortAudioDeviceManager::destroyCurrentDeviceImpl()
1461 {
1462         if (m_CurrentDevice != m_NoneDevice)
1463                 delete m_CurrentDevice;
1464
1465         m_CurrentDevice = 0;
1466 }
1467
1468
1469 WTErr WCMRPortAudioDeviceManager::getDeviceAvailableSampleRates(DeviceID deviceId, std::vector<int>& sampleRates)
1470 {
1471         sampleRates.clear();
1472         const PaDeviceInfo *pPaDeviceInfo = Pa_GetDeviceInfo(deviceId);
1473
1474         //now find supported sample rates
1475         //following parameters are needed for sample rates validation
1476         PaStreamParameters inputParameters, outputParameters;
1477         PaStreamParameters *pInS = NULL, *pOutS = NULL;
1478
1479         inputParameters.device = deviceId;
1480         inputParameters.channelCount = std::min<int>(2, pPaDeviceInfo->maxInputChannels);
1481         inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
1482         inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
1483         inputParameters.hostApiSpecificStreamInfo = 0;
1484
1485         if (inputParameters.channelCount)
1486                 pInS = &inputParameters;
1487
1488         outputParameters.device = deviceId;
1489         outputParameters.channelCount = std::min<int>(2, pPaDeviceInfo->maxOutputChannels);
1490         outputParameters.sampleFormat = paFloat32;
1491         outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
1492         outputParameters.hostApiSpecificStreamInfo = 0;
1493
1494         if (outputParameters.channelCount)
1495                 pOutS = &outputParameters;
1496
1497         for(int sr=0; gAllSampleRates[sr] > 0; sr++)
1498         {
1499                 if( paFormatIsSupported == Pa_IsFormatSupported(pInS, pOutS, gAllSampleRates[sr]) )
1500                 {
1501                         sampleRates.push_back ((int)gAllSampleRates[sr]);
1502                 }
1503         }
1504 }
1505
1506
1507 WTErr WCMRPortAudioDeviceManager::generateDeviceListImpl()
1508 {
1509         std::cout << "API::PortAudioDeviceManager::Generating device list" << std::endl;
1510         
1511         WTErr retVal = eNoErr;
1512
1513         //Initialize PortAudio and ASIO first
1514         PaError paErr = Pa_Initialize();
1515
1516         if (paErr != paNoError)
1517         {
1518                 //ToDo: throw an exception here!
1519                 retVal = eSomeThingNotInitailzed;
1520                 return retVal;
1521         }
1522
1523         // lock DeviceInfoVec firts
1524         wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex);
1525
1526         if (m_NoneDevice)
1527         {
1528                 DeviceInfo *pDevInfo = new DeviceInfo(NONE_DEVICE_ID, m_NoneDevice->DeviceName() );
1529                 pDevInfo->m_AvailableSampleRates = m_NoneDevice->SamplingRates();
1530                 m_DeviceInfoVec.push_back(pDevInfo);
1531         }
1532
1533         //Get device count...
1534         int numDevices = Pa_GetDeviceCount();
1535
1536         //for each device,
1537         for (int thisDeviceID = 0; thisDeviceID < numDevices; thisDeviceID++)
1538         {
1539                 //if it's of the required type...
1540                 const PaDeviceInfo *pPaDeviceInfo = Pa_GetDeviceInfo(thisDeviceID);
1541                 
1542                 if (Pa_GetHostApiInfo(pPaDeviceInfo->hostApi)->type == paASIO)
1543                 {
1544                         //build a device object...
1545                         try
1546                         {
1547                                 std::cout << "API::PortAudioDeviceManager::DeviceID: " << thisDeviceID << ", Device Name: " << pPaDeviceInfo->name << std::endl;
1548                                 TRACE_MSG ("PA DeviceID: " << thisDeviceID << ", Device Name: " << pPaDeviceInfo->name);
1549
1550                                 DeviceInfo *pDevInfo = new DeviceInfo(thisDeviceID, pPaDeviceInfo->name);
1551                                 if (pDevInfo)
1552                                 {
1553                                         std::vector<int> availableSampleRates;
1554                                         WTErr wErr = WCMRPortAudioDeviceManager::getDeviceAvailableSampleRates(thisDeviceID, availableSampleRates);
1555
1556                                         if (wErr != eNoErr)
1557                                         {
1558                                                 DEBUG_MSG ("Failed to get device available sample rates. Device ID: " << m_DeviceID);
1559                                                 delete pDevInfo;
1560                                                 continue; //proceed to the next device
1561                                         }
1562
1563                                         pDevInfo->m_AvailableSampleRates = availableSampleRates;
1564                                         pDevInfo->m_MaxInputChannels = pPaDeviceInfo->maxInputChannels;
1565                                         pDevInfo->m_MaxOutputChannels = pPaDeviceInfo->maxOutputChannels;
1566
1567                                         //Now check if this device is acceptable according to current input/output settings
1568                                         bool bRejectDevice = false;
1569                                         switch(m_eAudioDeviceFilter)
1570                                         {
1571                                                 case eInputOnlyDevices:
1572                                                         if (pDevInfo->m_MaxInputChannels != 0)
1573                                                         {
1574                                                                 m_DeviceInfoVec.push_back(pDevInfo);
1575                                                         }
1576                                                         else
1577                                                         {
1578                                                                 // Delete unnecesarry device
1579                                                                 bRejectDevice = true;
1580                                                         }
1581                                                         break;
1582                                                 case eOutputOnlyDevices:
1583                                                         if (pDevInfo->m_MaxOutputChannels != 0)
1584                                                         {
1585                                                                 m_DeviceInfoVec.push_back(pDevInfo);
1586                                                         }
1587                                                         else
1588                                                         {
1589                                                                 // Delete unnecesarry device
1590                                                                 bRejectDevice = true;
1591                                                         }
1592                                                         break;
1593                                                 case eFullDuplexDevices:
1594                                                         if (pDevInfo->m_MaxInputChannels != 0 && pDevInfo->m_MaxOutputChannels != 0)
1595                                                         {
1596                                                                 m_DeviceInfoVec.push_back(pDevInfo);
1597                                                         }
1598                                                         else
1599                                                         {
1600                                                                 // Delete unnecesarry device
1601                                                                 bRejectDevice = true;
1602                                                         }
1603                                                         break;
1604                                                 case eAllDevices:
1605                                                 default:
1606                                                         m_DeviceInfoVec.push_back(pDevInfo);
1607                                                         break;
1608                                         }
1609                 
1610                                         if(bRejectDevice)
1611                                         {
1612                                                 TRACE_MSG ("API::PortAudioDeviceManager::Device " << pDevInfo->m_DeviceName << "Rejected. \
1613                                                                         In Channels = " << pDevInfo->m_MaxInputChannels << "Out Channels = " <<pDevInfo->m_MaxOutputChannels );
1614                                                 delete pDevInfo;
1615                                         }
1616                                 }
1617                         }
1618                         catch (...)
1619                         {
1620                                 std::cout << "API::PortAudioDeviceManager::Unabled to create PA Device: " << std::endl;
1621                                 DEBUG_MSG ("Unabled to create PA Device: " << thisDeviceID);
1622                         }
1623                 }
1624         }
1625
1626         //If no devices were found, that's not a good thing!
1627         if (m_DeviceInfoVec.empty() )
1628         {
1629                 std::cout << "API::PortAudioDeviceManager::No matching PortAudio devices were found, total PA devices = " << numDevices << std::endl;
1630                 DEBUG_MSG ("No matching PortAudio devices were found, total PA devices = " << numDevices);
1631         }
1632
1633         //we don't need PA initialized right now
1634         Pa_Terminate();
1635
1636         return retVal;
1637 }
1638
1639
1640 WTErr WCMRPortAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& buffers) const
1641 {
1642         WTErr retVal = eNoErr;
1643         std::cout << "API::PortAudioDeviceManager::GetBufferSizes: getting buffer size for device: "<< deviceName << std::endl;
1644         //first check if the request has been made for None device
1645         if (deviceName == m_NoneDevice->DeviceName() )
1646         {
1647                 buffers = m_NoneDevice->BufferSizes();
1648                 return retVal;
1649         }
1650
1651         //if we have current device initialized and it's PA device, reset it
1652         //this procedure will reset PA corrently and update info for all PA devices as well
1653         
1654         bool paLocalInit = false;
1655         WCMRPortAudioDevice* portaudioDevice = dynamic_cast<WCMRPortAudioDevice*>(m_CurrentDevice);
1656         if (portaudioDevice)
1657         {
1658                 portaudioDevice->ResetDevice();
1659         }
1660         else
1661         {
1662                 //initialize PA to get buffers for the device
1663                 Pa_Initialize();
1664                 paLocalInit = true;
1665         }
1666
1667         DeviceInfo devInfo; 
1668         retVal = GetDeviceInfoByName(deviceName, devInfo);
1669
1670         if (eNoErr == retVal)
1671         {
1672                 //make PA request to get actual device buffer sizes
1673                 long minSize, maxSize, preferredSize, granularity;
1674                 PaError paErr = PaAsio_GetAvailableBufferSizes(devInfo.m_DeviceId, &minSize, &maxSize, &preferredSize, &granularity);
1675
1676                 //for Windows ASIO devices we always use prefferes buffer size ONLY
1677                 if (paNoError == paErr )
1678                 {
1679                         buffers.push_back(preferredSize);
1680                 }
1681                 else
1682                 {
1683                         retVal = eAsioFailed;
1684                         std::cout << "API::PortAudioDeviceManager::GetBufferSizes: error: " << paErr << " getting buffer size fo device: "<< deviceName << std::endl;
1685                 }
1686         }
1687         else
1688         {
1689                 std::cout << "API::PortAudioDeviceManager::GetBufferSizes: Device not found: "<< deviceName << std::endl;
1690         }
1691
1692         //deinitialize PA now
1693         if (paLocalInit)
1694                 Pa_Terminate();
1695
1696         return retVal;
1697 }