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