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 */

Generated on Sat Jul 17 18:43:23 2010 for OpenTTD by  doxygen 1.6.1