OpenTTD Source: src/sound/cocoa_s.cpp Source File

OpenTTD Source 12.0-beta1

cocoa_s.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
7
10 /*****************************************************************************
11 * Cocoa sound driver *
12 * Known things left to do: *
13 * - Might need to do endian checking for it to work on both ppc and x86 *
14 *****************************************************************************/
15
16 #ifdef WITH_COCOA
17
18 #include "../stdafx.h"
19 #include "../os/macosx/macos.h"
20 #include "../debug.h"
21 #include "../driver.h"
22 #include "../mixer.h"
23 #include "../core/endian_type.hpp"
24 #include "cocoa_s.h"
25
26 #define Rect OTTDRect
27 #define Point OTTDPoint
28 #include <AudioUnit/AudioUnit.h>
29 #undef Rect
30 #undef Point
31
32 #include "../safeguards.h"
33
34 static FSoundDriver_Cocoa iFSoundDriver_Cocoa;
35
36 static AudioUnit _outputAudioUnit;
37
38 /* The CoreAudio callback */
39 static OSStatus audioCallback(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData)
40 {
41 MxMixSamples(ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize / 4);
42
43 return noErr;
44 }
45
46
47 const char *SoundDriver_Cocoa::Start(const StringList &parm)
48 {
49 struct AURenderCallbackStruct callback;
50 AudioStreamBasicDescription requestedDesc;
51
52 /* Setup a AudioStreamBasicDescription with the requested format */
53 requestedDesc.mFormatID = kAudioFormatLinearPCM;
54 requestedDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
55 requestedDesc.mChannelsPerFrame = 2;
56 requestedDesc.mSampleRate = GetDriverParamInt(parm, "hz", 44100);
57
58 requestedDesc.mBitsPerChannel = 16;
59 requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
60
61 #if TTD_ENDIAN == TTD_BIG_ENDIAN
62 requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
63 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
64
65 requestedDesc.mFramesPerPacket = 1;
66 requestedDesc.mBytesPerFrame = requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8;
67 requestedDesc.mBytesPerPacket = requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket;
68
69 MxInitialize((uint)requestedDesc.mSampleRate);
70
71 /* Locate the default output audio unit */
72 AudioComponentDescription desc;
73 desc.componentType = kAudioUnitType_Output;
74 desc.componentSubType = kAudioUnitSubType_HALOutput;
75 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
76 desc.componentFlags = 0;
77 desc.componentFlagsMask = 0;
78
79 AudioComponent comp = AudioComponentFindNext (nullptr, &desc);
80 if (comp == nullptr) {
81 return "cocoa_s: Failed to start CoreAudio: AudioComponentFindNext returned nullptr";
82 }
83
84 /* Open & initialize the default output audio unit */
85 if (AudioComponentInstanceNew(comp, &_outputAudioUnit) != noErr) {
86 return "cocoa_s: Failed to start CoreAudio: AudioComponentInstanceNew";
87 }
88
89 if (AudioUnitInitialize(_outputAudioUnit) != noErr) {
90 return "cocoa_s: Failed to start CoreAudio: AudioUnitInitialize";
91 }
92
93 /* Set the input format of the audio unit. */
94 if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &requestedDesc, sizeof(requestedDesc)) != noErr) {
95 return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)";
96 }
97
98 /* Set the audio callback */
99 callback.inputProc = audioCallback;
100 callback.inputProcRefCon = nullptr;
101 if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) {
102 return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback)";
103 }
104
105 /* Finally, start processing of the audio unit */
106 if (AudioOutputUnitStart(_outputAudioUnit) != noErr) {
107 return "cocoa_s: Failed to start CoreAudio: AudioOutputUnitStart";
108 }
109
110 /* We're running! */
111 return nullptr;
112 }
113
114
115 void SoundDriver_Cocoa::Stop()
116 {
117 struct AURenderCallbackStruct callback;
118
119 /* stop processing the audio unit */
120 if (AudioOutputUnitStop(_outputAudioUnit) != noErr) {
121 Debug(driver, 0, "cocoa_s: Core_CloseAudio: AudioOutputUnitStop failed");
122 return;
123 }
124
125 /* Remove the input callback */
126 callback.inputProc = 0;
127 callback.inputProcRefCon = 0;
128 if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) {
129 Debug(driver, 0, "cocoa_s: Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback) failed");
130 return;
131 }
132
133 if (AudioComponentInstanceDispose(_outputAudioUnit) != noErr) {
134 Debug(driver, 0, "cocoa_s: Core_CloseAudio: AudioComponentInstanceDispose failed");
135 return;
136 }
137 }
138
139 #endif /* WITH_COCOA */
cocoa_s.h
SoundDriver_Cocoa::Stop
void Stop() override
Stop this driver.
StringList
std::vector< std::string > StringList
Type for a list of strings.
Definition: string_type.h:58
FSoundDriver_Cocoa
Definition: cocoa_s.h:23
GetDriverParamInt
int GetDriverParamInt(const StringList &parm, const char *name, int def)
Get an integer parameter the list of parameters.
Definition: driver.cpp:73
Debug
#define Debug(name, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
SoundDriver_Cocoa::Start
const char * Start(const StringList &param) override
Start this driver.