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