OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

cocoa_s.cpp
Go to the documentation of this file.
1 /* $Id: cocoa_s.cpp 26482 2014-04-23 20:13:33Z rubidium $ */
2
3 /*
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/>.
8 */
9
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 *****************************************************************************/
17
18 #ifdef WITH_COCOA
19
20 #include "../stdafx.h"
21 #include "../debug.h"
22 #include "../driver.h"
23 #include "../mixer.h"
24 #include "../core/endian_type.hpp"
25 #include "cocoa_s.h"
26
27 #define Rect OTTDRect
28 #define Point OTTDPoint
29 #include <AudioUnit/AudioUnit.h>
30 #undef Rect
31 #undef Point
32
33 #include "../safeguards.h"
34
35 static FSoundDriver_Cocoa iFSoundDriver_Cocoa;
36
37 static AudioUnit _outputAudioUnit;
38
39 /* The CoreAudio callback */
40 static OSStatus audioCallback(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData)
41 {
42 MxMixSamples(ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize / 4);
43
44 return noErr;
45 }
46
47
48 const char *SoundDriver_Cocoa::Start(const char * const *parm)
49 {
50 Component comp;
51 ComponentDescription desc;
52 struct AURenderCallbackStruct callback;
53 AudioStreamBasicDescription requestedDesc;
54
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);
60
61 requestedDesc.mBitsPerChannel = 16;
62 requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
63
64 #if TTD_ENDIAN == TTD_BIG_ENDIAN
65 requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
66 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
67
68 requestedDesc.mFramesPerPacket = 1;
69 requestedDesc.mBytesPerFrame = requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8;
70 requestedDesc.mBytesPerPacket = requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket;
71
72 MxInitialize((uint)requestedDesc.mSampleRate);
73
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;
80
81 comp = FindNextComponent (NULL, &desc);
82 if (comp == NULL) {
83 return "cocoa_s: Failed to start CoreAudio: FindNextComponent returned NULL";
84 }
85
86 /* Open & initialize the default output audio unit */
87 if (OpenAComponent(comp, &_outputAudioUnit) != noErr) {
88 return "cocoa_s: Failed to start CoreAudio: OpenAComponent";
89 }
90
91 if (AudioUnitInitialize(_outputAudioUnit) != noErr) {
92 return "cocoa_s: Failed to start CoreAudio: AudioUnitInitialize";
93 }
94
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)";
98 }
99
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)";
105 }
106
107 /* Finally, start processing of the audio unit */
108 if (AudioOutputUnitStart(_outputAudioUnit) != noErr) {
109 return "cocoa_s: Failed to start CoreAudio: AudioOutputUnitStart";
110 }
111
112 /* We're running! */
113 return NULL;
114 }
115
116
117 void SoundDriver_Cocoa::Stop()
118 {
119 struct AURenderCallbackStruct callback;
120
121 /* stop processing the audio unit */
122 if (AudioOutputUnitStop(_outputAudioUnit) != noErr) {
123 DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: AudioOutputUnitStop failed");
124 return;
125 }
126
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");
132 return;
133 }
134
135 if (CloseComponent(_outputAudioUnit) != noErr) {
136 DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: CloseComponent failed");
137 return;
138 }
139 }
140
141 #endif /* WITH_COCOA */