# cocoa_s.cpp

Go to the documentation of this file.

    00001 /* $Id: cocoa_s.cpp 17248 2009-08-21 20:21:05Z rubidium $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 /*****************************************************************************
    00013  *                             Cocoa sound driver                            *
    00014  * Known things left to do:                                                  *
    00015  * - Might need to do endian checking for it to work on both ppc and x86     *
    00016  *****************************************************************************/
    00017
    00018 #ifdef WITH_COCOA
    00019
    00020 #include "../stdafx.h"
    00021 #include "../debug.h"
    00022 #include "../driver.h"
    00023 #include "../mixer.h"
    00024 #include "../core/endian_type.hpp"
    00025 #include "cocoa_s.h"
    00026
    00027 #define Rect        OTTDRect
    00028 #define Point       OTTDPoint
    00029 #include <AudioUnit/AudioUnit.h>
    00030 #undef Rect
    00031 #undef Point
    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", 44100);
    00058
    00059   requestedDesc.mBitsPerChannel = 16;
    00060   requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
    00061
    00062 #if TTD_ENDIAN == TTD_BIG_ENDIAN
    00063   requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
    00064 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
    00065
    00066   requestedDesc.mFramesPerPacket = 1;
    00067   requestedDesc.mBytesPerFrame = requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8;
    00068   requestedDesc.mBytesPerPacket = requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket;
    00069
    00070   MxInitialize(requestedDesc.mSampleRate);
    00071
    00072   /* Locate the default output audio unit */
    00073   desc.componentType = kAudioUnitType_Output;
    00074   desc.componentSubType = kAudioUnitSubType_HALOutput;
    00075   desc.componentManufacturer = kAudioUnitManufacturer_Apple;
    00076   desc.componentFlags = 0;
    00077   desc.componentFlagsMask = 0;
    00078
    00079   comp = FindNextComponent (NULL, &desc);
    00080   if (comp == NULL) {
    00081     return "cocoa_s: Failed to start CoreAudio: FindNextComponent returned NULL";
    00082   }
    00083
    00084   /* Open & initialize the default output audio unit */
    00085   if (OpenAComponent(comp, &_outputAudioUnit) != noErr) {
    00086     return "cocoa_s: Failed to start CoreAudio: OpenAComponent";
    00087   }
    00088
    00089   if (AudioUnitInitialize(_outputAudioUnit) != noErr) {
    00090     return "cocoa_s: Failed to start CoreAudio: AudioUnitInitialize";
    00091   }
    00092
    00093   /* Set the input format of the audio unit. */
    00094   if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &requestedDesc, sizeof(requestedDesc)) != noErr) {
    00095     return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)";
    00096   }
    00097
    00098   /* Set the audio callback */
    00099   callback.inputProc = audioCallback;
    00100   callback.inputProcRefCon = NULL;
    00101   if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) {
    00102     return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback)";
    00103   }
    00104
    00105   /* Finally, start processing of the audio unit */
    00106   if (AudioOutputUnitStart(_outputAudioUnit) != noErr) {
    00107     return "cocoa_s: Failed to start CoreAudio: AudioOutputUnitStart";
    00108   }
    00109
    00110   /* We're running! */
    00111   return NULL;
    00112 }
    00113
    00114
    00115 void SoundDriver_Cocoa::Stop()
    00116 {
    00117   struct AURenderCallbackStruct callback;
    00118
    00119   /* stop processing the audio unit */
    00120   if (AudioOutputUnitStop(_outputAudioUnit) != noErr) {
    00121     DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: AudioOutputUnitStop failed");
    00122     return;
    00123   }
    00124
    00125   /* Remove the input callback */
    00126   callback.inputProc = 0;
    00127   callback.inputProcRefCon = 0;
    00128   if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) {
    00129     DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback) failed");
    00130     return;
    00131   }
    00132
    00133   if (CloseComponent(_outputAudioUnit) != noErr) {
    00134     DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: CloseComponent failed");
    00135     return;
    00136   }
    00137 }
    00138
    00139 #endif /* WITH_COCOA */