Merge branch 'master' of https://scm.cri.ensmp.fr/git/Faustine
[Faustine.git] / interpretor / faust-0.9.47mr3 / architecture / audio / coreaudio-dsp.h
1 /************************************************************************
2
3 IMPORTANT NOTE : this file contains two clearly delimited sections :
4 the ARCHITECTURE section (in two parts) and the USER section. Each section
5 is governed by its own copyright and license. Please check individually
6 each section for license and copyright information.
7 *************************************************************************/
8
9 #ifndef __coreaudio_dsp__
10 #define __coreaudio_dsp__
11
12 /*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/
13
14 /************************************************************************
15 FAUST Architecture File
16 Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
17 ---------------------------------------------------------------------
18 This Architecture section is free software; you can redistribute it
19 and/or modify it under the terms of the GNU General Public License
20 as published by the Free Software Foundation; either version 3 of
21 the License, or (at your option) any later version.
22
23 This program is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with this program; If not, see <http://www.gnu.org/licenses/>.
30
31 EXCEPTION : As a special exception, you may create a larger work
32 that contains this FAUST architecture section and distribute
33 that work under terms of your choice, so long as this FAUST
34 architecture section is not modified.
35
36
37 ************************************************************************
38 ************************************************************************/
39
40 #include <math.h>
41 #include <stdlib.h>
42 #include <stdio.h>
43
44 #include <vector>
45 #include <iostream>
46 #include <libgen.h>
47
48 #include <AudioToolbox/AudioConverter.h>
49 #include <CoreAudio/CoreAudio.h>
50 #include <AudioUnit/AudioUnit.h>
51 #include <CoreServices/CoreServices.h>
52
53 #include "audio.h"
54 #include "dsp.h"
55
56 using namespace std;
57
58 /******************************************************************************
59 *******************************************************************************
60
61 COREAUDIO INTERFACE
62
63 *******************************************************************************
64 *******************************************************************************/
65
66 //----------------------------------------------------------------------------
67 // number of physical input and output channels of the CA device
68 //----------------------------------------------------------------------------
69
70 int gDevNumInChans;
71 int gDevNumOutChans;
72
73 //----------------------------------------------------------------------------
74 // tables of noninterleaved input and output channels for FAUST
75 //----------------------------------------------------------------------------
76
77 float* gInChannel[256];
78 float* gOutChannel[256];
79
80 #define OPEN_ERR -1
81 #define NO_ERR 0
82
83 #define WAIT_COUNTER 60
84
85 typedef UInt8 CAAudioHardwareDeviceSectionID;
86 #define kAudioDeviceSectionInput ((CAAudioHardwareDeviceSectionID)0x01)
87 #define kAudioDeviceSectionOutput ((CAAudioHardwareDeviceSectionID)0x00)
88 #define kAudioDeviceSectionGlobal ((CAAudioHardwareDeviceSectionID)0x00)
89 #define kAudioDeviceSectionWildcard ((CAAudioHardwareDeviceSectionID)0xFF)
90
91 dsp * gDsp;
92
93 class TCoreAudioRenderer
94 {
95 private:
96 AudioBufferList* fInputData;
97 AudioDeviceID fDeviceID;
98 AudioUnit fAUHAL;
99 AudioObjectID fPluginID; // Used for aggregate device
100 bool fState;
101
102 OSStatus GetDefaultDevice(int inChan, int outChan, int samplerate, AudioDeviceID* id);
103
104 OSStatus CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, int samplerate, AudioDeviceID* outAggregateDevice);
105 OSStatus CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, int samplerate, AudioDeviceID* outAggregateDevice);
106 OSStatus DestroyAggregateDevice();
107
108 OSStatus GetDeviceNameFromID(AudioDeviceID id, char* name);
109
110 int SetupSampleRateAux(AudioDeviceID inDevice, int samplerate);
111
112 static OSStatus Render(void *inRefCon,
113 AudioUnitRenderActionFlags *ioActionFlags,
114 const AudioTimeStamp *inTimeStamp,
115 UInt32 inBusNumber,
116 UInt32 inNumberFrames,
117 AudioBufferList *ioData);
118
119
120 static OSStatus SRNotificationCallback(AudioDeviceID inDevice,
121 UInt32 inChannel,
122 Boolean isInput,
123 AudioDevicePropertyID inPropertyID,
124 void* inClientData);
125
126 public:
127
128 TCoreAudioRenderer()
129 :fInputData(0),fDeviceID(0),fAUHAL(0),fPluginID(0),fState(false)
130 {}
131 virtual ~TCoreAudioRenderer()
132 {}
133
134 long OpenDefault(long inChan, long outChan, long bufferSize, long sampleRate);
135 long Close();
136
137 long Start();
138 long Stop();
139
140 };
141
142 typedef TCoreAudioRenderer * TCoreAudioRendererPtr;
143
144 static void PrintStreamDesc(AudioStreamBasicDescription *inDesc)
145 {
146 cout << "- - - - - - - - - - - - - - - - - - - -" << endl;
147 cout << " Sample Rate: " << inDesc->mSampleRate << endl;
148 cout << " Format ID:%.*s\n" << sizeof(inDesc->mFormatID) << (char*)&inDesc->mFormatID << endl;
149 cout << " Format Flags " << inDesc->mFormatFlags << endl;
150 cout << " Bytes per Packet: " << inDesc->mBytesPerPacket << endl;
151 cout << " Frames per Packet: " << inDesc->mFramesPerPacket << endl;
152 cout << " Bytes per Frame: " << inDesc->mBytesPerFrame << endl;
153 cout << " Channels per Frame: "<< inDesc->mChannelsPerFrame << endl;
154 cout << " Bits per Channel: " << inDesc->mBitsPerChannel << endl;
155 cout << "- - - - - - - - - - - - - - - - - - - -" << endl;
156 }
157
158 static void printError(OSStatus err)
159 {
160 switch (err) {
161 case kAudioHardwareNoError:
162 printf("error code : kAudioHardwareNoError\n");
163 break;
164 case kAudioConverterErr_FormatNotSupported:
165 printf("error code : kAudioConverterErr_FormatNotSupported\n");
166 break;
167 case kAudioConverterErr_OperationNotSupported:
168 printf("error code : kAudioConverterErr_OperationNotSupported\n");
169 break;
170 case kAudioConverterErr_PropertyNotSupported:
171 printf("error code : kAudioConverterErr_PropertyNotSupported\n");
172 break;
173 case kAudioConverterErr_InvalidInputSize:
174 printf("error code : kAudioConverterErr_InvalidInputSize\n");
175 break;
176 case kAudioConverterErr_InvalidOutputSize:
177 printf("error code : kAudioConverterErr_InvalidOutputSize\n");
178 break;
179 case kAudioConverterErr_UnspecifiedError:
180 printf("error code : kAudioConverterErr_UnspecifiedError\n");
181 break;
182 case kAudioConverterErr_BadPropertySizeError:
183 printf("error code : kAudioConverterErr_BadPropertySizeError\n");
184 break;
185 case kAudioConverterErr_RequiresPacketDescriptionsError:
186 printf("error code : kAudioConverterErr_RequiresPacketDescriptionsError\n");
187 break;
188 case kAudioConverterErr_InputSampleRateOutOfRange:
189 printf("error code : kAudioConverterErr_InputSampleRateOutOfRange\n");
190 break;
191 case kAudioConverterErr_OutputSampleRateOutOfRange:
192 printf("error code : kAudioConverterErr_OutputSampleRateOutOfRange\n");
193 break;
194 case kAudioHardwareNotRunningError:
195 printf("error code : kAudioHardwareNotRunningError\n");
196 break;
197 case kAudioHardwareUnknownPropertyError:
198 printf("error code : kAudioHardwareUnknownPropertyError\n");
199 break;
200 case kAudioHardwareIllegalOperationError:
201 printf("error code : kAudioHardwareIllegalOperationError\n");
202 break;
203 case kAudioHardwareBadDeviceError:
204 printf("error code : kAudioHardwareBadDeviceError\n");
205 break;
206 case kAudioHardwareBadStreamError:
207 printf("error code : kAudioHardwareBadStreamError\n");
208 break;
209 case kAudioDeviceUnsupportedFormatError:
210 printf("error code : kAudioDeviceUnsupportedFormatError\n");
211 break;
212 case kAudioDevicePermissionsError:
213 printf("error code : kAudioDevicePermissionsError\n");
214 break;
215 default:
216 printf("error code : unknown\n");
217 break;
218 }
219 }
220
221 OSStatus TCoreAudioRenderer::Render(void *inRefCon,
222 AudioUnitRenderActionFlags *ioActionFlags,
223 const AudioTimeStamp *inTimeStamp,
224 UInt32,
225 UInt32 inNumberFrames,
226 AudioBufferList *ioData)
227 {
228 TCoreAudioRendererPtr renderer = (TCoreAudioRendererPtr)inRefCon;
229 AudioUnitRender(renderer->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, renderer->fInputData);
230 for (int i = 0; i < gDevNumInChans; i++) {
231 gInChannel[i] = (float*)renderer->fInputData->mBuffers[i].mData;
232 }
233 for (int i = 0; i < gDevNumOutChans; i++) {
234 gOutChannel[i] = (float*)ioData->mBuffers[i].mData;
235 }
236 gDsp->compute((int)inNumberFrames, gInChannel, gOutChannel);
237 return 0;
238 }
239
240 static CFStringRef GetDeviceName(AudioDeviceID id)
241 {
242 UInt32 size = sizeof(CFStringRef);
243 CFStringRef UIname;
244 OSStatus err = AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
245 return (err == noErr) ? UIname : NULL;
246 }
247
248 OSStatus TCoreAudioRenderer::GetDeviceNameFromID(AudioDeviceID id, char* name)
249 {
250 UInt32 size = 256;
251 return AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceName, &size, name);
252 }
253
254 OSStatus TCoreAudioRenderer::GetDefaultDevice(int inChan, int outChan, int samplerate, AudioDeviceID* id)
255 {
256 UInt32 theSize = sizeof(UInt32);
257 AudioDeviceID inDefault;
258 AudioDeviceID outDefault;
259 OSStatus res;
260
261 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
262 &theSize, &inDefault)) != noErr)
263 return res;
264
265 if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
266 &theSize, &outDefault)) != noErr)
267 return res;
268
269 // Duplex mode
270 if (inChan > 0 && outChan > 0) {
271 // Get the device only if default input and output are the same
272 if (inDefault == outDefault) {
273 *id = inDefault;
274 return noErr;
275 } else {
276 printf("GetDefaultDevice : input = %ld and output = %ld are not the same, create aggregate device...\n", inDefault, outDefault);
277 if (CreateAggregateDevice(inDefault, outDefault, samplerate, id) != noErr)
278 return kAudioHardwareBadDeviceError;
279 }
280 } else if (inChan > 0) {
281 *id = inDefault;
282 return noErr;
283 } else if (outChan > 0) {
284 *id = outDefault;
285 return noErr;
286 } else {
287 return kAudioHardwareBadDeviceError;
288 }
289
290 return noErr;
291 }
292
293 OSStatus TCoreAudioRenderer::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, int samplerate, AudioDeviceID* outAggregateDevice)
294 {
295 OSStatus err = noErr;
296 AudioObjectID sub_device[32];
297 UInt32 outSize = sizeof(sub_device);
298
299 err = AudioDeviceGetProperty(captureDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
300 vector<AudioDeviceID> captureDeviceIDArray;
301
302 if (err != noErr) {
303 printf("Input device does not have subdevices\n");
304 captureDeviceIDArray.push_back(captureDeviceID);
305 } else {
306 int num_devices = outSize / sizeof(AudioObjectID);
307 printf("Input device has %d subdevices\n", num_devices);
308 for (int i = 0; i < num_devices; i++) {
309 captureDeviceIDArray.push_back(sub_device[i]);
310 }
311 }
312
313 err = AudioDeviceGetProperty(playbackDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device);
314 vector<AudioDeviceID> playbackDeviceIDArray;
315
316 if (err != noErr) {
317 printf("Output device does not have subdevices\n");
318 playbackDeviceIDArray.push_back(playbackDeviceID);
319 } else {
320 int num_devices = outSize / sizeof(AudioObjectID);
321 printf("Output device has %d subdevices\n", num_devices);
322 for (int i = 0; i < num_devices; i++) {
323 playbackDeviceIDArray.push_back(sub_device[i]);
324 }
325 }
326
327 return CreateAggregateDeviceAux(captureDeviceIDArray, playbackDeviceIDArray, samplerate, outAggregateDevice);
328 }
329
330
331 OSStatus TCoreAudioRenderer::SRNotificationCallback(AudioDeviceID inDevice,
332 UInt32 /*inChannel*/,
333 Boolean /*isInput*/,
334 AudioDevicePropertyID inPropertyID,
335 void* inClientData)
336 {
337 TCoreAudioRenderer* driver = (TCoreAudioRenderer*)inClientData;
338
339 switch (inPropertyID) {
340
341 case kAudioDevicePropertyNominalSampleRate: {
342 printf("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate\n");
343 driver->fState = true;
344 // Check new sample rate
345 Float64 sampleRate;
346 UInt32 outSize = sizeof(Float64);
347 OSStatus err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
348 if (err != noErr) {
349 printf("Cannot get current sample rate\n");
350 printError(err);
351 } else {
352 printf("SRNotificationCallback : checked sample rate = %f\n", sampleRate);
353 }
354 break;
355 }
356 }
357
358 return noErr;
359 }
360
361 int TCoreAudioRenderer::SetupSampleRateAux(AudioDeviceID inDevice, int samplerate)
362 {
363 OSStatus err = noErr;
364 UInt32 outSize;
365 Float64 sampleRate;
366
367 // Get sample rate
368 outSize = sizeof(Float64);
369 err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
370 if (err != noErr) {
371 printf("Cannot get current sample rate\n");
372 printError(err);
373 return -1;
374 } else {
375 printf("Current sample rate = %f\n", sampleRate);
376 }
377
378 // If needed, set new sample rate
379 if (samplerate != (int)sampleRate) {
380 sampleRate = (Float64)samplerate;
381
382 // To get SR change notification
383 err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this);
384 if (err != noErr) {
385 printf("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate\n");
386 printError(err);
387 return -1;
388 }
389 err = AudioDeviceSetProperty(inDevice, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &sampleRate);
390 if (err != noErr) {
391 printf("Cannot set sample rate = %d\n", samplerate);
392 printError(err);
393 return -1;
394 }
395
396 // Waiting for SR change notification
397 int count = 0;
398 while (!fState && count++ < WAIT_COUNTER) {
399 usleep(100000);
400 printf("Wait count = %d\n", count);
401 }
402
403 // Check new sample rate
404 outSize = sizeof(Float64);
405 err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
406 if (err != noErr) {
407 printf("Cannot get current sample rate\n");
408 printError(err);
409 } else {
410 printf("Checked sample rate = %f\n", sampleRate);
411 }
412
413 // Remove SR change notification
414 AudioDeviceRemovePropertyListener(inDevice, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback);
415 }
416
417 return 0;
418 }
419
420 OSStatus TCoreAudioRenderer::CreateAggregateDeviceAux(vector<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> playbackDeviceID, int samplerate, AudioDeviceID* outAggregateDevice)
421 {
422 OSStatus osErr = noErr;
423 UInt32 outSize;
424 Boolean outWritable;
425
426 bool fClockDriftCompensate = true;
427
428 // Prepare sub-devices for clock drift compensation
429 // Workaround for bug in the HAL : until 10.6.2
430 AudioObjectPropertyAddress theAddressOwned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
431 AudioObjectPropertyAddress theAddressDrift = { kAudioSubDevicePropertyDriftCompensation, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
432 UInt32 theQualifierDataSize = sizeof(AudioObjectID);
433 AudioClassID inClass = kAudioSubDeviceClassID;
434 void* theQualifierData = &inClass;
435 UInt32 subDevicesNum = 0;
436
437 //---------------------------------------------------------------------------
438 // Setup SR of both devices otherwise creating AD may fail...
439 //---------------------------------------------------------------------------
440 UInt32 keptclockdomain = 0;
441 UInt32 clockdomain = 0;
442 outSize = sizeof(UInt32);
443 bool need_clock_drift_compensation = false;
444
445 for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
446 if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) {
447 printf("TCoreAudioRenderer::CreateAggregateDevice : cannot set SR of input device\n");
448 } else {
449 // Check clock domain
450 osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
451 if (osErr != 0) {
452 printf("TCoreAudioRenderer::CreateAggregateDevice : kAudioDevicePropertyClockDomain error\n");
453 printError(osErr);
454 } else {
455 keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
456 printf("TCoreAudioRenderer::CreateAggregateDevice : input clockdomain = %d\n", clockdomain);
457 if (clockdomain != 0 && clockdomain != keptclockdomain) {
458 printf("TCoreAudioRenderer::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...\n");
459 need_clock_drift_compensation = true;
460 }
461 }
462 }
463 }
464
465 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
466 if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) {
467 printf("TCoreAudioRenderer::CreateAggregateDevice : cannot set SR of output device\n");
468 } else {
469 // Check clock domain
470 osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain);
471 if (osErr != 0) {
472 printf("TCoreAudioRenderer::CreateAggregateDevice : kAudioDevicePropertyClockDomain error\n");
473 printError(osErr);
474 } else {
475 keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain;
476 printf("TCoreAudioRenderer::CreateAggregateDevice : output clockdomain = %d", clockdomain);
477 if (clockdomain != 0 && clockdomain != keptclockdomain) {
478 printf("TCoreAudioRenderer::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed...\n");
479 need_clock_drift_compensation = true;
480 }
481 }
482 }
483 }
484
485 // If no valid clock domain was found, then assume we have to compensate...
486 if (keptclockdomain == 0) {
487 need_clock_drift_compensation = true;
488 }
489
490 //---------------------------------------------------------------------------
491 // Start to create a new aggregate by getting the base audio hardware plugin
492 //---------------------------------------------------------------------------
493
494 char device_name[256];
495 for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
496 GetDeviceNameFromID(captureDeviceID[i], device_name);
497 printf("Separated input = '%s' \n", device_name);
498 }
499
500 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
501 GetDeviceNameFromID(playbackDeviceID[i], device_name);
502 printf("Separated output = '%s' \n", device_name);
503 }
504
505 osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable);
506 if (osErr != noErr) {
507 printf("TCoreAudioRenderer::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error\n");
508 printError(osErr);
509 return osErr;
510 }
511
512 AudioValueTranslation pluginAVT;
513
514 CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio");
515
516 pluginAVT.mInputData = &inBundleRef;
517 pluginAVT.mInputDataSize = sizeof(inBundleRef);
518 pluginAVT.mOutputData = &fPluginID;
519 pluginAVT.mOutputDataSize = sizeof(fPluginID);
520
521 osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT);
522 if (osErr != noErr) {
523 printf("TCoreAudioRenderer::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error\n");
524 printError(osErr);
525 return osErr;
526 }
527
528 //-------------------------------------------------
529 // Create a CFDictionary for our aggregate device
530 //-------------------------------------------------
531
532 CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
533
534 CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex");
535 CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex");
536
537 // add the name of the device to the dictionary
538 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef);
539
540 // add our choice of UID for the aggregate device to the dictionary
541 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef);
542
543 // add a "private aggregate key" to the dictionary
544 int value = 1;
545 CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value);
546
547 SInt32 system;
548 Gestalt(gestaltSystemVersion, &system);
549
550 printf("TCoreAudioRenderer::CreateAggregateDevice : system version = %x limit = %x\n", system, 0x00001054);
551
552 // Starting with 10.5.4 systems, the AD can be internal... (better)
553 if (system < 0x00001054) {
554 printf("TCoreAudioRenderer::CreateAggregateDevice : public aggregate device....\n");
555 } else {
556 printf("TCoreAudioRenderer::CreateAggregateDevice : private aggregate device....\n");
557 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef);
558 }
559
560 // Prepare sub-devices for clock drift compensation
561 CFMutableArrayRef subDevicesArrayClock = NULL;
562
563 /*
564 if (fClockDriftCompensate) {
565 if (need_clock_drift_compensation) {
566 jack_info("Clock drift compensation activated...");
567 subDevicesArrayClock = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
568
569 for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
570 CFStringRef UID = GetDeviceName(captureDeviceID[i]);
571 if (UID) {
572 CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
573 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
574 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
575 //CFRelease(UID);
576 CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
577 }
578 }
579
580 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
581 CFStringRef UID = GetDeviceName(playbackDeviceID[i]);
582 if (UID) {
583 CFMutableDictionaryRef subdeviceAggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
584 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceUIDKey), UID);
585 CFDictionaryAddValue(subdeviceAggDeviceDict, CFSTR(kAudioSubDeviceDriftCompensationKey), AggregateDeviceNumberRef);
586 //CFRelease(UID);
587 CFArrayAppendValue(subDevicesArrayClock, subdeviceAggDeviceDict);
588 }
589 }
590
591 // add sub-device clock array for the aggregate device to the dictionary
592 CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceSubDeviceListKey), subDevicesArrayClock);
593 } else {
594 jack_info("Clock drift compensation was asked but is not needed (devices use the same clock domain)");
595 }
596 }
597 */
598
599 //-------------------------------------------------
600 // Create a CFMutableArray for our sub-device list
601 //-------------------------------------------------
602
603 // we need to append the UID for each device to a CFMutableArray, so create one here
604 CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
605
606 vector<CFStringRef> captureDeviceUID;
607 for (UInt32 i = 0; i < captureDeviceID.size(); i++) {
608 CFStringRef ref = GetDeviceName(captureDeviceID[i]);
609 if (ref == NULL)
610 return -1;
611 captureDeviceUID.push_back(ref);
612 // input sub-devices in this example, so append the sub-device's UID to the CFArray
613 CFArrayAppendValue(subDevicesArray, ref);
614 }
615
616 vector<CFStringRef> playbackDeviceUID;
617 for (UInt32 i = 0; i < playbackDeviceID.size(); i++) {
618 CFStringRef ref = GetDeviceName(playbackDeviceID[i]);
619 if (ref == NULL)
620 return -1;
621 playbackDeviceUID.push_back(ref);
622 // output sub-devices in this example, so append the sub-device's UID to the CFArray
623 CFArrayAppendValue(subDevicesArray, ref);
624 }
625
626 //-----------------------------------------------------------------------
627 // Feed the dictionary to the plugin, to create a blank aggregate device
628 //-----------------------------------------------------------------------
629
630 AudioObjectPropertyAddress pluginAOPA;
631 pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice;
632 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
633 pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
634 UInt32 outDataSize;
635
636 osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
637 if (osErr != noErr) {
638 printf("TCoreAudioRenderer::CreateAggregateDevice : AudioObjectGetPropertyDataSize error\n");
639 printError(osErr);
640 goto error;
641 }
642
643 osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice);
644 if (osErr != noErr) {
645 printf("TCoreAudioRenderer::CreateAggregateDevice : AudioObjectGetPropertyData error\n");
646 printError(osErr);
647 goto error;
648 }
649
650 // pause for a bit to make sure that everything completed correctly
651 // this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created
652 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
653
654 //-------------------------
655 // Set the sub-device list
656 //-------------------------
657
658 pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList;
659 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
660 pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
661 outDataSize = sizeof(CFMutableArrayRef);
662 osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &subDevicesArray);
663 if (osErr != noErr) {
664 printf("TCoreAudioRenderer::CreateAggregateDevice : AudioObjectSetPropertyData for sub-device list error\n");
665 printError(osErr);
666 goto error;
667 }
668
669 // pause again to give the changes time to take effect
670 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
671
672 //-----------------------
673 // Set the master device
674 //-----------------------
675
676 // set the master device manually (this is the device which will act as the master clock for the aggregate device)
677 // pass in the UID of the device you want to use
678 pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice;
679 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
680 pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
681 outDataSize = sizeof(CFStringRef);
682 osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &captureDeviceUID[0]); // First apture is master...
683 if (osErr != noErr) {
684 printf("TCoreAudioRenderer::CreateAggregateDevice : AudioObjectSetPropertyData for master device error\n");
685 printError(osErr);
686 goto error;
687 }
688
689 // pause again to give the changes time to take effect
690 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
691
692 // Prepare sub-devices for clock drift compensation
693 // Workaround for bug in the HAL : until 10.6.2
694
695 if (fClockDriftCompensate) {
696 if (need_clock_drift_compensation) {
697 printf("Clock drift compensation activated...\n");
698
699 // Get the property data size
700 osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize);
701 if (osErr != noErr) {
702 printf("TCoreAudioRenderer::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error\n");
703 printError(osErr);
704 }
705
706 // Calculate the number of object IDs
707 subDevicesNum = outSize / sizeof(AudioObjectID);
708 printf("TCoreAudioRenderer::CreateAggregateDevice clock drift compensation, number of sub-devices = %d\n", subDevicesNum);
709 AudioObjectID subDevices[subDevicesNum];
710 outSize = sizeof(subDevices);
711
712 osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices);
713 if (osErr != noErr) {
714 printf("TCoreAudioRenderer::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error\n");
715 printError(osErr);
716 }
717
718 // Set kAudioSubDevicePropertyDriftCompensation property...
719 for (UInt32 index = 0; index < subDevicesNum; ++index) {
720 UInt32 theDriftCompensationValue = 1;
721 osErr = AudioObjectSetPropertyData(subDevices[index], &theAddressDrift, 0, NULL, sizeof(UInt32), &theDriftCompensationValue);
722 if (osErr != noErr) {
723 printf("TCoreAudioRenderer::CreateAggregateDevice kAudioSubDevicePropertyDriftCompensation error\n");
724 printError(osErr);
725 }
726 }
727 } else {
728 printf("Clock drift compensation was asked but is not needed (devices use the same clock domain)\n");
729 }
730 }
731
732 // pause again to give the changes time to take effect
733 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
734
735 //----------
736 // Clean up
737 //----------
738
739 // release the private AD key
740 CFRelease(AggregateDeviceNumberRef);
741
742 // release the CF objects we have created - we don't need them any more
743 CFRelease(aggDeviceDict);
744 CFRelease(subDevicesArray);
745
746 if (subDevicesArrayClock)
747 CFRelease(subDevicesArrayClock);
748
749 // release the device UID
750 for (UInt32 i = 0; i < captureDeviceUID.size(); i++) {
751 CFRelease(captureDeviceUID[i]);
752 }
753
754 for (UInt32 i = 0; i < playbackDeviceUID.size(); i++) {
755 CFRelease(playbackDeviceUID[i]);
756 }
757
758 printf("New aggregate device %d\n", *outAggregateDevice);
759 return noErr;
760
761 error:
762 DestroyAggregateDevice();
763 return -1;
764 }
765
766 OSStatus TCoreAudioRenderer::DestroyAggregateDevice()
767 {
768 OSStatus osErr = noErr;
769 AudioObjectPropertyAddress pluginAOPA;
770 pluginAOPA.mSelector = kAudioPlugInDestroyAggregateDevice;
771 pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
772 pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
773 UInt32 outDataSize;
774
775 if (fPluginID > 0) {
776
777 osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
778 if (osErr != noErr) {
779 printf("TCoreAudioRenderer::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error\n");
780 printError(osErr);
781 return osErr;
782 }
783
784 osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID);
785 if (osErr != noErr) {
786 printf("TCoreAudioRenderer::DestroyAggregateDevice : AudioObjectGetPropertyData error\n");
787 printError(osErr);
788 return osErr;
789 }
790
791 }
792
793 return noErr;
794 }
795
796
797 long TCoreAudioRenderer::OpenDefault(long inChan, long outChan, long bufferSize, long samplerate)
798 {
799 OSStatus err = noErr;
800 ComponentResult err1;
801 UInt32 outSize;
802 UInt32 enableIO;
803 Boolean isWritable;
804 AudioStreamBasicDescription srcFormat, dstFormat, sampleRate;
805 long in_nChannels, out_nChannels;
806
807 printf("OpenDefault inChan = %ld outChan = %ld bufferSize = %ld samplerate = %ld\n", inChan, outChan, bufferSize, samplerate);
808
809 SInt32 major;
810 SInt32 minor;
811 Gestalt(gestaltSystemVersionMajor, &major);
812 Gestalt(gestaltSystemVersionMinor, &minor);
813
814 // Starting with 10.6 systems, the HAL notification thread is created internally
815 if (major == 10 && minor >= 6) {
816 CFRunLoopRef theRunLoop = NULL;
817 AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
818 OSStatus osErr = AudioObjectSetPropertyData (kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
819 if (osErr != noErr) {
820 printf("TCoreAudioRenderer::Open kAudioHardwarePropertyRunLoop error\n");
821 printError(osErr);
822 }
823 }
824
825 if (GetDefaultDevice(inChan, outChan, samplerate,&fDeviceID) != noErr) {
826 printf("Cannot open default device\n");
827 return OPEN_ERR;
828 }
829
830 // Setting buffer size
831 outSize = sizeof(UInt32);
832 err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &bufferSize);
833 if (err != noErr) {
834 printf("Cannot set buffer size %ld\n", bufferSize);
835 printError(err);
836 return OPEN_ERR;
837 }
838
839 // Setting sample rate
840 outSize = sizeof(AudioStreamBasicDescription);
841 err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertyStreamFormat, &outSize, &sampleRate);
842 if (err != noErr) {
843 printf("Cannot get current sample rate\n");
844 printError(err);
845 return OPEN_ERR;
846 }
847
848 if (samplerate != long(sampleRate.mSampleRate)) {
849 sampleRate.mSampleRate = (Float64)(samplerate);
850 err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyStreamFormat, outSize, &sampleRate);
851 if (err != noErr) {
852 printf("Cannot set sample rate = %ld\n", samplerate);
853 printError(err);
854 return OPEN_ERR;
855 }
856 }
857
858 // AUHAL
859 ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
860 Component HALOutput = FindNextComponent(NULL, &cd);
861
862 err1 = OpenAComponent(HALOutput, &fAUHAL);
863 if (err1 != noErr) {
864 printf("Error calling OpenAComponent\n");
865 printError(err1);
866 goto error;
867 }
868
869 err1 = AudioUnitInitialize(fAUHAL);
870 if (err1 != noErr) {
871 printf("Cannot initialize AUHAL unit\n");
872 printError(err1);
873 goto error;
874 }
875
876 enableIO = 1;
877 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
878 if (err1 != noErr) {
879 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output\n");
880 printError(err1);
881 goto error;
882 }
883
884 enableIO = 1;
885 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
886 if (err1 != noErr) {
887 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input\n");
888 printError(err1);
889 goto error;
890 }
891
892 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fDeviceID, sizeof(AudioDeviceID));
893 if (err1 != noErr) {
894 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice\n");
895 printError(err1);
896 goto error;
897 }
898
899 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&bufferSize, sizeof(UInt32));
900 if (err1 != noErr) {
901 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
902 printError(err1);
903 goto error;
904 }
905
906 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&bufferSize, sizeof(UInt32));
907 if (err1 != noErr) {
908 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
909 printError(err1);
910 goto error;
911 }
912
913 err1 = AudioUnitGetPropertyInfo(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Input, 1, &outSize, &isWritable);
914 if (err1 != noErr) {
915 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap-INFO 1\n");
916 printError(err1);
917 }
918
919 in_nChannels = (err1 == noErr) ? outSize / sizeof(SInt32) : 0;
920 printf("in_nChannels = %ld\n", in_nChannels);
921
922 err1 = AudioUnitGetPropertyInfo(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, &outSize, &isWritable);
923 if (err1 != noErr) {
924 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap-INFO 0\n");
925 printError(err1);
926 }
927
928 out_nChannels = (err1 == noErr) ? outSize / sizeof(SInt32) : 0;
929 printf("out_nChannels = %ld\n", out_nChannels);
930
931 /*
932 Just ignore this case : seems to work without any further change...
933
934 if (outChan > out_nChannels) {
935 printf("This device hasn't required output channels\n");
936 goto error;
937 }
938 if (inChan > in_nChannels) {
939 printf("This device hasn't required input channels\n");
940 goto error;
941 }
942 */
943
944 if (outChan < out_nChannels) {
945 SInt32 chanArr[out_nChannels];
946 for (int i = 0; i < out_nChannels; i++) {
947 chanArr[i] = -1;
948 }
949 for (int i = 0; i < outChan; i++) {
950 chanArr[i] = i;
951 }
952 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_nChannels);
953 if (err1 != noErr) {
954 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0\n");
955 printError(err1);
956 }
957 }
958
959 if (inChan < in_nChannels) {
960 SInt32 chanArr[in_nChannels];
961 for (int i = 0; i < in_nChannels; i++) {
962 chanArr[i] = -1;
963 }
964 for (int i = 0; i < inChan; i++) {
965 chanArr[i] = i;
966 }
967 AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_nChannels);
968 if (err1 != noErr) {
969 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1\n");
970 printError(err1);
971 }
972 }
973
974 if (inChan > 0) {
975 outSize = sizeof(AudioStreamBasicDescription);
976 err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, &outSize);
977 if (err1 != noErr) {
978 printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
979 printError(err1);
980 }
981 PrintStreamDesc(&srcFormat);
982
983 srcFormat.mSampleRate = samplerate;
984 srcFormat.mFormatID = kAudioFormatLinearPCM;
985 srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
986 srcFormat.mBytesPerPacket = sizeof(float);
987 srcFormat.mFramesPerPacket = 1;
988 srcFormat.mBytesPerFrame = sizeof(float);
989 srcFormat.mChannelsPerFrame = inChan;
990 srcFormat.mBitsPerChannel = 32;
991
992 PrintStreamDesc(&srcFormat);
993
994 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription));
995 if (err1 != noErr) {
996 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
997 printError(err1);
998 }
999 }
1000
1001 if (outChan > 0) {
1002 outSize = sizeof(AudioStreamBasicDescription);
1003 err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, &outSize);
1004 if (err1 != noErr) {
1005 printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
1006 printError(err1);
1007 }
1008 PrintStreamDesc(&dstFormat);
1009
1010 dstFormat.mSampleRate = samplerate;
1011 dstFormat.mFormatID = kAudioFormatLinearPCM;
1012 dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
1013 dstFormat.mBytesPerPacket = sizeof(float);
1014 dstFormat.mFramesPerPacket = 1;
1015 dstFormat.mBytesPerFrame = sizeof(float);
1016 dstFormat.mChannelsPerFrame = outChan;
1017 dstFormat.mBitsPerChannel = 32;
1018
1019 PrintStreamDesc(&dstFormat);
1020
1021 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription));
1022 if (err1 != noErr) {
1023 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
1024 printError(err1);
1025 }
1026 }
1027
1028 if (inChan > 0 && outChan == 0) {
1029 AURenderCallbackStruct output;
1030 output.inputProc = Render;
1031 output.inputProcRefCon = this;
1032 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
1033 if (err1 != noErr) {
1034 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1\n");
1035 printError(err1);
1036 goto error;
1037 }
1038 } else {
1039 AURenderCallbackStruct output;
1040 output.inputProc = Render;
1041 output.inputProcRefCon = this;
1042 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
1043 if (err1 != noErr) {
1044 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0\n");
1045 printError(err1);
1046 goto error;
1047 }
1048 }
1049
1050 fInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inChan * sizeof(AudioBuffer));
1051 if (fInputData == 0) {
1052 printf("Cannot allocate memory for input buffers\n");
1053 goto error;
1054 }
1055 fInputData->mNumberBuffers = inChan;
1056
1057 // Prepare buffers
1058 for (int i = 0; i < inChan; i++) {
1059 fInputData->mBuffers[i].mNumberChannels = 1;
1060 fInputData->mBuffers[i].mData = malloc(bufferSize * sizeof(float));
1061 fInputData->mBuffers[i].mDataByteSize = bufferSize * sizeof(float);
1062 }
1063
1064 return NO_ERR;
1065
1066 error:
1067 AudioUnitUninitialize(fAUHAL);
1068 CloseComponent(fAUHAL);
1069 return OPEN_ERR;
1070 }
1071
1072 long TCoreAudioRenderer::Close()
1073 {
1074 for (int i = 0; i < gDevNumInChans; i++) {
1075 free(fInputData->mBuffers[i].mData);
1076 }
1077 free(fInputData);
1078 AudioUnitUninitialize(fAUHAL);
1079 CloseComponent(fAUHAL);
1080 DestroyAggregateDevice();
1081 return NO_ERR;
1082 }
1083
1084 long TCoreAudioRenderer::Start()
1085 {
1086 OSStatus err = AudioOutputUnitStart(fAUHAL);
1087
1088 if (err != noErr) {
1089 printf("Error while opening device : device open error \n");
1090 return OPEN_ERR;
1091 } else {
1092 return NO_ERR;
1093 }
1094 }
1095
1096 long TCoreAudioRenderer::Stop()
1097 {
1098 OSStatus err = AudioOutputUnitStop(fAUHAL);
1099
1100 if (err != noErr) {
1101 printf("Error while closing device : device close error \n");
1102 return OPEN_ERR;
1103 } else {
1104 return NO_ERR;
1105 }
1106 }
1107
1108
1109
1110 /******************************************************************************
1111 *******************************************************************************
1112
1113 CORE AUDIO INTERFACE
1114
1115 *******************************************************************************
1116 *******************************************************************************/
1117 class coreaudio : public audio {
1118
1119 TCoreAudioRenderer audio_device;
1120 long fSampleRate, fFramesPerBuf;
1121
1122 public:
1123 coreaudio(long srate, long fpb) : fSampleRate(srate), fFramesPerBuf(fpb) {}
1124 virtual ~coreaudio() {}
1125
1126 virtual bool init(const char* /*name*/, dsp* DSP) {
1127 gDsp = DSP;
1128 DSP->init (fSampleRate);
1129 gDevNumInChans = DSP->getNumInputs();
1130 gDevNumOutChans = DSP->getNumOutputs();
1131 if (audio_device.OpenDefault(gDevNumInChans, gDevNumOutChans, fFramesPerBuf, fSampleRate) < 0) {
1132 printf("Cannot open CoreAudio device\n");
1133 return false;
1134 }
1135 return true;
1136 }
1137
1138 virtual bool start() {
1139 if (audio_device.Start() < 0) {
1140 printf("Cannot start CoreAudio device\n");
1141 return false;
1142 }
1143 return true;
1144 }
1145
1146 virtual void stop() {
1147 audio_device.Stop();
1148 audio_device.Close();
1149 }
1150
1151 };
1152
1153 #endif
1154
1155 /********************END ARCHITECTURE SECTION (part 2/2)****************/
1156
1157