Jack2  1.9.8
TiPhoneCoreAudioRenderer.cpp
00001 /*
00002 Copyright (C) 2010 Grame
00003 
00004 This program is free software; you can redistribute it and/or modify
00005 it under the terms of the GNU General Public License as published by
00006 the Free Software Foundation; either version 2 of the License, or
00007 (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017 
00018 */
00019 
00020 #include "TiPhoneCoreAudioRenderer.h"
00021 
00022 static void PrintStreamDesc(AudioStreamBasicDescription *inDesc)
00023 {
00024     printf("- - - - - - - - - - - - - - - - - - - -\n");
00025     printf("  Sample Rate:%f\n", inDesc->mSampleRate);
00026     printf("  Format ID:%.*s\n", (int) sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID);
00027     printf("  Format Flags:%lX\n", inDesc->mFormatFlags);
00028     printf("  Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
00029     printf("  Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
00030     printf("  Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
00031     printf("  Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
00032     printf("  Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
00033     printf("- - - - - - - - - - - - - - - - - - - -\n");
00034 }
00035 
00036 static void printError(OSStatus err)
00037 {
00038     switch (err) {
00039         case kAudioConverterErr_FormatNotSupported:
00040             printf("error code : kAudioConverterErr_FormatNotSupported\n");
00041             break;
00042         case kAudioConverterErr_OperationNotSupported:
00043             printf("error code : kAudioConverterErr_OperationNotSupported\n");
00044             break;
00045         case kAudioConverterErr_PropertyNotSupported:
00046             printf("error code : kAudioConverterErr_PropertyNotSupported\n");
00047             break;
00048         case kAudioConverterErr_InvalidInputSize:
00049             printf("error code : kAudioConverterErr_InvalidInputSize\n");
00050             break;
00051         case kAudioConverterErr_InvalidOutputSize:
00052             printf("error code : kAudioConverterErr_InvalidOutputSize\n");
00053             break;
00054         case kAudioConverterErr_UnspecifiedError:
00055             printf("error code : kAudioConverterErr_UnspecifiedError\n");
00056             break;
00057         case kAudioConverterErr_BadPropertySizeError:
00058             printf("error code : kAudioConverterErr_BadPropertySizeError\n");
00059             break;
00060         case kAudioConverterErr_RequiresPacketDescriptionsError:
00061             printf("error code : kAudioConverterErr_RequiresPacketDescriptionsError\n");
00062             break;
00063         case kAudioConverterErr_InputSampleRateOutOfRange:
00064             printf("error code : kAudioConverterErr_InputSampleRateOutOfRange\n");
00065             break;
00066         case kAudioConverterErr_OutputSampleRateOutOfRange:
00067             printf("error code : kAudioConverterErr_OutputSampleRateOutOfRange\n");
00068             break;
00069         default:
00070             printf("error code : unknown\n");
00071             break;
00072     }
00073 }
00074 
00075 OSStatus TiPhoneCoreAudioRenderer::Render(void *inRefCon,
00076                                          AudioUnitRenderActionFlags *ioActionFlags,
00077                                          const AudioTimeStamp *inTimeStamp,
00078                                          UInt32,
00079                                          UInt32 inNumberFrames,
00080                                          AudioBufferList *ioData)
00081 {
00082     TiPhoneCoreAudioRendererPtr renderer = (TiPhoneCoreAudioRendererPtr)inRefCon;
00083     AudioUnitRender(renderer->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, renderer->fCAInputData);
00084     
00085     float coef = float(LONG_MAX);
00086     float inv_coef = 1.f/float(LONG_MAX);
00087     
00088     for (int chan = 0; chan < renderer->fDevNumInChans; chan++) {
00089         for (int frame = 0; frame < inNumberFrames; frame++) {
00090             renderer->fInChannel[chan][frame] = float(((int*)renderer->fCAInputData->mBuffers[chan].mData)[frame]) * inv_coef;
00091         }
00092     }
00093     
00094     renderer->PerformAudioCallback((int)inNumberFrames);
00095     
00096     for (int chan = 0; chan < renderer->fDevNumOutChans; chan++) {
00097         for (int frame = 0; frame < inNumberFrames; frame++) {
00098            ((int*)ioData->mBuffers[chan].mData)[frame] = int(renderer->fOutChannel[chan][frame] * coef); 
00099         }
00100     }
00101     
00102         return 0;
00103 }
00104 
00105 void TiPhoneCoreAudioRenderer::InterruptionListener(void *inClientData, UInt32 inInterruption)
00106 {
00107         TiPhoneCoreAudioRenderer *obj = (TiPhoneCoreAudioRenderer*)inClientData;
00108         printf("Session interrupted! --- %s ---", inInterruption == kAudioSessionBeginInterruption ? "Begin Interruption" : "End Interruption");
00109         
00110         if (inInterruption == kAudioSessionEndInterruption) {
00111                 // make sure we are again the active session
00112                 AudioSessionSetActive(true);
00113                 AudioOutputUnitStart(obj->fAUHAL);
00114         }
00115         
00116         if (inInterruption == kAudioSessionBeginInterruption) {
00117                 AudioOutputUnitStop(obj->fAUHAL);
00118     }
00119 }
00120 
00121 int TiPhoneCoreAudioRenderer::Open(int bufferSize, int samplerate)
00122 {
00123     OSStatus err1;
00124     UInt32 outSize;
00125     UInt32 enableIO;
00126         AudioStreamBasicDescription srcFormat, dstFormat;
00127     
00128     printf("Open fDevNumInChans = %ld fDevNumOutChans = %ld bufferSize = %ld samplerate = %ld\n", fDevNumInChans, fDevNumOutChans, bufferSize, samplerate);
00129           
00130     // Initialize and configure the audio session
00131     err1 = AudioSessionInitialize(NULL, NULL, InterruptionListener, this);
00132     if (err1 != noErr) {
00133         printf("Couldn't initialize audio session\n");
00134         printError(err1);
00135         return OPEN_ERR;
00136     }
00137     
00138     err1 = AudioSessionSetActive(true);
00139     if (err1 != noErr) {
00140         printf("Couldn't set audio session active\n");
00141         printError(err1);
00142         return OPEN_ERR;
00143     }
00144                         
00145     UInt32 audioCategory = kAudioSessionCategory_PlayAndRecord;
00146         err1 = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory);
00147     if (err1 != noErr) {
00148         printf("Couldn't set audio category\n");
00149         printError(err1);
00150         return OPEN_ERR;
00151     }
00152     
00153         //err1 = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, propListener, self), "couldn't set property listener");
00154     
00155     Float64 hwSampleRate;
00156     outSize = sizeof(hwSampleRate);
00157         err1 = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate, &outSize, &hwSampleRate);
00158     if (err1 != noErr) {
00159         printf("Couldn't get hw sample rate\n");
00160         printError(err1);
00161         return OPEN_ERR;
00162     } else {
00163          printf("Get hw sample rate %f\n", hwSampleRate);
00164     }
00165     
00166     Float32 hwBufferSize;
00167     outSize = sizeof(hwBufferSize);
00168         err1 = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &outSize, &hwBufferSize);
00169     if (err1 != noErr) {
00170         printf("Couldn't get hw buffer duration\n");
00171         printError(err1);
00172         return OPEN_ERR;
00173     } else {
00174          printf("Get hw buffer duration %f\n", hwBufferSize);
00175     }
00176 
00177     UInt32 hwInput;
00178     outSize = sizeof(hwInput);
00179         err1 = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputNumberChannels, &outSize, &hwInput);
00180     if (err1 != noErr) {
00181         printf("Couldn't get hw input channels\n");
00182         printError(err1);
00183         return OPEN_ERR;
00184     } else {
00185         printf("Get hw input channels %d\n", hwInput);
00186     }
00187 
00188     UInt32 hwOutput;
00189     outSize = sizeof(hwOutput);
00190         err1 = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputNumberChannels, &outSize, &hwOutput);
00191     if (err1 != noErr) {
00192         printf("Couldn't get hw output channels\n");
00193         printError(err1);
00194         return OPEN_ERR;
00195     } else {
00196         printf("Get hw output channels %d\n", hwOutput);
00197     }
00198                         
00199     Float32 preferredBufferSize = float(bufferSize) / float(samplerate);
00200     printf("preferredBufferSize %f \n", preferredBufferSize);
00201     
00202         err1 = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredBufferSize), &preferredBufferSize);
00203     if (err1 != noErr) {
00204         printf("Couldn't set i/o buffer duration\n");
00205         printError(err1);
00206         return OPEN_ERR;
00207     }
00208         
00209     Float64 preferredSamplerate = float(samplerate);
00210         err1 = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareSampleRate, sizeof(preferredSamplerate), &preferredSamplerate);
00211     if (err1 != noErr) {
00212         printf("Couldn't set i/o sample rate\n");
00213         printError(err1);
00214         return OPEN_ERR;
00215     }
00216         
00217     // AUHAL
00218     AudioComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_RemoteIO, kAudioUnitManufacturer_Apple, 0, 0};
00219     AudioComponent HALOutput = AudioComponentFindNext(NULL, &cd);
00220 
00221     err1 = AudioComponentInstanceNew(HALOutput, &fAUHAL);
00222     if (err1 != noErr) {
00223                 printf("Error calling OpenAComponent\n");
00224         printError(err1);
00225         goto error;
00226         }
00227 
00228     enableIO = 1;
00229     err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
00230     if (err1 != noErr) {
00231         printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output\n");
00232         printError(err1);
00233         goto error;
00234     }
00235     
00236     enableIO = 1;
00237     err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
00238     if (err1 != noErr) {
00239         printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input\n");
00240         printError(err1);
00241         goto error;
00242     }
00243     
00244     UInt32 maxFPS;
00245     outSize = sizeof(maxFPS);
00246     err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFPS, &outSize);
00247     if (err1 != noErr) {
00248         printf("Couldn't get kAudioUnitProperty_MaximumFramesPerSlice\n");
00249         printError(err1);
00250         goto error;
00251     } else {
00252         printf("Get kAudioUnitProperty_MaximumFramesPerSlice %d\n", maxFPS);
00253     }
00254    
00255     err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&bufferSize, sizeof(UInt32));
00256     if (err1 != noErr) {
00257         printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
00258         printError(err1);
00259         goto error;
00260     }
00261 
00262     err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&bufferSize, sizeof(UInt32));
00263     if (err1 != noErr) {
00264         printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
00265         printError(err1);
00266         goto error;
00267     }
00268 
00269     err1 = AudioUnitInitialize(fAUHAL);
00270     if (err1 != noErr) {
00271                 printf("Cannot initialize AUHAL unit\n");
00272                 printError(err1);
00273         goto error;
00274         }
00275 
00276     // Setting format
00277         
00278     if (fDevNumInChans > 0) {
00279         outSize = sizeof(AudioStreamBasicDescription);
00280         err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, &outSize);
00281         if (err1 != noErr) {
00282             printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
00283             printError(err1);
00284         }
00285         PrintStreamDesc(&srcFormat);
00286         
00287         srcFormat.mFormatID = kAudioFormatLinearPCM;
00288         srcFormat.mFormatFlags = kAudioFormatFlagsCanonical | kLinearPCMFormatFlagIsNonInterleaved;
00289         srcFormat.mBytesPerPacket = sizeof(AudioUnitSampleType);
00290         srcFormat.mFramesPerPacket = 1;
00291         srcFormat.mBytesPerFrame = sizeof(AudioUnitSampleType);
00292         srcFormat.mChannelsPerFrame = fDevNumInChans;
00293         srcFormat.mBitsPerChannel = 32;
00294         
00295         PrintStreamDesc(&srcFormat);
00296         
00297         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription));
00298         if (err1 != noErr) {
00299             printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
00300             printError(err1);
00301         }    
00302     }
00303         
00304     if (fDevNumOutChans > 0) {
00305         outSize = sizeof(AudioStreamBasicDescription);
00306         err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, &outSize);
00307         if (err1 != noErr) {
00308             printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input\n");
00309             printError(err1);
00310         }
00311         PrintStreamDesc(&dstFormat);
00312         
00313         dstFormat.mFormatID = kAudioFormatLinearPCM;
00314         dstFormat.mFormatFlags = kAudioFormatFlagsCanonical | kLinearPCMFormatFlagIsNonInterleaved;
00315         dstFormat.mBytesPerPacket = sizeof(AudioUnitSampleType);
00316         dstFormat.mFramesPerPacket = 1;
00317         dstFormat.mBytesPerFrame = sizeof(AudioUnitSampleType);
00318         dstFormat.mChannelsPerFrame = fDevNumOutChans;
00319         dstFormat.mBitsPerChannel = 32;
00320         
00321         PrintStreamDesc(&dstFormat);
00322 
00323         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription));
00324         if (err1 != noErr) {
00325             printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input\n");
00326             printError(err1);
00327         }
00328     }
00329     
00330     if (fDevNumInChans > 0 && fDevNumOutChans == 0) {
00331         AURenderCallbackStruct output;
00332         output.inputProc = Render;
00333         output.inputProcRefCon = this;
00334         err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
00335         if (err1 != noErr) {
00336             printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1\n");
00337             printError(err1);
00338             goto error;
00339         }
00340     } else {
00341         AURenderCallbackStruct output;
00342         output.inputProc = Render;
00343         output.inputProcRefCon = this;
00344         err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
00345         if (err1 != noErr) {
00346             printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0\n");
00347             printError(err1);
00348             goto error;
00349         }
00350     }
00351     
00352     // Prepare buffers
00353     fCAInputData = (AudioBufferList*)malloc(sizeof(UInt32) + fDevNumInChans * sizeof(AudioBuffer));
00354     fCAInputData->mNumberBuffers = fDevNumInChans;
00355     for (int i = 0; i < fDevNumInChans; i++) {
00356         fCAInputData->mBuffers[i].mNumberChannels = 1;
00357         fCAInputData->mBuffers[i].mDataByteSize = bufferSize * sizeof(int);
00358         fCAInputData->mBuffers[i].mData = malloc(bufferSize * sizeof(int));
00359     }
00360     
00361     /*
00362     // Add listeners
00363     err1 = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback, this);
00364     if (err != noErr) {
00365         jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload");
00366         printError(err);
00367         return -1;
00368     }
00369     */
00370 
00371     return NO_ERR;
00372 
00373 error:
00374     AudioUnitUninitialize(fAUHAL);
00375     AudioComponentInstanceDispose(fAUHAL);
00376     return OPEN_ERR;
00377 }
00378 
00379 int TiPhoneCoreAudioRenderer::Close()
00380 {
00381         AudioUnitUninitialize(fAUHAL);
00382     AudioComponentInstanceDispose(fAUHAL);
00383     return NO_ERR;
00384 }
00385 
00386 int TiPhoneCoreAudioRenderer::Start()
00387 {
00388     AudioSessionSetActive(true);
00389         OSStatus err = AudioOutputUnitStart(fAUHAL);
00390   
00391     if (err != noErr) {
00392         printf("Error while opening device : device open error \n");
00393         return OPEN_ERR;
00394     } else {
00395         return NO_ERR;
00396         }
00397 }
00398 
00399 int TiPhoneCoreAudioRenderer::Stop()
00400 {
00401     OSStatus err = AudioOutputUnitStop(fAUHAL);
00402 
00403     if (err != noErr) {
00404         printf("Error while closing device : device close error \n");
00405         return OPEN_ERR;
00406     } else {
00407         return NO_ERR;
00408         }
00409 }