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, ¤t_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, ¤t_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, ¤t_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, ¤t_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