# cocoa_s.cpp

    00001 /* $Id: cocoa_s.cpp 11694 2007-12-25 13:28:09Z rubidium $ */
    00002
    00003 /*****************************************************************************
    00004  *                             Cocoa sound driver                            *
    00005  * Known things left to do:                                                  *
    00006  * - Might need to do endian checking for it to work on both ppc and x86     *
    00007  *****************************************************************************/
    00008
    00009 #ifdef WITH_COCOA
    00010
    00011 #define MAC_OS_X_VERSION_MIN_REQUIRED    MAC_OS_X_VERSION_10_3
    00012 #include <AvailabilityMacros.h>
    00013
    00014 #include <AudioUnit/AudioUnit.h>
    00015
    00016 /* Name conflict */
    00017 #define Rect        OTTDRect
    00018 #define Point       OTTDPoint
    00019 #define WindowClass OTTDWindowClass
    00020
    00021 #include "../stdafx.h"
    00022 #include "../debug.h"
    00023 #include "../driver.h"
    00024 #include "../mixer.h"
    00025 #include "../core/endian_func.hpp"
    00026
    00027 #include "cocoa_s.h"
    00028
    00029 #undef WindowClass
    00030 #undef Point
    00031 #undef Rect
    00032
    00033 static FSoundDriver_Cocoa iFSoundDriver_Cocoa;
    00034
    00035 static AudioUnit _outputAudioUnit;
    00036
    00037 /* The CoreAudio callback */
    00038 static OSStatus audioCallback(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData)
    00039 {
    00040   MxMixSamples(ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize / 4);
    00041
    00042   return noErr;
    00043 }
    00044
    00045
    00046 const char *SoundDriver_Cocoa::Start(const char * const *parm)
    00047 {
    00048   Component comp;
    00049   ComponentDescription desc;
    00050   struct AURenderCallbackStruct callback;
    00051   AudioStreamBasicDescription requestedDesc;
    00052
    00053   /* Setup a AudioStreamBasicDescription with the requested format */
    00054   requestedDesc.mFormatID = kAudioFormatLinearPCM;
    00055   requestedDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
    00056   requestedDesc.mChannelsPerFrame = 2;
    00057   requestedDesc.mSampleRate = GetDriverParamInt(parm, "hz", 11025);
    00058
    00059   requestedDesc.mBitsPerChannel = 16;
    00060   requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
    00061
    00062 #ifdef TTD_BIG_ENDIAN
    00063   requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
    00064 #endif
    00065
    00066   requestedDesc.mFramesPerPacket = 1;
    00067   requestedDesc.mBytesPerFrame = requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8;
    00068   requestedDesc.mBytesPerPacket = requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket;
    00069
    00070
    00071   /* Locate the default output audio unit */
    00072   desc.componentType = kAudioUnitType_Output;
    00073   desc.componentSubType = kAudioUnitSubType_HALOutput;
    00074   desc.componentManufacturer = kAudioUnitManufacturer_Apple;
    00075   desc.componentFlags = 0;
    00076   desc.componentFlagsMask = 0;
    00077
    00078   comp = FindNextComponent (NULL, &desc);
    00079   if (comp == NULL) {
    00080     return "cocoa_s: Failed to start CoreAudio: FindNextComponent returned NULL";
    00081   }
    00082
    00083   /* Open & initialize the default output audio unit */
    00084   if (OpenAComponent(comp, &_outputAudioUnit) != noErr) {
    00085     return "cocoa_s: Failed to start CoreAudio: OpenAComponent";
    00086   }
    00087
    00088   if (AudioUnitInitialize(_outputAudioUnit) != noErr) {
    00089     return "cocoa_s: Failed to start CoreAudio: AudioUnitInitialize";
    00090   }
    00091
    00092   /* Set the input format of the audio unit. */
    00093   if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &requestedDesc, sizeof(requestedDesc)) != noErr) {
    00094     return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)";
    00095   }
    00096
    00097   /* Set the audio callback */
    00098   callback.inputProc = audioCallback;
    00099   callback.inputProcRefCon = NULL;
    00100   if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) {
    00101     return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback)";
    00102   }
    00103
    00104   /* Finally, start processing of the audio unit */
    00105   if (AudioOutputUnitStart(_outputAudioUnit) != noErr) {
    00106     return "cocoa_s: Failed to start CoreAudio: AudioOutputUnitStart";
    00107   }
    00108
    00109   /* We're running! */
    00110   return NULL;
    00111 }
    00112
    00113
    00114 void SoundDriver_Cocoa::Stop()
    00115 {
    00116   struct AURenderCallbackStruct callback;
    00117
    00118   /* stop processing the audio unit */
    00119   if (AudioOutputUnitStop(_outputAudioUnit) != noErr) {
    00120     DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: AudioOutputUnitStop failed");
    00121     return;
    00122   }
    00123
    00124   /* Remove the input callback */
    00125   callback.inputProc = 0;
    00126   callback.inputProcRefCon = 0;
    00127   if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) {
    00128     DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback) failed");
    00129     return;
    00130   }
    00131
    00132   if (CloseComponent(_outputAudioUnit) != noErr) {
    00133     DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: CloseComponent failed");
    00134     return;
    00135   }
    00136 }
    00137
    00138 #endif /* WITH_COCOA */