comparison src/audio/macosx/SDL_coreaudio.c @ 935:f8d5ddc7aef1

Audio improvements from Max Horn, including a new CoreAudio driver for MacOSX
author Sam Lantinga <slouken@libsdl.org>
date Sat, 21 Aug 2004 02:06:30 +0000
parents
children 84f930aebaeb
comparison
equal deleted inserted replaced
934:af585d6efec8 935:f8d5ddc7aef1
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2004 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21 */
22
23 #ifdef SAVE_RCSID
24 static char rcsid =
25 "@(#) $Id$";
26 #endif
27
28 #include <AudioUnit/AudioUnit.h>
29
30 #include <assert.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34
35 #include "SDL_endian.h"
36 #include "SDL_audio.h"
37 #include "SDL_audio_c.h"
38 #include "SDL_audiomem.h"
39 #include "SDL_sysaudio.h"
40 #include "SDL_coreaudio.h"
41
42
43 /* Audio driver functions */
44
45 static int Core_OpenAudio(_THIS, SDL_AudioSpec *spec);
46 static void Core_WaitAudio(_THIS);
47 static void Core_PlayAudio(_THIS);
48 static Uint8 *Core_GetAudioBuf(_THIS);
49 static void Core_CloseAudio(_THIS);
50
51 /* Audio driver bootstrap functions */
52
53 static int Audio_Available(void)
54 {
55 return(1);
56 }
57
58 static void Audio_DeleteDevice(SDL_AudioDevice *device)
59 {
60 free(device->hidden);
61 free(device);
62 }
63
64 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
65 {
66 SDL_AudioDevice *this;
67
68 /* Initialize all variables that we clean on shutdown */
69 this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
70 if ( this ) {
71 memset(this, 0, (sizeof *this));
72 this->hidden = (struct SDL_PrivateAudioData *)
73 malloc((sizeof *this->hidden));
74 }
75 if ( (this == NULL) || (this->hidden == NULL) ) {
76 SDL_OutOfMemory();
77 if ( this ) {
78 free(this);
79 }
80 return(0);
81 }
82 memset(this->hidden, 0, (sizeof *this->hidden));
83
84 /* Set the function pointers */
85 this->OpenAudio = Core_OpenAudio;
86 this->WaitAudio = Core_WaitAudio;
87 this->PlayAudio = Core_PlayAudio;
88 this->GetAudioBuf = Core_GetAudioBuf;
89 this->CloseAudio = Core_CloseAudio;
90
91 this->free = Audio_DeleteDevice;
92
93 return this;
94 }
95
96 AudioBootStrap COREAUDIO_bootstrap = {
97 "coreaudio", "Mac OS X CoreAudio",
98 Audio_Available, Audio_CreateDevice
99 };
100
101 /* The CoreAudio callback */
102 static OSStatus audioCallback (void *inRefCon,
103 AudioUnitRenderActionFlags inActionFlags,
104 const AudioTimeStamp *inTimeStamp,
105 UInt32 inBusNumber,
106 AudioBuffer *ioData)
107 {
108 SDL_AudioDevice *this = (SDL_AudioDevice *)inRefCon;
109 UInt32 remaining, len;
110 void *ptr;
111
112 /* Only do anything if audio is enabled and not paused */
113 if ( ! this->enabled || this->paused ) {
114 memset(ioData->mData, this->spec.silence, ioData->mDataByteSize);
115 return 0;
116 }
117
118 /* No SDL conversion should be needed here, ever, since we accept
119 any input format in OpenAudio, and leave the conversion to CoreAudio.
120 */
121 assert(!this->convert.needed);
122 assert(this->spec.channels == ioData->mNumberChannels);
123
124 remaining = ioData->mDataByteSize;
125 ptr = ioData->mData;
126 while (remaining > 0) {
127 if (bufferOffset >= bufferSize) {
128 /* Generate the data */
129 memset(buffer, this->spec.silence, bufferSize);
130 SDL_mutexP(this->mixer_lock);
131 (*this->spec.callback)(this->spec.userdata,
132 buffer, bufferSize);
133 SDL_mutexV(this->mixer_lock);
134 bufferOffset = 0;
135 }
136
137 len = bufferSize - bufferOffset;
138 if (len > remaining)
139 len = remaining;
140 memcpy(ptr, buffer + bufferOffset, len);
141 ptr += len;
142 remaining -= len;
143 bufferOffset += len;
144 }
145
146 return 0;
147 }
148
149 /* Dummy functions -- we don't use thread-based audio */
150 void Core_WaitAudio(_THIS)
151 {
152 return;
153 }
154
155 void Core_PlayAudio(_THIS)
156 {
157 return;
158 }
159
160 Uint8 *Core_GetAudioBuf(_THIS)
161 {
162 return(NULL);
163 }
164
165 void Core_CloseAudio(_THIS)
166 {
167 OSStatus result;
168 AudioUnitInputCallback callback;
169
170 /* stop processing the audio unit */
171 result = AudioOutputUnitStop (outputAudioUnit);
172 if (result != noErr) {
173 SDL_SetError("Core_CloseAudio: AudioOutputUnitStop");
174 return;
175 }
176
177 /* Remove the input callback */
178 callback.inputProc = 0;
179 callback.inputProcRefCon = 0;
180 result = AudioUnitSetProperty (outputAudioUnit,
181 kAudioUnitProperty_SetInputCallback,
182 kAudioUnitScope_Input,
183 0,
184 &callback,
185 sizeof(callback));
186 if (result != noErr) {
187 SDL_SetError("Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)");
188 return;
189 }
190
191 result = CloseComponent(outputAudioUnit);
192 if (result != noErr) {
193 SDL_SetError("Core_CloseAudio: CloseComponent");
194 return;
195 }
196
197 free(buffer);
198 }
199
200 #define CHECK_RESULT(msg) \
201 if (result != noErr) { \
202 SDL_SetError("Failed to start CoreAudio: " msg); \
203 return -1; \
204 }
205
206
207 int Core_OpenAudio(_THIS, SDL_AudioSpec *spec)
208 {
209 OSStatus result = noErr;
210 Component comp;
211 ComponentDescription desc;
212 AudioUnitInputCallback callback;
213 AudioStreamBasicDescription requestedDesc;
214
215 /* Setup a AudioStreamBasicDescription with the requested format */
216 requestedDesc.mFormatID = kAudioFormatLinearPCM;
217 requestedDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
218 requestedDesc.mChannelsPerFrame = spec->channels;
219 requestedDesc.mSampleRate = spec->freq;
220
221 requestedDesc.mBitsPerChannel = spec->format & 0xFF;
222 if (spec->format & 0x8000)
223 requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
224 if (spec->format & 0x1000)
225 requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
226
227 requestedDesc.mFramesPerPacket = 1;
228 requestedDesc.mBytesPerFrame = requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8;
229 requestedDesc.mBytesPerPacket = requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket;
230
231
232 /* Locate the default output audio unit */
233 desc.componentType = kAudioUnitComponentType;
234 desc.componentSubType = kAudioUnitSubType_Output;
235 desc.componentManufacturer = kAudioUnitID_DefaultOutput;
236 desc.componentFlags = 0;
237 desc.componentFlagsMask = 0;
238
239 comp = FindNextComponent (NULL, &desc);
240 if (comp == NULL) {
241 SDL_SetError ("Failed to start CoreAudio: FindNextComponent returned NULL");
242 return -1;
243 }
244
245 /* Open & initialize the default output audio unit */
246 result = OpenAComponent (comp, &outputAudioUnit);
247 CHECK_RESULT("OpenAComponent")
248
249 result = AudioUnitInitialize (outputAudioUnit);
250 CHECK_RESULT("AudioUnitInitialize")
251
252 /* Set the input format of the audio unit. */
253 result = AudioUnitSetProperty (outputAudioUnit,
254 kAudioUnitProperty_StreamFormat,
255 kAudioUnitScope_Input,
256 0,
257 &requestedDesc,
258 sizeof (requestedDesc));
259 CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)")
260
261 /* Set the audio callback */
262 callback.inputProc = audioCallback;
263 callback.inputProcRefCon = this;
264 result = AudioUnitSetProperty (outputAudioUnit,
265 kAudioUnitProperty_SetInputCallback,
266 kAudioUnitScope_Input,
267 0,
268 &callback,
269 sizeof(callback));
270 CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)")
271
272 /* Calculate the final parameters for this audio specification */
273 SDL_CalculateAudioSpec(spec);
274
275 /* Allocate a sample buffer */
276 bufferOffset = bufferSize = this->spec.size;
277 buffer = malloc(bufferSize);
278 assert(buffer);
279
280 /* Finally, start processing of the audio unit */
281 result = AudioOutputUnitStart (outputAudioUnit);
282 CHECK_RESULT("AudioOutputUnitStart")
283
284
285 /* We're running! */
286 return(1);
287 }