peter1138@2743: /* $Id$ */ peter1138@2743: rubidium@9111: /** @file cocoa_s.cpp Sound driver for cocoa. */ rubidium@9111: 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: egladil@7965: #define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_3 egladil@7965: #include egladil@7965: 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" smatz@9543: #include "../core/endian_type.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: peter1138@7170: static FSoundDriver_Cocoa iFSoundDriver_Cocoa; bjarni@2736: bjarni@2736: static AudioUnit _outputAudioUnit; bjarni@2736: bjarni@2736: /* The CoreAudio callback */ egladil@7839: static OSStatus audioCallback(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData) bjarni@2736: { egladil@7839: MxMixSamples(ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize / 4); bjarni@2736: bjarni@2736: return noErr; bjarni@2736: } bjarni@2736: bjarni@2736: peter1138@7170: const char *SoundDriver_Cocoa::Start(const char * const *parm) bjarni@2736: { bjarni@2736: Component comp; bjarni@2736: ComponentDescription desc; egladil@7839: 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: smatz@9543: #if TTD_ENDIAN == TTD_BIG_ENDIAN bjarni@2736: requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; smatz@9543: #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */ 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 */ egladil@7839: desc.componentType = kAudioUnitType_Output; egladil@7839: desc.componentSubType = kAudioUnitSubType_HALOutput; egladil@7839: 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; egladil@7839: if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) { egladil@7839: 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: peter1138@7170: void SoundDriver_Cocoa::Stop() bjarni@2736: { egladil@7839: struct AURenderCallbackStruct callback; bjarni@2736: bjarni@2736: /* stop processing the audio unit */ tron@4077: if (AudioOutputUnitStop(_outputAudioUnit) != noErr) { rubidium@5383: 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; egladil@7839: if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) { egladil@7839: 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@5383: DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: CloseComponent failed"); bjarni@2736: return; bjarni@2736: } bjarni@2736: } bjarni@2736: bjarni@2736: #endif /* WITH_COCOA */