comparison src/audio/macosx/SDL_coreaudio.c @ 3784:37c9c4590689 SDL-ryan-multiple-audio-device

First batch of heavy lifting on supporting multiple audio devices at once. This has a long way to go yet, most of the drivers aren't updated for the new interfaces, and it's still got some obvious bugs, FIXMEs, and wistlist items. Don't use yet.
author Ryan C. Gordon <icculus@icculus.org>
date Sun, 01 Oct 2006 05:24:03 +0000
parents adf732f1f016
children da2ea0694d11
comparison
equal deleted inserted replaced
3783:dc3870a3f30d 3784:37c9c4590689
29 #include "SDL_coreaudio.h" 29 #include "SDL_coreaudio.h"
30 30
31 31
32 /* Audio driver functions */ 32 /* Audio driver functions */
33 33
34 static int Core_OpenAudio(_THIS, SDL_AudioSpec * spec); 34 static int COREAUDIO_OpenAudio(_THIS, const char *devname, int iscapture);
35 static void Core_WaitAudio(_THIS); 35 static void COREAUDIO_WaitAudio(_THIS);
36 static void Core_PlayAudio(_THIS); 36 static void COREAUDIO_PlayAudio(_THIS);
37 static Uint8 *Core_GetAudioBuf(_THIS); 37 static Uint8 *COREAUDIO_GetAudioBuf(_THIS);
38 static void Core_CloseAudio(_THIS); 38 static void COREAUDIO_CloseAudio(_THIS);
39 39
40 /* Audio driver bootstrap functions */ 40 /* Audio driver bootstrap functions */
41 41
42 static int 42 static int
43 Audio_Available(void) 43 COREAUDIO_Available(void)
44 { 44 {
45 return (1); 45 return (1);
46 } 46 }
47 47
48 static void 48 static int
49 Audio_DeleteDevice(SDL_AudioDevice * device) 49 COREAUDIO_Init(SDL_AudioDriverImpl *impl)
50 { 50 {
51 SDL_free(device->hidden);
52 SDL_free(device);
53 }
54
55 static SDL_AudioDevice *
56 Audio_CreateDevice(int devindex)
57 {
58 SDL_AudioDevice *this;
59
60 /* Initialize all variables that we clean on shutdown */
61 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
62 if (this) {
63 SDL_memset(this, 0, (sizeof *this));
64 this->hidden = (struct SDL_PrivateAudioData *)
65 SDL_malloc((sizeof *this->hidden));
66 }
67 if ((this == NULL) || (this->hidden == NULL)) {
68 SDL_OutOfMemory();
69 if (this) {
70 SDL_free(this);
71 }
72 return (0);
73 }
74 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
75
76 /* Set the function pointers */ 51 /* Set the function pointers */
77 this->OpenAudio = Core_OpenAudio; 52 impl->OpenAudio = COREAUDIO_OpenAudio;
78 this->WaitAudio = Core_WaitAudio; 53 impl->WaitAudio = COREAUDIO_WaitAudio;
79 this->PlayAudio = Core_PlayAudio; 54 impl->PlayAudio = COREAUDIO_PlayAudio;
80 this->GetAudioBuf = Core_GetAudioBuf; 55 impl->GetAudioBuf = COREAUDIO_GetAudioBuf;
81 this->CloseAudio = Core_CloseAudio; 56 impl->CloseAudio = COREAUDIO_CloseAudio;
82 57
83 this->free = Audio_DeleteDevice; 58 return 1;
84
85 return this;
86 } 59 }
87 60
88 AudioBootStrap COREAUDIO_bootstrap = { 61 AudioBootStrap COREAUDIO_bootstrap = {
89 "coreaudio", "Mac OS X CoreAudio", 62 "coreaudio", "Mac OS X CoreAudio",
90 Audio_Available, Audio_CreateDevice 63 COREAUDIO_Available, COREAUDIO_Init
91 }; 64 };
92 65
93 /* The CoreAudio callback */ 66 /* The CoreAudio callback */
94 static OSStatus 67 static OSStatus
95 audioCallback(void *inRefCon, 68 audioCallback(void *inRefCon,
116 */ 89 */
117 90
118 remaining = ioData->mDataByteSize; 91 remaining = ioData->mDataByteSize;
119 ptr = ioData->mData; 92 ptr = ioData->mData;
120 while (remaining > 0) { 93 while (remaining > 0) {
121 if (bufferOffset >= bufferSize) { 94 if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
122 /* Generate the data */ 95 /* Generate the data */
123 SDL_memset(buffer, this->spec.silence, bufferSize); 96 SDL_memset(this->hidden->buffer, this->spec.silence,
97 this->hidden->bufferSize);
124 SDL_mutexP(this->mixer_lock); 98 SDL_mutexP(this->mixer_lock);
125 (*this->spec.callback) (this->spec.userdata, buffer, bufferSize); 99 (*this->spec.callback) (this->spec.userdata, this->hidden->buffer,
100 this->hidden->bufferSize);
126 SDL_mutexV(this->mixer_lock); 101 SDL_mutexV(this->mixer_lock);
127 bufferOffset = 0; 102 this->hidden->bufferOffset = 0;
128 } 103 }
129 104
130 len = bufferSize - bufferOffset; 105 len = this->hidden->bufferSize - this->hidden->bufferOffset;
131 if (len > remaining) 106 if (len > remaining)
132 len = remaining; 107 len = remaining;
133 SDL_memcpy(ptr, (char *) buffer + bufferOffset, len); 108 SDL_memcpy(ptr,
109 (char *) this->hidden->buffer + this->hidden->bufferOffset,
110 len);
134 ptr = (char *) ptr + len; 111 ptr = (char *) ptr + len;
135 remaining -= len; 112 remaining -= len;
136 bufferOffset += len; 113 this->hidden->bufferOffset += len;
137 } 114 }
138 115
139 return 0; 116 return 0;
140 } 117 }
141 118
142 /* Dummy functions -- we don't use thread-based audio */ 119 /* Dummy functions -- we don't use thread-based audio */
143 void 120 void
144 Core_WaitAudio(_THIS) 121 COREAUDIO_WaitAudio(_THIS)
145 { 122 {
146 return; 123 return;
147 } 124 }
148 125
149 void 126 void
150 Core_PlayAudio(_THIS) 127 COREAUDIO_PlayAudio(_THIS)
151 { 128 {
152 return; 129 return;
153 } 130 }
154 131
155 Uint8 * 132 Uint8 *
156 Core_GetAudioBuf(_THIS) 133 COREAUDIO_GetAudioBuf(_THIS)
157 { 134 {
158 return (NULL); 135 return (NULL);
159 } 136 }
160 137
161 void 138 void
162 Core_CloseAudio(_THIS) 139 COREAUDIO_CloseAudio(_THIS)
163 { 140 {
164 OSStatus result; 141 OSStatus result;
165 struct AudioUnitInputCallback callback; 142 struct AudioUnitInputCallback callback;
166 143
144 if (this->hidden == NULL) {
145 return;
146 }
147
167 /* stop processing the audio unit */ 148 /* stop processing the audio unit */
168 result = AudioOutputUnitStop(outputAudioUnit); 149 result = AudioOutputUnitStop(this->hidden->outputAudioUnit);
169 if (result != noErr) { 150 if (result != noErr) {
170 SDL_SetError("Core_CloseAudio: AudioOutputUnitStop"); 151 SDL_SetError("COREAUDIO_CloseAudio: AudioOutputUnitStop");
171 return; 152 return;
172 } 153 }
173 154
174 /* Remove the input callback */ 155 /* Remove the input callback */
175 callback.inputProc = 0; 156 callback.inputProc = 0;
176 callback.inputProcRefCon = 0; 157 callback.inputProcRefCon = 0;
177 result = AudioUnitSetProperty(outputAudioUnit, 158 result = AudioUnitSetProperty(this->hidden->outputAudioUnit,
178 kAudioUnitProperty_SetInputCallback, 159 kAudioUnitProperty_SetInputCallback,
179 kAudioUnitScope_Input, 160 kAudioUnitScope_Input,
180 0, &callback, sizeof(callback)); 161 0, &callback, sizeof(callback));
181 if (result != noErr) { 162 if (result != noErr) {
182 SDL_SetError 163 SDL_SetError
183 ("Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)"); 164 ("COREAUDIO_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)");
184 return; 165 return;
185 } 166 }
186 167
187 result = CloseComponent(outputAudioUnit); 168 result = CloseComponent(this->hidden->outputAudioUnit);
188 if (result != noErr) { 169 if (result != noErr) {
189 SDL_SetError("Core_CloseAudio: CloseComponent"); 170 SDL_SetError("COREAUDIO_CloseAudio: CloseComponent");
190 return; 171 return;
191 } 172 }
192 173
193 SDL_free(buffer); 174 SDL_free(this->hidden->buffer);
175 SDL_free(this->hidden);
176 this->hidden = NULL;
194 } 177 }
195 178
196 #define CHECK_RESULT(msg) \ 179 #define CHECK_RESULT(msg) \
197 if (result != noErr) { \ 180 if (result != noErr) { \
181 COREAUDIO_CloseAudio(this); \
198 SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \ 182 SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
199 return -1; \ 183 return -1; \
200 } 184 }
201 185
202 186
203 int 187 int
204 Core_OpenAudio(_THIS, SDL_AudioSpec * spec) 188 COREAUDIO_OpenAudio(_THIS, const char *devname, int iscapture)
205 { 189 {
206 OSStatus result = noErr; 190 OSStatus result = noErr;
207 Component comp; 191 Component comp;
208 ComponentDescription desc; 192 ComponentDescription desc;
209 struct AudioUnitInputCallback callback; 193 struct AudioUnitInputCallback callback;
210 AudioStreamBasicDescription strdesc; 194 AudioStreamBasicDescription strdesc;
211 SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format); 195 SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
212 int valid_datatype = 0; 196 int valid_datatype = 0;
197
198 /* Initialize all variables that we clean on shutdown */
199 this->hidden = (struct SDL_PrivateAudioData *)
200 SDL_malloc((sizeof *this->hidden));
201 if (this->hidden == NULL) {
202 SDL_OutOfMemory();
203 return (0);
204 }
205 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
206
207 /* !!! FIXME: check devname and iscapture... */
213 208
214 /* Setup a AudioStreamBasicDescription with the requested format */ 209 /* Setup a AudioStreamBasicDescription with the requested format */
215 memset(&strdesc, '\0', sizeof(AudioStreamBasicDescription)); 210 memset(&strdesc, '\0', sizeof(AudioStreamBasicDescription));
216 strdesc.mFormatID = kAudioFormatLinearPCM; 211 strdesc.mFormatID = kAudioFormatLinearPCM;
217 strdesc.mFormatFlags = kLinearPCMFormatFlagIsPacked; 212 strdesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
218 strdesc.mChannelsPerFrame = spec->channels; 213 strdesc.mChannelsPerFrame = this->spec.channels;
219 strdesc.mSampleRate = spec->freq; 214 strdesc.mSampleRate = this->spec.freq;
220 strdesc.mFramesPerPacket = 1; 215 strdesc.mFramesPerPacket = 1;
221 216
222 while ((!valid_datatype) && (test_format)) { 217 while ((!valid_datatype) && (test_format)) {
223 spec->format = test_format; 218 this->spec.format = test_format;
224 /* Just a list of valid SDL formats, so people don't pass junk here. */ 219 /* Just a list of valid SDL formats, so people don't pass junk here. */
225 switch (test_format) { 220 switch (test_format) {
226 case AUDIO_U8: 221 case AUDIO_U8:
227 case AUDIO_S8: 222 case AUDIO_S8:
228 case AUDIO_U16LSB: 223 case AUDIO_U16LSB:
232 case AUDIO_S32LSB: 227 case AUDIO_S32LSB:
233 case AUDIO_S32MSB: 228 case AUDIO_S32MSB:
234 case AUDIO_F32LSB: 229 case AUDIO_F32LSB:
235 case AUDIO_F32MSB: 230 case AUDIO_F32MSB:
236 valid_datatype = 1; 231 valid_datatype = 1;
237 strdesc.mBitsPerChannel = SDL_AUDIO_BITSIZE(spec->format); 232 strdesc.mBitsPerChannel = SDL_AUDIO_BITSIZE(this->spec.format);
238 if (SDL_AUDIO_ISBIGENDIAN(spec->format)) 233 if (SDL_AUDIO_ISBIGENDIAN(this->spec.format))
239 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; 234 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
240 235
241 if (SDL_AUDIO_ISFLOAT(spec->format)) 236 if (SDL_AUDIO_ISFLOAT(this->spec.format))
242 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsFloat; 237 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
243 else if (SDL_AUDIO_ISSIGNED(spec->format)) 238 else if (SDL_AUDIO_ISSIGNED(this->spec.format))
244 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; 239 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
245 break; 240 break;
246 } 241 }
247 } 242 }
248 243
249 if (!valid_datatype) { /* shouldn't happen, but just in case... */ 244 if (!valid_datatype) { /* shouldn't happen, but just in case... */
250 SDL_SetError("Unsupported audio format"); 245 SDL_SetError("Unsupported audio format");
251 return (-1); 246 return 0;
252 } 247 }
253 248
254 strdesc.mBytesPerFrame = 249 strdesc.mBytesPerFrame =
255 strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8; 250 strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8;
256 strdesc.mBytesPerPacket = 251 strdesc.mBytesPerPacket =
264 desc.componentFlags = 0; 259 desc.componentFlags = 0;
265 desc.componentFlagsMask = 0; 260 desc.componentFlagsMask = 0;
266 261
267 comp = FindNextComponent(NULL, &desc); 262 comp = FindNextComponent(NULL, &desc);
268 if (comp == NULL) { 263 if (comp == NULL) {
264 COREAUDIO_CloseAudio(this);
269 SDL_SetError 265 SDL_SetError
270 ("Failed to start CoreAudio: FindNextComponent returned NULL"); 266 ("Failed to start CoreAudio: FindNextComponent returned NULL");
271 return -1; 267 return 0;
272 } 268 }
273 269
274 /* Open & initialize the default output audio unit */ 270 /* Open & initialize the default output audio unit */
275 result = OpenAComponent(comp, &outputAudioUnit); 271 result = OpenAComponent(comp, &this->hidden->outputAudioUnit);
276 CHECK_RESULT("OpenAComponent") 272 CHECK_RESULT("OpenAComponent")
277 result = AudioUnitInitialize(outputAudioUnit); 273 result = AudioUnitInitialize(this->hidden->outputAudioUnit);
278 CHECK_RESULT("AudioUnitInitialize") 274 CHECK_RESULT("AudioUnitInitialize")
279 /* Set the input format of the audio unit. */ 275 /* Set the input format of the audio unit. */
280 result = AudioUnitSetProperty(outputAudioUnit, 276 result = AudioUnitSetProperty(this->hidden->outputAudioUnit,
281 kAudioUnitProperty_StreamFormat, 277 kAudioUnitProperty_StreamFormat,
282 kAudioUnitScope_Input, 278 kAudioUnitScope_Input,
283 0, &strdesc, sizeof(strdesc)); 279 0, &strdesc, sizeof(strdesc));
284 CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)") 280 CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)")
285 /* Set the audio callback */ 281 /* Set the audio callback */
286 callback.inputProc = audioCallback; 282 callback.inputProc = audioCallback;
287 callback.inputProcRefCon = this; 283 callback.inputProcRefCon = this;
288 result = AudioUnitSetProperty(outputAudioUnit, 284 result = AudioUnitSetProperty(this->hidden->outputAudioUnit,
289 kAudioUnitProperty_SetInputCallback, 285 kAudioUnitProperty_SetInputCallback,
290 kAudioUnitScope_Input, 286 kAudioUnitScope_Input,
291 0, &callback, sizeof(callback)); 287 0, &callback, sizeof(callback));
292 CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)") 288 CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)")
293 /* Calculate the final parameters for this audio specification */ 289 /* Calculate the final parameters for this audio specification */
294 SDL_CalculateAudioSpec(spec); 290 SDL_CalculateAudioSpec(&this->spec);
295 291
296 /* Allocate a sample buffer */ 292 /* Allocate a sample buffer */
297 bufferOffset = bufferSize = this->spec.size; 293 this->hidden->bufferOffset = this->hidden->bufferSize = this->spec.size;
298 buffer = SDL_malloc(bufferSize); 294 this->hidden->buffer = SDL_malloc(this->hidden->bufferSize);
299 295
300 /* Finally, start processing of the audio unit */ 296 /* Finally, start processing of the audio unit */
301 result = AudioOutputUnitStart(outputAudioUnit); 297 result = AudioOutputUnitStart(this->hidden->outputAudioUnit);
302 CHECK_RESULT("AudioOutputUnitStart") 298 CHECK_RESULT("AudioOutputUnitStart")
303 /* We're running! */ 299 /* We're running! */
304 return (1); 300 return (1);
305 } 301 }
306 302