Merge branch 'ripple-mode-cc' into cairocanvas
[ardour.git] / libs / backends / wavesaudio / wavesapi / devicemanager / WCMRCoreAudioDeviceManager.cpp
1 //----------------------------------------------------------------------------------
2 //
3 // Copyright (c) 2008 Waves Audio Ltd. All rights reserved.
4 //
5 //! \file   WCMRCoreAudioDeviceManager.cpp
6 //!
7 //! WCMRCoreAudioDeviceManager and related class declarations
8 //!
9 //---------------------------------------------------------------------------------*/
10 #include "WCMRCoreAudioDeviceManager.h"
11 #include <CoreServices/CoreServices.h>
12 #include "MiscUtils/safe_delete.h"
13 #include <sstream>
14 #include <syslog.h>
15
16 // This flag is turned to 1, but it does not work with aggregated devices.
17 // due to problems with aggregated devices this flag is not functional there
18 #define ENABLE_DEVICE_CHANGE_LISTNER 1
19
20 #define PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS 10
21 #define PROPERTY_CHANGE_TIMEOUT_SECONDS 5 
22 #define USE_IOCYCLE_TIMES 1 ///< Set this to 0 to use individual thread cpu measurement
23
24 using namespace wvNS;
25 ///< Supported Sample rates
26 static const double gAllSampleRates[] =
27 {
28     44100.0, 48000.0, 88200.0, 96000.0, -1 /* negative terminated  list */
29 };
30
31
32 ///< Default Supported Buffer Sizes.
33 static const int gAllBufferSizes[] =
34 {
35     32, 64, 96, 128, 192, 256, 512, 1024, 2048, -1 /* negative terminated  list */
36 };
37     
38
39 ///< The default SR.
40 static const int DEFAULT_SR = 44100;
41 ///< The default buffer size.
42 static const int DEFAULT_BUFFERSIZE = 128;
43
44 static const int NONE_DEVICE_ID = -1;
45
46 ///< Number of stalls to wait before notifying user...
47 static const int NUM_STALLS_FOR_NOTIFICATION = 2 * 50; // 2*50 corresponds to 2 * 50 x 42 ms idle timer - about 4 seconds.
48 static const int CHANGE_CHECK_COUNTER_PERIOD = 100; // 120 corresponds to 120 x 42 ms idle timer - about 4 seconds.
49
50 #define AUHAL_OUTPUT_ELEMENT 0  
51 #define AUHAL_INPUT_ELEMENT 1
52
53 #include <sys/sysctl.h>
54
55 static int getProcessorCount() 
56 {
57     int     count = 1;
58     size_t size = sizeof(count);
59
60     if (sysctlbyname("hw.ncpu", &count, &size, NULL, 0)) 
61         return 1;
62
63     //if something did not work, let's revert to a safe value...
64     if (count == 0)
65         count = 1;
66         
67     return count; 
68 }
69
70
71 //**********************************************************************************************
72 // WCMRCoreAudioDevice::WCMRCoreAudioDevice 
73 //
74 //! Constructor for the audio device. Opens the PA device and gets information about the device.
75 //!     such as determining supported sampling rates, buffer sizes, and channel counts.
76 //!
77 //! \param *pManager : The audio device manager that's managing this device.
78 //! \param deviceID : The port audio device ID.
79 //! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true.
80 //! 
81 //! \return Nothing.
82 //! 
83 //**********************************************************************************************
84 WCMRCoreAudioDevice::WCMRCoreAudioDevice (WCMRCoreAudioDeviceManager *pManager, AudioDeviceID deviceID, bool useMultithreading, bool bNocopy) 
85   : WCMRNativeAudioDevice (pManager, useMultithreading, bNocopy)
86   , m_SampleCountAtLastIdle (0)
87   , m_StalledSampleCounter(0)
88   , m_SampleCounter(0)
89   , m_BufferSizeChangeRequested (0)
90   , m_BufferSizeChangeReported (0)
91   , m_ResetRequested (0)
92   , m_ResetReported (0)
93   , m_ResyncRequested (0)
94   , m_ResyncReported (0)
95   , m_SRChangeRequested (0)
96   , m_SRChangeReported (0)
97   , m_ChangeCheckCounter(0)
98   , m_IOProcThreadPort (0)
99   , m_DropsDetected(0)
100   , m_DropsReported(0)
101   , m_IgnoreThisDrop(true)
102   , m_LastCPULog(0)
103 #if WV_USE_TONE_GEN
104   , m_pToneData(0)
105   , m_ToneDataSamples (0)
106   , m_NextSampleToUse (0)
107 #endif //WV_USE_TONE_GEN
108 {
109     AUTO_FUNC_DEBUG;
110     UInt32 propSize = 0;
111     OSStatus err = kAudioHardwareNoError;
112
113     //Update device info...
114     m_DeviceID = deviceID;
115     
116     m_CurrentSamplingRate = DEFAULT_SR;
117     m_CurrentBufferSize = DEFAULT_BUFFERSIZE;
118     m_StopRequested = true;
119     m_pInputData = NULL;
120     
121     m_CPUCount = getProcessorCount();
122     m_LastCPULog = wvThread::now() - 10 * wvThread::ktdOneSecond;
123     
124     
125
126     /*
127       @constant       kAudioDevicePropertyNominalSampleRate
128       A Float64 that indicates the current nominal sample rate of the AudioDevice.
129     */
130     Float64 currentNominalRate;
131     propSize = sizeof (currentNominalRate);
132     err = kAudioHardwareNoError;
133     if (AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &currentNominalRate) != kAudioHardwareNoError)
134         err = AudioDeviceGetProperty(m_DeviceID, 0, 1, kAudioDevicePropertyNominalSampleRate, &propSize, &currentNominalRate);
135         
136     if (err == kAudioHardwareNoError)
137         m_CurrentSamplingRate = (int)currentNominalRate;
138         
139     /*
140       @constant       kAudioDevicePropertyBufferFrameSize
141       A UInt32 whose value indicates the number of frames in the IO buffers.
142     */
143
144     UInt32 bufferSize;
145     propSize = sizeof (bufferSize);
146     err = kAudioHardwareNoError;
147     if (AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyBufferFrameSize, &propSize, &bufferSize) != kAudioHardwareNoError)
148         err = AudioDeviceGetProperty(m_DeviceID, 0, 1, kAudioDevicePropertyBufferFrameSize, &propSize, &bufferSize);
149         
150     if (err == kAudioHardwareNoError)
151         m_CurrentBufferSize = (int)bufferSize;
152     
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     
168     //should use a valid current buffer size
169     if (m_BufferSizes.size())
170     {
171         //see if the current sr is present in the buffersize list, if not, use the first one!
172         std::vector<int>::iterator intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), m_CurrentBufferSize);
173         if (intIter == m_BufferSizes.end())
174         {
175             //not found... use the first one
176             m_CurrentBufferSize = m_BufferSizes[0];
177         }
178     }
179     
180     //build our input/output level lists
181     for (unsigned int currentChannel = 0; currentChannel < m_InputChannels.size(); currentChannel++)
182     {
183         m_InputLevels.push_back (0.0);
184     }
185
186     //build our input/output level lists
187     for (unsigned int currentChannel = 0; currentChannel < m_OutputChannels.size(); currentChannel++)
188     {
189         m_OutputLevels.push_back (0.0);
190     }
191     
192 }
193
194
195
196 //**********************************************************************************************
197 // WCMRCoreAudioDevice::~WCMRCoreAudioDevice 
198 //
199 //! Destructor for the audio device. The base release all the connections that were created, if
200 //!     they have not been already destroyed! Here we simply stop streaming, and close device
201 //!     handles if necessary.
202 //!
203 //! \param none
204 //! 
205 //! \return Nothing.
206 //! 
207 //**********************************************************************************************
208 WCMRCoreAudioDevice::~WCMRCoreAudioDevice ()
209 {
210     AUTO_FUNC_DEBUG;
211
212     try
213     {
214         //If device is streaming, need to stop it!
215         if (Streaming())
216         {
217             SetStreaming (false);
218         }
219         
220         //If device is active (meaning stream is open) we need to close it.
221         if (Active())
222         {
223             SetActive (false);
224         }
225         
226     }
227     catch (...)
228     {
229         //destructors should absorb exceptions, no harm in logging though!!
230         DEBUG_MSG ("Exception during destructor");
231     }
232
233 }
234
235
236 //**********************************************************************************************
237 // WCMRCoreAudioDevice::UpdateDeviceInfo 
238 //
239 //! Updates Device Information about channels, sampling rates, buffer sizes.
240 //! 
241 //! \return WTErr.
242 //! 
243 //**********************************************************************************************
244 WTErr WCMRCoreAudioDevice::UpdateDeviceInfo ()
245 {
246     AUTO_FUNC_DEBUG;
247     
248     WTErr retVal = eNoErr;  
249     
250     // Update all devices parts regardless of errors
251     WTErr errName = UpdateDeviceName();
252     WTErr errIn =   UpdateDeviceInputs();
253     WTErr errOut =  UpdateDeviceOutputs();
254     WTErr errSR =   eNoErr; 
255     WTErr errBS =   eNoErr; 
256     
257     errSR = UpdateDeviceSampleRates();
258     errBS = UpdateDeviceBufferSizes();
259
260     if(errName != eNoErr || errIn != eNoErr || errOut != eNoErr || errSR != eNoErr || errBS != eNoErr)
261     {
262         retVal = eCoreAudioFailed;
263     }
264     
265     return retVal;  
266 }
267
268 //**********************************************************************************************
269 // WCMRCoreAudioDevice::UpdateDeviceName 
270 //
271 //! Updates Device name.
272 //!
273 //! Use 'kAudioDevicePropertyDeviceName'
274 //!
275 //! 1. Get property name size.
276 //! 2. Get property: name.
277 //! 
278 //! \return WTErr.
279 //! 
280 //**********************************************************************************************
281 WTErr WCMRCoreAudioDevice::UpdateDeviceName()
282 {
283     AUTO_FUNC_DEBUG;
284     WTErr retVal = eNoErr;  
285     OSStatus err = kAudioHardwareNoError;
286     UInt32 propSize = 0;
287     
288     // Initiate name to unknown.
289     m_DeviceName = "Unknown";
290     
291     //! 1. Get property name size.
292     err = AudioDeviceGetPropertyInfo(m_DeviceID, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL);
293     if (err == kAudioHardwareNoError)
294     {
295         //! 2. Get property: name.
296         char* deviceName = new char[propSize];
297         err = AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyDeviceName, &propSize, deviceName);
298         if (err == kAudioHardwareNoError)
299         {
300             m_DeviceName = deviceName;
301         }
302         else
303         {
304             retVal = eCoreAudioFailed;
305             DEBUG_MSG("Failed to get device name. Device ID: " << m_DeviceID);
306         }
307         
308         delete [] deviceName;
309     }
310     else
311     {
312         retVal = eCoreAudioFailed;
313         DEBUG_MSG("Failed to get device name property size. Device ID: " << m_DeviceID);
314     }
315     
316     return retVal;
317 }
318
319 //**********************************************************************************************
320 // WCMRCoreAudioDevice::UpdateDeviceInputs 
321 //
322 //! Updates Device Inputs.
323 //!
324 //! Use 'kAudioDevicePropertyStreamConfiguration'
325 //! This property returns the stream configuration of the device in an
326 //! AudioBufferList (with the buffer pointers set to NULL) which describes the
327 //! list of streams and the number of channels in each stream. This corresponds
328 //! to what will be passed into the IOProc.
329 //!
330 //! 1. Get property cannels input size.
331 //! 2. Get property: cannels input.
332 //! 3. Update input channels
333 //! 
334 //! \return WTErr.
335 //! 
336 //**********************************************************************************************
337 WTErr WCMRCoreAudioDevice::UpdateDeviceInputs()
338 {
339     AUTO_FUNC_DEBUG;
340     WTErr retVal = eNoErr;  
341     OSStatus err = kAudioHardwareNoError;
342     UInt32 propSize = 0;
343     int maxInputChannels = 0;
344     
345     // 1. Get property cannels input size.
346     err = AudioDeviceGetPropertyInfo (m_DeviceID, 0, 1/* Input */, kAudioDevicePropertyStreamConfiguration, &propSize, NULL);
347     if (err == kAudioHardwareNoError)
348     {
349         //! 2. Get property: cannels input.
350
351         // Allocate size according to the property size. Note that this is a variable sized struct...
352         AudioBufferList *pStreamBuffers = (AudioBufferList *)malloc(propSize);
353         
354         if (pStreamBuffers)
355         {
356             memset (pStreamBuffers, 0, propSize);
357         
358             // Get the Input channels
359             err = AudioDeviceGetProperty (m_DeviceID, 0, 1/* Input */, kAudioDevicePropertyStreamConfiguration, &propSize, pStreamBuffers);
360             if (err == kAudioHardwareNoError)
361             {
362                 // Calculate the number of input channels
363                 for (UInt32 streamIndex = 0; streamIndex < pStreamBuffers->mNumberBuffers; streamIndex++)
364                 {
365                     maxInputChannels += pStreamBuffers->mBuffers[streamIndex].mNumberChannels;
366                 }
367             }
368             else
369             {
370                 retVal = eCoreAudioFailed;
371                 DEBUG_MSG("Failed to get device Input channels. Device Name: " << m_DeviceName.c_str());
372             }
373             
374             free (pStreamBuffers);
375         }
376         else
377         {
378             retVal = eMemOutOfMemory;
379             DEBUG_MSG("Faild to allocate memory. Device Name: " << m_DeviceName.c_str());
380         }
381     }
382     else
383     {
384         retVal = eCoreAudioFailed;
385         DEBUG_MSG("Failed to get device Input channels property size. Device Name: " << m_DeviceName.c_str());
386     }
387     
388     // Update input channels
389     m_InputChannels.clear();
390     for (int channel = 0; channel < maxInputChannels; channel++)
391     {
392         std::stringstream chNameStream;
393         //A better implementation would be to retrieve the names from ASIO or CoreAudio interfaces
394         chNameStream << "Input " << (channel+1);
395         m_InputChannels.push_back (chNameStream.str());
396     }
397     
398     return retVal;
399 }
400
401 //**********************************************************************************************
402 // WCMRCoreAudioDevice::UpdateDeviceOutputs 
403 //
404 //! Updates Device Outputs.
405 //!
406 //! Use 'kAudioDevicePropertyStreamConfiguration'
407 //! This property returns the stream configuration of the device in an
408 //! AudioBufferList (with the buffer pointers set to NULL) which describes the
409 //! list of streams and the number of channels in each stream. This corresponds
410 //! to what will be passed into the IOProc.
411 //!
412 //! 1. Get property cannels output size.
413 //! 2. Get property: cannels output.
414 //! 3. Update output channels
415 //! 
416 //! \return Nothing.
417 //! 
418 //**********************************************************************************************
419 WTErr WCMRCoreAudioDevice::UpdateDeviceOutputs()
420 {
421     AUTO_FUNC_DEBUG;
422     
423     WTErr retVal = eNoErr;  
424     OSStatus err = kAudioHardwareNoError;
425     UInt32 propSize = 0;
426     int maxOutputChannels = 0;
427     
428     //! 1. Get property cannels output size.
429     err = AudioDeviceGetPropertyInfo (m_DeviceID, 0, 0/* Output */, kAudioDevicePropertyStreamConfiguration, &propSize, NULL);
430     if (err == kAudioHardwareNoError)
431     {
432         //! 2. Get property: cannels output.
433         
434         // Allocate size according to the property size. Note that this is a variable sized struct...
435         AudioBufferList *pStreamBuffers = (AudioBufferList *)malloc(propSize);
436         if (pStreamBuffers)
437         {
438             memset (pStreamBuffers, 0, propSize);
439         
440             // Get the Output channels
441             err = AudioDeviceGetProperty (m_DeviceID, 0, 0/* Output */, kAudioDevicePropertyStreamConfiguration, &propSize, pStreamBuffers);
442             if (err == kAudioHardwareNoError)
443             {
444                 // Calculate the number of output channels
445                 for (UInt32 streamIndex = 0; streamIndex < pStreamBuffers->mNumberBuffers; streamIndex++)
446                 {
447                     maxOutputChannels += pStreamBuffers->mBuffers[streamIndex].mNumberChannels;
448                 }
449             }
450             else
451             {
452                 retVal = eCoreAudioFailed;
453                 DEBUG_MSG("Failed to get device Output channels. Device Name: " << m_DeviceName.c_str());
454             }
455             free (pStreamBuffers);
456         }
457         else
458         {
459             retVal = eMemOutOfMemory;
460             DEBUG_MSG("Faild to allocate memory. Device Name: " << m_DeviceName.c_str());
461         }
462     }
463     else
464     {
465         retVal = eCoreAudioFailed;
466         DEBUG_MSG("Failed to get device Output channels property size. Device Name: " << m_DeviceName.c_str());
467     }
468     
469     // Update output channels
470     m_OutputChannels.clear();
471     for (int channel = 0; channel < maxOutputChannels; channel++)
472     {
473         std::stringstream chNameStream;
474         //A better implementation would be to retrieve the names from ASIO or CoreAudio interfaces
475         chNameStream << "Output " << (channel+1);
476         m_OutputChannels.push_back (chNameStream.str());
477     }
478     
479     return retVal;
480 }
481
482 //**********************************************************************************************
483 // WCMRCoreAudioDevice::UpdateDeviceSampleRates 
484 //
485 //! Updates Device Sample rates.
486 //!
487 //! Use 'kAudioDevicePropertyAvailableNominalSampleRates'
488 //!
489 //! 1. Get sample rate property size.
490 //! 2. Get property: sample rates.
491 //! 3. Update sample rates
492 //! 
493 //! \return Nothing.
494 //! 
495 //**********************************************************************************************
496 WTErr WCMRCoreAudioDevice::UpdateDeviceSampleRates()
497 {
498     AUTO_FUNC_DEBUG;
499     
500     WTErr retVal = eNoErr;  
501     OSStatus err = kAudioHardwareNoError;
502     UInt32 propSize = 0;
503     
504     m_SamplingRates.clear();
505     
506     //! 1. Get sample rate property size.
507     err = AudioDeviceGetPropertyInfo(m_DeviceID, 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, NULL);
508     if (err == kAudioHardwareNoError)
509     {
510         //! 2. Get property: cannels output.
511         
512         // Allocate size accrding to the number of audio values
513         int numRates = propSize / sizeof(AudioValueRange);
514         AudioValueRange* supportedRates = new AudioValueRange[numRates];
515         
516         // Get sampling rates from Audio device
517         err = AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, supportedRates);
518         if (err == kAudioHardwareNoError)
519         {
520             //! 3. Update sample rates
521             
522             // now iterate through our standard SRs
523             for(int ourSR=0; gAllSampleRates[ourSR] > 0; ourSR++)
524             {
525                 //check to see if our SR is in the supported rates...
526                 for (int deviceSR = 0; deviceSR < numRates; deviceSR++)
527                 {
528                     if ((supportedRates[deviceSR].mMinimum <= gAllSampleRates[ourSR]) && 
529                         (supportedRates[deviceSR].mMaximum >= gAllSampleRates[ourSR]))
530                     {
531                         m_SamplingRates.push_back ((int)gAllSampleRates[ourSR]);
532                         break;
533                     }
534                 }
535             }
536         }
537         else
538         {
539             retVal = eCoreAudioFailed;
540             DEBUG_MSG("Failed to get device Sample rates. Device Name: " << m_DeviceName.c_str());
541         }
542         
543         delete [] supportedRates;
544     }
545     else
546     {
547         retVal = eCoreAudioFailed;
548         DEBUG_MSG("Failed to get device Sample rates property size. Device Name: " << m_DeviceName.c_str());
549     }
550     
551     return retVal;
552 }
553
554
555 //**********************************************************************************************
556 // WCMRCoreAudioDevice::UpdateDeviceBufferSizes_Simple 
557 //
558 // Use kAudioDevicePropertyBufferFrameSizeRange
559 //
560 // in case of 'eMatchedDuplexDevices' and a matching device exists return common device name
561 // in all other cases retur base class function implementation
562 //
563 // 1. Get buffer size range
564 // 2. Run on all ranges and add them to the list
565 // 
566 // \return error code
567 // 
568 //**********************************************************************************************
569 WTErr WCMRCoreAudioDevice::UpdateDeviceBufferSizes ()
570 {
571     AUTO_FUNC_DEBUG;
572     
573     WTErr retVal = eNoErr;
574     OSStatus err = kAudioHardwareNoError;
575     UInt32 propSize = 0;
576     
577     // Clear buffer sizes
578     m_BufferSizes.clear();
579     
580     // 1. Get buffer size range
581     AudioValueRange bufferSizesRange;
582     propSize = sizeof (AudioValueRange);
583     err = AudioDeviceGetProperty (m_DeviceID, 0, 0, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &bufferSizesRange);
584     if(err == kAudioHardwareNoError)
585     {
586         // 2. Run on all ranges and add them to the list
587         for(int bsize=0; gAllBufferSizes[bsize] > 0; bsize++)
588         {
589             if ((bufferSizesRange.mMinimum <= gAllBufferSizes[bsize]) && (bufferSizesRange.mMaximum >= gAllBufferSizes[bsize]))
590             {
591                 m_BufferSizes.push_back (gAllBufferSizes[bsize]);
592             }
593         }
594         
595         //if we didn't get a single hit, let's simply add the min. and the max...
596         if (m_BufferSizes.empty())
597         {
598             m_BufferSizes.push_back ((int)bufferSizesRange.mMinimum);
599             m_BufferSizes.push_back ((int)bufferSizesRange.mMaximum);
600         }
601     }
602     else
603     {
604         retVal = eCoreAudioFailed;
605         DEBUG_MSG("Failed to get device buffer sizes range. Device Name: " << m_DeviceName.c_str());
606     }
607     
608     return retVal;
609 }
610
611
612 //**********************************************************************************************
613 // WCMRCoreAudioDevice::DeviceName 
614 //
615 //! in case of 'eMatchedDuplexDevices' and a matching device exists return common device name
616 //! in all other cases retur base class function implementation
617 //!
618 //! \param none
619 //! 
620 //! \return current device name
621 //! 
622 //**********************************************************************************************
623 const std::string& WCMRCoreAudioDevice::DeviceName() const
624 {
625     return WCMRAudioDevice::DeviceName();
626 }
627
628 //**********************************************************************************************
629 // WCMRCoreAudioDevice::InputChannels 
630 //
631 //! return base class function implementation
632 //!
633 //! \param none
634 //! 
635 //! \return base class function implementation
636 //! 
637 //**********************************************************************************************
638 const std::vector<std::string>& WCMRCoreAudioDevice::InputChannels()
639 {
640     return WCMRAudioDevice::InputChannels();
641 }
642
643 //**********************************************************************************************
644 // WCMRCoreAudioDevice::OutputChannels 
645 //
646 //! in case of 'eMatchedDuplexDevices' return matching device output channel if there is one
647 //! in all other cases retur base class function implementation
648 //!
649 //! \param none
650 //! 
651 //! \return list of output channels of current device
652 //! 
653 //**********************************************************************************************
654 const std::vector<std::string>& WCMRCoreAudioDevice::OutputChannels()
655 {
656     return WCMRAudioDevice::OutputChannels();
657 }
658
659
660 //**********************************************************************************************
661 // WCMRCoreAudioDevice::SamplingRates 
662 //
663 //! in case of 'eMatchedDuplexDevices' and a matching device exists return common sample rate
664 //! in all other cases retur base class function implementation
665 //!
666 //! \param none
667 //! 
668 //! \return current sample rate
669 //! 
670 //**********************************************************************************************
671 const std::vector<int>& WCMRCoreAudioDevice::SamplingRates()
672 {
673     return WCMRAudioDevice::SamplingRates();
674 }
675
676 //**********************************************************************************************
677 // WCMRCoreAudioDevice::CurrentSamplingRate 
678 //
679 //! The device's current sampling rate. This may be overridden, if the device needs to 
680 //!     query the driver for the current rate.
681 //!
682 //! \param none
683 //! 
684 //! \return The device's current sampling rate. -1 on error.
685 //! 
686 //**********************************************************************************************
687 int WCMRCoreAudioDevice::CurrentSamplingRate ()
688 {
689     AUTO_FUNC_DEBUG;
690     //ToDo: Perhaps for ASIO devices that are active, we should retrive the SR from the device...
691     UInt32 propSize = 0;
692     OSStatus err = kAudioHardwareNoError;
693
694     Float64 currentNominalRate;
695     propSize = sizeof (currentNominalRate);
696     err = kAudioHardwareNoError;
697     if (AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &currentNominalRate) != kAudioHardwareNoError)
698         err = AudioDeviceGetProperty(m_DeviceID, 0, 1, kAudioDevicePropertyNominalSampleRate, &propSize, &currentNominalRate);
699         
700     if (err == kAudioHardwareNoError)
701         m_CurrentSamplingRate = (int)currentNominalRate;
702     else
703     {
704         DEBUG_MSG("Unable to get sampling rate!");
705     }
706
707     return (m_CurrentSamplingRate);
708 }
709
710
711
712
713 //**********************************************************************************************
714 // WCMRCoreAudioDevice::SetCurrentSamplingRate 
715 //
716 //! Change the sampling rate to be used by the device. 
717 //!
718 //! \param newRate : The rate to use (samples per sec).
719 //! 
720 //! \return eNoErr always. The derived classes may return error codes.
721 //! 
722 //**********************************************************************************************
723 WTErr WCMRCoreAudioDevice::SetCurrentSamplingRate (int newRate)
724 {
725     AUTO_FUNC_DEBUG;
726     std::vector<int>::iterator intIter;
727     WTErr retVal = eNoErr;
728
729     //changes the status.
730     int oldRate = CurrentSamplingRate();
731     bool oldActive = Active();
732     
733     //no change, nothing to do
734     if (oldRate == newRate)
735         goto Exit;
736
737     //see if this is one of our supported rates...
738     intIter = find(m_SamplingRates.begin(), m_SamplingRates.end(), newRate);
739     if (intIter == m_SamplingRates.end())
740     {
741         //Can't change, perhaps use an "invalid param" type of error
742         retVal = eCommandLineParameter;
743         goto Exit;
744     }
745     
746     if (Streaming())
747     {
748         //Can't change, perhaps use an "in use" type of error
749         retVal = eGenericErr;
750         goto Exit;
751     }
752
753     if (oldActive)
754     {
755         //Deactivate it for the change...
756         SetActive (false);
757     }
758     
759     retVal = SetAndCheckCurrentSamplingRate (newRate);
760     if(retVal == eNoErr)
761     {
762         retVal = UpdateDeviceInfo ();
763     }
764
765     //reactivate it.    
766     if (oldActive)
767     {
768         retVal = SetActive (true);
769     }
770     
771 Exit:
772
773     return (retVal);
774         
775 }
776
777 //**********************************************************************************************
778 // WCMRCoreAudioDevice::SetAndCheckCurrentSamplingRate 
779 //
780 //! Change the sampling rate to be used by the device. 
781 //!
782 //! \param newRate : The rate to use (samples per sec).
783 //! 
784 //! \return eNoErr always. The derived classes may return error codes.
785 //! 
786 //**********************************************************************************************
787 WTErr WCMRCoreAudioDevice::SetAndCheckCurrentSamplingRate (int newRate)
788 {
789     AUTO_FUNC_DEBUG;
790     std::vector<int>::iterator intIter;
791     WTErr retVal = eNoErr;
792     OSStatus err = kAudioHardwareNoError;
793     UInt32 propSize = 0;
794     
795     // 1. Set new sampling rate
796     Float64 newNominalRate = newRate;
797     propSize = sizeof (Float64);
798     err = AudioDeviceSetProperty(m_DeviceID, NULL, 0, 0, kAudioDevicePropertyNominalSampleRate, propSize, &newNominalRate);
799     
800     m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Changed the Sampling Rate.");
801     
802     if (err != kAudioHardwareNoError)
803     {
804         retVal = eCoreAudioFailed;
805         DEBUG_MSG ("Unable to set SR! Device name: " << m_DeviceName.c_str());
806     }
807     else
808     {
809         // 2. wait for the SR to actually change...
810         
811         // Set total time out time
812         int tryAgain = ((PROPERTY_CHANGE_TIMEOUT_SECONDS * 1000) / PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS) ;
813         int actualWait = 0;
814         Float64 actualSamplingRate = 0.0;
815         
816         // Run as ling as time out is not finished
817         while (tryAgain)
818         {
819             // Get current sampling rate
820             err = AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &actualSamplingRate);
821             if (err == kAudioHardwareNoError)
822             {
823                 if (actualSamplingRate == newNominalRate)
824                 {
825                     //success, let's get out!
826                     break;
827                 }
828             }
829             else
830             {
831                 //error reading rate, but let's not complain too much!
832                 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Could not read Sampling Rate for verification.");
833                 DEBUG_MSG ("Unable to get SR. Device name: " << m_DeviceName.c_str());
834             }
835             
836             // oh well...there's always another millisecond...
837             wvThread::sleep_milliseconds (PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS);
838             tryAgain--;
839             actualWait++;
840         }
841         
842         // If sample rate actually changed
843         if (tryAgain != 0)
844         {
845             // Update member with new rate
846             m_CurrentSamplingRate = newRate;
847             
848             char debugMsg[128];
849             snprintf (debugMsg, sizeof(debugMsg), "Actual Wait for SR Change was %d milliseconds", actualWait * PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS);
850             m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)debugMsg);
851         }
852         // If sample rate did not change after time out
853         else
854         {
855             // Update member with last read value
856             m_CurrentSamplingRate = static_cast<int>(actualSamplingRate);
857             
858             char debugMsg[128];
859             snprintf (debugMsg, sizeof(debugMsg), "Unable to change SR, even after waiting for %d milliseconds", actualWait * PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS);
860             m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)debugMsg);
861         }
862     }
863     
864     return (retVal);
865 }
866
867
868 //**********************************************************************************************
869 // WCMRCoreAudioDevice::BufferSizes 
870 //
871 //! in case of 'eMatchedDuplexDevices' and a matching device exists return common buffer sizes
872 //! in all other cases retur base class function implementation
873 //!
874 //! \param none
875 //! 
876 //! \return current sample rate
877 //! 
878 //**********************************************************************************************
879 const std::vector<int>& WCMRCoreAudioDevice::BufferSizes()
880 {
881     return WCMRAudioDevice::BufferSizes();
882 }
883
884
885 //**********************************************************************************************
886 // WCMRCoreAudioDevice::CurrentBufferSize
887 //
888 //! The device's current buffer size in use. This may be overridden, if the device needs to 
889 //!     query the driver for the current size.
890 //!
891 //! \param none
892 //! 
893 //! \return The device's current buffer size. 0 on error.
894 //! 
895 //**********************************************************************************************
896 int WCMRCoreAudioDevice::CurrentBufferSize ()
897 {
898     AUTO_FUNC_DEBUG;
899
900     return (m_CurrentBufferSize);
901 }
902
903
904
905 //**********************************************************************************************
906 // WCMRCoreAudioDevice::SetCurrentBufferSize
907 //
908 //! Change the buffer size to be used by the device. This will most likely be overridden, 
909 //!     the base class simply updates the member variable.
910 //!
911 //! \param newSize : The buffer size to use (in sample-frames)
912 //! 
913 //! \return eNoErr always. The derived classes may return error codes.
914 //! 
915 //**********************************************************************************************
916 WTErr WCMRCoreAudioDevice::SetCurrentBufferSize (int newSize)
917 {
918     AUTO_FUNC_DEBUG;
919     WTErr retVal = eNoErr;
920     std::vector<int>::iterator intIter;
921
922     //changes the status.
923     int oldSize = CurrentBufferSize();
924     bool oldActive = Active();
925
926     //same size, nothing to do.
927     if (oldSize == newSize)
928         goto Exit;
929     
930     if (Streaming())
931     {
932         //Can't change, perhaps use an "in use" type of error
933         retVal = eGenericErr;
934         goto Exit;
935     }
936     
937     if (oldActive)
938     {
939         //Deactivate it for the change...
940         SetActive (false);
941     }
942     
943     // when audio device is inactive it is safe to set a working buffer size according to new buffer size
944     // if 'newSize' is not a valid buffer size, another valid buffer size will be set
945     retVal = SetWorkingBufferSize(newSize);
946     if(retVal != eNoErr)
947     {
948         DEBUG_MSG("Unable to set a working buffer size. Device Name: " << DeviceName().c_str());
949         goto Exit;
950     }
951
952     //reactivate it.    
953     if (oldActive)
954     {
955         retVal = SetActive (true);
956         if(retVal != eNoErr)
957         {
958             DEBUG_MSG("Unable to activate device. Device Name: " << DeviceName().c_str());
959             goto Exit;
960         }
961     }
962     
963 Exit:
964     
965     return (retVal);
966 }
967
968 WTErr WCMRCoreAudioDevice::SetWorkingBufferSize(int newSize)
969 {
970     AUTO_FUNC_DEBUG;
971     WTErr retVal = eNoErr;
972     OSStatus err = kAudioHardwareNoError;
973     
974     // 1. Set new buffer size
975     err = SetBufferSizesByIO(newSize);
976     
977     // If there's no error it means this buffer size is supported
978     if(err == kAudioHardwareNoError)
979     {
980         m_CurrentBufferSize = newSize;
981     }
982     // If there was an error it means that this buffer size was not supported
983     else
984     {
985         // In case the new buffer size could not be set, set another working buffer size
986
987         // Run on all buffer sizes:
988         
989         // Try setting buffer sizes that are bigger then selected buffer size first,
990         // Since bigger buffer sizes usually work safer 
991         for(std::vector<int>::const_iterator iter = m_BufferSizes.begin();iter != m_BufferSizes.end();++iter)
992         {
993             int nCurBS = *iter;
994             
995             if(nCurBS > newSize)
996             {
997                 // Try setting current buffer size
998                 err = SetBufferSizesByIO(nCurBS);
999                 
1000                 // in case buffer size is valid
1001                 if(err == kAudioHardwareNoError)
1002                 {
1003                     // Set current buffer size
1004                     m_CurrentBufferSize = nCurBS;
1005                     break;
1006                 }
1007             }
1008         }
1009         
1010         // If bigger buffer sizes failed, go to smaller buffer sizes
1011         if(err != kAudioHardwareNoError)
1012         {
1013             for(std::vector<int>::const_iterator iter = m_BufferSizes.begin();iter != m_BufferSizes.end();++iter)
1014             {
1015                 int nCurBS = *iter;
1016                 
1017                 if(nCurBS < newSize)
1018                 {
1019                     // Try setting current buffer size
1020                     err = SetBufferSizesByIO(*iter);
1021                     
1022                     // in case buffer size is valid
1023                     if(err == kAudioHardwareNoError)
1024                     {
1025                         // Set current buffer size
1026                         m_CurrentBufferSize = *iter;
1027                         break;
1028                     }
1029                 }
1030             }
1031         }
1032         
1033         // Check if a valid buffer size was found
1034         if(err == kAudioHardwareNoError)
1035         {
1036             // Notify that a different sample rate is set
1037             char debugMsg[256];
1038             snprintf (debugMsg, sizeof(debugMsg), "Could not set buffer size: %d, Set buffer size to: %d.", newSize, m_CurrentBufferSize);
1039             m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)debugMsg);
1040         }
1041         // if there was no buffer size that could be set
1042         else
1043         {
1044             // Set the parameter buffer size by default, set a debug message
1045             m_CurrentBufferSize = newSize;
1046             DEBUG_MSG("Unable to set any buffer size. Device Name: " << m_DeviceName.c_str());
1047         }
1048     }
1049     
1050     return retVal;
1051 }
1052
1053 OSStatus WCMRCoreAudioDevice::SetBufferSizesByIO(int newSize)
1054 {
1055     OSStatus err = kAudioHardwareNoError;
1056     
1057     // 1. Set new buffer size
1058     UInt32 bufferSize = (UInt32)newSize;
1059     UInt32 propSize = sizeof (UInt32);
1060     
1061     // Set new buffer size to input
1062     if (!m_InputChannels.empty())
1063     {
1064         err = AudioDeviceSetProperty(m_DeviceID, NULL, 0, 1, kAudioDevicePropertyBufferFrameSize, propSize, &bufferSize);
1065     }
1066     else
1067     {
1068         err = AudioDeviceSetProperty(m_DeviceID, NULL, 0, 0, kAudioDevicePropertyBufferFrameSize, propSize, &bufferSize);
1069     }
1070     
1071     return err;
1072 }
1073
1074 //**********************************************************************************************
1075 // WCMRCoreAudioDevice::ConnectionStatus 
1076 //
1077 //! Retrieves the device's current connection status. This will most likely be overridden,
1078 //!     in case some driver communication is required to query the status.
1079 //!
1080 //! \param none
1081 //! 
1082 //! \return A ConnectionStates value.
1083 //! 
1084 //**********************************************************************************************
1085 WCMRCoreAudioDevice::ConnectionStates WCMRCoreAudioDevice::ConnectionStatus ()
1086 {
1087     AUTO_FUNC_DEBUG;
1088     //ToDo: May want to do something more to extract the actual status!
1089     return (m_ConnectionStatus);
1090     
1091 }
1092
1093
1094 //**********************************************************************************************
1095 // WCMRCoreAudioDevice::EnableAudioUnitIO
1096 //
1097 //! Sets up the AUHAL for IO, allowing changes to the devices to be used by the AudioUnit.
1098 //!
1099 //! \param none
1100 //! 
1101 //! \return eNoErr on success, an error code on failure.
1102 //! 
1103 //**********************************************************************************************
1104 WTErr WCMRCoreAudioDevice::EnableAudioUnitIO()
1105 {
1106     AUTO_FUNC_DEBUG;
1107     WTErr retVal = eNoErr;
1108     OSStatus err = kAudioHardwareNoError;
1109     
1110     UInt32 enableIO = 1;
1111     if (!m_InputChannels.empty())
1112     {
1113         ///////////////
1114         //ENABLE IO (INPUT)
1115         //You must enable the Audio Unit (AUHAL) for input 
1116         
1117         //Enable input on the AUHAL
1118         err =  AudioUnitSetProperty(m_AUHALAudioUnit, 
1119                                     kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input,
1120                                     AUHAL_INPUT_ELEMENT,
1121                                     &enableIO, sizeof(enableIO));
1122
1123         if (err)
1124         {
1125             DEBUG_MSG("Couldn't Enable IO on input scope of input element, error = " << err);
1126             retVal = eGenericErr;
1127             goto Exit;
1128         }
1129     }
1130     
1131     //disable Output on the AUHAL if there's no output
1132     if (m_OutputChannels.empty())
1133         enableIO = 0;
1134     else
1135         enableIO = 1;
1136         
1137     err = AudioUnitSetProperty(m_AUHALAudioUnit,
1138                                kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output,
1139                                AUHAL_OUTPUT_ELEMENT,
1140                                &enableIO, sizeof(enableIO));
1141         
1142     if (err)
1143     {
1144         DEBUG_MSG("Couldn't Enable/Disable IO on output scope of output element, error = " << err);
1145         retVal = eGenericErr;
1146         goto Exit;
1147     }
1148
1149 Exit:
1150     return retVal;
1151 }
1152
1153
1154 //**********************************************************************************************
1155 // WCMRCoreAudioDevice::EnableListeners
1156 //
1157 //! Sets up listeners to listen for Audio Device property changes, so that app can be notified.
1158 //!
1159 //! \param none
1160 //! 
1161 //! \return eNoErr on success, an error code on failure.
1162 //! 
1163 //**********************************************************************************************
1164 WTErr WCMRCoreAudioDevice::EnableListeners()
1165 {
1166     AUTO_FUNC_DEBUG;
1167     WTErr retVal = eNoErr;
1168     OSStatus err = kAudioHardwareNoError;
1169
1170     //listner for SR change...
1171     err = AudioDeviceAddPropertyListener(m_DeviceID, 0, 0, kAudioDevicePropertyNominalSampleRate,
1172                                          StaticPropertyChangeProc, this);
1173     
1174     if (err)
1175     {
1176         DEBUG_MSG("Couldn't Setup SR Property Listner, error = " << err);
1177         retVal = eGenericErr;
1178         goto Exit;
1179     }
1180
1181 #if ENABLE_DEVICE_CHANGE_LISTNER    
1182     {
1183         //listner for device change...
1184         err = AudioDeviceAddPropertyListener(m_DeviceID, 0, 0, kAudioDevicePropertyDeviceHasChanged,
1185                                              StaticPropertyChangeProc, this);
1186         
1187         if (err)
1188         {
1189             DEBUG_MSG("Couldn't Setup device change Property Listner, error = " << err);
1190             retVal = eGenericErr;
1191             goto Exit;
1192         }
1193     }
1194 #endif //ENABLE_DEVICE_CHANGE_LISTNER   
1195     
1196     //listner for dropouts...
1197     err = AudioDeviceAddPropertyListener(m_DeviceID, 0, 0, kAudioDeviceProcessorOverload,
1198                                          StaticPropertyChangeProc, this);
1199         
1200     if (err)
1201     {
1202         DEBUG_MSG("Couldn't Setup Processor Overload Property Listner, error = " << err);
1203         retVal = eGenericErr;
1204         goto Exit;
1205     }
1206     
1207
1208 Exit:   
1209     return retVal;
1210 }
1211
1212
1213
1214 //**********************************************************************************************
1215 // WCMRCoreAudioDevice::DisableListeners
1216 //
1217 //! Undoes the work done by EnableListeners
1218 //!
1219 //! \param none
1220 //! 
1221 //! \return eNoErr on success, an error code on failure.
1222 //! 
1223 //**********************************************************************************************
1224 WTErr WCMRCoreAudioDevice::DisableListeners()
1225 {
1226     AUTO_FUNC_DEBUG;
1227     WTErr retVal = eNoErr;
1228     OSStatus err = kAudioHardwareNoError;
1229
1230     //listner for SR change...
1231     err = AudioDeviceRemovePropertyListener(m_DeviceID, 0, 0, kAudioDevicePropertyNominalSampleRate,
1232                                             StaticPropertyChangeProc);
1233         
1234     if (err)
1235     {
1236         DEBUG_MSG("Couldn't Cleanup SR Property Listner, error = " << err);
1237         //not sure if we need to report this...
1238     }
1239
1240 #if ENABLE_DEVICE_CHANGE_LISTNER    
1241     {
1242         err = AudioDeviceRemovePropertyListener(m_DeviceID, 0, 0, kAudioDevicePropertyDeviceHasChanged,
1243                                                 StaticPropertyChangeProc);
1244             
1245         if (err)
1246         {
1247             DEBUG_MSG("Couldn't Cleanup device change Property Listner, error = " << err);
1248             //not sure if we need to report this...
1249         }
1250     }
1251 #endif //ENABLE_DEVICE_CHANGE_LISTNER   
1252
1253     err = AudioDeviceRemovePropertyListener(m_DeviceID, 0, 0, kAudioDeviceProcessorOverload,
1254                                             StaticPropertyChangeProc);
1255         
1256     if (err)
1257     {
1258         DEBUG_MSG("Couldn't Cleanup device change Property Listner, error = " << err);
1259         //not sure if we need to report this...
1260     }
1261     
1262
1263     return retVal;
1264 }
1265
1266
1267 //**********************************************************************************************
1268 // WCMRCoreAudioDevice::StaticPropertyChangeProc
1269 //
1270 //! The property change function called (as a result of EnableListeners) when device properties change.
1271 //!     It calls upon the non-static PropertyChangeProc to do the work.
1272 //!
1273 //! \param inDevice : The audio device in question.
1274 //! \param inChannel : The channel on which the property has change.
1275 //! \param isInput : If the change is for Input.
1276 //! \param inPropertyID : The property that has changed.
1277 //! \param inClientData: What was passed when listener was enabled, in our case teh WCMRCoreAudioDevice object.
1278 //! 
1279 //! \return 0 always.
1280 //! 
1281 //**********************************************************************************************
1282 OSStatus WCMRCoreAudioDevice::StaticPropertyChangeProc (AudioDeviceID /*inDevice*/, UInt32 /*inChannel*/, Boolean /*isInput*/,
1283                                                         AudioDevicePropertyID inPropertyID, void *inClientData)
1284 {
1285     if (inClientData)
1286     {
1287         WCMRCoreAudioDevice* pCoreDevice = (WCMRCoreAudioDevice *)inClientData;
1288         pCoreDevice->PropertyChangeProc (inPropertyID);
1289     }
1290         
1291     return 0;
1292 }
1293
1294
1295
1296 //**********************************************************************************************
1297 // WCMRCoreAudioDevice::PropertyChangeProc
1298 //
1299 //! The non-static property change proc. Gets called when properties change. Since this gets called
1300 //!     on an arbitrary thread, we simply update the request counters and return.
1301 //!
1302 //! \param none
1303 //! 
1304 //! \return nothing.
1305 //! 
1306 //**********************************************************************************************
1307 void WCMRCoreAudioDevice::PropertyChangeProc (AudioDevicePropertyID inPropertyID)
1308 {
1309     switch (inPropertyID)
1310     {
1311     case kAudioDevicePropertyNominalSampleRate:
1312         m_SRChangeRequested++;
1313         break;
1314 #if ENABLE_DEVICE_CHANGE_LISTNER    
1315     case kAudioDevicePropertyDeviceHasChanged:
1316         {
1317             m_ResetRequested++;
1318         }
1319         break;
1320 #endif //ENABLE_DEVICE_CHANGE_LISTNER   
1321     case kAudioDeviceProcessorOverload:
1322         if (m_IgnoreThisDrop)
1323             m_IgnoreThisDrop = false; //We'll ignore once, just once!
1324         else
1325             m_DropsDetected++;
1326         break;
1327     default:
1328         break;
1329     }
1330 }
1331
1332
1333 //**********************************************************************************************
1334 // WCMRCoreAudioDevice::SetupAUHAL
1335 //
1336 //! Sets up the AUHAL AudioUnit for device IO.
1337 //!
1338 //! \param none
1339 //! 
1340 //! \return eNoErr on success, an error code on failure.
1341 //! 
1342 //**********************************************************************************************
1343 WTErr WCMRCoreAudioDevice::SetupAUHAL()
1344 {
1345     AUTO_FUNC_DEBUG;
1346     WTErr retVal = eNoErr;
1347     OSStatus err = kAudioHardwareNoError;
1348     UInt32 propSize = 0;
1349     Component comp;
1350     ComponentDescription desc;
1351     AudioStreamBasicDescription streamFormatToUse, auhalStreamFormat;
1352
1353     //There are several different types of Audio Units.
1354     //Some audio units serve as Outputs, Mixers, or DSP
1355     //units. See AUComponent.h for listing
1356     desc.componentType = kAudioUnitType_Output;
1357     
1358     //Every Component has a subType, which will give a clearer picture
1359     //of what this components function will be.
1360     desc.componentSubType = kAudioUnitSubType_HALOutput;
1361     
1362     //all Audio Units in AUComponent.h must use 
1363     //"kAudioUnitManufacturer_Apple" as the Manufacturer
1364     desc.componentManufacturer = kAudioUnitManufacturer_Apple;
1365     desc.componentFlags = 0;
1366     desc.componentFlagsMask = 0;
1367     
1368     //Finds a component that meets the desc spec's
1369     comp = FindNextComponent(NULL, &desc);
1370     if (comp == NULL)
1371     {
1372         DEBUG_MSG("Couldn't find AUHAL Component");
1373         retVal = eGenericErr;
1374         goto Exit;
1375     }
1376     
1377     //gains access to the services provided by the component
1378     OpenAComponent(comp, &m_AUHALAudioUnit);  
1379
1380     
1381     retVal = EnableAudioUnitIO();
1382     if (retVal != eNoErr)
1383         goto Exit;
1384
1385     //Now setup the device to use by the audio unit...
1386     
1387     //input
1388     if (!m_InputChannels.empty())
1389     {
1390         err = AudioUnitSetProperty(m_AUHALAudioUnit, kAudioOutputUnitProperty_CurrentDevice,
1391                                    kAudioUnitScope_Global, AUHAL_INPUT_ELEMENT,
1392                                    &m_DeviceID, sizeof(m_DeviceID));
1393
1394         if (err)
1395         {
1396             DEBUG_MSG("Couldn't Set the audio device property for Input Element Global scope, error = " << err);
1397             retVal = eGenericErr;
1398             goto Exit;
1399         }
1400     }
1401
1402     //output
1403     if (!m_OutputChannels.empty())
1404     {
1405         err = AudioUnitSetProperty(m_AUHALAudioUnit, kAudioOutputUnitProperty_CurrentDevice,
1406                                    kAudioUnitScope_Global, AUHAL_OUTPUT_ELEMENT,
1407                                    &m_DeviceID, sizeof(m_DeviceID));
1408
1409         if (err)
1410         {
1411             DEBUG_MSG("Couldn't Set the audio device property for Output Element Global scope, error = " << err);
1412             retVal = eGenericErr;
1413             goto Exit;
1414         }
1415     }
1416     
1417     //also set Sample Rate...
1418     {
1419         retVal = SetAndCheckCurrentSamplingRate(m_CurrentSamplingRate);
1420         if(retVal != eNoErr)
1421         {
1422             DEBUG_MSG ("Unable to set SR, error = " << err);
1423             goto Exit;
1424         }
1425     }
1426
1427     //now set the buffer size...
1428     {
1429         err = SetWorkingBufferSize(m_CurrentBufferSize);
1430         if (err)
1431         {
1432             DEBUG_MSG("Couldn't Set the buffer size property, error = " << err);
1433             //we don't really quit here..., just keep going even if this does not work,
1434             //the AUHAL is supposed to take care of this by way of slicing...
1435             m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Could not set buffer size.");
1436             
1437         }
1438     }
1439     
1440     //convertor quality
1441     {
1442         UInt32 quality = kAudioConverterQuality_Max;
1443         propSize = sizeof (quality);
1444         err = AudioUnitSetProperty(m_AUHALAudioUnit,
1445                                    kAudioUnitProperty_RenderQuality, kAudioUnitScope_Global,
1446                                    AUHAL_OUTPUT_ELEMENT,
1447                                    &quality, sizeof (quality));
1448             
1449         if (err != kAudioHardwareNoError)
1450         {
1451             DEBUG_MSG ("Unable to set Convertor Quality, error = " << err);
1452             retVal = eGenericErr;
1453             goto Exit;
1454         }
1455     }
1456     
1457     memset (&auhalStreamFormat, 0, sizeof (auhalStreamFormat));
1458     propSize = sizeof (auhalStreamFormat);
1459     err = AudioUnitGetProperty(m_AUHALAudioUnit,
1460                                kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
1461                                AUHAL_INPUT_ELEMENT,
1462                                &auhalStreamFormat, &propSize);
1463     if (err != kAudioHardwareNoError)
1464     {
1465         DEBUG_MSG ("Unable to get Input format, error = " << err);
1466         retVal = eGenericErr;
1467         goto Exit;
1468     }
1469     
1470     if (auhalStreamFormat.mSampleRate != (Float64)m_CurrentSamplingRate)
1471     {
1472         TRACE_MSG ("AUHAL's Input SR differs from expected SR, expected = " << m_CurrentSamplingRate << ", AUHAL's = " << (UInt32)auhalStreamFormat.mSampleRate);
1473     }
1474     
1475     //format, and slice size...
1476     memset (&streamFormatToUse, 0, sizeof (streamFormatToUse));
1477     streamFormatToUse.mFormatID = kAudioFormatLinearPCM;
1478     streamFormatToUse.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
1479     streamFormatToUse.mFramesPerPacket = 1;
1480     streamFormatToUse.mBitsPerChannel = sizeof (float) * 8;
1481     streamFormatToUse.mSampleRate = auhalStreamFormat.mSampleRate;
1482
1483     if (!m_InputChannels.empty())
1484     {
1485         streamFormatToUse.mChannelsPerFrame = m_InputChannels.size();
1486         streamFormatToUse.mBytesPerFrame = sizeof (float)*streamFormatToUse.mChannelsPerFrame;
1487         streamFormatToUse.mBytesPerPacket = streamFormatToUse.mBytesPerFrame;
1488         propSize = sizeof (streamFormatToUse);
1489         err = AudioUnitSetProperty(m_AUHALAudioUnit,
1490                                    kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
1491                                    AUHAL_INPUT_ELEMENT,
1492                                    &streamFormatToUse, sizeof (streamFormatToUse));
1493
1494         if (err != kAudioHardwareNoError)
1495         {
1496             DEBUG_MSG ("Unable to set Input format, error = " << err);
1497             retVal = eGenericErr;
1498             goto Exit;
1499         }
1500         
1501         UInt32 bufferSize = m_CurrentBufferSize;
1502         err = AudioUnitSetProperty(m_AUHALAudioUnit,
1503                                    kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output,
1504                                    AUHAL_INPUT_ELEMENT,
1505                                    &bufferSize, sizeof (bufferSize));
1506
1507         if (err != kAudioHardwareNoError)
1508         {
1509             DEBUG_MSG ("Unable to set Input frames, error = " << err);
1510             retVal = eGenericErr;
1511             goto Exit;
1512         }
1513         
1514     }
1515
1516     if (!m_OutputChannels.empty())
1517     {
1518         err = AudioUnitGetProperty(m_AUHALAudioUnit,
1519                                    kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
1520                                    AUHAL_OUTPUT_ELEMENT,
1521                                    &auhalStreamFormat, &propSize);
1522         if (err != kAudioHardwareNoError)
1523         {
1524             DEBUG_MSG ("Unable to get Output format, error = " << err);
1525             retVal = eGenericErr;
1526             goto Exit;
1527         }
1528         
1529         if (auhalStreamFormat.mSampleRate != (Float64)m_CurrentSamplingRate)
1530         {
1531             TRACE_MSG ("AUHAL's Output SR differs from expected SR, expected = " << m_CurrentSamplingRate << ", AUHAL's = " << (UInt32)auhalStreamFormat.mSampleRate);
1532         }
1533         
1534         
1535         streamFormatToUse.mChannelsPerFrame = m_OutputChannels.size();
1536         streamFormatToUse.mBytesPerFrame = sizeof (float)*streamFormatToUse.mChannelsPerFrame;
1537         streamFormatToUse.mBytesPerPacket = streamFormatToUse.mBytesPerFrame;
1538         streamFormatToUse.mSampleRate = auhalStreamFormat.mSampleRate;
1539         propSize = sizeof (streamFormatToUse);
1540         err = AudioUnitSetProperty(m_AUHALAudioUnit,
1541                                    kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
1542                                    AUHAL_OUTPUT_ELEMENT,
1543                                    &streamFormatToUse, sizeof (streamFormatToUse));
1544
1545         if (err != kAudioHardwareNoError)
1546         {
1547             DEBUG_MSG ("Unable to set Output format, error = " << err);
1548             retVal = eGenericErr;
1549             goto Exit;
1550         }
1551
1552         UInt32 bufferSize = m_CurrentBufferSize;
1553         err = AudioUnitSetProperty(m_AUHALAudioUnit,
1554                                    kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Input,
1555                                    AUHAL_OUTPUT_ELEMENT,
1556                                    &bufferSize, sizeof (bufferSize));
1557
1558         if (err != kAudioHardwareNoError)
1559         {
1560             DEBUG_MSG ("Unable to set Output frames, error = " << err);
1561             retVal = eGenericErr;
1562             goto Exit;
1563         }
1564
1565     }
1566     
1567     //setup callback (IOProc)
1568     {
1569         AURenderCallbackStruct renderCallback;
1570         memset (&renderCallback, 0, sizeof (renderCallback));
1571         propSize = sizeof (renderCallback);
1572         renderCallback.inputProc = StaticAudioIOProc;
1573         renderCallback.inputProcRefCon = this;
1574         
1575         err = AudioUnitSetProperty(m_AUHALAudioUnit,
1576                                    (m_OutputChannels.empty() ? (AudioUnitPropertyID)kAudioOutputUnitProperty_SetInputCallback : (AudioUnitPropertyID)kAudioUnitProperty_SetRenderCallback),
1577                                    kAudioUnitScope_Output,
1578                                    m_OutputChannels.empty() ? AUHAL_INPUT_ELEMENT : AUHAL_OUTPUT_ELEMENT,
1579                                    &renderCallback, sizeof (renderCallback));
1580             
1581         if (err != kAudioHardwareNoError)
1582         {
1583             DEBUG_MSG ("Unable to set callback, error = " << err);
1584             retVal = eGenericErr;
1585             goto Exit;
1586         }
1587     }
1588
1589     retVal = EnableListeners();
1590     if (retVal != eNoErr)
1591         goto Exit;
1592
1593     //also prepare the buffer list for input...
1594     if (!m_InputChannels.empty())
1595     {
1596         
1597         //now setup the buffer list.
1598         memset (&m_InputAudioBufferList, 0, sizeof (m_InputAudioBufferList));
1599         m_InputAudioBufferList.mNumberBuffers = 1;
1600         m_InputAudioBufferList.mBuffers[0].mNumberChannels = m_InputChannels.size();
1601         m_InputAudioBufferList.mBuffers[0].mDataByteSize = m_InputAudioBufferList.mBuffers[0].mNumberChannels *
1602             m_CurrentBufferSize * sizeof(float);
1603         //allocate the data buffer...
1604         try
1605         {
1606             m_pInputData = new float[m_InputAudioBufferList.mBuffers[0].mNumberChannels * m_CurrentBufferSize];
1607         }
1608         catch (...)
1609         {
1610             retVal = eMemNewFailed;
1611             goto Exit;
1612         }
1613         
1614         m_InputAudioBufferList.mBuffers[0].mData = m_pInputData;
1615         
1616         //zero it out...
1617         memset (m_InputAudioBufferList.mBuffers[0].mData, 0, m_InputAudioBufferList.mBuffers[0].mDataByteSize);
1618     
1619     }
1620
1621     //initialize the audio-unit now!
1622     err = AudioUnitInitialize(m_AUHALAudioUnit);
1623     if (err != kAudioHardwareNoError)
1624     {
1625         DEBUG_MSG ("Unable to Initialize AudioUnit = " << err);
1626         retVal = eGenericErr;
1627         goto Exit;
1628     }
1629     
1630 Exit:
1631     if (retVal != eNoErr)
1632         TearDownAUHAL();
1633         
1634     return retVal;
1635 }
1636
1637
1638
1639 //**********************************************************************************************
1640 // WCMRCoreAudioDevice::TearDownAUHAL
1641 //
1642 //! Undoes the work done by SetupAUHAL
1643 //!
1644 //! \param none
1645 //! 
1646 //! \return eNoErr on success, an error code on failure.
1647 //! 
1648 //**********************************************************************************************
1649 WTErr WCMRCoreAudioDevice::TearDownAUHAL()
1650 {
1651     WTErr retVal = eNoErr;
1652
1653     if (m_AUHALAudioUnit)
1654     {
1655         DisableListeners ();
1656         AudioUnitUninitialize(m_AUHALAudioUnit);
1657         CloseComponent(m_AUHALAudioUnit);
1658         m_AUHALAudioUnit = NULL;
1659     }
1660     
1661     safe_delete_array(m_pInputData);
1662
1663     return retVal;
1664 }
1665
1666
1667
1668 //**********************************************************************************************
1669 // WCMRCoreAudioDevice::SetActive 
1670 //
1671 //! Sets the device's activation status. Essentially, opens or closes the PA device. 
1672 //!     If it's an ASIO device it may result in buffer size change in some cases.
1673 //!
1674 //! \param newState : Should be true to activate, false to deactivate. This roughly corresponds
1675 //!     to opening and closing the device handle/stream/audio unit.
1676 //! 
1677 //! \return eNoErr on success, an error code otherwise.
1678 //! 
1679 //**********************************************************************************************
1680 WTErr WCMRCoreAudioDevice::SetActive (bool newState)
1681 {
1682     AUTO_FUNC_DEBUG;
1683
1684     WTErr retVal = eNoErr;
1685     
1686     if (Active() == newState)
1687         goto Exit;
1688
1689
1690     if (newState)
1691     {
1692         
1693         m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Setting up AUHAL.");
1694         retVal = SetupAUHAL();
1695
1696         if (retVal != eNoErr)
1697             goto Exit;
1698
1699         m_BufferSizeChangeRequested = 0;
1700         m_BufferSizeChangeReported = 0;
1701         m_ResetRequested = 0;
1702         m_ResetReported = 0;
1703         m_ResyncRequested = 0;
1704         m_ResyncReported = 0;
1705         m_SRChangeRequested = 0;
1706         m_SRChangeReported = 0;
1707         m_DropsDetected = 0;
1708         m_DropsReported = 0;
1709         m_IgnoreThisDrop = true;
1710     }
1711     else
1712     {
1713         if (Streaming())
1714         {
1715             SetStreaming (false);
1716         }
1717
1718         m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Tearing down AUHAL.");
1719         retVal = TearDownAUHAL();
1720         if (retVal != eNoErr)
1721             goto Exit;
1722
1723         m_BufferSizeChangeRequested = 0;
1724         m_BufferSizeChangeReported = 0;
1725         m_ResetRequested = 0;
1726         m_ResetReported = 0;
1727         m_ResyncRequested = 0;
1728         m_ResyncReported = 0;
1729         m_SRChangeRequested = 0;
1730         m_SRChangeReported = 0;
1731         m_DropsDetected = 0;
1732         m_DropsReported = 0;
1733         m_IgnoreThisDrop = true;
1734
1735         UpdateDeviceInfo();
1736
1737     }
1738     
1739     m_IsActive = newState;
1740     
1741 Exit:   
1742     return (retVal);
1743 }
1744
1745
1746 #if WV_USE_TONE_GEN
1747 //**********************************************************************************************
1748 // WCMRCoreAudioDevice::SetupToneGenerator
1749 //
1750 //! Sets up the Tone generator - only if a file /tmp/tonegen.txt is present. If the file is
1751 //!     present, it reads the value in the file and uses that as the frequency for the tone. This
1752 //!     code attempts to create an array of samples that would constitute an integral number of
1753 //!     cycles - for the currently active sampling rate. If tonegen is active, then the input
1754 //!     from the audio device is ignored, instead a data is supplied from the tone generator's
1755 //!     array - for all channels. The array is in m_pToneData, the size of the array is in
1756 //!     m_ToneDataSamples, and m_NextSampleToUse holds the index in the array from where
1757 //!     the next sample is going to be taken.
1758 //!
1759 //!
1760 //! \return : Nothing
1761 //!
1762 //**********************************************************************************************
1763 void WCMRCoreAudioDevice::SetupToneGenerator ()
1764 {
1765     safe_delete_array(m_pToneData);
1766     m_ToneDataSamples = 0;
1767
1768     //if tonegen exists?
1769     FILE *toneGenHandle = fopen ("/tmp/tonegen.txt", "r");
1770     if (toneGenHandle)
1771     {
1772         int toneFreq = 0;
1773         fscanf(toneGenHandle, "%d", &toneFreq);
1774         if ((toneFreq <= 0) || (toneFreq > (m_CurrentSamplingRate/2)))
1775         {
1776             toneFreq = 1000;    
1777         }
1778         
1779         
1780         m_ToneDataSamples = m_CurrentSamplingRate / toneFreq;
1781         int toneDataSamplesFrac = m_CurrentSamplingRate % m_ToneDataSamples;
1782         int powerOfTen = 1;
1783         while (toneDataSamplesFrac)
1784         {
1785             m_ToneDataSamples = (uint32_t)((pow(10, powerOfTen) * m_CurrentSamplingRate) / toneFreq);
1786             toneDataSamplesFrac = m_CurrentSamplingRate % m_ToneDataSamples;
1787             powerOfTen++;
1788         }
1789         
1790         //allocate
1791         m_pToneData = new float_t[m_ToneDataSamples];
1792         
1793         //fill with a -6dB Sine Tone
1794         uint32_t numSamplesLeft = m_ToneDataSamples;
1795         float_t *pNextSample = m_pToneData;
1796         double phase = 0;
1797         double phaseIncrement = (M_PI * 2.0 * toneFreq ) / ((double)m_CurrentSamplingRate);
1798         while (numSamplesLeft)
1799         {
1800             *pNextSample = (float_t)(0.5 * sin(phase));
1801             phase += phaseIncrement;
1802             pNextSample++;
1803             numSamplesLeft--;
1804         }
1805         
1806         m_NextSampleToUse = 0;
1807         
1808         fclose(toneGenHandle);
1809     }
1810 }
1811 #endif //WV_USE_TONE_GEN
1812
1813
1814 //**********************************************************************************************
1815 // WCMRCoreAudioDevice::SetStreaming
1816 //
1817 //! Sets the device's streaming status. Calls PA's Start/Stop stream routines.
1818 //!
1819 //! \param newState : Should be true to start streaming, false to stop streaming. This roughly
1820 //!     corresponds to calling Start/Stop on the lower level interface.
1821 //! 
1822 //! \return eNoErr always, the derived classes may return appropriate error code.
1823 //! 
1824 //**********************************************************************************************
1825 WTErr WCMRCoreAudioDevice::SetStreaming (bool newState)
1826 {
1827     AUTO_FUNC_DEBUG;
1828     WTErr retVal = eNoErr;
1829     ComponentResult err = 0;
1830
1831     if (Streaming () == newState)
1832         goto Exit;
1833
1834     if (newState)
1835     {
1836 #if WV_USE_TONE_GEN
1837         SetupToneGenerator ();
1838 #endif //WV_USE_TONE_GEN
1839
1840         m_StopRequested = false;
1841         m_SampleCountAtLastIdle = 0;
1842         m_StalledSampleCounter = 0;
1843         m_SampleCounter = 0;
1844         m_IOProcThreadPort = 0;
1845         m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Starting AUHAL.");
1846         
1847         if (m_UseMultithreading)
1848         {
1849             //set thread constraints...
1850             unsigned int periodAndConstraintUS = (unsigned int)((1000000.0 * m_CurrentBufferSize) / m_CurrentSamplingRate);
1851             unsigned int computationUS = (unsigned int)(0.8 * periodAndConstraintUS); //assuming we may want to use up to 80% CPU
1852             //ErrandManager().SetRealTimeConstraintsForAllThreads (periodAndConstraintUS, computationUS, periodAndConstraintUS);
1853         }
1854         
1855         err = AudioOutputUnitStart (m_AUHALAudioUnit);
1856         
1857         if(err)
1858         {
1859             DEBUG_MSG( "Failed to start AudioUnit, err " << err );
1860             retVal = eGenericErr;
1861             goto Exit;
1862         }
1863     }
1864     else
1865     {
1866         m_StopRequested = true;
1867         m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Stopping AUHAL.");
1868         err = AudioOutputUnitStop (m_AUHALAudioUnit);
1869         if (!err)
1870         {
1871             if (!m_InputChannels.empty());
1872             {
1873                 err = AudioUnitReset (m_AUHALAudioUnit, kAudioUnitScope_Global, AUHAL_INPUT_ELEMENT);
1874             }
1875             if (!m_OutputChannels.empty());
1876             {
1877                 err = AudioUnitReset (m_AUHALAudioUnit, kAudioUnitScope_Global, AUHAL_OUTPUT_ELEMENT);
1878             }
1879         }
1880         
1881         if(err)
1882         {
1883             DEBUG_MSG( "Failed to stop AudioUnit " << err );
1884             retVal = eGenericErr;
1885             goto Exit;
1886         }
1887         m_IOProcThreadPort = 0;
1888     }
1889
1890     // After units restart, reset request for reset and SR change
1891     m_SRChangeReported = m_SRChangeRequested;
1892     m_ResetReported = m_ResetRequested;
1893     
1894     m_IsStreaming = newState;
1895
1896 Exit:   
1897     return (retVal);
1898 }
1899
1900
1901 //**********************************************************************************************
1902 // WCMRCoreAudioDevice::DoIdle 
1903 //
1904 //! A place for doing idle time processing. The other derived classes will probably do something
1905 //!     meaningful.
1906 //!
1907 //! \param none
1908 //! 
1909 //! \return eNoErr always.
1910 //! 
1911 //**********************************************************************************************
1912 WTErr WCMRCoreAudioDevice::DoIdle ()
1913 {
1914     if (m_BufferSizeChangeRequested != m_BufferSizeChangeReported)
1915     {
1916         m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged);
1917         m_BufferSizeChangeReported = m_BufferSizeChangeRequested;
1918     }
1919
1920     if (m_ResetRequested != m_ResetReported)
1921     {
1922         m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
1923         m_ResetReported = m_ResetRequested;
1924     }
1925
1926
1927     if (m_ResyncRequested != m_ResyncReported)
1928     {
1929         m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestResync);
1930         m_ResyncReported = m_ResyncRequested;
1931     }
1932     
1933     if (m_SRChangeReported != m_SRChangeRequested)
1934     {
1935         m_SRChangeReported = m_SRChangeRequested;
1936         int newSR = CurrentSamplingRate();
1937         m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::SamplingRateChanged, (void *)newSR);
1938     }
1939
1940     if (m_DropsReported != m_DropsDetected)
1941     {
1942         m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDroppedSamples);
1943         m_DropsReported = m_DropsDetected;
1944     }
1945
1946     
1947     //Perhaps add checks to make sure a stream counter is incrementing if
1948     //stream is supposed to be streaming!
1949     if (Streaming())
1950     {
1951         //latch the value
1952         int64_t currentSampleCount = m_SampleCounter;
1953         if (m_SampleCountAtLastIdle == currentSampleCount)
1954             m_StalledSampleCounter++;
1955         else
1956         {
1957             m_SampleCountAtLastIdle = (int)currentSampleCount;
1958             m_StalledSampleCounter = 0;
1959         }
1960
1961         if (m_StalledSampleCounter > NUM_STALLS_FOR_NOTIFICATION)
1962         {
1963             m_StalledSampleCounter = 0;
1964             m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStoppedStreaming, (void *)currentSampleCount);
1965         }
1966     }
1967
1968     
1969     return (eNoErr);
1970 }
1971
1972
1973
1974
1975
1976 //**********************************************************************************************
1977 // WCMRCoreAudioDevice::SetMonitorChannels 
1978 //
1979 //! Used to set the channels to be used for monitoring.
1980 //!
1981 //! \param leftChannel : Left monitor channel index.
1982 //! \param rightChannel : Right monitor channel index.
1983 //! 
1984 //! \return eNoErr always, the derived classes may return appropriate errors.
1985 //! 
1986 //**********************************************************************************************
1987 WTErr WCMRCoreAudioDevice::SetMonitorChannels (int leftChannel, int rightChannel)
1988 {
1989     AUTO_FUNC_DEBUG;
1990     //This will most likely be overridden, the base class simply
1991     //changes the member.
1992     m_LeftMonitorChannel = leftChannel;
1993     m_RightMonitorChannel = rightChannel;
1994     return (eNoErr);
1995 }
1996
1997
1998
1999 //**********************************************************************************************
2000 // WCMRCoreAudioDevice::SetMonitorGain 
2001 //
2002 //! Used to set monitor gain (or atten).
2003 //!
2004 //! \param newGain : The new gain or atten. value to use. Specified as a linear multiplier (not dB) 
2005 //! 
2006 //! \return eNoErr always, the derived classes may return appropriate errors.
2007 //! 
2008 //**********************************************************************************************
2009 WTErr WCMRCoreAudioDevice::SetMonitorGain (float newGain)
2010 {
2011     AUTO_FUNC_DEBUG;
2012     //This will most likely be overridden, the base class simply
2013     //changes the member.
2014     
2015     
2016     m_MonitorGain = newGain;
2017     return (eNoErr);
2018 }
2019
2020
2021
2022
2023 //**********************************************************************************************
2024 // WCMRCoreAudioDevice::ShowConfigPanel 
2025 //
2026 //! Used to show device specific config/control panel. Some interfaces may not support it.
2027 //!     Some interfaces may require the device to be active before it can display a panel.
2028 //!
2029 //! \param pParam : A device/interface specific parameter, should be the app window handle for ASIO.
2030 //! 
2031 //! \return eNoErr always, the derived classes may return errors.
2032 //! 
2033 //**********************************************************************************************
2034 WTErr WCMRCoreAudioDevice::ShowConfigPanel (void */*pParam*/)
2035 {
2036     AUTO_FUNC_DEBUG;
2037     WTErr retVal = eNoErr;
2038     
2039     CFStringRef configAP;
2040     UInt32 propSize = sizeof (configAP);
2041     /*
2042       @constant       kAudioDevicePropertyConfigurationApplication
2043       A CFString that contains the bundle ID for an application that provides a
2044       GUI for configuring the AudioDevice. By default, the value of this property
2045       is the bundle ID for Audio MIDI Setup. The caller is responsible for
2046       releasing the returned CFObject.
2047     */
2048     
2049     if (AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyConfigurationApplication, &propSize, &configAP) == kAudioHardwareNoError)
2050     {
2051         //  get the FSRef of the config app
2052         FSRef theAppFSRef;
2053         OSStatus theError = LSFindApplicationForInfo(kLSUnknownCreator, configAP, NULL, &theAppFSRef, NULL);
2054         if (!theError)
2055         {
2056             LSOpenFSRef(&theAppFSRef, NULL);
2057         }
2058         CFRelease (configAP);
2059     }
2060     
2061     return (retVal);
2062 }
2063
2064
2065 //**********************************************************************************************
2066 // WCMRCoreAudioDevice::StaticAudioIOProc
2067 //
2068 //! The AudioIOProc that gets called when the AudioUnit is ready with recorded audio, and wants to get audio.
2069 //!     This one simply calls the non-static member.
2070 //!
2071 //! \param inRefCon : What was passed when setting up the Callback (in our case a pointer to teh WCMRCoreAudioDevice object).
2072 //! \param ioActionFlags : What actios has to be taken.
2073 //! \param inTimeStamp: When the data will be played back.
2074 //! \param inBusNumber : The AU element.
2075 //! \param inNumberFrames: Number af Audio frames that are requested.
2076 //! \param ioData : Where the playback data is to be placed.
2077 //! 
2078 //! \return 0 always
2079 //! 
2080 //**********************************************************************************************
2081 OSStatus WCMRCoreAudioDevice::StaticAudioIOProc(void *inRefCon, AudioUnitRenderActionFlags *    ioActionFlags,
2082                                                 const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
2083                                                 AudioBufferList *ioData)
2084 {
2085     WCMRCoreAudioDevice *pMyDevice = (WCMRCoreAudioDevice *)inRefCon;
2086     if (pMyDevice)
2087         return pMyDevice->AudioIOProc (ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
2088     else
2089         return 0;
2090 }
2091
2092
2093
2094
2095 //**********************************************************************************************
2096 // WCMRCoreAudioDevice::AudioIOProc
2097 //
2098 //! The non-static AudioIOProc that gets called when the AudioUnit is ready with recorded audio, and wants to get audio.
2099 //!     We retrieve the recorded audio, and then do our processing, to generate audio to be played back.
2100 //!
2101 //! \param ioActionFlags : What actios has to be taken.
2102 //! \param inTimeStamp: When the data will be played back.
2103 //! \param inBusNumber : The AU element.
2104 //! \param inNumberFrames: Number af Audio frames that are requested.
2105 //! \param ioData : Where the playback data is to be placed.
2106 //! 
2107 //! \return 0 always
2108 //! 
2109 //**********************************************************************************************
2110 OSStatus WCMRCoreAudioDevice::AudioIOProc(AudioUnitRenderActionFlags *  ioActionFlags,
2111                                           const AudioTimeStamp *inTimeStamp, UInt32 /*inBusNumber*/, UInt32 inNumberFrames,
2112                                           AudioBufferList *ioData)
2113 {
2114     UInt64 theStartTime = AudioGetCurrentHostTime();
2115
2116     OSStatus retVal = 0;
2117     
2118     if (m_StopRequested)
2119         goto Exit;
2120
2121     if (m_IOProcThreadPort == 0)
2122         m_IOProcThreadPort = mach_thread_self ();
2123     
2124     //cannot really deal with it unless the number of frames are the same as our buffer size!
2125     if (inNumberFrames != (UInt32)m_CurrentBufferSize)
2126         goto Exit;
2127     
2128     //Retrieve the input data...
2129     if (!m_InputChannels.empty())
2130     {
2131         retVal = AudioUnitRender(m_AUHALAudioUnit, ioActionFlags, inTimeStamp, AUHAL_INPUT_ELEMENT, inNumberFrames, &m_InputAudioBufferList);
2132     }
2133     
2134     //is this an input only device?
2135     if (m_OutputChannels.empty())
2136         AudioCallback (NULL, inNumberFrames, (uint32_t)inTimeStamp->mSampleTime, theStartTime);
2137     else if ((!m_OutputChannels.empty()) && (ioData->mBuffers[0].mNumberChannels == m_OutputChannels.size()))
2138         AudioCallback ((float *)ioData->mBuffers[0].mData, inNumberFrames, (uint32_t)inTimeStamp->mSampleTime, theStartTime);
2139     
2140 Exit:   
2141     return retVal;
2142 }
2143
2144
2145 //**********************************************************************************************
2146 // WCMRCoreAudioDevice::AudioCallback 
2147 //
2148 //! Here's where the actual audio processing happens. We call upon all the active connections' 
2149 //!     sinks to provide data to us which can be put/mixed in the output buffer! Also, we make the 
2150 //!     input data available to any sources that may call upon us during this time!
2151 //!
2152 //! \param *pOutputBuffer : Points to a buffer to receive playback data. For Input only devices, this will be NULL
2153 //! \param framesPerBuffer : Number of sample frames in input and output buffers. Number of channels,
2154 //!     which are interleaved, is fixed at Device Open (Active) time. In this implementation,
2155 //!     the number of channels are fixed to use the maximum available.
2156 //! 
2157 //! \return true
2158 //! 
2159 //**********************************************************************************************
2160 int WCMRCoreAudioDevice::AudioCallback (float *pOutputBuffer, unsigned long framesPerBuffer, uint32_t inSampleTime, uint64_t inCycleStartTime)
2161 {
2162     struct WCMRAudioDeviceManagerClient::AudioCallbackData audioCallbackData =
2163     {
2164         m_pInputData,
2165         pOutputBuffer,
2166         framesPerBuffer,
2167         inSampleTime,
2168         AudioConvertHostTimeToNanos(inCycleStartTime)
2169     };
2170     
2171     m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::AudioCallback, (void *)&audioCallbackData);
2172     
2173     m_SampleCounter += framesPerBuffer;
2174     return m_StopRequested;
2175 }
2176
2177
2178 //**********************************************************************************************
2179 // WCMRCoreAudioDevice::GetLatency
2180 //
2181 //! Get Latency for device.
2182 //!
2183 //! Use 'kAudioDevicePropertyLatency' and 'kAudioDevicePropertySafetyOffset' + GetStreamLatencies
2184 //!
2185 //! \param isInput : Return latency for the input if isInput is true, otherwise the output latency
2186 //!                  wiil be returned.
2187 //! \return Latency in samples.
2188 //!
2189 //**********************************************************************************************
2190 uint32_t WCMRCoreAudioDevice::GetLatency(bool isInput)
2191 {
2192     WTErr retVal = eNoErr;
2193     OSStatus err = kAudioHardwareNoError;
2194
2195     UInt32 propSize = sizeof(UInt32);
2196     UInt32 value1 = 0;
2197     UInt32 value2 = 0;
2198     
2199     UInt32 latency = 0;
2200     std::vector<int> streamLatencies;
2201     
2202     
2203     err = AudioDeviceGetProperty(m_DeviceID, 0, isInput, kAudioDevicePropertyLatency, &propSize, &value1);
2204     if (err != kAudioHardwareNoError)
2205     {
2206         DEBUG_MSG("GetLatency kAudioDevicePropertyLatency err = " << err);
2207     }
2208
2209     err = AudioDeviceGetProperty(m_DeviceID, 0, isInput, kAudioDevicePropertySafetyOffset, &propSize, &value2);
2210     if (err != kAudioHardwareNoError)
2211     {
2212         DEBUG_MSG("GetLatency kAudioDevicePropertySafetyOffset err = " << err);
2213     }
2214
2215     latency = value1 + value2;
2216
2217     err = GetStreamLatency(m_DeviceID, isInput, streamLatencies);
2218     if (err == kAudioHardwareNoError)
2219     {
2220         for ( int i = 0; i < streamLatencies.size(); i++) {
2221             latency += streamLatencies[i];
2222         }
2223     }
2224     
2225     return latency;
2226 }
2227
2228 //**********************************************************************************************
2229 // WCMRCoreAudioDevice::GetStreamLatency
2230 //
2231 //! Get stream latency for device.
2232 //!
2233 //! \param deviceID : The audio device ID.
2234 //!
2235 //! \param isInput : Return latency for the input if isInput is true, otherwise the output latency
2236 //!                  wiil be returned.
2237 //**********************************************************************************************
2238 OSStatus WCMRCoreAudioDevice::GetStreamLatency(AudioDeviceID device, bool isInput, std::vector<int>& latencies)
2239 {
2240     OSStatus err = kAudioHardwareNoError;
2241     UInt32 outSize1, outSize2, outSize3;
2242     Boolean     outWritable;
2243     
2244     err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreams, &outSize1, &outWritable);
2245     if (err == noErr) {
2246         int stream_count = outSize1 / sizeof(UInt32);
2247         AudioStreamID streamIDs[stream_count];
2248         AudioBufferList bufferList[stream_count];
2249         UInt32 streamLatency;
2250         outSize2 = sizeof(UInt32);
2251         
2252         err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreams, &outSize1, streamIDs);
2253         if (err != noErr) {
2254             DEBUG_MSG("GetStreamLatencies kAudioDevicePropertyStreams err = " << err);
2255             return err;
2256         }
2257         
2258         err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize3, &outWritable);
2259         if (err != noErr) {
2260             DEBUG_MSG("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = " << err);
2261             return err;
2262         }
2263         
2264         for (int i = 0; i < stream_count; i++) {
2265             err = AudioStreamGetProperty(streamIDs[i], 0, kAudioStreamPropertyLatency, &outSize2, &streamLatency);
2266             if (err != noErr) {
2267                 DEBUG_MSG("GetStreamLatencies kAudioStreamPropertyLatency err = " << err);
2268                 return err;
2269             }
2270             err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize3, bufferList);
2271             if (err != noErr) {
2272                 DEBUG_MSG("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = " << err);
2273                 return err;
2274             }
2275             latencies.push_back(streamLatency);
2276         }
2277     }
2278     return err;
2279 }
2280
2281
2282 //**********************************************************************************************
2283 // WCMRCoreAudioDeviceManager::WCMRCoreAudioDeviceManager
2284 //
2285 //! The constructuor, we initialize PA, and build the device list.
2286 //!
2287 //! \param *pTheClient : The manager's client object (which receives notifications).
2288 //! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true.
2289 //! 
2290 //! \return Nothing.
2291 //! 
2292 //**********************************************************************************************
2293 WCMRCoreAudioDeviceManager::WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient,
2294                             eAudioDeviceFilter eCurAudioDeviceFilter, bool useMultithreading, bool bNocopy)
2295   : WCMRAudioDeviceManager (pTheClient, eCurAudioDeviceFilter)
2296   , m_UseMultithreading (useMultithreading)
2297   , m_bNoCopyAudioBuffer(bNocopy)
2298 {
2299     AUTO_FUNC_DEBUG;
2300
2301     //first of all, tell HAL to use it's own run loop, not to wait for our runloop to do
2302     //it's dirty work...
2303     //Essentially, this makes the HAL on Snow Leopard behave like Leopard.
2304     //It's not yet (as of October 2009 documented), but the following discussion
2305     //has the information provided by Jeff Moore @ Apple:
2306     // http://lists.apple.com/archives/coreaudio-api/2009/Oct/msg00214.html
2307     //
2308     // As per Jeff's suggestion, opened an Apple Bug on this - ID# 7364011
2309     
2310     CFRunLoopRef nullRunLoop = 0;
2311     OSStatus err = AudioHardwareSetProperty (kAudioHardwarePropertyRunLoop, sizeof(CFRunLoopRef), &nullRunLoop);
2312
2313     if (err != kAudioHardwareNoError)
2314     {
2315         syslog (LOG_NOTICE, "Unable to set RunLoop for Audio Hardware");
2316     }
2317
2318     //add a listener to find out when devices change...
2319     AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, DevicePropertyChangeCallback, this);
2320     
2321     //Always add the None device first...
2322     m_NoneDevice = new WCMRNativeAudioNoneDevice(this);
2323
2324     //prepare our initial list...
2325     generateDeviceListImpl();
2326
2327     return;
2328 }
2329
2330
2331
2332 //**********************************************************************************************
2333 // WCMRCoreAudioDeviceManager::~WCMRCoreAudioDeviceManager
2334 //
2335 //! It clears the device list, releasing each of the device.
2336 //!
2337 //! \param none
2338 //! 
2339 //! \return Nothing.
2340 //! 
2341 //**********************************************************************************************
2342 WCMRCoreAudioDeviceManager::~WCMRCoreAudioDeviceManager()
2343 {
2344     AUTO_FUNC_DEBUG;
2345
2346     try
2347     {
2348         delete m_NoneDevice;
2349     }
2350     catch (...)
2351     {
2352         //destructors should absorb exceptions, no harm in logging though!!
2353         DEBUG_MSG ("Exception during destructor");
2354     }
2355
2356 }
2357
2358
2359 WCMRAudioDevice* WCMRCoreAudioDeviceManager::initNewCurrentDeviceImpl(const std::string & deviceName)
2360 {
2361     destroyCurrentDeviceImpl();
2362     
2363     std::cout << "API::PortAudioDeviceManager::initNewCurrentDevice " << deviceName << std::endl;
2364         if (deviceName == m_NoneDevice->DeviceName() )
2365         {
2366                 m_CurrentDevice = m_NoneDevice;
2367                 return m_CurrentDevice;
2368         }
2369     
2370         DeviceInfo devInfo;
2371     WTErr err = GetDeviceInfoByName(deviceName, devInfo);
2372     
2373         if (eNoErr == err)
2374         {
2375                 try
2376                 {
2377                         std::cout << "API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName << std::endl;
2378                         TRACE_MSG ("API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName);
2379             
2380             m_CurrentDevice = new WCMRCoreAudioDevice (this, devInfo.m_DeviceId, m_UseMultithreading, m_bNoCopyAudioBuffer);
2381                 }
2382                 catch (...)
2383                 {
2384                         std::cout << "Unabled to create PA Device: " << devInfo.m_DeviceId << std::endl;
2385                         DEBUG_MSG ("Unabled to create PA Device: " << devInfo.m_DeviceId);
2386                 }
2387         }
2388     
2389         return m_CurrentDevice;
2390 }
2391
2392
2393 void WCMRCoreAudioDeviceManager::destroyCurrentDeviceImpl()
2394 {
2395     if (m_CurrentDevice != m_NoneDevice)
2396         delete m_CurrentDevice;
2397     
2398     m_CurrentDevice = 0;
2399 }
2400     
2401     
2402 WTErr WCMRCoreAudioDeviceManager::getDeviceAvailableSampleRates(DeviceID deviceId, std::vector<int>& sampleRates)
2403 {
2404     AUTO_FUNC_DEBUG;
2405     
2406     WTErr retVal = eNoErr;
2407     OSStatus err = kAudioHardwareNoError;
2408     UInt32 propSize = 0;
2409     
2410     sampleRates.clear();
2411     
2412     //! 1. Get sample rate property size.
2413     err = AudioDeviceGetPropertyInfo(deviceId, 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, NULL);
2414     if (err == kAudioHardwareNoError)
2415     {
2416         //! 2. Get property: cannels output.
2417         
2418         // Allocate size accrding to the number of audio values
2419         int numRates = propSize / sizeof(AudioValueRange);
2420         AudioValueRange* supportedRates = new AudioValueRange[numRates];
2421         
2422         // Get sampling rates from Audio device
2423         err = AudioDeviceGetProperty(deviceId, 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, supportedRates);
2424         if (err == kAudioHardwareNoError)
2425         {
2426             //! 3. Update sample rates
2427             
2428             // now iterate through our standard SRs
2429             for(int ourSR=0; gAllSampleRates[ourSR] > 0; ourSR++)
2430             {
2431                 //check to see if our SR is in the supported rates...
2432                 for (int deviceSR = 0; deviceSR < numRates; deviceSR++)
2433                 {
2434                     if ((supportedRates[deviceSR].mMinimum <= gAllSampleRates[ourSR]) &&
2435                         (supportedRates[deviceSR].mMaximum >= gAllSampleRates[ourSR]))
2436                     {
2437                         sampleRates.push_back ((int)gAllSampleRates[ourSR]);
2438                         break;
2439                     }
2440                 }
2441             }
2442         }
2443         else
2444         {
2445             retVal = eCoreAudioFailed;
2446             DEBUG_MSG("Failed to get device Sample rates. Device Name: " << m_DeviceName.c_str());
2447         }
2448         
2449         delete [] supportedRates;
2450     }
2451     else
2452     {
2453         retVal = eCoreAudioFailed;
2454         DEBUG_MSG("Failed to get device Sample rates property size. Device Name: " << m_DeviceName.c_str());
2455     }
2456     
2457     return retVal;
2458 }
2459     
2460     
2461 WTErr WCMRCoreAudioDeviceManager::getDeviceMaxInputChannels(DeviceID deviceId, unsigned int& inputChannels)
2462 {
2463     AUTO_FUNC_DEBUG;
2464     WTErr retVal = eNoErr;
2465     OSStatus err = kAudioHardwareNoError;
2466     UInt32 propSize = 0;
2467     inputChannels = 0;
2468     
2469     // 1. Get property cannels input size.
2470     err = AudioDeviceGetPropertyInfo (deviceId, 0, 1/* Input */, kAudioDevicePropertyStreamConfiguration, &propSize, NULL);
2471     if (err == kAudioHardwareNoError)
2472     {
2473         //! 2. Get property: cannels input.
2474         
2475         // Allocate size according to the property size. Note that this is a variable sized struct...
2476         AudioBufferList *pStreamBuffers = (AudioBufferList *)malloc(propSize);
2477         
2478         if (pStreamBuffers)
2479         {
2480             memset (pStreamBuffers, 0, propSize);
2481             
2482             // Get the Input channels
2483             err = AudioDeviceGetProperty (deviceId, 0, 1/* Input */, kAudioDevicePropertyStreamConfiguration, &propSize, pStreamBuffers);
2484             if (err == kAudioHardwareNoError)
2485             {
2486                 // Calculate the number of input channels
2487                 for (UInt32 streamIndex = 0; streamIndex < pStreamBuffers->mNumberBuffers; streamIndex++)
2488                 {
2489                     inputChannels += pStreamBuffers->mBuffers[streamIndex].mNumberChannels;
2490                 }
2491             }
2492             else
2493             {
2494                 retVal = eCoreAudioFailed;
2495                 DEBUG_MSG("Failed to get device Input channels. Device Name: " << m_DeviceName.c_str());
2496             }
2497             
2498             free (pStreamBuffers);
2499         }
2500         else
2501         {
2502             retVal = eMemOutOfMemory;
2503             DEBUG_MSG("Faild to allocate memory. Device Name: " << m_DeviceName.c_str());
2504         }
2505     }
2506     else
2507     {
2508         retVal = eCoreAudioFailed;
2509         DEBUG_MSG("Failed to get device Input channels property size. Device Name: " << m_DeviceName.c_str());
2510     }
2511     
2512     return retVal;
2513 }
2514     
2515
2516 WTErr WCMRCoreAudioDeviceManager::getDeviceMaxOutputChannels(DeviceID deviceId, unsigned int& outputChannels)
2517 {
2518     AUTO_FUNC_DEBUG;
2519     
2520     WTErr retVal = eNoErr;
2521     OSStatus err = kAudioHardwareNoError;
2522     UInt32 propSize = 0;
2523     outputChannels = 0;
2524     
2525     //! 1. Get property cannels output size.
2526     err = AudioDeviceGetPropertyInfo (deviceId, 0, 0/* Output */, kAudioDevicePropertyStreamConfiguration, &propSize, NULL);
2527     if (err == kAudioHardwareNoError)
2528     {
2529         //! 2. Get property: cannels output.
2530         
2531         // Allocate size according to the property size. Note that this is a variable sized struct...
2532         AudioBufferList *pStreamBuffers = (AudioBufferList *)malloc(propSize);
2533         if (pStreamBuffers)
2534         {
2535             memset (pStreamBuffers, 0, propSize);
2536             
2537             // Get the Output channels
2538             err = AudioDeviceGetProperty (deviceId, 0, 0/* Output */, kAudioDevicePropertyStreamConfiguration, &propSize, pStreamBuffers);
2539             if (err == kAudioHardwareNoError)
2540             {
2541                 // Calculate the number of output channels
2542                 for (UInt32 streamIndex = 0; streamIndex < pStreamBuffers->mNumberBuffers; streamIndex++)
2543                 {
2544                     outputChannels += pStreamBuffers->mBuffers[streamIndex].mNumberChannels;
2545                 }
2546             }
2547             else
2548             {
2549                 retVal = eCoreAudioFailed;
2550                 DEBUG_MSG("Failed to get device Output channels. Device Name: " << m_DeviceName.c_str());
2551             }
2552             free (pStreamBuffers);
2553         }
2554         else
2555         {
2556             retVal = eMemOutOfMemory;
2557             DEBUG_MSG("Faild to allocate memory. Device Name: " << m_DeviceName.c_str());
2558         }
2559     }
2560     else
2561     {
2562         retVal = eCoreAudioFailed;
2563         DEBUG_MSG("Failed to get device Output channels property size. Device Name: " << m_DeviceName.c_str());
2564     }
2565  
2566     return retVal;
2567 }
2568     
2569     
2570 WTErr WCMRCoreAudioDeviceManager::generateDeviceListImpl()
2571 {
2572     AUTO_FUNC_DEBUG;
2573     
2574     // lock the list first
2575     wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex);
2576     m_DeviceInfoVec.clear();
2577     
2578     //First, get info from None device which is always present
2579     if (m_NoneDevice)
2580     {
2581         DeviceInfo *pDevInfo = new DeviceInfo(NONE_DEVICE_ID, m_NoneDevice->DeviceName() );
2582         pDevInfo->m_AvailableSampleRates = m_NoneDevice->SamplingRates();
2583         m_DeviceInfoVec.push_back(pDevInfo);
2584     }
2585     
2586     WTErr retVal = eNoErr;
2587     OSStatus osErr = noErr;
2588     AudioDeviceID* deviceIDs = 0;
2589     
2590     openlog("WCMRCoreAudioDeviceManager", LOG_PID | LOG_CONS, LOG_USER);
2591     
2592     try
2593     {
2594         //Get device count...
2595         UInt32 propSize = 0;
2596         osErr = AudioHardwareGetPropertyInfo (kAudioHardwarePropertyDevices, &propSize, NULL);
2597         ASSERT_ERROR(osErr, "AudioHardwareGetProperty 1");
2598         if (WUIsError(osErr))
2599             throw osErr;
2600         
2601         size_t numDevices = propSize / sizeof (AudioDeviceID);
2602         deviceIDs = new AudioDeviceID[numDevices];
2603         
2604         //retrieve the device IDs
2605         propSize = numDevices * sizeof (AudioDeviceID);
2606         osErr = AudioHardwareGetProperty (kAudioHardwarePropertyDevices, &propSize, deviceIDs);
2607         ASSERT_ERROR(osErr, "Error while getting audio devices: AudioHardwareGetProperty 2");
2608         if (WUIsError(osErr))
2609             throw osErr;
2610         
2611         //now add the ones that are not there...
2612         for (size_t deviceIndex = 0; deviceIndex < numDevices; deviceIndex++)
2613         {
2614             DeviceInfo* pDevInfo = 0;
2615             
2616             //Get device name and create new DeviceInfo entry
2617             //Get property name size.
2618             osErr = AudioDeviceGetPropertyInfo(deviceIDs[deviceIndex], 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL);
2619             if (osErr == kAudioHardwareNoError)
2620             {
2621                 //Get property: name.
2622                 char* deviceName = new char[propSize];
2623                 osErr = AudioDeviceGetProperty(deviceIDs[deviceIndex], 0, 0, kAudioDevicePropertyDeviceName, &propSize, deviceName);
2624                 if (osErr == kAudioHardwareNoError)
2625                 {
2626                     pDevInfo = new DeviceInfo(deviceIDs[deviceIndex], deviceName);
2627                 }
2628                 else
2629                 {
2630                     retVal = eCoreAudioFailed;
2631                     DEBUG_MSG("Failed to get device name. Device ID: " << m_DeviceID);
2632                 }
2633                 
2634                 delete [] deviceName;
2635             }
2636             else
2637             {
2638                 retVal = eCoreAudioFailed;
2639                 DEBUG_MSG("Failed to get device name property size. Device ID: " << m_DeviceID);
2640             }
2641             
2642             if (pDevInfo)
2643             {
2644                 //Retrieve all the information we need for the device
2645                 WTErr wErr = eNoErr;
2646                 
2647                 //Get available sample rates for the device
2648                 std::vector<int> availableSampleRates;
2649                 wErr = getDeviceAvailableSampleRates(pDevInfo->m_DeviceId, availableSampleRates);
2650                 
2651                 if (wErr != eNoErr)
2652                 {
2653                     DEBUG_MSG ("Failed to get device available sample rates. Device ID: " << m_DeviceID);
2654                     delete pDevInfo;
2655                     continue; //proceed to the next device
2656                 }
2657                 
2658                 pDevInfo->m_AvailableSampleRates = availableSampleRates;
2659                 
2660                 //Get max input channels
2661                 uint32_t maxInputChannels;
2662                 wErr = getDeviceMaxInputChannels(pDevInfo->m_DeviceId, maxInputChannels);
2663                 
2664                 if (wErr != eNoErr)
2665                 {
2666                     DEBUG_MSG ("Failed to get device max input channels count. Device ID: " << m_DeviceID);
2667                     delete pDevInfo;
2668                     continue; //proceed to the next device
2669                 }
2670                 
2671                 pDevInfo->m_MaxInputChannels = maxInputChannels;
2672                 
2673                 //Get max output channels
2674                 uint32_t maxOutputChannels;
2675                 wErr = getDeviceMaxOutputChannels(pDevInfo->m_DeviceId, maxOutputChannels);
2676                 
2677                 if (wErr != eNoErr)
2678                 {
2679                     DEBUG_MSG ("Failed to get device max output channels count. Device ID: " << m_DeviceID);
2680                     delete pDevInfo;
2681                     continue; //proceed to the next device
2682                 }
2683                 
2684                 pDevInfo->m_MaxOutputChannels = maxOutputChannels;
2685                 
2686                 //Now check if this device is acceptable according to current input/output settings
2687                 bool bRejectDevice = false;
2688                 switch(m_eAudioDeviceFilter)
2689                 {
2690                     case eInputOnlyDevices:
2691                         if (pDevInfo->m_MaxInputChannels != 0)
2692                         {
2693                             m_DeviceInfoVec.push_back(pDevInfo);
2694                         }
2695                         else
2696                         {
2697                             // Delete unnecesarry device
2698                             bRejectDevice = true;
2699                         }
2700                         break;
2701                     case eOutputOnlyDevices:
2702                         if (pDevInfo->m_MaxOutputChannels != 0)
2703                         {
2704                             m_DeviceInfoVec.push_back(pDevInfo);
2705                         }
2706                         else
2707                         {
2708                             // Delete unnecesarry device
2709                             bRejectDevice = true;
2710                         }
2711                         break;
2712                     case eFullDuplexDevices:
2713                         if (pDevInfo->m_MaxInputChannels != 0 && pDevInfo->m_MaxOutputChannels != 0)
2714                         {
2715                             m_DeviceInfoVec.push_back(pDevInfo);
2716                         }
2717                         else
2718                         {
2719                             // Delete unnecesarry device
2720                             bRejectDevice = true;
2721                         }
2722                         break;
2723                     case eAllDevices:
2724                     default:
2725                         m_DeviceInfoVec.push_back(pDevInfo);
2726                         break;
2727                 }
2728                 
2729                 if(bRejectDevice)
2730                 {
2731                     syslog (LOG_NOTICE, "%s rejected, In Channels = %d, Out Channels = %d\n",
2732                             pDevInfo->m_DeviceName.c_str(), pDevInfo->m_MaxInputChannels, pDevInfo->m_MaxOutputChannels);
2733                     // In case of Input and Output both channels being Zero, we will release memory; since we created CoreAudioDevice but we are Not adding it in list.
2734                     delete pDevInfo;
2735                 }
2736             }
2737         }
2738         
2739         
2740         //If no devices were found, that's not a good thing!
2741         if (m_DeviceInfoVec.empty())
2742         {
2743             DEBUG_MSG ("No matching CoreAudio devices were found\n");
2744         }        
2745     }
2746     catch (...)
2747     {
2748         if (WUNoError(retVal))
2749             retVal = eCoreAudioFailed;
2750     }
2751     
2752     delete[] deviceIDs;
2753     closelog();
2754     
2755     return retVal;
2756 }
2757
2758
2759 WTErr WCMRCoreAudioDeviceManager::updateDeviceListImpl()
2760 {
2761     wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex);
2762     WTErr err = generateDeviceListImpl();
2763     
2764     if (eNoErr != err)
2765     {
2766         std::cout << "API::PortAudioDeviceManager::updateDeviceListImpl: Device list update error: "<< err << std::endl;
2767         return err;
2768     }
2769     
2770     if (m_CurrentDevice)
2771     {
2772         // if we have device initialized we should find out if this device is still connected
2773         DeviceInfo devInfo;
2774         WTErr deviceLookUpErr = GetDeviceInfoByName(m_CurrentDevice->DeviceName(), devInfo );
2775     
2776         if (eNoErr != deviceLookUpErr)
2777         {
2778             NotifyClient (WCMRAudioDeviceManagerClient::IODeviceDisconnected);
2779             return err;
2780         }
2781     }
2782     
2783     NotifyClient (WCMRAudioDeviceManagerClient::DeviceListChanged);
2784     
2785     return err;
2786 }
2787
2788
2789 WTErr WCMRCoreAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& bufferSizes) const
2790 {
2791     AUTO_FUNC_DEBUG;
2792     
2793     WTErr retVal = eNoErr;
2794     OSStatus err = kAudioHardwareNoError;
2795     UInt32 propSize = 0;
2796     
2797     bufferSizes.clear();
2798     
2799     //first check if the request has been made for None device
2800         if (deviceName == m_NoneDevice->DeviceName() )
2801         {
2802                 bufferSizes = m_NoneDevice->BufferSizes();
2803                 return retVal;
2804         }
2805     
2806     DeviceInfo devInfo;
2807     retVal = GetDeviceInfoByName(deviceName, devInfo);
2808     
2809     if (eNoErr == retVal)
2810     {
2811         // 1. Get buffer size range
2812         AudioValueRange bufferSizesRange;
2813         propSize = sizeof (AudioValueRange);
2814         err = AudioDeviceGetProperty (devInfo.m_DeviceId, 0, 0, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &bufferSizesRange);
2815         if(err == kAudioHardwareNoError)
2816         {
2817             // 2. Run on all ranges and add them to the list
2818             for(int bsize=0; gAllBufferSizes[bsize] > 0; bsize++)
2819             {
2820                 if ((bufferSizesRange.mMinimum <= gAllBufferSizes[bsize]) && (bufferSizesRange.mMaximum >= gAllBufferSizes[bsize]))
2821                 {
2822                     bufferSizes.push_back (gAllBufferSizes[bsize]);
2823                 }
2824             }
2825             
2826             //if we didn't get a single hit, let's simply add the min. and the max...
2827             if (bufferSizes.empty())
2828             {
2829                 bufferSizes.push_back ((int)bufferSizesRange.mMinimum);
2830                 bufferSizes.push_back ((int)bufferSizesRange.mMaximum);
2831             }
2832         }
2833         else
2834         {
2835             retVal = eCoreAudioFailed;
2836             DEBUG_MSG("Failed to get device buffer sizes range. Device Name: " << m_DeviceName.c_str());
2837         }
2838     }
2839     else
2840         {
2841                 retVal = eRMResNotFound;
2842                 std::cout << "API::PortAudioDeviceManager::GetBufferSizes: Device not found: "<< deviceName << std::endl;
2843         }
2844
2845     
2846     return retVal;
2847 }
2848
2849
2850 OSStatus WCMRCoreAudioDeviceManager::DevicePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* inClientData)
2851 {
2852     switch (inPropertyID)
2853     {
2854         case kAudioHardwarePropertyDevices:
2855             {
2856                 WCMRCoreAudioDeviceManager* pManager = (WCMRCoreAudioDeviceManager*)inClientData;
2857                 if (pManager)
2858                     pManager->updateDeviceListImpl();
2859             }
2860             break;
2861         default:
2862             break;
2863     }
2864     
2865     return 0;
2866 }