Mercurial > sdl-ios-xcode
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 |