1 /************************** BEGIN coreaudio-ios-dsp.h **************************/
2 /************************************************************************
3  FAUST Architecture File
4  Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
5  ---------------------------------------------------------------------
6  This Architecture section is free software; you can redistribute it
7  and/or modify it under the terms of the GNU General Public License
8  as published by the Free Software Foundation; either version 3 of
9  the License, or (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; If not, see <http://www.gnu.org/licenses/>.
18 
19  EXCEPTION : As a special exception, you may create a larger work
20  that contains this FAUST architecture section and distribute
21  that work under terms of your choice, so long as this FAUST
22  architecture section is not modified.
23  ************************************************************************/
24 
25 #ifndef __coreaudio_ios_dsp__
26 #define __coreaudio_ios_dsp__
27 
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <limits.h>
32 #include <math.h>
33 #include <errno.h>
34 #include <time.h>
35 
36 #include "faust/audio/audio.h"
37 #include "faust/dsp/dsp.h"
38 
39 #include <AudioToolbox/AudioConverter.h>
40 #include <AudioToolbox/AudioServices.h>
41 #include <AudioUnit/AudioUnit.h>
42 
43 using namespace std;
44 
45 /******************************************************************************
46 *******************************************************************************
47 
48 							COREAUDIO INTERFACE
49 
50 *******************************************************************************
51 *******************************************************************************/
52 
53 #define OPEN_ERR -1
54 #define NO_ERR 0
55 
56 class TiPhoneCoreAudioRenderer
57 {
58 
59     protected:
60 
61         AudioUnit fAUHAL;
62 
63         int	fDevNumInChans;
64         int	fDevNumOutChans;
65 
66         int fHWNumInChans;
67         int fHWNumOutChans;
68 
69         dsp* fDSP;
70 
71         audio* fAudio;
72 
73         AudioBufferList* fCAInputData;
74 
PrintStreamDesc(AudioStreamBasicDescription * inDesc)75         static void PrintStreamDesc(AudioStreamBasicDescription *inDesc)
76         {
77             printf("- - - - - - - - - - - - - - - - - - - -\n");
78             printf("  Sample Rate:%f\n", inDesc->mSampleRate);
79             printf("  Format ID:%.*s\n", (int) sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID);
80             printf("  Format Flags:%lX\n", inDesc->mFormatFlags);
81             printf("  Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
82             printf("  Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
83             printf("  Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
84             printf("  Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
85             printf("  Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
86             printf("- - - - - - - - - - - - - - - - - - - -\n");
87         }
88 
printError(OSStatus err)89         static void printError(OSStatus err)
90         {
91             switch (err) {
92                 case kAudioConverterErr_FormatNotSupported:
93                     printf("error code : kAudioConverterErr_FormatNotSupported\n");
94                     break;
95                 case kAudioConverterErr_OperationNotSupported:
96                     printf("error code : kAudioConverterErr_OperationNotSupported\n");
97                     break;
98                 case kAudioConverterErr_PropertyNotSupported:
99                     printf("error code : kAudioConverterErr_PropertyNotSupported\n");
100                     break;
101                 case kAudioConverterErr_InvalidInputSize:
102                     printf("error code : kAudioConverterErr_InvalidInputSize\n");
103                     break;
104                 case kAudioConverterErr_InvalidOutputSize:
105                     printf("error code : kAudioConverterErr_InvalidOutputSize\n");
106                     break;
107                 case kAudioConverterErr_UnspecifiedError:
108                     printf("error code : kAudioConverterErr_UnspecifiedError\n");
109                     break;
110                 case kAudioConverterErr_BadPropertySizeError:
111                     printf("error code : kAudioConverterErr_BadPropertySizeError\n");
112                     break;
113                 case kAudioConverterErr_RequiresPacketDescriptionsError:
114                     printf("error code : kAudioConverterErr_RequiresPacketDescriptionsError\n");
115                     break;
116                 case kAudioConverterErr_InputSampleRateOutOfRange:
117                     printf("error code : kAudioConverterErr_InputSampleRateOutOfRange\n");
118                     break;
119                 case kAudioConverterErr_OutputSampleRateOutOfRange:
120                     printf("error code : kAudioConverterErr_OutputSampleRateOutOfRange\n");
121                     break;
122                 default:
123                     printf("error code : unknown\n");
124                     break;
125             }
126         }
127 
Render(void * inRefCon,AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32,UInt32 inNumberFrames,AudioBufferList * ioData)128         static OSStatus Render(void *inRefCon,AudioUnitRenderActionFlags *ioActionFlags,
129                                const AudioTimeStamp *inTimeStamp,
130                                UInt32,
131                                UInt32 inNumberFrames,
132                                AudioBufferList *ioData)
133         {
134             return static_cast<TiPhoneCoreAudioRenderer*>(inRefCon)->Render(ioActionFlags, inTimeStamp, inNumberFrames, ioData);
135         }
136 
Render(AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inNumberFrames,AudioBufferList * ioData)137         OSStatus Render(AudioUnitRenderActionFlags *ioActionFlags,
138                         const AudioTimeStamp *inTimeStamp,
139                         UInt32 inNumberFrames,
140                         AudioBufferList *ioData)
141         {
142             OSStatus err = noErr;
143 
144             if (fDevNumInChans > 0) {
145                 err = AudioUnitRender(fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, fCAInputData);
146             }
147 
148             if (err == noErr) {
149                 float* fInChannel[fDevNumInChans];
150                 float* fOutChannel[fDevNumOutChans];
151 
152                 for (int chan = 0; chan < fDevNumInChans; chan++) {
153                     fInChannel[chan] = (float*)fCAInputData->mBuffers[chan].mData;
154                 }
155 
156                 for (int chan = 0; chan < fDevNumOutChans; chan++) {
157                     fOutChannel[chan] = (float*)ioData->mBuffers[chan].mData;
158                 }
159 
160                 fDSP->compute((int)inNumberFrames, fInChannel, fOutChannel);
161 
162                 fAudio->runControlCallbacks();
163             }
164             return err;
165         }
166 
InterruptionListener(void * inClientData,UInt32 inInterruption)167         static void InterruptionListener(void *inClientData, UInt32 inInterruption)
168         {
169             TiPhoneCoreAudioRenderer *obj = (TiPhoneCoreAudioRenderer*)inClientData;
170             printf("Session interrupted! --- %s ---", (inInterruption == kAudioSessionBeginInterruption) ? "Begin Interruption" : "End Interruption");
171 
172             if (inInterruption == kAudioSessionEndInterruption) {
173                 // Make sure we are again the active session
174                 AudioSessionSetActive(true);
175                 obj->SetupMixing();
176                 AudioOutputUnitStart(obj->fAUHAL);
177             }
178 
179             if (inInterruption == kAudioSessionBeginInterruption) {
180                 AudioOutputUnitStop(obj->fAUHAL);
181             }
182         }
183 
SetupMixing()184         int SetupMixing()
185         {
186             OSStatus err;
187 
188             /*
189             01/07/2014 : cause iRig to fail, so deactivated for now...
190             CFStringRef route;
191             UInt32 routesize = sizeof(route);
192             OSStatus err  = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &routesize, &route);
193             if (err == noErr) {
194                 if (CFStringCompare(route, CFSTR("ReceiverAndMicrophone"), 0) == kCFCompareEqualTo || CFStringCompare(route,CFSTR("Receiver"), 0) == kCFCompareEqualTo) {
195                     // Re-route audio to the speaker (not the receiver, which no music app will ever want)
196                     printf("Rerouting audio to speaker\n");
197                     UInt32 newRoute = kAudioSessionOverrideAudioRoute_Speaker;
198                     AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(newRoute), &newRoute);
199                 }
200              }
201             */
202 
203             UInt32 allowMixing = true;
204             err = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(allowMixing), &allowMixing);
205             if (err != noErr) {
206                 printf("Could not set audio session mixing\n");
207                 printError(err);
208                 return -1;
209             } else {
210                 return 0;
211             }
212         }
213 
AudioSessionPropertyListener(void * inClientData,AudioSessionPropertyID inID,UInt32 inDataSize,const void * inData)214         static void AudioSessionPropertyListener(void* inClientData, AudioSessionPropertyID inID, UInt32 inDataSize, const void* inData)
215         {
216             TiPhoneCoreAudioRenderer *obj = (TiPhoneCoreAudioRenderer*)inData;
217             switch (inID) {
218                 case kAudioSessionProperty_ServerDied: {
219                     printf("kAudioSessionProperty_ServerDied\n");
220                     break;
221                 }
222                 case kAudioSessionProperty_AudioRouteChange: {
223                     printf("kAudioSessionProperty_AudioRouteChange\n");
224                     obj->SetupMixing();
225                     break;
226                 }
227                 case kAudioSessionProperty_AudioInputAvailable: {
228                     printf("kAudioSessionProperty_AudioInputAvailable\n");
229                     obj->SetupMixing();
230                     break;
231                 }
232             }
233         }
234 
SetAudioCategory(int input,int output)235         static int SetAudioCategory(int input, int output)
236         {
237             // Set the audioCategory the way Faust DSP wants
238             UInt32 audioCategory;
239             if ((input > 0) && (output > 0)) {
240                 audioCategory = kAudioSessionCategory_PlayAndRecord;
241                 printf("AudioCategory kAudioSessionCategory_PlayAndRecord\n");
242             } else if (input > 0) {
243                 audioCategory = kAudioSessionCategory_RecordAudio;
244                 printf("AudioCategory kAudioSessionCategory_RecordAudio\n");
245             } else  if (output > 0) {
246                 audioCategory = kAudioSessionCategory_MediaPlayback;
247                 printf("AudioCategory kAudioSessionCategory_MediaPlayback\n");
248             }
249 
250             OSStatus err = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory);
251             if (err != noErr) {
252                 printf("Couldn't set audio category\n");
253                 printError(err);
254                 return OPEN_ERR;
255             }
256 
257             // 09/07/2015 : https://developer.apple.com/library/ios/qa/qa1754/_index.html
258             if (audioCategory == kAudioSessionCategory_PlayAndRecord) {
259 
260                 // 21/09/2017 Compatible with bluetooth devices. Deactivate bluetooth micro which run at 16khz, use internal micro instead.
261                 /*
262                 UInt32 overrideAudioRoute = 1;
263                 err = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker, sizeof(UInt32), &overrideAudioRoute);
264                 if (err != noErr) {
265                     printf("Error setting kAudioSessionProperty_OverrideCategoryDefaultToSpeaker\n");
266                     printError(err);
267                 }
268 
269                 UInt32 allowBluetoothInput = 1;
270                 err = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryEnableBluetoothInput, sizeof(UInt32), &allowBluetoothInput);
271                 if (err != noErr) {
272                     printf("Error setting kAudioSessionProperty_OverrideCategoryEnableBluetoothInput\n");
273                     printError(err);
274                 }
275                 */
276 
277                 // On devices with more than one built-in microphone, the microphone closest to the video camera is used.
278                 UInt32 allowInternalInput = kAudioSessionMode_VideoRecording;
279                 err = AudioSessionSetProperty(kAudioSessionProperty_Mode, sizeof(UInt32), &allowInternalInput);
280                 if (err != noErr) {
281                     printf("Error setting kAudioSessionMode_VideoRecording\n");
282                     printError(err);
283                 }
284 
285             }
286 
287         #if NOAGC
288             // If input is used, disable AGC
289             if (audioCategory == kAudioSessionCategory_RecordAudio || audioCategory == kAudioSessionCategory_PlayAndRecord) {
290 
291                 UInt32 sessionMode = kAudioSessionMode_Measurement;
292                 err = AudioSessionSetProperty(kAudioSessionProperty_Mode, sizeof(sessionMode), &sessionMode);
293                 if (err != noErr) {
294                     printf("Error setting kAudioSessionMode_Measurement\n");
295                     printError(err);
296                 }
297 
298                 UInt32 availableGain;
299                 UInt32 outSize = sizeof(availableGain);
300                 err = AudioSessionGetProperty(kAudioSessionProperty_InputGainAvailable, &outSize, &availableGain);
301                 if (err != noErr) {
302                     printf("Error getting kAudioSessionProperty_InputGainAvailable\n");
303                     printError(err);
304                 } else {
305                     Float32 gain;
306                     printf("Getting kAudioSessionProperty_InputGainAvailable OK\n");
307                     outSize = sizeof(Float32);
308                     AudioSessionGetProperty(kAudioSessionProperty_InputGainScalar, &outSize, &gain);
309                     printf("Getting kAudioSessionProperty_InputGainScalar :  %f\n", gain);
310                     gain = 1.0f;
311                     err = AudioSessionSetProperty(kAudioSessionProperty_InputGainScalar, sizeof(Float32), &gain);
312                     if (err != noErr) {
313                         printf("Error setting kAudioSessionProperty_InputGainScalar\n");
314                         printError(err);
315                     } else {
316                         printf("Setting kAudioSessionProperty_InputGainAvailable to 1.0 OK\n");
317                     }
318                 }
319             }
320         #endif
321 
322             return NO_ERR;
323         }
324 
SetParameters(int bufferSize,int samplerate)325         int SetParameters(int bufferSize, int samplerate)
326         {
327             OSStatus err;
328             UInt32 outSize;
329             UInt32 enableIO;
330             AudioStreamBasicDescription srcFormat, dstFormat;
331 
332             printf("SetParameters fDevNumInChans = %d fDevNumOutChans = %d bufferSize = %d samplerate = %d\n", fDevNumInChans, fDevNumOutChans, bufferSize, samplerate);
333 
334             err = AudioSessionSetActive(true);
335             if (err != noErr) {
336                 printf("Couldn't set audio session active\n");
337                 printError(err);
338                 return OPEN_ERR;
339             }
340 
341             AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, AudioSessionPropertyListener, this);
342             AudioSessionAddPropertyListener(kAudioSessionProperty_AudioInputAvailable, AudioSessionPropertyListener, this);
343             AudioSessionAddPropertyListener(kAudioSessionProperty_ServerDied, AudioSessionPropertyListener, this);
344 
345             if (SetAudioCategory(fDevNumInChans, fDevNumOutChans) != NO_ERR) {
346                 return OPEN_ERR;
347             }
348 
349             // Scan Hardware
350             outSize = sizeof(fHWNumInChans);
351             err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputNumberChannels, &outSize, &fHWNumInChans);
352             if (err != noErr) {
353                 fHWNumInChans = 0;
354                 printf("Couldn't get hw input channels\n");
355                 printError(err);
356             } else {
357                 printf("Get hw input channels %d\n", fHWNumInChans);
358             }
359 
360             outSize = sizeof(fHWNumOutChans);
361             err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputNumberChannels, &outSize, &fHWNumOutChans);
362             if (err != noErr) {
363                 fHWNumOutChans = 0;
364                 printf("Couldn't get hw output channels\n");
365                 printError(err);
366             } else {
367                 printf("Get hw output channels %d\n", fHWNumOutChans);
368             }
369             /*
370             // Possibly reset the audioCategory the way hardware allows
371             // 21/09/2017 cause problem when use bluetooth, deactive for now
372             if (SetAudioCategory(fHWNumInChans, fHWNumOutChans) != NO_ERR) {
373                 return OPEN_ERR;
374             }
375             */
376             if (SetupMixing() < 0) {
377                 return OPEN_ERR;
378             }
379 
380             Float64 hwSampleRate;
381             outSize = sizeof(hwSampleRate);
382             err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate, &outSize, &hwSampleRate);
383             if (err != noErr) {
384                 printf("Couldn't get hw sample rate\n");
385                 printError(err);
386                 return OPEN_ERR;
387             } else {
388                 printf("Get hw sample rate %f\n", hwSampleRate);
389             }
390 
391             Float32 hwBufferSize;
392             outSize = sizeof(hwBufferSize);
393             err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &outSize, &hwBufferSize);
394             if (err != noErr) {
395                 printf("Couldn't get hw buffer duration\n");
396                 printError(err);
397                 return OPEN_ERR;
398             } else {
399                 printf("Get hw buffer duration %f\n", hwBufferSize);
400             }
401 
402             Float32 preferredPeriodDuration = float(bufferSize) / float(samplerate);
403             printf("preferredPeriodDuration %f \n", preferredPeriodDuration);
404 
405             err = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredPeriodDuration), &preferredPeriodDuration);
406             if (err != noErr) {
407                 printf("Couldn't set i/o buffer duration\n");
408                 printError(err);
409                 return OPEN_ERR;
410             }
411 
412             Float32 actualPeriodDuration;
413             outSize = sizeof(actualPeriodDuration);
414             err = AudioSessionGetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, &outSize, &actualPeriodDuration);
415             if (err != noErr) {
416                 printf("Couldn't get hw buffer duration\n");
417                 printError(err);
418                 return OPEN_ERR;
419             }
420 
421             printf("preferredPeriodDuration %f actualPeriodDuration %f\n", preferredPeriodDuration, actualPeriodDuration);
422             if (preferredPeriodDuration != actualPeriodDuration) {
423                 printf("Couldn't set hw buffer duration\n");
424                 return OPEN_ERR;
425             }
426 
427             Float64 preferredSamplerate = float(samplerate);
428             err = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareSampleRate, sizeof(preferredSamplerate), &preferredSamplerate);
429             if (err != noErr) {
430                 printf("Couldn't set i/o sample rate\n");
431                 printError(err);
432                 return OPEN_ERR;
433             }
434 
435             Float32 inputLatency;
436             outSize = sizeof(inputLatency);
437             err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputLatency, &outSize, &inputLatency);
438             if (err != noErr) {
439                 printf("Couldn't get inputLatency\n");
440                 printError(err);
441             } else {
442                 printf("inputLatency in sec : %f\n", inputLatency);
443             }
444 
445             Float32 outputLatency;
446             outSize = sizeof(outputLatency);
447             err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputLatency, &outSize, &outputLatency);
448             if (err != noErr) {
449                 printf("Couldn't get outputLatency\n");
450                 printError(err);
451             } else {
452                 printf("outputLatency in sec : %f\n", outputLatency);
453             }
454 
455             // AUHAL
456             AudioComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_RemoteIO, kAudioUnitManufacturer_Apple, 0, 0};
457             AudioComponent HALOutput = AudioComponentFindNext(NULL, &cd);
458 
459             err = AudioComponentInstanceNew(HALOutput, &fAUHAL);
460             if (err != noErr) {
461                 printf("Error calling OpenAComponent\n");
462                 printError(err);
463                 goto error;
464             }
465 
466             enableIO = 1;
467             err = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
468             if (err != noErr) {
469                 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output\n");
470                 printError(err);
471                 goto error;
472             }
473 
474             if (fDevNumInChans > 0) {
475                 enableIO = 1;
476             } else {
477                 enableIO = 0;
478             }
479             err = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
480             if (err != noErr) {
481                 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input\n");
482                 printError(err);
483                 goto error;
484             }
485 
486             UInt32 maxFPS;
487             outSize = sizeof(maxFPS);
488             err = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFPS, &outSize);
489             if (err != noErr) {
490                 printf("Couldn't get kAudioUnitProperty_MaximumFramesPerSlice\n");
491                 printError(err);
492                 goto error;
493             } else {
494                 printf("Get kAudioUnitProperty_MaximumFramesPerSlice %d\n", (unsigned int)maxFPS);
495             }
496 
497             err = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&bufferSize, sizeof(UInt32));
498             if (err != noErr) {
499                 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
500                 printError(err);
501                 goto error;
502             }
503 
504             err = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&bufferSize, sizeof(UInt32));
505             if (err != noErr) {
506                 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
507                 printError(err);
508                 goto error;
509             }
510 
511             err = AudioUnitInitialize(fAUHAL);
512             if (err != noErr) {
513                 printf("Cannot initialize AUHAL unit\n");
514                 printError(err);
515                 goto error;
516             }
517 
518             // Setting format
519             if (fDevNumInChans > 0) {
520                 outSize = sizeof(AudioStreamBasicDescription);
521                 err = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, &outSize);
522                 if (err != noErr) {
523                     printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
524                     printError(err);
525                 }
526                 PrintStreamDesc(&srcFormat);
527 
528                 srcFormat.mFormatID = kAudioFormatLinearPCM;
529                 srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
530                 srcFormat.mBytesPerPacket = sizeof(AudioUnitSampleType);
531                 srcFormat.mFramesPerPacket = 1;
532                 srcFormat.mBytesPerFrame = sizeof(AudioUnitSampleType);
533                 srcFormat.mChannelsPerFrame = fDevNumInChans;
534                 srcFormat.mBitsPerChannel = 32;
535 
536                 PrintStreamDesc(&srcFormat);
537 
538                 err = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription));
539                 if (err != noErr) {
540                     printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
541                     printError(err);
542                 }
543             }
544 
545             if (fDevNumOutChans > 0) {
546                 outSize = sizeof(AudioStreamBasicDescription);
547                 err = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, &outSize);
548                 if (err != noErr) {
549                     printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input\n");
550                     printError(err);
551                 }
552                 PrintStreamDesc(&dstFormat);
553 
554                 dstFormat.mFormatID = kAudioFormatLinearPCM;
555                 dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
556                 dstFormat.mBytesPerPacket = sizeof(AudioUnitSampleType);
557                 dstFormat.mFramesPerPacket = 1;
558                 dstFormat.mBytesPerFrame = sizeof(AudioUnitSampleType);
559                 dstFormat.mChannelsPerFrame = fDevNumOutChans;
560                 dstFormat.mBitsPerChannel = 32;
561 
562                 PrintStreamDesc(&dstFormat);
563 
564                 err = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription));
565                 if (err != noErr) {
566                     printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input\n");
567                     printError(err);
568                 }
569             }
570 
571             if (fDevNumInChans > 0 && fDevNumOutChans == 0) {
572                 AURenderCallbackStruct output;
573                 output.inputProc = Render;
574                 output.inputProcRefCon = this;
575                 err = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
576                 if (err != noErr) {
577                     printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1\n");
578                     printError(err);
579                     goto error;
580                 }
581             } else {
582                 AURenderCallbackStruct output;
583                 output.inputProc = Render;
584                 output.inputProcRefCon = this;
585                 err = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
586                 if (err != noErr) {
587                     printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0\n");
588                     printError(err);
589                     goto error;
590                 }
591             }
592 
593             // Possibly prepare input buffers
594             if (fDevNumInChans > 0) {
595                 fCAInputData = (AudioBufferList*)malloc(sizeof(float) + fDevNumInChans * sizeof(AudioBuffer));
596                 fCAInputData->mNumberBuffers = fDevNumInChans;
597                 for (int i = 0; i < fDevNumInChans; i++) {
598                     fCAInputData->mBuffers[i].mNumberChannels = 1;
599                     fCAInputData->mBuffers[i].mDataByteSize = bufferSize * sizeof(float);
600                     fCAInputData->mBuffers[i].mData = malloc(bufferSize * sizeof(float));
601                 }
602             }
603 
604             return NO_ERR;
605 
606         error:
607             AudioUnitUninitialize(fAUHAL);
608             AudioComponentInstanceDispose(fAUHAL);
609             return OPEN_ERR;
610         }
611 
612     public:
613 
TiPhoneCoreAudioRenderer(audio * audio)614         TiPhoneCoreAudioRenderer(audio* audio)
615             :fAUHAL(0), fDevNumInChans(0), fDevNumOutChans(0),
616             fHWNumInChans(0), fHWNumOutChans(0),
617             fDSP(0), fAudio(audio), fCAInputData(NULL)
618         {}
619 
~TiPhoneCoreAudioRenderer()620         virtual ~TiPhoneCoreAudioRenderer()
621         {
622             if (fCAInputData) {
623                 for (int i = 0; i < fDevNumInChans; i++) {
624                     free(fCAInputData->mBuffers[i].mData);
625                 }
626                 free(fCAInputData);
627             }
628         }
629 
Open(dsp * dsp,int inChan,int outChan,int buffersize,int samplerate)630         int Open(dsp* dsp, int inChan, int outChan, int buffersize, int samplerate)
631         {
632             fDSP = dsp;
633             fDevNumInChans = inChan;
634             fDevNumOutChans = outChan;
635 
636             // Initialize and configure the audio session
637             OSStatus err = AudioSessionInitialize(NULL, NULL, InterruptionListener, this);
638             if (err != noErr && err != kAudioSessionAlreadyInitialized) {
639                 printf("Couldn't initialize audio session\n");
640                 printError(err);
641                 return OPEN_ERR;
642             }
643 
644             if (SetParameters(buffersize, samplerate) < 0) {
645                 printf("Cannot set parameters to CoreAudio device\n");
646                 return OPEN_ERR;
647             }
648 
649             return NO_ERR;
650         }
651 
Close()652         int Close()
653         {
654             AudioUnitUninitialize(fAUHAL);
655             AudioComponentInstanceDispose(fAUHAL);
656             return NO_ERR;
657         }
658 
Start()659         int Start()
660         {
661             AudioSessionSetActive(true);
662 
663             if (AudioOutputUnitStart(fAUHAL) != noErr) {
664                 printf("Error while opening device : device open error\n");
665                 return OPEN_ERR;
666             } else {
667                 return NO_ERR;
668             }
669         }
670 
Stop()671         int Stop()
672         {
673             AudioSessionSetActive(false);
674 
675             if (AudioOutputUnitStop(fAUHAL) != noErr) {
676                 printf("Error while closing device : device close error\n");
677                 return OPEN_ERR;
678             } else {
679                 return NO_ERR;
680             }
681         }
682 
GetNumInputs()683         int GetNumInputs() { return fHWNumInChans; }
GetNumOutputs()684         int GetNumOutputs() { return fHWNumOutChans; }
685 
686 };
687 
688 /******************************************************************************
689  *******************************************************************************
690 
691                                 CORE AUDIO INTERFACE
692 
693  *******************************************************************************
694  *******************************************************************************/
695 
696 class iosaudio : public audio {
697 
698     protected:
699 
700         TiPhoneCoreAudioRenderer fAudioDevice;
701         int fSampleRate, fBufferSize;
702 
703     public:
704 
iosaudio(int srate,int bsize)705         iosaudio(int srate, int bsize)
706         :fAudioDevice(this), fSampleRate(srate), fBufferSize(bsize)
707         {}
708 
~iosaudio()709         virtual ~iosaudio() { fAudioDevice.Close(); }
710 
init(const char *,dsp * DSP)711         virtual bool init(const char* /*name*/, dsp* DSP)
712         {
713             DSP->init(fSampleRate);
714             if (fAudioDevice.Open(DSP, DSP->getNumInputs(), DSP->getNumOutputs(), fBufferSize, fSampleRate) < 0) {
715                 printf("Cannot open iOS audio device\n");
716                 return false;
717             }
718             return true;
719         }
720 
start()721         virtual bool start()
722         {
723             if (fAudioDevice.Start() < 0) {
724                 printf("Cannot start iOS audio device\n");
725                 return false;
726             }
727             return true;
728         }
729 
stop()730         virtual void stop()
731         {
732             fAudioDevice.Stop();
733         }
734 
getBufferSize()735         virtual int getBufferSize() { return fBufferSize; }
getSampleRate()736         virtual int getSampleRate() { return fSampleRate; }
737 
getNumInputs()738         virtual int getNumInputs() { return fAudioDevice.GetNumInputs(); }
getNumOutputs()739         virtual int getNumOutputs() { return fAudioDevice.GetNumOutputs(); }
740 
741 };
742 
743 #endif
744 
745 /********************END ARCHITECTURE SECTION (part 2/2)****************/
746 /**************************  END  coreaudio-ios-dsp.h **************************/
747