peter1138@2743: /* $Id$ */ peter1138@2743: richk@10724: /** @file cocoa_s.cpp Sound driver for cocoa. */ richk@10724: peter1138@2953: /***************************************************************************** peter1138@2953: * Cocoa sound driver * peter1138@2953: * Known things left to do: * peter1138@2953: * - Might need to do endian checking for it to work on both ppc and x86 * peter1138@2953: *****************************************************************************/ bjarni@2736: bjarni@2736: #ifdef WITH_COCOA bjarni@2736: rubidium@6871: #define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_3 rubidium@6871: #include rubidium@6871: bjarni@2736: #include bjarni@2736: bjarni@2736: /* Name conflict */ peter1138@2953: #define Rect OTTDRect peter1138@2953: #define Point OTTDPoint peter1138@2953: #define WindowClass OTTDWindowClass bjarni@2736: bjarni@2736: #include "../stdafx.h" bjarni@2736: #include "../debug.h" bjarni@2736: #include "../driver.h" bjarni@2736: #include "../mixer.h" rubidium@6872: #include "../core/endian_func.hpp" bjarni@2736: bjarni@2736: #include "cocoa_s.h" bjarni@2736: bjarni@2736: #undef WindowClass bjarni@2736: #undef Point bjarni@2736: #undef Rect bjarni@2736: richk@6720: static FSoundDriver_Cocoa iFSoundDriver_Cocoa; bjarni@2736: bjarni@2736: static AudioUnit _outputAudioUnit; bjarni@2736: bjarni@2736: /* The CoreAudio callback */ rubidium@6871: static OSStatus audioCallback(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData) bjarni@2736: { rubidium@6871: MxMixSamples(ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize / 4); bjarni@2736: bjarni@2736: return noErr; bjarni@2736: } bjarni@2736: bjarni@2736: richk@6720: const char *SoundDriver_Cocoa::Start(const char * const *parm) bjarni@2736: { bjarni@2736: Component comp; bjarni@2736: ComponentDescription desc; rubidium@6871: struct AURenderCallbackStruct callback; bjarni@2736: AudioStreamBasicDescription requestedDesc; bjarni@2736: bjarni@2736: /* Setup a AudioStreamBasicDescription with the requested format */ bjarni@2736: requestedDesc.mFormatID = kAudioFormatLinearPCM; bjarni@2736: requestedDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked; bjarni@2736: requestedDesc.mChannelsPerFrame = 2; bjarni@2736: requestedDesc.mSampleRate = GetDriverParamInt(parm, "hz", 11025); bjarni@2736: bjarni@2736: requestedDesc.mBitsPerChannel = 16; bjarni@2736: requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; bjarni@2837: bjarni@2837: #ifdef TTD_BIG_ENDIAN bjarni@2736: requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; bjarni@2736: #endif bjarni@2736: bjarni@2736: requestedDesc.mFramesPerPacket = 1; bjarni@2736: requestedDesc.mBytesPerFrame = requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8; bjarni@2736: requestedDesc.mBytesPerPacket = requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket; bjarni@2736: bjarni@2736: bjarni@2736: /* Locate the default output audio unit */ rubidium@6871: desc.componentType = kAudioUnitType_Output; rubidium@6871: desc.componentSubType = kAudioUnitSubType_HALOutput; rubidium@6871: desc.componentManufacturer = kAudioUnitManufacturer_Apple; bjarni@2736: desc.componentFlags = 0; bjarni@2736: desc.componentFlagsMask = 0; bjarni@2736: bjarni@2736: comp = FindNextComponent (NULL, &desc); tron@4077: if (comp == NULL) { bjarni@2736: return "cocoa_s: Failed to start CoreAudio: FindNextComponent returned NULL"; tron@4077: } bjarni@2736: bjarni@2736: /* Open & initialize the default output audio unit */ tron@4077: if (OpenAComponent(comp, &_outputAudioUnit) != noErr) { bjarni@2736: return "cocoa_s: Failed to start CoreAudio: OpenAComponent"; tron@4077: } bjarni@2736: tron@4077: if (AudioUnitInitialize(_outputAudioUnit) != noErr) { bjarni@2736: return "cocoa_s: Failed to start CoreAudio: AudioUnitInitialize"; tron@4077: } bjarni@2736: bjarni@2736: /* Set the input format of the audio unit. */ tron@4077: if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &requestedDesc, sizeof(requestedDesc)) != noErr) { peter1138@2953: return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)"; tron@4077: } bjarni@2736: bjarni@2736: /* Set the audio callback */ bjarni@2736: callback.inputProc = audioCallback; bjarni@2736: callback.inputProcRefCon = NULL; rubidium@6871: if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) { rubidium@6871: return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback)"; tron@4077: } bjarni@2736: bjarni@2736: /* Finally, start processing of the audio unit */ tron@4077: if (AudioOutputUnitStart(_outputAudioUnit) != noErr) { bjarni@2736: return "cocoa_s: Failed to start CoreAudio: AudioOutputUnitStart"; tron@4077: } bjarni@2736: bjarni@2736: /* We're running! */ bjarni@2736: return NULL; bjarni@2736: } bjarni@2736: bjarni@2736: richk@6720: void SoundDriver_Cocoa::Stop() bjarni@2736: { rubidium@6871: struct AURenderCallbackStruct callback; bjarni@2736: bjarni@2736: /* stop processing the audio unit */ tron@4077: if (AudioOutputUnitStop(_outputAudioUnit) != noErr) { rubidium@5571: DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: AudioOutputUnitStop failed"); bjarni@2736: return; bjarni@2736: } bjarni@2736: bjarni@2736: /* Remove the input callback */ bjarni@2736: callback.inputProc = 0; bjarni@2736: callback.inputProcRefCon = 0; rubidium@6871: if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) { rubidium@6871: DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback) failed"); bjarni@2736: return; bjarni@2736: } bjarni@2736: bjarni@2736: if (CloseComponent(_outputAudioUnit) != noErr) { rubidium@5571: DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: CloseComponent failed"); bjarni@2736: return; bjarni@2736: } bjarni@2736: } bjarni@2736: bjarni@2736: #endif /* WITH_COCOA */