1 /************************************************************************
2 	IMPORTANT NOTE : this file contains two clearly delimited sections :
3 	the ARCHITECTURE section (in two parts) and the USER section. Each section
4 	is governed by its own copyright and license. Please check individually
5 	each section for license and copyright information.
6 *************************************************************************/
7 
8 /*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/
9 
10 /************************************************************************
11     FAUST Architecture File
12     Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
13     ---------------------------------------------------------------------
14     This Architecture section is free software; you can redistribute it
15     and/or modify it under the terms of the GNU General Public License
16     as published by the Free Software Foundation; either version 3 of
17     the License, or (at your option) any later version.
18 
19     This program is distributed in the hope that it will be useful,
20     but WITHOUT ANY WARRANTY; without even the implied warranty of
21     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22     GNU General Public License for more details.
23 
24     You should have received a copy of the GNU General Public License
25     along with this program; If not, see <http://www.gnu.org/licenses/>.
26 
27     EXCEPTION : As a special exception, you may create a larger work
28     that contains this FAUST architecture section and distribute
29     that work under terms of your choice, so long as this FAUST
30     architecture section is not modified.
31 
32 
33  ************************************************************************
34  ************************************************************************/
35 
36 #ifndef __coreaudio_dsp__
37 #define __coreaudio_dsp__
38 
39 #include <math.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <vector>
43 #include <iostream>
44 #include <sys/time.h>
45 
46 #include <AudioToolbox/AudioConverter.h>
47 #include <CoreAudio/CoreAudio.h>
48 #include <AudioUnit/AudioUnit.h>
49 #include <CoreServices/CoreServices.h>
50 
51 #include "faust/audio/audio.h"
52 #include "faust/dsp/dsp.h"
53 
54 /******************************************************************************
55 *******************************************************************************
56 
57 							COREAUDIO INTERNAL INTERFACE
58 
59 *******************************************************************************
60 *******************************************************************************/
61 
62 #define OPEN_ERR -1
63 #define CLOSE_ERR -1
64 #define NO_ERR 0
65 
66 #define WAIT_NOTIFICATION_COUNTER 60
67 
68 typedef	UInt8	CAAudioHardwareDeviceSectionID;
69 #define	kAudioDeviceSectionInput	((CAAudioHardwareDeviceSectionID)0x01)
70 #define	kAudioDeviceSectionOutput	((CAAudioHardwareDeviceSectionID)0x00)
71 #define	kAudioDeviceSectionGlobal	((CAAudioHardwareDeviceSectionID)0x00)
72 #define	kAudioDeviceSectionWildcard	((CAAudioHardwareDeviceSectionID)0xFF)
73 
74 class TCoreAudioRenderer;
75 typedef TCoreAudioRenderer* TCoreAudioRendererPtr;
76 
PrintStreamDesc(AudioStreamBasicDescription * inDesc)77 static void PrintStreamDesc(AudioStreamBasicDescription *inDesc)
78 {
79     printf("- - - - - - - - - - - - - - - - - - - -\n");
80     printf("  Sample Rate:%f\n", inDesc->mSampleRate);
81     printf("  Format ID:%.*s\n", (int)sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID);
82     printf("  Format Flags:%lX\n", inDesc->mFormatFlags);
83     printf("  Bytes per Packet:%ld\n", (long)inDesc->mBytesPerPacket);
84     printf("  Frames per Packet:%ld\n", (long)inDesc->mFramesPerPacket);
85     printf("  Bytes per Frame:%ld\n", (long)inDesc->mBytesPerFrame);
86     printf("  Channels per Frame:%ld\n", (long)inDesc->mChannelsPerFrame);
87     printf("  Bits per Channel:%ld\n", (long)inDesc->mBitsPerChannel);
88     printf("- - - - - - - - - - - - - - - - - - - -\n");
89 }
90 
printError(OSStatus err)91 static void printError(OSStatus err)
92 {
93     switch (err) {
94         case kAudioHardwareNoError:
95             printf("error code : kAudioHardwareNoError\n");
96             break;
97 		case kAudioConverterErr_FormatNotSupported:
98             printf("error code : kAudioConverterErr_FormatNotSupported\n");
99             break;
100         case kAudioConverterErr_OperationNotSupported:
101             printf("error code : kAudioConverterErr_OperationNotSupported\n");
102             break;
103         case kAudioConverterErr_PropertyNotSupported:
104             printf("error code : kAudioConverterErr_PropertyNotSupported\n");
105             break;
106         case kAudioConverterErr_InvalidInputSize:
107             printf("error code : kAudioConverterErr_InvalidInputSize\n");
108             break;
109         case kAudioConverterErr_InvalidOutputSize:
110             printf("error code : kAudioConverterErr_InvalidOutputSize\n");
111             break;
112         case kAudioConverterErr_UnspecifiedError:
113             printf("error code : kAudioConverterErr_UnspecifiedError\n");
114             break;
115         case kAudioConverterErr_BadPropertySizeError:
116             printf("error code : kAudioConverterErr_BadPropertySizeError\n");
117             break;
118         case kAudioConverterErr_RequiresPacketDescriptionsError:
119             printf("error code : kAudioConverterErr_RequiresPacketDescriptionsError\n");
120             break;
121         case kAudioConverterErr_InputSampleRateOutOfRange:
122             printf("error code : kAudioConverterErr_InputSampleRateOutOfRange\n");
123             break;
124         case kAudioConverterErr_OutputSampleRateOutOfRange:
125             printf("error code : kAudioConverterErr_OutputSampleRateOutOfRange\n");
126             break;
127 		case kAudioHardwareNotRunningError:
128             printf("error code : kAudioHardwareNotRunningError\n");
129             break;
130         case kAudioHardwareUnknownPropertyError:
131             printf("error code : kAudioHardwareUnknownPropertyError\n");
132             break;
133         case kAudioHardwareIllegalOperationError:
134             printf("error code : kAudioHardwareIllegalOperationError\n");
135             break;
136         case kAudioHardwareBadDeviceError:
137             printf("error code : kAudioHardwareBadDeviceError\n");
138             break;
139         case kAudioHardwareBadStreamError:
140             printf("error code : kAudioHardwareBadStreamError\n");
141             break;
142         case kAudioDeviceUnsupportedFormatError:
143             printf("error code : kAudioDeviceUnsupportedFormatError\n");
144             break;
145         case kAudioDevicePermissionsError:
146             printf("error code : kAudioDevicePermissionsError\n");
147             break;
148         default:
149             printf("error code : err = %d\n", err);
150             break;
151     }
152 }
153 
GetNominalSampleRate(AudioDeviceID inDevice)154 static Float64 GetNominalSampleRate(AudioDeviceID inDevice)
155 {
156     Float64 sampleRate = 0;
157     UInt32 outSize =  sizeof(Float64);
158     OSStatus err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
159     if (err != noErr) {
160         printf("Cannot get current sample rate\n");
161         printError(err);
162         return -1;
163     } else {
164         return sampleRate;
165     }
166 }
167 
GetDeviceName(AudioDeviceID id)168 static CFStringRef GetDeviceName(AudioDeviceID id)
169 {
170     UInt32 size = sizeof(CFStringRef);
171     CFStringRef UIname;
172     OSStatus err = AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
173     return (err == noErr) ? UIname : NULL;
174 }
175 
176 static bool CheckAvailableDeviceName(const char* device_name, AudioDeviceID* device_id, int len = -1)
177 {
178     UInt32 size;
179     Boolean isWritable;
180     int i, deviceNum;
181     OSStatus err;
182 
183     err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable);
184     if (err != noErr) {
185         return false;
186     }
187 
188     deviceNum = size / sizeof(AudioDeviceID);
189     AudioDeviceID devices[deviceNum];
190 
191     err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
192     if (err != noErr) {
193         return false;
194     }
195 
196     for (i = 0; i < deviceNum; i++) {
197         char device_name_aux[256];
198 
199         size = 256;
200         err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name_aux);
201         if (err != noErr) {
202             return false;
203         }
204 
205         if (strncmp(device_name_aux, device_name, (len == -1) ? strlen(device_name) : len) == 0) {
206             *device_id = devices[i];
207             return true;
208         }
209     }
210 
211     return false;
212 }
213 
214 class TCoreAudioRenderer
215 {
216 
217     protected:
218 
219         AudioDeviceID fAggregateDeviceID;
220         AudioObjectID fAggregatePluginID;    // Used for aggregate device
221 
222         int fDevNumInChans;
223         int fDevNumOutChans;
224 
225         int fPhysicalInputs;
226         int fPhysicalOutputs;
227 
228         float** fInChannel;
229         float** fOutChannel;
230 
231         int fBufferSize;
232         int fSampleRate;
233 
234         bool fIsInJackDevice;
235         bool fIsOutJackDevice;
236 
237         dsp* fDSP;
238 
239         AudioBufferList* fInputData;
240         AudioDeviceID fDeviceID;
241         AudioUnit fAUHAL;
242         bool fState;
243 
GetDefaultDeviceAndSampleRate(int inChan,int outChan,int & sample_rate,AudioDeviceID * device)244         OSStatus GetDefaultDeviceAndSampleRate(int inChan, int outChan, int& sample_rate, AudioDeviceID* device)
245         {
246 
247             UInt32 theSize = sizeof(UInt32);
248             AudioDeviceID inDefault;
249             AudioDeviceID outDefault;
250             OSStatus res;
251 
252             if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
253                                                 &theSize, &inDefault)) != noErr) {
254                 return res;
255             }
256 
257             if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
258                                                 &theSize, &outDefault)) != noErr) {
259                 return res;
260             }
261 
262             /*
263             // TODO
264             if (inDefault == 0) {
265                 printf("Error default input device is 0, will take 'Built-in'...\n");
266                 if (CheckAvailableDeviceName("Built-in Microphone", &inDefault)
267                     || CheckAvailableDeviceName("Built-in Line", &inDefault)) {
268                     printf("GetDefaultInputDevice : output = %ld\n", inDefault);
269                 } else {
270                     printf("Cannot find any input device to use...");
271                     return -1;
272                 }
273             }
274 
275             if (outDefault == 0) {
276                 printf("Error default ouput device is 0, will take 'Built-in'...\n");
277                 if (CheckAvailableDeviceName("Built-in Output", &outDefault)) {
278                     printf("GetDefaultOutputDevice : output = %ld\n", outDefault);
279                 } else {
280                     printf("Cannot find any output device to use...\n");
281                     return -1;
282                 }
283             }
284             */
285 
286             //printf("GetDefaultDevice : input = %d output = %d\n", inDefault, outDefault);
287 
288             // Duplex mode
289             if (inChan > 0 && outChan > 0) {
290                 // Get the device only if default input and output are the same
291                 if (inDefault == outDefault) {
292                     *device = inDefault;
293                     goto end;
294                 } else {
295                     if (CreateAggregateDevice(inDefault, outDefault, sample_rate) != noErr) {
296                         return kAudioHardwareBadDeviceError;
297                     }
298                     //printf("fAggregateDeviceID %d\n", fAggregateDeviceID);
299                     *device = fAggregateDeviceID;
300                     goto end;
301                 }
302             } else if (inChan > 0) {
303                 *device = inDefault;
304                 goto end;
305             } else if (outChan > 0) {
306                 *device = outDefault;
307                 goto end;
308             } else {
309                 return kAudioHardwareBadDeviceError;
310             }
311 
312         end:
313 
314             if (sample_rate == -1) {
315                 // Possible take the current sample rate
316                 sample_rate = int(GetNominalSampleRate(*device));
317             } else {
318                 // Otherwise force the one we want...
319                 SetupSampleRateAux(*device, sample_rate);
320             }
321             //printf("samplerate %d\n", sample_rate);
322             fSampleRate = sample_rate;
323             return noErr;
324         }
325 
CreateAggregateDevice(AudioDeviceID captureDeviceID,AudioDeviceID playbackDeviceID,int & sample_rate)326         OSStatus CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, int& sample_rate)
327         {
328             OSStatus err = noErr;
329             AudioObjectID sub_device[32];
330             UInt32 outSize = sizeof(sub_device);
331 
332             //printf("CreateAggregateDevice : input device %d\n", captureDeviceID);
333 
334             err = AudioDeviceGetProperty(captureDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
335             std::vector<AudioDeviceID> captureDeviceIDArray;
336 
337             if (err != noErr) {
338                 //printf("Input device does not have subdevices\n");
339                 captureDeviceIDArray.push_back(captureDeviceID);
340             } else {
341                 int num_devices = outSize / sizeof(AudioObjectID);
342                 //printf("Input device has %d subdevices\n", num_devices);
343                 for (int i = 0; i < num_devices; i++) {
344                     //printf("Input sub_device %d\n", sub_device[i]);
345                     captureDeviceIDArray.push_back(sub_device[i]);
346                 }
347             }
348 
349             outSize = sizeof(sub_device);
350             err = AudioDeviceGetProperty(playbackDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
351             std::vector<AudioDeviceID> playbackDeviceIDArray;
352 
353             if (err != noErr) {
354                 //printf("Output device does not have subdevices\n");
355                 playbackDeviceIDArray.push_back(playbackDeviceID);
356             } else {
357                 int num_devices = outSize / sizeof(AudioObjectID);
358                 //printf("Output device has %d subdevices\n", num_devices);
359                 for (int i = 0; i < num_devices; i++) {
360                     //printf("Output sub_device %d\n", sub_device[i]);
361                     playbackDeviceIDArray.push_back(sub_device[i]);
362                 }
363             }
364 
365             return CreateAggregateDeviceAux(captureDeviceIDArray, playbackDeviceIDArray, sample_rate);
366         }
367 
CreateAggregateDeviceAux(std::vector<AudioDeviceID> captureDeviceID,std::vector<AudioDeviceID> playbackDeviceID,int & sample_rate)368         OSStatus CreateAggregateDeviceAux(std::vector<AudioDeviceID> captureDeviceID, std::vector<AudioDeviceID> playbackDeviceID, int& sample_rate)
369         {
370             OSStatus osErr = noErr;
371             UInt32 outSize;
372             Boolean outWritable;
373             bool fClockDriftCompensate = true;
374 
375             // Prepare sub-devices for clock drift compensation
376             // Workaround for bug in the HAL : until 10.6.2
377             AudioObjectPropertyAddress theAddressOwned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
378             AudioObjectPropertyAddress theAddressDrift = { kAudioSubDevicePropertyDriftCompensation, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
379             UInt32 theQualifierDataSize = sizeof(AudioObjectID);
380             AudioClassID inClass = kAudioSubDeviceClassID;
381             void* theQualifierData = &inClass;
382             UInt32 subDevicesNum = 0;
383 
384             //---------------------------------------------------------------------------
385             // Setup SR of both devices otherwise creating AD may fail...
386             //---------------------------------------------------------------------------
387             UInt32 keptclockdomain = 0;
388             UInt32 clockdomain = 0;
389             outSize = sizeof(UInt32);
390             bool need_clock_drift_compensation = false;
391 
392             for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
393                 if (SetupSampleRateAux(captureDeviceID[i], sample_rate) < 0) {
394                     printf("TCoreAudioRenderer::CreateAggregateDeviceAux : cannot set SR of input device\n");
395                 } else  {
396                     // Check clock domain
397                     osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
398                     if (osErr != 0) {
399                         printf("TCoreAudioRenderer::CreateAggregateDeviceAux : kAudioDevicePropertyClockDomain error\n");
400                         printError(osErr);
401                     } else {
402                         keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
403                         //printf("TCoreAudioRenderer::CreateAggregateDevice : input clockdomain = %d\n", clockdomain);
404                         if (clockdomain != 0 && clockdomain != keptclockdomain) {
405                             //printf("TCoreAudioRenderer::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...\n");
406                             need_clock_drift_compensation = true;
407                         }
408                     }
409                 }
410             }
411 
412             for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
413                 if (SetupSampleRateAux(playbackDeviceID[i], sample_rate) < 0) {
414                     printf("TCoreAudioRenderer::CreateAggregateDeviceAux : cannot set SR of output device\n");
415                 } else {
416                     // Check clock domain
417                     osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
418                     if (osErr != 0) {
419                         printf("TCoreAudioRenderer::CreateAggregateDeviceAux : kAudioDevicePropertyClockDomain error\n");
420                         printError(osErr);
421                     } else {
422                         keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
423                         //printf("TCoreAudioRenderer::CreateAggregateDevice : output clockdomain = %d", clockdomain);
424                         if (clockdomain != 0 && clockdomain != keptclockdomain) {
425                             //printf("TCoreAudioRenderer::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...\n");
426                             need_clock_drift_compensation = true;
427                         }
428                     }
429                 }
430             }
431 
432             // If no valid clock domain was found, then assume we have to compensate...
433             if (keptclockdomain == 0) {
434                 need_clock_drift_compensation = true;
435             }
436 
437             //---------------------------------------------------------------------------
438             // Start to create a new aggregate by getting the base audio hardware plugin
439             //---------------------------------------------------------------------------
440 
441             char device_name[256];
442             for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
443                 GetDeviceNameFromID(captureDeviceID[i], device_name);
444                 //printf("Separated input = '%s' \n", device_name);
445             }
446 
447             for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
448                 GetDeviceNameFromID(playbackDeviceID[i], device_name);
449                 //printf("Separated output = '%s' \n", device_name);
450             }
451 
452             osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable);
453             if (osErr != noErr) {
454                 printf("TCoreAudioRenderer::CreateAggregateDeviceAux : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error\n");
455                 printError(osErr);
456                 return osErr;
457             }
458 
459             AudioValueTranslation pluginAVT;
460             CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio");
461 
462             pluginAVT.mInputData = &inBundleRef;
463             pluginAVT.mInputDataSize = sizeof(inBundleRef);
464             pluginAVT.mOutputData = &fAggregatePluginID;
465             pluginAVT.mOutputDataSize = sizeof(fAggregatePluginID);
466 
467             osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT);
468             if (osErr != noErr) {
469                 printf("TCoreAudioRenderer::CreateAggregateDeviceAux : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error\n");
470                 printError(osErr);
471                 return osErr;
472             }
473 
474             //-------------------------------------------------
475             // Create a CFDictionary for our aggregate device
476             //-------------------------------------------------
477 
478             CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
479 
480             char buffer1[64];
481             char buffer2[64];
482 
483             // generate "random" name
484             struct timeval fTv1;
485             struct timezone tz;
486             gettimeofday(&fTv1, &tz);
487 
488             sprintf(buffer1, "com.grame.%d", fTv1.tv_sec + fTv1.tv_usec);
489             sprintf(buffer2, "%d", fTv1.tv_sec + fTv1.tv_usec);
490 
491             CFStringRef AggregateDeviceNameRef = CFStringCreateWithCString(kCFAllocatorDefault, buffer1, CFStringGetSystemEncoding());
492             CFStringRef AggregateDeviceUIDRef = CFStringCreateWithCString(kCFAllocatorDefault, buffer2, CFStringGetSystemEncoding());
493 
494             // add the name of the device to the dictionary
495             CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef);
496 
497             // add our choice of UID for the aggregate device to the dictionary
498             CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef);
499 
500             // add a "private aggregate key" to the dictionary
501             int value = 1;
502             CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value);
503 
504             SInt32 system;
505             Gestalt(gestaltSystemVersion, &system);
506 
507             //printf("TCoreAudioRenderer::CreateAggregateDevice : system version = %x limit = %x\n", system, 0x00001054);
508 
509             // Starting with 10.5.4 systems, the AD can be internal... (better)
510             if (system < 0x00001054) {
511                 //printf("TCoreAudioRenderer::CreateAggregateDevice : public aggregate device....\n");
512             } else {
513                 //printf("TCoreAudioRenderer::CreateAggregateDevice : private aggregate device....\n");
514                 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef);
515             }
516 
517             // Prepare sub-devices for clock drift compensation
518             CFMutableArrayRef subDevicesArrayClock = NULL;
519 
520             /*
521              if (fClockDriftCompensate) {
522                  if (need_clock_drift_compensation) {
523                      jack_info("Clock drift compensation activated...");
524                      subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
525 
526                      for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
527                          CFStringRef UID = GetDeviceName(captureDeviceID[i]);
528                          if (UID) {
529                          CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
530                          CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
531                          CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
532                          //CFRelease(UID);
533                          CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
534                      }
535                  }
536 
537                  for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
538                      CFStringRef UID = GetDeviceName(playbackDeviceID[i]);
539                      if (UID) {
540                          CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
541                          CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
542                          CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
543                          //CFRelease(UID);
544                          CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
545                      }
546                  }
547 
548                      // add sub-device clock array for the aggregate device to the dictionary
549                      CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock);
550                      } else {
551                      jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
552                  }
553             }
554             */
555 
556             //-------------------------------------------------
557             // Create a CFMutableArray for our sub-device list
558             //-------------------------------------------------
559 
560             // we need to append the UID for each device to a CFMutableArray, so create one here
561             CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
562 
563             std::vector<CFStringRef> captureDeviceUID;
564             for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
565                 CFStringRef ref = GetDeviceName(captureDeviceID[i]);
566                 if (ref == NULL) {
567                     return -1;
568                 }
569                 captureDeviceUID.push_back(ref);
570                 // input sub-devices in this example, so append the sub-device's UID to the CFArray
571                 CFArrayAppendValue(subDevicesArray, ref);
572             }
573 
574             std::vector<CFStringRef> playbackDeviceUID;
575             for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
576                 CFStringRef ref = GetDeviceName(playbackDeviceID[i]);
577                 if (ref == NULL) {
578                     return -1;
579                 }
580                 playbackDeviceUID.push_back(ref);
581                 // output sub-devices in this example, so append the sub-device's UID to the CFArray
582                 CFArrayAppendValue(subDevicesArray, ref);
583             }
584 
585             //-----------------------------------------------------------------------
586             // Feed the dictionary to the plugin, to create a blank aggregate device
587             //-----------------------------------------------------------------------
588 
589             AudioObjectPropertyAddress pluginAOPA;
590             pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice;
591             pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
592             pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
593             UInt32 outDataSize;
594 
595             osErr = AudioObjectGetPropertyDataSize(fAggregatePluginID, &pluginAOPA, 0, NULL, &outDataSize);
596             if (osErr != noErr) {
597                 printf("TCoreAudioRenderer::CreateAggregateDeviceAux : AudioObjectGetPropertyDataSize error\n");
598                 printError(osErr);
599                 goto error;
600             }
601 
602             osErr = AudioObjectGetPropertyData(fAggregatePluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, &fAggregateDeviceID);
603             if (osErr != noErr) {
604                 printf("TCoreAudioRenderer::CreateAggregateDeviceAux : AudioObjectGetPropertyData error\n");
605                 printError(osErr);
606                 goto error;
607             }
608 
609             // pause for a bit to make sure that everything completed correctly
610             // this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created
611             CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
612 
613             //-------------------------
614             // Set the sub-device list
615             //-------------------------
616 
617             pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList;
618             pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
619             pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
620             outDataSize = sizeof(CFMutableArrayRef);
621             osErr = AudioObjectSetPropertyData(fAggregateDeviceID, &pluginAOPA, 0, NULL, outDataSize, &subDevicesArray);
622             if (osErr != noErr) {
623                 printf("TCoreAudioRenderer::CreateAggregateDeviceAux : AudioObjectSetPropertyData for sub-device list error\n");
624                 printError(osErr);
625                 goto error;
626             }
627 
628             // pause again to give the changes time to take effect
629             CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
630 
631             //-----------------------
632             // Set the master device
633             //-----------------------
634 
635             // set the master device manually (this is the device which will act as the master clock for the aggregate device)
636             // pass in the UID of the device you want to use
637             pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice;
638             pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
639             pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
640             outDataSize = sizeof(CFStringRef);
641             osErr = AudioObjectSetPropertyData(fAggregateDeviceID, &pluginAOPA, 0, NULL, outDataSize, &playbackDeviceUID[0]);  // First playback is master...
642             if (osErr != noErr) {
643                 printf("TCoreAudioRenderer::CreateAggregateDeviceAux : AudioObjectSetPropertyData for master device error\n");
644                 printError(osErr);
645                 goto error;
646             }
647 
648             // pause again to give the changes time to take effect
649             CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
650 
651             // Prepare sub-devices for clock drift compensation
652             // Workaround for bug in the HAL : until 10.6.2
653 
654             if (fClockDriftCompensate) {
655                 if (need_clock_drift_compensation) {
656                     //printf("Clock drift compensation activated...\n");
657 
658                     // Get the property data size
659                     osErr = AudioObjectGetPropertyDataSize(fAggregateDeviceID, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize);
660                     if (osErr != noErr) {
661                         printf("TCoreAudioRenderer::CreateAggregateDeviceAux kAudioObjectPropertyOwnedObjects error\n");
662                         printError(osErr);
663                     }
664 
665                     //	Calculate the number of object IDs
666                     subDevicesNum = outSize / sizeof(AudioObjectID);
667                     //printf("TCoreAudioRenderer::CreateAggregateDevice clock drift compensation, number of sub-devices = %d\n", subDevicesNum);
668                     AudioObjectID subDevices[subDevicesNum];
669                     outSize = sizeof(subDevices);
670 
671                     osErr = AudioObjectGetPropertyData(fAggregateDeviceID, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices);
672                     if (osErr != noErr) {
673                         printf("TCoreAudioRenderer::CreateAggregateDeviceAux kAudioObjectPropertyOwnedObjects error\n");
674                         printError(osErr);
675                     }
676 
677                     // Set kAudioSubDevicePropertyDriftCompensation property...
678                     for (UInt32 index = 0; index < subDevicesNum; ++index) {
679                         UInt32 theDriftCompensationValue = 1;
680                         osErr = AudioObjectSetPropertyData(subDevices[index], &theAddressDrift, 0, NULL, sizeof(UInt32), &theDriftCompensationValue);
681                         if (osErr != noErr) {
682                             printf("TCoreAudioRenderer::CreateAggregateDeviceAux kAudioSubDevicePropertyDriftCompensation error\n");
683                             printError(osErr);
684                         }
685                     }
686                 } else {
687                     //printf("Clock drift compensation was asked but is not needed (devices use the same clock domain)\n");
688                 }
689             }
690 
691             // pause again to give the changes time to take effect
692             CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
693 
694             //----------
695             // Clean up
696             //----------
697 
698             // release the private AD key
699             CFRelease(AggregateDeviceNumberRef);
700 
701             // release the CF objects we have created - we don't need them any more
702             CFRelease(aggDeviceDict);
703             CFRelease(subDevicesArray);
704 
705             if (subDevicesArrayClock)
706                 CFRelease(subDevicesArrayClock);
707 
708             // release the device UID
709             for (UInt32 i = 0; i < captureDeviceUID.size(); i++) {
710                 CFRelease(captureDeviceUID[i]);
711             }
712 
713             for (UInt32 i = 0; i < playbackDeviceUID.size(); i++) {
714                 CFRelease(playbackDeviceUID[i]);
715             }
716 
717             //printf("New aggregate device %d\n", fAggregateDeviceID);
718             return noErr;
719 
720         error:
721             DestroyAggregateDevice();
722             return -1;
723         }
724 
DestroyAggregateDevice()725         void DestroyAggregateDevice()
726         {
727             if (fAggregateDeviceID > 0) {
728                 OSStatus osErr = noErr;
729                 AudioObjectPropertyAddress pluginAOPA;
730                 pluginAOPA.mSelector = kAudioPlugInDestroyAggregateDevice;
731                 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
732                 pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
733                 UInt32 outDataSize;
734                 if (fAggregatePluginID > 0)   {
735                     osErr = AudioObjectGetPropertyDataSize(fAggregatePluginID, &pluginAOPA, 0, NULL, &outDataSize);
736                     if (osErr != noErr) {
737                         printf("TCoreAudioRenderer::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error\n");
738                         printError(osErr);
739                     }
740                     osErr = AudioObjectGetPropertyData(fAggregatePluginID, &pluginAOPA, 0, NULL, &outDataSize, &fAggregateDeviceID);
741                     if (osErr != noErr) {
742                         printf("TCoreAudioRenderer::DestroyAggregateDevice : AudioObjectGetPropertyData error\n");
743                         printError(osErr);
744                     }
745                 }
746             }
747         }
748 
GetDeviceNameFromID(AudioDeviceID id,char * name)749         OSStatus GetDeviceNameFromID(AudioDeviceID id, char* name)
750         {
751             UInt32 size = 256;
752             return AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceName, &size, name);
753         }
754 
SetupBufferSize(int buffer_size)755         int SetupBufferSize(int buffer_size)
756         {
757             // Setting buffer size
758             OSStatus err = noErr;
759             UInt32 current_buffer_size = buffer_size;
760             UInt32 outSize;
761             AudioValueRange buffer_size_range;
762 
763             outSize = sizeof(AudioValueRange);
764             err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertyBufferFrameSizeRange, &outSize, &buffer_size_range);
765             if (err != noErr) {
766                 printf("Cannot get buffer size range\n");
767                 printError(err);
768                 return -1;
769             } else {
770                 //printf("SetupBufferSize : buffer size range min = %ld max = %ld\n", (int)buffer_size_range.mMinimum, (int)buffer_size_range.mMaximum);
771             }
772 
773             outSize = sizeof(UInt32);
774             err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyBufferFrameSize, &outSize, &current_buffer_size);
775             if (err != noErr) {
776                 printf("Cannot get buffer size\n");
777                 printError(err);
778                 return -1;
779             } else {
780                 //printf("SetupBufferSize : current buffer size %ld\n", current_buffer_size);
781             }
782 
783             // If needed, set new buffer size
784             if (buffer_size != current_buffer_size && buffer_size >= (int)buffer_size_range.mMinimum && buffer_size <= (int)buffer_size_range.mMaximum) {
785                 current_buffer_size = buffer_size;
786 
787                 // To get BS change notification
788                 err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyBufferFrameSize, BSNotificationCallback, this);
789                 if (err != noErr) {
790                     printf("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyBufferFrameSize\n");
791                     printError(err);
792                     return -1;
793                 }
794 
795                 // Waiting for BS change notification
796                 int count = 0;
797                 fState = false;
798 
799                 err = AudioDeviceSetProperty(fDeviceID, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyBufferFrameSize, outSize, &current_buffer_size);
800                 if (err != noErr) {
801                     printf("SetupBufferSize : cannot set buffer size = %ld\n", current_buffer_size);
802                     printError(err);
803                     goto error;
804                 }
805 
806                 while (!fState && count++ < WAIT_NOTIFICATION_COUNTER) {
807                     usleep(100000);
808                     //printf("SetupBufferSize : wait count = %d\n", count);
809                 }
810 
811                 if (count >= WAIT_NOTIFICATION_COUNTER) {
812                     printf("Did not get buffer size notification...\n");
813                     goto error;
814                 }
815 
816                 // Check new buffer size
817                 outSize = sizeof(UInt32);
818                 err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyBufferFrameSize, &outSize, &current_buffer_size);
819                 if (err != noErr) {
820                     printf("Cannot get current buffer size\n");
821                     printError(err);
822                 } else {
823                     //printf("SetupBufferSize : checked buffer size = %ld\n", current_buffer_size);
824                 }
825 
826                 // Remove BS change notification
827                 AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyBufferFrameSize, BSNotificationCallback);
828             } else {
829                 //printf("Keep current buffer size = %ld\n", current_buffer_size);
830             }
831 
832             fBufferSize = current_buffer_size;
833             return 0;
834 
835         error:
836 
837             // Remove BS change notification
838             AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyBufferFrameSize, BSNotificationCallback);
839             return -1;
840         }
841 
BSNotificationCallback(AudioDeviceID inDevice,UInt32 inChannel,Boolean isInput,AudioDevicePropertyID inPropertyID,void * inClientData)842         static OSStatus BSNotificationCallback(AudioDeviceID inDevice,
843                                                          UInt32 inChannel,
844                                                          Boolean isInput,
845                                                          AudioDevicePropertyID inPropertyID,
846                                                          void* inClientData)
847         {
848             TCoreAudioRenderer* driver = (TCoreAudioRenderer*)inClientData;
849 
850             switch (inPropertyID) {
851 
852                 case kAudioDevicePropertyBufferFrameSize: {
853                     //printf("BSNotificationCallback kAudioDevicePropertyBufferFrameSize\n");
854                     // Check new buffer size
855                     UInt32 current_buffer_size;
856                     UInt32 outSize = sizeof(UInt32);
857                     OSStatus err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyBufferFrameSize, &outSize, &current_buffer_size);
858                     if (err != noErr) {
859                         printf("Cannot get current buffer size\n");
860                         printError(err);
861                     } else {
862                         //printf("BSNotificationCallback : checked current buffer size = %d\n", current_buffer_size);
863                     }
864                     driver->fState = true;
865                     break;
866                 }
867             }
868 
869             return noErr;
870         }
871 
SetupSampleRateAux(AudioDeviceID inDevice,int & sample_rate)872         int SetupSampleRateAux(AudioDeviceID inDevice, int& sample_rate)
873         {
874             OSStatus err = noErr;
875             UInt32 outSize = sizeof(Float64);
876             Float64 sampleRate = GetNominalSampleRate(inDevice);
877 
878             if (sample_rate != -1 && sample_rate != (int)sampleRate) {
879                 sampleRate = (Float64)sample_rate;
880 
881                 // To get SR change notification
882                 err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this);
883                 if (err != noErr) {
884                     printf("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate\n");
885                     printError(err);
886                     return -1;
887                 }
888                 err = AudioDeviceSetProperty(inDevice, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &sampleRate);
889                 if (err != noErr) {
890                     printf("Cannot set sample rate = %d\n", sample_rate);
891                     printError(err);
892                     return -1;
893                 }
894 
895                 // Waiting for SR change notification
896                 int count = 0;
897                 while (!fState && count++ < WAIT_NOTIFICATION_COUNTER) {
898                     usleep(100000);
899                     //printf("Wait count = %d\n", count);
900                 }
901 
902                 // Check new sample rate
903                 outSize = sizeof(Float64);
904                 err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
905                 if (err != noErr) {
906                     printf("Cannot get current sample rate\n");
907                     printError(err);
908                 } else {
909                     //printf("Checked sample rate = %f\n", sampleRate);
910                 }
911 
912                 // Remove SR change notification
913                 AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback);
914             }
915 
916             sample_rate = int(sampleRate);
917             return 0;
918         }
919 
Render(void * inRefCon,AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames,AudioBufferList * ioData)920         static OSStatus Render(void *inRefCon,
921                            AudioUnitRenderActionFlags *ioActionFlags,
922                            const AudioTimeStamp *inTimeStamp,
923                            UInt32 inBusNumber,
924                            UInt32 inNumberFrames,
925                            AudioBufferList *ioData)
926         {
927             return static_cast<TCoreAudioRendererPtr>(inRefCon)->Render(ioActionFlags, inTimeStamp, inNumberFrames, ioData);
928         }
929 
SRNotificationCallback(AudioDeviceID inDevice,UInt32 inChannel,Boolean isInput,AudioDevicePropertyID inPropertyID,void * inClientData)930         static OSStatus SRNotificationCallback(AudioDeviceID inDevice,
931                                             UInt32 inChannel,
932                                             Boolean	isInput,
933                                             AudioDevicePropertyID inPropertyID,
934                                                void* inClientData)
935         {
936             TCoreAudioRenderer* driver = (TCoreAudioRenderer*)inClientData;
937 
938             switch (inPropertyID) {
939 
940                 case kAudioDevicePropertyNominalSampleRate: {
941                     //printf("SRNotificationCallback kAudioDevicePropertyNominalSampleRate\n");
942                     driver->fState = true;
943                     // Check new sample rate
944                     Float64 sampleRate;
945                     UInt32 outSize = sizeof(Float64);
946                     OSStatus err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
947                     if (err != noErr) {
948                         printf("Cannot get current sample rate\n");
949                         printError(err);
950                     } else {
951                         //printf("SRNotificationCallback : checked sample rate = %f\n", sampleRate);
952                     }
953                     break;
954                 }
955             }
956 
957             return noErr;
958         }
959 
Render(AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inNumberFrames,AudioBufferList * ioData)960         virtual OSStatus Render(AudioUnitRenderActionFlags *ioActionFlags,
961                             const AudioTimeStamp *inTimeStamp,
962                             UInt32 inNumberFrames,
963                             AudioBufferList *ioData)
964         {
965             OSStatus err = noErr;
966             if (fDevNumInChans > 0) {
967                 err = AudioUnitRender(fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, fInputData);
968             }
969             if (err == noErr) {
970                 for (int i = 0; i < fDevNumInChans; i++) {
971                     fInChannel[i] = (float*)fInputData->mBuffers[i].mData;
972                 }
973                 for (int i = 0; i < fDevNumOutChans; i++) {
974                     fOutChannel[i] = (float*)ioData->mBuffers[i].mData;
975                 }
976                 fDSP->compute(double(AudioConvertHostTimeToNanos(inTimeStamp->mHostTime))/1000., inNumberFrames, fInChannel, fOutChannel);
977             } else {
978                 printf("AudioUnitRender error... %x\n", fInputData);
979                 printError(err);
980             }
981             return err;
982         }
983 
984     public:
985 
TCoreAudioRenderer()986         TCoreAudioRenderer()
987             :fAggregateDeviceID(-1),fAggregatePluginID(-1),
988             fDevNumInChans(0),fDevNumOutChans(0),
989             fPhysicalInputs(0), fPhysicalOutputs(0),
990             fInChannel(0),fOutChannel(0),
991             fBufferSize(0),fSampleRate(0),
992             fDSP(0),fInputData(0),
993             fDeviceID(0),fAUHAL(0),
994             fState(false),
995             fIsInJackDevice(false),
996             fIsOutJackDevice(false)
997         {}
998 
~TCoreAudioRenderer()999         virtual ~TCoreAudioRenderer()
1000         {}
1001 
GetBufferSize()1002         int GetBufferSize() {return fBufferSize;}
GetSampleRate()1003         int GetSampleRate() {return fSampleRate;}
1004 
RestartProc(AudioObjectID objectID,UInt32 numberAddresses,const AudioObjectPropertyAddress inAddresses[],void * clientData)1005         static OSStatus RestartProc(AudioObjectID objectID, UInt32 numberAddresses,
1006                                    const AudioObjectPropertyAddress inAddresses[],
1007                                    void *clientData)
1008         {
1009             /*
1010             TCoreAudioRenderer* renderer = (TCoreAudioRenderer*)clientData;
1011             AudioDeviceID defaultDevice;
1012             UInt32 theSize = sizeof(UInt32);
1013             OSStatus res;
1014             char device_name[256];
1015 
1016             // Test if new device is "JackRouter"
1017             if (inAddresses[0].mSelector == kAudioHardwarePropertyDefaultInputDevice) {
1018 
1019                 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
1020                                                     &theSize, &defaultDevice)) == noErr) {
1021                     renderer->GetDeviceNameFromID(defaultDevice, device_name);
1022                     renderer->fIsInJackDevice = strcmp(device_name, "JackRouter") == 0;
1023                 }
1024 
1025             } else  if (inAddresses[0].mSelector == kAudioHardwarePropertyDefaultOutputDevice) {
1026 
1027                 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
1028                                                     &theSize, &defaultDevice)) == noErr) {
1029                     renderer->GetDeviceNameFromID(defaultDevice, device_name);
1030                     renderer->fIsOutJackDevice = strcmp(device_name, "JackRouter") == 0;
1031                 }
1032 
1033             }
1034 
1035             // Switch only of input and output are "JackRouter"
1036             if (renderer->fIsInJackDevice && renderer->fIsOutJackDevice || !renderer->fIsInJackDevice && !renderer->fIsOutJackDevice) {
1037                 renderer->Stop();
1038                 renderer->Close();
1039                 int sampleRate = -1; // Use the current sample rate
1040                 int bufferSize = (renderer->fBufferSize > 0) ? renderer->fBufferSize : 512; // Use default if needed
1041                 renderer->OpenDefault(renderer->fDSP, renderer->fDevNumInChans, renderer->fDevNumOutChans, bufferSize, sampleRate);
1042                 renderer->Start();
1043             }
1044             */
1045             return 0;
1046         }
1047 
OpenDefault(dsp * DSP,int inChan,int outChan,int bufferSize,int & sampleRate)1048         int OpenDefault(dsp* DSP, int inChan, int outChan, int bufferSize, int& sampleRate)
1049         {
1050             fDevNumInChans = 0;
1051             fDevNumOutChans = 0;
1052             fInChannel = 0;
1053             fOutChannel = 0;
1054             fBufferSize = 0;
1055             fSampleRate = 0;
1056             fDSP = 0;
1057             fInputData = 0;
1058             fDeviceID = 0;
1059             fAUHAL = 0;
1060             fState = false;
1061             return OpenDefault(inChan, outChan, bufferSize, sampleRate);
1062         }
1063 
OpenDefault(int inChan,int outChan,int buffer_size,int & sample_rate)1064         int OpenDefault(int inChan, int outChan, int buffer_size, int& sample_rate)
1065         {
1066             OSStatus err;
1067             UInt32 outSize;
1068             UInt32 enableIO;
1069             Boolean isWritable;
1070             AudioStreamBasicDescription srcFormat, dstFormat, sampleRate;
1071 
1072             fDevNumInChans = inChan;
1073             fDevNumOutChans = outChan;
1074 
1075             fInChannel = new float*[fDevNumInChans];
1076             fOutChannel = new float*[fDevNumOutChans];
1077 
1078             //printf("OpenDefault inChan = %ld outChan = %ld bufferSize = %ld sample_rate = %ld\n", inChan, outChan, bufferSize, sample_rate);
1079 
1080             SInt32 major;
1081             SInt32 minor;
1082             Gestalt(gestaltSystemVersionMajor, &major);
1083             Gestalt(gestaltSystemVersionMinor, &minor);
1084 
1085             // Starting with 10.6 systems, the HAL notification thread is created internally
1086             if (major == 10 && minor >= 6) {
1087                 CFRunLoopRef theRunLoop = NULL;
1088                 AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
1089                 OSStatus osErr = AudioObjectSetPropertyData (kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
1090                 if (osErr != noErr) {
1091                     printf("TCoreAudioRenderer::Open kAudioHardwarePropertyRunLoop error\n");
1092                     printError(osErr);
1093                 }
1094             }
1095 
1096             if (GetDefaultDeviceAndSampleRate(inChan, outChan, sample_rate, &fDeviceID) != noErr) {
1097                 printf("Cannot open default device\n");
1098                 return OPEN_ERR;
1099             }
1100 
1101             // Setting buffer size
1102             if (SetupBufferSize(buffer_size) < 0) {
1103                 return OPEN_ERR;
1104             }
1105 
1106             // fBufferSize now has the real value, either 'bufferSize' (if could be changed) or driver current one
1107 
1108             // AUHAL
1109 
1110         #ifdef MAC_OS_X_VERSION_10_5
1111             ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
1112             Component HALOutput = FindNextComponent(NULL, &cd);
1113             err = OpenAComponent(HALOutput, &fAUHAL);
1114             if (err != noErr) {
1115                 printf("Error calling OpenAComponent\n");
1116                 printError(err);
1117                 goto error;
1118             }
1119         #else
1120             AudioComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
1121             AudioComponent HALOutput = AudioComponentFindNext(NULL, &cd);
1122             err = AudioComponentInstanceNew(HALOutput, &fAUHAL);
1123             if (err != noErr) {
1124                 printf("Error calling AudioComponentInstanceNew\n");
1125                 printError(err);
1126                 goto error;
1127             }
1128         #endif
1129 
1130             err = AudioUnitInitialize(fAUHAL);
1131             if (err != noErr) {
1132                 printf("Cannot initialize AUHAL unit\n");
1133                 printError(err);
1134                 goto error;
1135             }
1136 
1137             if (inChan > 0) {
1138                 enableIO = 1;
1139                 //printf("OpenAUHAL : setup AUHAL input on\n");
1140             } else {
1141                 enableIO = 0;
1142                 //printf("OpenAUHAL : setup AUHAL input off\n");
1143             }
1144 
1145             err = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
1146             if (err != noErr) {
1147                 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input\n");
1148                 printError(err);
1149                 goto error;
1150             }
1151 
1152             if (outChan > 0) {
1153                 enableIO = 1;
1154                 //printf("OpenAUHAL : setup AUHAL output on\n");
1155             } else {
1156                 enableIO = 0;
1157                 //printf("OpenAUHAL : setup AUHAL output off\n");
1158             }
1159 
1160             err = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
1161             if (err != noErr) {
1162                 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output\n");
1163                 printError(err);
1164                 goto error;
1165             }
1166 
1167             AudioDeviceID currAudioDeviceID;
1168             outSize = sizeof(AudioDeviceID);
1169             err = AudioUnitGetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &currAudioDeviceID, &outSize);
1170             if (err != noErr) {
1171                 printf("Error calling AudioUnitGetProperty - kAudioOutputUnitProperty_CurrentDevice\n");
1172                 printError(err);
1173                 goto error;
1174             } else {
1175                 //printf("AudioUnitGetPropertyCurrentDevice = %d\n", currAudioDeviceID);
1176             }
1177 
1178             // Setup up choosen device, in both input and output cases
1179             err = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fDeviceID, sizeof(AudioDeviceID));
1180             if (err != noErr) {
1181                 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice\n");
1182                 printError(err);
1183                 goto error;
1184             }
1185 
1186             if (inChan > 0) {
1187                 err = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&fBufferSize, sizeof(UInt32));
1188                 if (err != noErr) {
1189                     printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
1190                     printError(err);
1191                     goto error;
1192                 }
1193             }
1194 
1195             if (outChan > 0) {
1196                 err = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&fBufferSize, sizeof(UInt32));
1197                 if (err != noErr) {
1198                     printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
1199                     printError(err);
1200                     goto error;
1201                 }
1202             }
1203 
1204             err = AudioUnitGetPropertyInfo(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Input, 1, &outSize, &isWritable);
1205             if (err != noErr) {
1206                 //printf("Error calling AudioUnitGetPropertyInfo - kAudioOutputUnitProperty_ChannelMap 1\n");
1207                 //printError(err);
1208             } else {
1209                 fPhysicalInputs = (err == noErr) ? outSize / sizeof(SInt32) : 0;
1210                 //printf("fPhysicalInputs = %ld\n", fPhysicalInputs);
1211             }
1212 
1213             err = AudioUnitGetPropertyInfo(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, &outSize, &isWritable);
1214             if (err != noErr) {
1215                 //printf("Error calling AudioUnitGetPropertyInfo - kAudioOutputUnitProperty_ChannelMap 0\n");
1216                 //printError(err);
1217             } else {
1218                 fPhysicalOutputs = (err == noErr) ? outSize / sizeof(SInt32) : 0;
1219                 //printf("fPhysicalOutputs = %ld\n", fPhysicalOutputs);
1220             }
1221 
1222             /*
1223              Just ignore this case : seems to work without any further change...
1224 
1225              if (outChan > fPhysicalOutputs) {
1226                 printf("This device hasn't required output channels\n");
1227                 goto error;
1228              }
1229              if (inChan > fPhysicalInputs) {
1230                 printf("This device hasn't required input channels\n");
1231                 goto error;
1232              }
1233              */
1234 
1235             if (inChan < fPhysicalInputs) {
1236                 SInt32 chanArr[fPhysicalInputs];
1237                 for (int i = 0; i < fPhysicalInputs; i++) {
1238                     chanArr[i] = -1;
1239                 }
1240                 for (int i = 0; i < inChan; i++) {
1241                     chanArr[i] = i;
1242                 }
1243                 AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * fPhysicalInputs);
1244                 if (err != noErr) {
1245                     printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1\n");
1246                     printError(err);
1247                 }
1248             }
1249 
1250             if (outChan < fPhysicalOutputs) {
1251                 SInt32 chanArr[fPhysicalOutputs];
1252                 for (int i = 0;	i < fPhysicalOutputs; i++) {
1253                     chanArr[i] = -1;
1254                 }
1255                 for (int i = 0; i < outChan; i++) {
1256                     chanArr[i] = i;
1257                 }
1258                 err = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * fPhysicalOutputs);
1259                 if (err != noErr) {
1260                     printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0\n");
1261                     printError(err);
1262                 }
1263             }
1264 
1265             if (inChan > 0) {
1266                 outSize = sizeof(AudioStreamBasicDescription);
1267                 err = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, &outSize);
1268                 if (err != noErr) {
1269                     printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
1270                     printError(err);
1271                 }
1272                 //PrintStreamDesc(&srcFormat);
1273 
1274                 srcFormat.mSampleRate = sample_rate;
1275                 srcFormat.mFormatID = kAudioFormatLinearPCM;
1276                 srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
1277                 srcFormat.mBytesPerPacket = sizeof(float);
1278                 srcFormat.mFramesPerPacket = 1;
1279                 srcFormat.mBytesPerFrame = sizeof(float);
1280                 srcFormat.mChannelsPerFrame = inChan;
1281                 srcFormat.mBitsPerChannel = 32;
1282 
1283                 //PrintStreamDesc(&srcFormat);
1284 
1285                 err = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription));
1286                 if (err != noErr) {
1287                     printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
1288                     printError(err);
1289                 }
1290             }
1291 
1292             if (outChan > 0) {
1293                 outSize = sizeof(AudioStreamBasicDescription);
1294                 err = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, &outSize);
1295                 if (err != noErr) {
1296                     printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
1297                     printError(err);
1298                 }
1299                 //PrintStreamDesc(&dstFormat);
1300 
1301                 dstFormat.mSampleRate = sample_rate;
1302                 dstFormat.mFormatID = kAudioFormatLinearPCM;
1303                 dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
1304                 dstFormat.mBytesPerPacket = sizeof(float);
1305                 dstFormat.mFramesPerPacket = 1;
1306                 dstFormat.mBytesPerFrame = sizeof(float);
1307                 dstFormat.mChannelsPerFrame = outChan;
1308                 dstFormat.mBitsPerChannel = 32;
1309 
1310                 //PrintStreamDesc(&dstFormat);
1311 
1312                 err = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription));
1313                 if (err != noErr) {
1314                     printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
1315                     printError(err);
1316                 }
1317             }
1318 
1319             if (inChan > 0 && outChan == 0) {
1320                 AURenderCallbackStruct output;
1321                 output.inputProc = Render;
1322                 output.inputProcRefCon = this;
1323                 err = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
1324                 if (err != noErr) {
1325                     printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1\n");
1326                     printError(err);
1327                     goto error;
1328                 }
1329             } else {
1330                 AURenderCallbackStruct output;
1331                 output.inputProc = Render;
1332                 output.inputProcRefCon = this;
1333                 err = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
1334                 if (err != noErr) {
1335                     printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0\n");
1336                     printError(err);
1337                     goto error;
1338                 }
1339             }
1340 
1341             if (inChan > 0) {
1342                 fInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inChan * sizeof(AudioBuffer));
1343                 assert(fInputData);
1344                 fInputData->mNumberBuffers = inChan;
1345 
1346                 // Prepare buffers
1347                 for (int i = 0; i < inChan; i++) {
1348                     fInputData->mBuffers[i].mNumberChannels = 1;
1349                     fInputData->mBuffers[i].mData = malloc(fBufferSize * sizeof(float));
1350                     assert(fInputData->mBuffers[i].mData),
1351                     fInputData->mBuffers[i].mDataByteSize = fBufferSize * sizeof(float);
1352                 }
1353             }
1354 
1355             AudioObjectPropertyAddress property_address;
1356             property_address.mScope = kAudioObjectPropertyScopeGlobal;
1357             property_address.mElement = kAudioObjectPropertyElementMaster;
1358 
1359             property_address.mSelector = kAudioHardwarePropertyDefaultInputDevice;
1360             if (AudioObjectAddPropertyListener(kAudioObjectSystemObject, &property_address, RestartProc, this)) {
1361                 printf("AudioObjectAddPropertyListener() failed\n");
1362                 return OPEN_ERR;
1363             } else {
1364                 //printf("AudioObjectAddPropertyListener() OK\n");
1365             }
1366 
1367             property_address.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
1368             if (AudioObjectAddPropertyListener(kAudioObjectSystemObject, &property_address, RestartProc, this)) {
1369                 printf("AudioObjectAddPropertyListener() failed\n");
1370                 return OPEN_ERR;
1371             } else {
1372                 //printf("AudioObjectAddPropertyListener() OK\n");
1373             }
1374 
1375             return NO_ERR;
1376 
1377         error:
1378             AudioUnitUninitialize(fAUHAL);
1379             CloseComponent(fAUHAL);
1380             fAUHAL = 0;
1381             return OPEN_ERR;
1382         }
1383 
Close()1384         int Close()
1385         {
1386             if (!fAUHAL) {
1387                 return CLOSE_ERR;
1388             }
1389 
1390             for (int i = 0; i < fDevNumInChans; i++) {
1391                 free(fInputData->mBuffers[i].mData);
1392             }
1393             if (fInputData) {
1394                 free(fInputData);
1395             }
1396             AudioUnitUninitialize(fAUHAL);
1397             CloseComponent(fAUHAL);
1398             fAUHAL = NULL;
1399 
1400             DestroyAggregateDevice();
1401 
1402             delete[] fInChannel;
1403             delete[] fOutChannel;
1404 
1405             AudioObjectPropertyAddress property_address;
1406             property_address.mScope = kAudioObjectPropertyScopeGlobal;
1407             property_address.mElement = kAudioObjectPropertyElementMaster;
1408 
1409             property_address.mSelector = kAudioHardwarePropertyDefaultInputDevice;
1410             AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &property_address, RestartProc, this);
1411 
1412             property_address.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
1413             AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &property_address, RestartProc, this);
1414 
1415             return NO_ERR;
1416         }
1417 
Start()1418         int Start()
1419         {
1420             if (!fAUHAL) {
1421                 return OPEN_ERR;
1422             }
1423 
1424             OSStatus err = AudioOutputUnitStart(fAUHAL);
1425 
1426             if (err != noErr) {
1427                 printf("Error while opening device : device open error \n");
1428                 return OPEN_ERR;
1429             } else {
1430                 return NO_ERR;
1431             }
1432         }
1433 
Stop()1434         int Stop()
1435         {
1436             if (!fAUHAL) {
1437                 return OPEN_ERR;
1438             }
1439 
1440             OSStatus err = AudioOutputUnitStop(fAUHAL);
1441 
1442             if (err != noErr) {
1443                 printf("Error while closing device : device close error \n");
1444                 return OPEN_ERR;
1445             } else {
1446                 return NO_ERR;
1447             }
1448         }
1449 
set_dsp(dsp * DSP)1450         void set_dsp(dsp* DSP)
1451         {
1452             fDSP = DSP;
1453         }
1454 
GetNumInputs()1455         int GetNumInputs() { return fPhysicalInputs; }
GetNumOutputs()1456         int GetNumOutputs() { return fPhysicalOutputs; }
1457 
1458 };
1459 
1460 /******************************************************************************
1461 *******************************************************************************
1462 
1463 							CORE AUDIO INTERFACE
1464 
1465 *******************************************************************************
1466 *******************************************************************************/
1467 class coreaudio : public audio {
1468 
1469     protected:
1470 
1471         TCoreAudioRenderer fAudioDevice;
1472         int fSampleRate, fBufferSize;
1473 
1474     public:
1475 
coreaudio(int srate,int bsize)1476         coreaudio(int srate, int bsize) : fSampleRate(srate), fBufferSize(bsize) {}
coreaudio(int bsize)1477             coreaudio(int bsize) : fSampleRate(-1), fBufferSize(bsize) {}
~coreaudio()1478         virtual ~coreaudio() { fAudioDevice.Close(); }
1479 
init(const char *,dsp * DSP)1480         virtual bool init(const char* /*name*/, dsp* DSP)
1481         {
1482             if (fAudioDevice.OpenDefault(DSP, DSP->getNumInputs(), DSP->getNumOutputs(), fBufferSize, fSampleRate) < 0) {
1483                 printf("Cannot open CoreAudio device\n");
1484                 return false;
1485             }
1486             fAudioDevice.set_dsp(DSP);
1487             // If -1 was given, fSampleRate will be changed by OpenDefault
1488             DSP->init(fSampleRate);
1489             return true;
1490         }
1491 
start()1492         virtual bool start()
1493         {
1494             if (fAudioDevice.Start() < 0) {
1495                 printf("Cannot start CoreAudio device\n");
1496                 return false;
1497             }
1498             return true;
1499         }
1500 
stop()1501         virtual void stop()
1502         {
1503             fAudioDevice.Stop();
1504         }
1505 
get_buffer_size()1506         virtual int get_buffer_size() { return fAudioDevice.GetBufferSize(); }
get_sample_rate()1507         virtual int get_sample_rate() { return fAudioDevice.GetSampleRate(); }
1508 
get_num_inputs()1509         virtual int get_num_inputs() { return fAudioDevice.GetNumInputs(); }
get_num_outputs()1510         virtual int get_num_outputs() { return fAudioDevice.GetNumOutputs(); }
1511 
1512 };
1513 
1514 #endif
1515 
1516 /********************END ARCHITECTURE SECTION (part 2/2)****************/
1517 
1518 
1519