4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
10 /** @file cocoa_s.cpp Sound driver for cocoa. */
12 /*****************************************************************************
13 * Cocoa sound driver *
14 * Known things left to do: *
15 * - Might need to do endian checking for it to work on both ppc and x86 *
16 *****************************************************************************/
20 #include "../stdafx.h"
22 #include "../driver.h"
24 #include "../core/endian_type.hpp"
28 #define Point OTTDPoint
29 #include <AudioUnit/AudioUnit.h>
33 #include "../safeguards.h"
35 static FSoundDriver_Cocoa iFSoundDriver_Cocoa
;
37 static AudioUnit _outputAudioUnit
;
39 /* The CoreAudio callback */
40 static OSStatus
audioCallback(void *inRefCon
, AudioUnitRenderActionFlags
*inActionFlags
, const AudioTimeStamp
*inTimeStamp
, UInt32 inBusNumber
, UInt32 inNumberFrames
, AudioBufferList
* ioData
)
42 MxMixSamples(ioData
->mBuffers
[0].mData
, ioData
->mBuffers
[0].mDataByteSize
/ 4);
48 const char *SoundDriver_Cocoa::Start(const char * const *parm
)
51 ComponentDescription desc
;
52 struct AURenderCallbackStruct callback
;
53 AudioStreamBasicDescription requestedDesc
;
55 /* Setup a AudioStreamBasicDescription with the requested format */
56 requestedDesc
.mFormatID
= kAudioFormatLinearPCM
;
57 requestedDesc
.mFormatFlags
= kLinearPCMFormatFlagIsPacked
;
58 requestedDesc
.mChannelsPerFrame
= 2;
59 requestedDesc
.mSampleRate
= GetDriverParamInt(parm
, "hz", 44100);
61 requestedDesc
.mBitsPerChannel
= 16;
62 requestedDesc
.mFormatFlags
|= kLinearPCMFormatFlagIsSignedInteger
;
64 #if TTD_ENDIAN == TTD_BIG_ENDIAN
65 requestedDesc
.mFormatFlags
|= kLinearPCMFormatFlagIsBigEndian
;
66 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
68 requestedDesc
.mFramesPerPacket
= 1;
69 requestedDesc
.mBytesPerFrame
= requestedDesc
.mBitsPerChannel
* requestedDesc
.mChannelsPerFrame
/ 8;
70 requestedDesc
.mBytesPerPacket
= requestedDesc
.mBytesPerFrame
* requestedDesc
.mFramesPerPacket
;
72 MxInitialize((uint
)requestedDesc
.mSampleRate
);
74 /* Locate the default output audio unit */
75 desc
.componentType
= kAudioUnitType_Output
;
76 desc
.componentSubType
= kAudioUnitSubType_HALOutput
;
77 desc
.componentManufacturer
= kAudioUnitManufacturer_Apple
;
78 desc
.componentFlags
= 0;
79 desc
.componentFlagsMask
= 0;
81 comp
= FindNextComponent (NULL
, &desc
);
83 return "cocoa_s: Failed to start CoreAudio: FindNextComponent returned NULL";
86 /* Open & initialize the default output audio unit */
87 if (OpenAComponent(comp
, &_outputAudioUnit
) != noErr
) {
88 return "cocoa_s: Failed to start CoreAudio: OpenAComponent";
91 if (AudioUnitInitialize(_outputAudioUnit
) != noErr
) {
92 return "cocoa_s: Failed to start CoreAudio: AudioUnitInitialize";
95 /* Set the input format of the audio unit. */
96 if (AudioUnitSetProperty(_outputAudioUnit
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Input
, 0, &requestedDesc
, sizeof(requestedDesc
)) != noErr
) {
97 return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)";
100 /* Set the audio callback */
101 callback
.inputProc
= audioCallback
;
102 callback
.inputProcRefCon
= NULL
;
103 if (AudioUnitSetProperty(_outputAudioUnit
, kAudioUnitProperty_SetRenderCallback
, kAudioUnitScope_Input
, 0, &callback
, sizeof(callback
)) != noErr
) {
104 return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback)";
107 /* Finally, start processing of the audio unit */
108 if (AudioOutputUnitStart(_outputAudioUnit
) != noErr
) {
109 return "cocoa_s: Failed to start CoreAudio: AudioOutputUnitStart";
117 void SoundDriver_Cocoa::Stop()
119 struct AURenderCallbackStruct callback
;
121 /* stop processing the audio unit */
122 if (AudioOutputUnitStop(_outputAudioUnit
) != noErr
) {
123 DEBUG(driver
, 0, "cocoa_s: Core_CloseAudio: AudioOutputUnitStop failed");
127 /* Remove the input callback */
128 callback
.inputProc
= 0;
129 callback
.inputProcRefCon
= 0;
130 if (AudioUnitSetProperty(_outputAudioUnit
, kAudioUnitProperty_SetRenderCallback
, kAudioUnitScope_Input
, 0, &callback
, sizeof(callback
)) != noErr
) {
131 DEBUG(driver
, 0, "cocoa_s: Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback) failed");
135 if (CloseComponent(_outputAudioUnit
) != noErr
) {
136 DEBUG(driver
, 0, "cocoa_s: Core_CloseAudio: CloseComponent failed");
141 #endif /* WITH_COCOA */