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