SDL  2.0
SDL_coreaudio.m
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #if SDL_AUDIO_DRIVER_COREAUDIO
24 
25 /* !!! FIXME: clean out some of the macro salsa in here. */
26 
27 #include "SDL_audio.h"
28 #include "SDL_hints.h"
29 #include "../SDL_audio_c.h"
30 #include "../SDL_sysaudio.h"
31 #include "SDL_coreaudio.h"
32 #include "SDL_assert.h"
33 #include "../../thread/SDL_systhread.h"
34 
35 #define DEBUG_COREAUDIO 0
36 
37 #define CHECK_RESULT(msg) \
38  if (result != noErr) { \
39  SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
40  return 0; \
41  }
42 
43 #if MACOSX_COREAUDIO
44 static const AudioObjectPropertyAddress devlist_address = {
45  kAudioHardwarePropertyDevices,
46  kAudioObjectPropertyScopeGlobal,
47  kAudioObjectPropertyElementMaster
48 };
49 
50 typedef void (*addDevFn)(const char *name, const int iscapture, AudioDeviceID devId, void *data);
51 
52 typedef struct AudioDeviceList
53 {
54  AudioDeviceID devid;
56  struct AudioDeviceList *next;
57 } AudioDeviceList;
58 
59 static AudioDeviceList *output_devs = NULL;
60 static AudioDeviceList *capture_devs = NULL;
61 
62 static SDL_bool
63 add_to_internal_dev_list(const int iscapture, AudioDeviceID devId)
64 {
65  AudioDeviceList *item = (AudioDeviceList *) SDL_malloc(sizeof (AudioDeviceList));
66  if (item == NULL) {
67  return SDL_FALSE;
68  }
69  item->devid = devId;
70  item->alive = SDL_TRUE;
71  item->next = iscapture ? capture_devs : output_devs;
72  if (iscapture) {
73  capture_devs = item;
74  } else {
75  output_devs = item;
76  }
77 
78  return SDL_TRUE;
79 }
80 
81 static void
82 addToDevList(const char *name, const int iscapture, AudioDeviceID devId, void *data)
83 {
84  if (add_to_internal_dev_list(iscapture, devId)) {
85  SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
86  }
87 }
88 
89 static void
90 build_device_list(int iscapture, addDevFn addfn, void *addfndata)
91 {
92  OSStatus result = noErr;
93  UInt32 size = 0;
94  AudioDeviceID *devs = NULL;
95  UInt32 i = 0;
96  UInt32 max = 0;
97 
98  result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
99  &devlist_address, 0, NULL, &size);
100  if (result != kAudioHardwareNoError)
101  return;
102 
103  devs = (AudioDeviceID *) alloca(size);
104  if (devs == NULL)
105  return;
106 
107  result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
108  &devlist_address, 0, NULL, &size, devs);
109  if (result != kAudioHardwareNoError)
110  return;
111 
112  max = size / sizeof (AudioDeviceID);
113  for (i = 0; i < max; i++) {
114  CFStringRef cfstr = NULL;
115  char *ptr = NULL;
116  AudioDeviceID dev = devs[i];
117  AudioBufferList *buflist = NULL;
118  int usable = 0;
119  CFIndex len = 0;
120  const AudioObjectPropertyAddress addr = {
121  kAudioDevicePropertyStreamConfiguration,
122  iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
123  kAudioObjectPropertyElementMaster
124  };
125 
126  const AudioObjectPropertyAddress nameaddr = {
127  kAudioObjectPropertyName,
128  iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
129  kAudioObjectPropertyElementMaster
130  };
131 
132  result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size);
133  if (result != noErr)
134  continue;
135 
136  buflist = (AudioBufferList *) SDL_malloc(size);
137  if (buflist == NULL)
138  continue;
139 
140  result = AudioObjectGetPropertyData(dev, &addr, 0, NULL,
141  &size, buflist);
142 
143  if (result == noErr) {
144  UInt32 j;
145  for (j = 0; j < buflist->mNumberBuffers; j++) {
146  if (buflist->mBuffers[j].mNumberChannels > 0) {
147  usable = 1;
148  break;
149  }
150  }
151  }
152 
153  SDL_free(buflist);
154 
155  if (!usable)
156  continue;
157 
158 
159  size = sizeof (CFStringRef);
160  result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr);
161  if (result != kAudioHardwareNoError)
162  continue;
163 
164  len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
165  kCFStringEncodingUTF8);
166 
167  ptr = (char *) SDL_malloc(len + 1);
168  usable = ((ptr != NULL) &&
169  (CFStringGetCString
170  (cfstr, ptr, len + 1, kCFStringEncodingUTF8)));
171 
172  CFRelease(cfstr);
173 
174  if (usable) {
175  len = strlen(ptr);
176  /* Some devices have whitespace at the end...trim it. */
177  while ((len > 0) && (ptr[len - 1] == ' ')) {
178  len--;
179  }
180  usable = (len > 0);
181  }
182 
183  if (usable) {
184  ptr[len] = '\0';
185 
186 #if DEBUG_COREAUDIO
187  printf("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n",
188  ((iscapture) ? "capture" : "output"),
189  (int) i, ptr, (int) dev);
190 #endif
191  addfn(ptr, iscapture, dev, addfndata);
192  }
193  SDL_free(ptr); /* addfn() would have copied the string. */
194  }
195 }
196 
197 static void
198 free_audio_device_list(AudioDeviceList **list)
199 {
200  AudioDeviceList *item = *list;
201  while (item) {
202  AudioDeviceList *next = item->next;
203  SDL_free(item);
204  item = next;
205  }
206  *list = NULL;
207 }
208 
209 static void
210 COREAUDIO_DetectDevices(void)
211 {
212  build_device_list(SDL_TRUE, addToDevList, NULL);
213  build_device_list(SDL_FALSE, addToDevList, NULL);
214 }
215 
216 static void
217 build_device_change_list(const char *name, const int iscapture, AudioDeviceID devId, void *data)
218 {
219  AudioDeviceList **list = (AudioDeviceList **) data;
220  AudioDeviceList *item;
221  for (item = *list; item != NULL; item = item->next) {
222  if (item->devid == devId) {
223  item->alive = SDL_TRUE;
224  return;
225  }
226  }
227 
228  add_to_internal_dev_list(iscapture, devId); /* new device, add it. */
229  SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
230 }
231 
232 static void
233 reprocess_device_list(const int iscapture, AudioDeviceList **list)
234 {
235  AudioDeviceList *item;
236  AudioDeviceList *prev = NULL;
237  for (item = *list; item != NULL; item = item->next) {
238  item->alive = SDL_FALSE;
239  }
240 
241  build_device_list(iscapture, build_device_change_list, list);
242 
243  /* free items in the list that aren't still alive. */
244  item = *list;
245  while (item != NULL) {
246  AudioDeviceList *next = item->next;
247  if (item->alive) {
248  prev = item;
249  } else {
250  SDL_RemoveAudioDevice(iscapture, (void *) ((size_t) item->devid));
251  if (prev) {
252  prev->next = item->next;
253  } else {
254  *list = item->next;
255  }
256  SDL_free(item);
257  }
258  item = next;
259  }
260 }
261 
262 /* this is called when the system's list of available audio devices changes. */
263 static OSStatus
264 device_list_changed(AudioObjectID systemObj, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
265 {
266  reprocess_device_list(SDL_TRUE, &capture_devs);
267  reprocess_device_list(SDL_FALSE, &output_devs);
268  return 0;
269 }
270 #endif
271 
272 
273 static int open_playback_devices = 0;
274 static int open_capture_devices = 0;
275 
276 #if !MACOSX_COREAUDIO
277 
278 static void interruption_begin(_THIS)
279 {
280  if (this != NULL && this->hidden->audioQueue != NULL) {
281  this->hidden->interrupted = SDL_TRUE;
282  AudioQueuePause(this->hidden->audioQueue);
283  }
284 }
285 
286 static void interruption_end(_THIS)
287 {
288  if (this != NULL && this->hidden != NULL && this->hidden->audioQueue != NULL
289  && this->hidden->interrupted
290  && AudioQueueStart(this->hidden->audioQueue, NULL) == AVAudioSessionErrorCodeNone) {
291  this->hidden->interrupted = SDL_FALSE;
292  }
293 }
294 
295 @interface SDLInterruptionListener : NSObject
296 
297 @property (nonatomic, assign) SDL_AudioDevice *device;
298 
299 @end
300 
301 @implementation SDLInterruptionListener
302 
303 - (void)audioSessionInterruption:(NSNotification *)note
304 {
305  @synchronized (self) {
306  NSNumber *type = note.userInfo[AVAudioSessionInterruptionTypeKey];
307  if (type.unsignedIntegerValue == AVAudioSessionInterruptionTypeBegan) {
308  interruption_begin(self.device);
309  } else {
310  interruption_end(self.device);
311  }
312  }
313 }
314 
315 - (void)applicationBecameActive:(NSNotification *)note
316 {
317  @synchronized (self) {
318  interruption_end(self.device);
319  }
320 }
321 
322 @end
323 
324 static BOOL update_audio_session(_THIS, SDL_bool open)
325 {
326  @autoreleasepool {
327  AVAudioSession *session = [AVAudioSession sharedInstance];
328  NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
329 
330  /* Set category to ambient by default so that other music continues playing. */
331  NSString *category = AVAudioSessionCategoryAmbient;
332  NSString *mode = AVAudioSessionModeDefault;
333  NSUInteger options = 0;
334  NSError *err = nil;
335 
336  if (open_playback_devices && open_capture_devices) {
337  category = AVAudioSessionCategoryPlayAndRecord;
338 #if !TARGET_OS_TV
339  options = AVAudioSessionCategoryOptionDefaultToSpeaker;
340 #endif
341  } else if (open_capture_devices) {
342  category = AVAudioSessionCategoryRecord;
343  } else {
344  const char *hint = SDL_GetHint(SDL_HINT_AUDIO_CATEGORY);
345  if (hint) {
346  if (SDL_strcasecmp(hint, "AVAudioSessionCategoryAmbient") == 0) {
347  category = AVAudioSessionCategoryAmbient;
348  } else if (SDL_strcasecmp(hint, "AVAudioSessionCategorySoloAmbient") == 0) {
349  category = AVAudioSessionCategorySoloAmbient;
350  } else if (SDL_strcasecmp(hint, "AVAudioSessionCategoryPlayback") == 0 ||
351  SDL_strcasecmp(hint, "playback") == 0) {
352  category = AVAudioSessionCategoryPlayback;
353  }
354  }
355  }
356 
357  if ([session respondsToSelector:@selector(setCategory:mode:options:error:)]) {
358  if (![session setCategory:category mode:mode options:options error:&err]) {
359  NSString *desc = err.description;
360  SDL_SetError("Could not set Audio Session category: %s", desc.UTF8String);
361  return NO;
362  }
363  } else {
364  if (![session setCategory:category error:&err]) {
365  NSString *desc = err.description;
366  SDL_SetError("Could not set Audio Session category: %s", desc.UTF8String);
367  return NO;
368  }
369  }
370 
371  if (open && (open_playback_devices + open_capture_devices) == 1) {
372  if (![session setActive:YES error:&err]) {
373  NSString *desc = err.description;
374  SDL_SetError("Could not activate Audio Session: %s", desc.UTF8String);
375  return NO;
376  }
377  } else if (!open_playback_devices && !open_capture_devices) {
378  [session setActive:NO error:nil];
379  }
380 
381  if (open) {
382  SDLInterruptionListener *listener = [SDLInterruptionListener new];
383  listener.device = this;
384 
385  [center addObserver:listener
386  selector:@selector(audioSessionInterruption:)
387  name:AVAudioSessionInterruptionNotification
388  object:session];
389 
390  /* An interruption end notification is not guaranteed to be sent if
391  we were previously interrupted... resuming if needed when the app
392  becomes active seems to be the way to go. */
393  // Note: object: below needs to be nil, as otherwise it filters by the object, and session doesn't send foreground / active notifications. johna
394  [center addObserver:listener
395  selector:@selector(applicationBecameActive:)
396  name:UIApplicationDidBecomeActiveNotification
397  object:nil];
398 
399  [center addObserver:listener
400  selector:@selector(applicationBecameActive:)
401  name:UIApplicationWillEnterForegroundNotification
402  object:nil];
403 
404  this->hidden->interruption_listener = CFBridgingRetain(listener);
405  } else {
406  if (this->hidden->interruption_listener != NULL) {
407  SDLInterruptionListener *listener = nil;
408  listener = (SDLInterruptionListener *) CFBridgingRelease(this->hidden->interruption_listener);
409  [center removeObserver:listener];
410  @synchronized (listener) {
411  listener.device = NULL;
412  }
413  }
414  }
415  }
416 
417  return YES;
418 }
419 #endif
420 
421 
422 /* The AudioQueue callback */
423 static void
424 outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
425 {
426  SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
427  if (SDL_AtomicGet(&this->hidden->shutdown)) {
428  return; /* don't do anything. */
429  }
430 
431  if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
432  /* Supply silence if audio is not enabled or paused */
433  SDL_memset(inBuffer->mAudioData, this->spec.silence, inBuffer->mAudioDataBytesCapacity);
434  } else if (this->stream ) {
435  UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
436  Uint8 *ptr = (Uint8 *) inBuffer->mAudioData;
437 
438  while (remaining > 0) {
439  if ( SDL_AudioStreamAvailable(this->stream) == 0 ) {
440  /* Generate the data */
441  SDL_LockMutex(this->mixer_lock);
442  (*this->callbackspec.callback)(this->callbackspec.userdata,
443  this->hidden->buffer, this->hidden->bufferSize);
444  SDL_UnlockMutex(this->mixer_lock);
445  this->hidden->bufferOffset = 0;
446  SDL_AudioStreamPut(this->stream, this->hidden->buffer, this->hidden->bufferSize);
447  }
448  if ( SDL_AudioStreamAvailable(this->stream) > 0 ) {
449  int got;
450  UInt32 len = SDL_AudioStreamAvailable(this->stream);
451  if ( len > remaining )
452  len = remaining;
453  got = SDL_AudioStreamGet(this->stream, ptr, len);
454  SDL_assert((got < 0) || (got == len));
455  if (got != len) {
456  SDL_memset(ptr, this->spec.silence, len);
457  }
458  ptr = ptr + len;
459  remaining -= len;
460  }
461  }
462  } else {
463  UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
464  Uint8 *ptr = (Uint8 *) inBuffer->mAudioData;
465 
466  while (remaining > 0) {
467  UInt32 len;
468  if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
469  /* Generate the data */
470  SDL_LockMutex(this->mixer_lock);
471  (*this->callbackspec.callback)(this->callbackspec.userdata,
472  this->hidden->buffer, this->hidden->bufferSize);
473  SDL_UnlockMutex(this->mixer_lock);
474  this->hidden->bufferOffset = 0;
475  }
476 
477  len = this->hidden->bufferSize - this->hidden->bufferOffset;
478  if (len > remaining) {
479  len = remaining;
480  }
481  SDL_memcpy(ptr, (char *)this->hidden->buffer +
482  this->hidden->bufferOffset, len);
483  ptr = ptr + len;
484  remaining -= len;
485  this->hidden->bufferOffset += len;
486  }
487  }
488 
489  AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
490 
491  inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity;
492 }
493 
494 static void
495 inputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer,
496  const AudioTimeStamp *inStartTime, UInt32 inNumberPacketDescriptions,
497  const AudioStreamPacketDescription *inPacketDescs )
498 {
499  SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
500 
501  if (SDL_AtomicGet(&this->shutdown)) {
502  return; /* don't do anything. */
503  }
504 
505  /* ignore unless we're active. */
506  if (!SDL_AtomicGet(&this->paused) && SDL_AtomicGet(&this->enabled) && !SDL_AtomicGet(&this->paused)) {
507  const Uint8 *ptr = (const Uint8 *) inBuffer->mAudioData;
508  UInt32 remaining = inBuffer->mAudioDataByteSize;
509  while (remaining > 0) {
510  UInt32 len = this->hidden->bufferSize - this->hidden->bufferOffset;
511  if (len > remaining) {
512  len = remaining;
513  }
514 
515  SDL_memcpy((char *)this->hidden->buffer + this->hidden->bufferOffset, ptr, len);
516  ptr += len;
517  remaining -= len;
518  this->hidden->bufferOffset += len;
519 
520  if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
521  SDL_LockMutex(this->mixer_lock);
522  (*this->callbackspec.callback)(this->callbackspec.userdata, this->hidden->buffer, this->hidden->bufferSize);
523  SDL_UnlockMutex(this->mixer_lock);
524  this->hidden->bufferOffset = 0;
525  }
526  }
527  }
528 
529  AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
530 }
531 
532 
533 #if MACOSX_COREAUDIO
534 static const AudioObjectPropertyAddress alive_address =
535 {
536  kAudioDevicePropertyDeviceIsAlive,
537  kAudioObjectPropertyScopeGlobal,
538  kAudioObjectPropertyElementMaster
539 };
540 
541 static OSStatus
542 device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
543 {
545  SDL_bool dead = SDL_FALSE;
546  UInt32 isAlive = 1;
547  UInt32 size = sizeof (isAlive);
548  OSStatus error;
549 
550  if (!SDL_AtomicGet(&this->enabled)) {
551  return 0; /* already known to be dead. */
552  }
553 
554  error = AudioObjectGetPropertyData(this->hidden->deviceID, &alive_address,
555  0, NULL, &size, &isAlive);
556 
557  if (error == kAudioHardwareBadDeviceError) {
558  dead = SDL_TRUE; /* device was unplugged. */
559  } else if ((error == kAudioHardwareNoError) && (!isAlive)) {
560  dead = SDL_TRUE; /* device died in some other way. */
561  }
562 
563  if (dead) {
565  }
566 
567  return 0;
568 }
569 #endif
570 
571 static void
572 COREAUDIO_CloseDevice(_THIS)
573 {
574  const SDL_bool iscapture = this->iscapture;
575 
576 /* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */
577 /* !!! FIXME: (we only do a "default" device on iOS right now...can we do more?) */
578 #if MACOSX_COREAUDIO
579  /* Fire a callback if the device stops being "alive" (disconnected, etc). */
580  AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
581 #endif
582 
583  if (iscapture) {
584  open_capture_devices--;
585  } else {
586  open_playback_devices--;
587  }
588 
589 #if !MACOSX_COREAUDIO
590  update_audio_session(this, SDL_FALSE);
591 #endif
592 
593  /* if callback fires again, feed silence; don't call into the app. */
594  SDL_AtomicSet(&this->paused, 1);
595 
596  if (this->hidden->audioQueue) {
597  AudioQueueDispose(this->hidden->audioQueue, 1);
598  }
599 
600  if (this->hidden->thread) {
601  SDL_AtomicSet(&this->hidden->shutdown, 1);
602  SDL_WaitThread(this->hidden->thread, NULL);
603  }
604 
605  if (this->hidden->ready_semaphore) {
606  SDL_DestroySemaphore(this->hidden->ready_semaphore);
607  }
608 
609  /* AudioQueueDispose() frees the actual buffer objects. */
610  SDL_free(this->hidden->audioBuffer);
611  SDL_free(this->hidden->thread_error);
612  SDL_free(this->hidden->buffer);
613  SDL_free(this->hidden);
614 }
615 
616 #if MACOSX_COREAUDIO
617 static int
618 prepare_device(_THIS, void *handle, int iscapture)
619 {
620  AudioDeviceID devid = (AudioDeviceID) ((size_t) handle);
621  OSStatus result = noErr;
622  UInt32 size = 0;
623  UInt32 alive = 0;
624  pid_t pid = 0;
625 
626  AudioObjectPropertyAddress addr = {
627  0,
628  kAudioObjectPropertyScopeGlobal,
629  kAudioObjectPropertyElementMaster
630  };
631 
632  if (handle == NULL) {
633  size = sizeof (AudioDeviceID);
634  addr.mSelector =
635  ((iscapture) ? kAudioHardwarePropertyDefaultInputDevice :
636  kAudioHardwarePropertyDefaultOutputDevice);
637  result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr,
638  0, NULL, &size, &devid);
639  CHECK_RESULT("AudioHardwareGetProperty (default device)");
640  }
641 
642  addr.mSelector = kAudioDevicePropertyDeviceIsAlive;
643  addr.mScope = iscapture ? kAudioDevicePropertyScopeInput :
644  kAudioDevicePropertyScopeOutput;
645 
646  size = sizeof (alive);
647  result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &alive);
648  CHECK_RESULT
649  ("AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)");
650 
651  if (!alive) {
652  SDL_SetError("CoreAudio: requested device exists, but isn't alive.");
653  return 0;
654  }
655 
656  addr.mSelector = kAudioDevicePropertyHogMode;
657  size = sizeof (pid);
658  result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &pid);
659 
660  /* some devices don't support this property, so errors are fine here. */
661  if ((result == noErr) && (pid != -1)) {
662  SDL_SetError("CoreAudio: requested device is being hogged.");
663  return 0;
664  }
665 
666  this->hidden->deviceID = devid;
667  return 1;
668 }
669 #endif
670 
671 static int
672 prepare_audioqueue(_THIS)
673 {
674  const AudioStreamBasicDescription *strdesc = &this->hidden->strdesc;
675  const int iscapture = this->iscapture;
676  OSStatus result;
677  int i;
678 
679  SDL_assert(CFRunLoopGetCurrent() != NULL);
680 
681  if (iscapture) {
682  result = AudioQueueNewInput(strdesc, inputCallback, this, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &this->hidden->audioQueue);
683  CHECK_RESULT("AudioQueueNewInput");
684  } else {
685  result = AudioQueueNewOutput(strdesc, outputCallback, this, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &this->hidden->audioQueue);
686  CHECK_RESULT("AudioQueueNewOutput");
687  }
688 
689 #if MACOSX_COREAUDIO
690 {
691  const AudioObjectPropertyAddress prop = {
692  kAudioDevicePropertyDeviceUID,
693  iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
694  kAudioObjectPropertyElementMaster
695  };
696  CFStringRef devuid;
697  UInt32 devuidsize = sizeof (devuid);
698  result = AudioObjectGetPropertyData(this->hidden->deviceID, &prop, 0, NULL, &devuidsize, &devuid);
699  CHECK_RESULT("AudioObjectGetPropertyData (kAudioDevicePropertyDeviceUID)");
700  result = AudioQueueSetProperty(this->hidden->audioQueue, kAudioQueueProperty_CurrentDevice, &devuid, devuidsize);
701  CHECK_RESULT("AudioQueueSetProperty (kAudioQueueProperty_CurrentDevice)");
702 
703  /* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */
704  /* !!! FIXME: (we only do a "default" device on iOS right now...can we do more?) */
705  /* Fire a callback if the device stops being "alive" (disconnected, etc). */
706  AudioObjectAddPropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
707 }
708 #endif
709 
710  /* Calculate the final parameters for this audio specification */
712 
713  /* Set the channel layout for the audio queue */
714  AudioChannelLayout layout;
715  SDL_zero(layout);
716  switch (this->spec.channels) {
717  case 1:
718  layout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
719  break;
720  case 2:
721  layout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
722  break;
723  case 3:
724  layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_4;
725  break;
726  case 4:
727  layout.mChannelLayoutTag = kAudioChannelLayoutTag_Quadraphonic;
728  break;
729  case 5:
730  layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_5_0_A;
731  break;
732  case 6:
733  layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_5_1_A;
734  break;
735  case 7:
736  /* FIXME: Need to move channel[4] (BC) to channel[6] */
737  layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_6_1_A;
738  break;
739  case 8:
740  layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_7_1_A;
741  break;
742  }
743  if (layout.mChannelLayoutTag != 0) {
744  result = AudioQueueSetProperty(this->hidden->audioQueue, kAudioQueueProperty_ChannelLayout, &layout, sizeof(layout));
745  CHECK_RESULT("AudioQueueSetProperty(kAudioQueueProperty_ChannelLayout)");
746  }
747 
748  /* Allocate a sample buffer */
749  this->hidden->bufferSize = this->spec.size;
750  this->hidden->bufferOffset = iscapture ? 0 : this->hidden->bufferSize;
751 
752  this->hidden->buffer = SDL_malloc(this->hidden->bufferSize);
753  if (this->hidden->buffer == NULL) {
754  SDL_OutOfMemory();
755  return 0;
756  }
757 
758  /* Make sure we can feed the device a minimum amount of time */
759  double MINIMUM_AUDIO_BUFFER_TIME_MS = 15.0;
760 #if defined(__IPHONEOS__)
761  if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1) {
762  /* Older iOS hardware, use 40 ms as a minimum time */
763  MINIMUM_AUDIO_BUFFER_TIME_MS = 40.0;
764  }
765 #endif
766  const double msecs = (this->spec.samples / ((double) this->spec.freq)) * 1000.0;
767  int numAudioBuffers = 2;
768  if (msecs < MINIMUM_AUDIO_BUFFER_TIME_MS) { /* use more buffers if we have a VERY small sample set. */
769  numAudioBuffers = ((int)SDL_ceil(MINIMUM_AUDIO_BUFFER_TIME_MS / msecs) * 2);
770  }
771 
772  this->hidden->audioBuffer = SDL_calloc(1, sizeof (AudioQueueBufferRef) * numAudioBuffers);
773  if (this->hidden->audioBuffer == NULL) {
774  SDL_OutOfMemory();
775  return 0;
776  }
777 
778 #if DEBUG_COREAUDIO
779  printf("COREAUDIO: numAudioBuffers == %d\n", numAudioBuffers);
780 #endif
781 
782  for (i = 0; i < numAudioBuffers; i++) {
783  result = AudioQueueAllocateBuffer(this->hidden->audioQueue, this->spec.size, &this->hidden->audioBuffer[i]);
784  CHECK_RESULT("AudioQueueAllocateBuffer");
785  SDL_memset(this->hidden->audioBuffer[i]->mAudioData, this->spec.silence, this->hidden->audioBuffer[i]->mAudioDataBytesCapacity);
786  this->hidden->audioBuffer[i]->mAudioDataByteSize = this->hidden->audioBuffer[i]->mAudioDataBytesCapacity;
787  result = AudioQueueEnqueueBuffer(this->hidden->audioQueue, this->hidden->audioBuffer[i], 0, NULL);
788  CHECK_RESULT("AudioQueueEnqueueBuffer");
789  }
790 
791  result = AudioQueueStart(this->hidden->audioQueue, NULL);
792  CHECK_RESULT("AudioQueueStart");
793 
794  /* We're running! */
795  return 1;
796 }
797 
798 static int
799 audioqueue_thread(void *arg)
800 {
801  SDL_AudioDevice *this = (SDL_AudioDevice *) arg;
802  const int rc = prepare_audioqueue(this);
803  if (!rc) {
804  this->hidden->thread_error = SDL_strdup(SDL_GetError());
805  SDL_SemPost(this->hidden->ready_semaphore);
806  return 0;
807  }
808 
810 
811  /* init was successful, alert parent thread and start running... */
812  SDL_SemPost(this->hidden->ready_semaphore);
813  while (!SDL_AtomicGet(&this->hidden->shutdown)) {
814  CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
815  }
816 
817  if (!this->iscapture) { /* Drain off any pending playback. */
818  const CFTimeInterval secs = (((this->spec.size / (SDL_AUDIO_BITSIZE(this->spec.format) / 8)) / this->spec.channels) / ((CFTimeInterval) this->spec.freq)) * 2.0;
819  CFRunLoopRunInMode(kCFRunLoopDefaultMode, secs, 0);
820  }
821 
822  return 0;
823 }
824 
825 static int
826 COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
827 {
828  AudioStreamBasicDescription *strdesc;
829  SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
830  int valid_datatype = 0;
831 
832  /* Initialize all variables that we clean on shutdown */
833  this->hidden = (struct SDL_PrivateAudioData *)
834  SDL_malloc((sizeof *this->hidden));
835  if (this->hidden == NULL) {
836  return SDL_OutOfMemory();
837  }
838  SDL_zerop(this->hidden);
839 
840  strdesc = &this->hidden->strdesc;
841 
842  if (iscapture) {
843  open_capture_devices++;
844  } else {
845  open_playback_devices++;
846  }
847 
848 #if !MACOSX_COREAUDIO
849  if (!update_audio_session(this, SDL_TRUE)) {
850  return -1;
851  }
852 
853  /* Stop CoreAudio from doing expensive audio rate conversion */
854  @autoreleasepool {
855  AVAudioSession* session = [AVAudioSession sharedInstance];
856  [session setPreferredSampleRate:this->spec.freq error:nil];
857  this->spec.freq = (int)session.sampleRate;
858 #if TARGET_OS_TV
859  if (iscapture) {
860  [session setPreferredInputNumberOfChannels:this->spec.channels error:nil];
861  this->spec.channels = session.preferredInputNumberOfChannels;
862  } else {
863  [session setPreferredOutputNumberOfChannels:this->spec.channels error:nil];
864  this->spec.channels = session.preferredOutputNumberOfChannels;
865  }
866 #else
867  /* Calling setPreferredOutputNumberOfChannels seems to break audio output on iOS */
868 #endif /* TARGET_OS_TV */
869  }
870 #endif
871 
872  /* Setup a AudioStreamBasicDescription with the requested format */
874  strdesc->mFormatID = kAudioFormatLinearPCM;
875  strdesc->mFormatFlags = kLinearPCMFormatFlagIsPacked;
876  strdesc->mChannelsPerFrame = this->spec.channels;
877  strdesc->mSampleRate = this->spec.freq;
878  strdesc->mFramesPerPacket = 1;
879 
880  while ((!valid_datatype) && (test_format)) {
881  this->spec.format = test_format;
882  /* CoreAudio handles most of SDL's formats natively, but not U16, apparently. */
883  switch (test_format) {
884  case AUDIO_U8:
885  case AUDIO_S8:
886  case AUDIO_S16LSB:
887  case AUDIO_S16MSB:
888  case AUDIO_S32LSB:
889  case AUDIO_S32MSB:
890  case AUDIO_F32LSB:
891  case AUDIO_F32MSB:
892  valid_datatype = 1;
893  strdesc->mBitsPerChannel = SDL_AUDIO_BITSIZE(this->spec.format);
894  if (SDL_AUDIO_ISBIGENDIAN(this->spec.format))
895  strdesc->mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
896 
897  if (SDL_AUDIO_ISFLOAT(this->spec.format))
898  strdesc->mFormatFlags |= kLinearPCMFormatFlagIsFloat;
899  else if (SDL_AUDIO_ISSIGNED(this->spec.format))
900  strdesc->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
901  break;
902 
903  default:
904  test_format = SDL_NextAudioFormat();
905  break;
906  }
907  }
908 
909  if (!valid_datatype) { /* shouldn't happen, but just in case... */
910  return SDL_SetError("Unsupported audio format");
911  }
912 
913  strdesc->mBytesPerFrame = strdesc->mChannelsPerFrame * strdesc->mBitsPerChannel / 8;
914  strdesc->mBytesPerPacket = strdesc->mBytesPerFrame * strdesc->mFramesPerPacket;
915 
916 #if MACOSX_COREAUDIO
917  if (!prepare_device(this, handle, iscapture)) {
918  return -1;
919  }
920 #endif
921 
922  /* This has to init in a new thread so it can get its own CFRunLoop. :/ */
923  SDL_AtomicSet(&this->hidden->shutdown, 0);
924  this->hidden->ready_semaphore = SDL_CreateSemaphore(0);
925  if (!this->hidden->ready_semaphore) {
926  return -1; /* oh well. */
927  }
928 
929  this->hidden->thread = SDL_CreateThreadInternal(audioqueue_thread, "AudioQueue thread", 512 * 1024, this);
930  if (!this->hidden->thread) {
931  return -1;
932  }
933 
934  SDL_SemWait(this->hidden->ready_semaphore);
935  SDL_DestroySemaphore(this->hidden->ready_semaphore);
936  this->hidden->ready_semaphore = NULL;
937 
938  if ((this->hidden->thread != NULL) && (this->hidden->thread_error != NULL)) {
939  SDL_SetError("%s", this->hidden->thread_error);
940  return -1;
941  }
942 
943  return (this->hidden->thread != NULL) ? 0 : -1;
944 }
945 
946 static void
947 COREAUDIO_Deinitialize(void)
948 {
949 #if MACOSX_COREAUDIO
950  AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL);
951  free_audio_device_list(&capture_devs);
952  free_audio_device_list(&output_devs);
953 #endif
954 }
955 
956 static int
957 COREAUDIO_Init(SDL_AudioDriverImpl * impl)
958 {
959  /* Set the function pointers */
960  impl->OpenDevice = COREAUDIO_OpenDevice;
961  impl->CloseDevice = COREAUDIO_CloseDevice;
962  impl->Deinitialize = COREAUDIO_Deinitialize;
963 
964 #if MACOSX_COREAUDIO
965  impl->DetectDevices = COREAUDIO_DetectDevices;
966  AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL);
967 #else
968  impl->OnlyHasDefaultOutputDevice = 1;
969  impl->OnlyHasDefaultCaptureDevice = 1;
970 #endif
971 
972  impl->ProvidesOwnCallbackThread = 1;
973  impl->HasCaptureSupport = 1;
974 
975  return 1; /* this audio target is available. */
976 }
977 
979  "coreaudio", "CoreAudio", COREAUDIO_Init, 0
980 };
981 
982 #endif /* SDL_AUDIO_DRIVER_COREAUDIO */
983 
984 /* vi: set ts=4 sw=4 expandtab: */
SDL_zero
#define SDL_zero(x)
Definition: SDL_stdinc.h:418
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:179
SDL_SetThreadPriority
#define SDL_SetThreadPriority
Definition: SDL_dynapi_overrides.h:477
SDL_memset
#define SDL_memset
Definition: SDL_dynapi_overrides.h:386
SDL_FirstAudioFormat
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
Definition: SDL_audio.c:1647
SDL_GetError
#define SDL_GetError
Definition: SDL_dynapi_overrides.h:113
SDL_AudioSpec::channels
Uint8 channels
Definition: SDL_audio.h:182
SDL_AudioDriverImpl::HasCaptureSupport
int HasCaptureSupport
Definition: SDL_sysaudio.h:90
SDL_AudioDriverImpl::ProvidesOwnCallbackThread
int ProvidesOwnCallbackThread
Definition: SDL_sysaudio.h:88
alive
int alive
Definition: testsem.c:24
SDL_coreaudio.h
if
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
Definition: pixman-arm-neon-asm.h:469
SDL_CreateSemaphore
#define SDL_CreateSemaphore
Definition: SDL_dynapi_overrides.h:264
SDL_LockMutex
#define SDL_LockMutex
Definition: SDL_dynapi_overrides.h:260
SDL_ceil
#define SDL_ceil
Definition: SDL_dynapi_overrides.h:426
NULL
#define NULL
Definition: begin_code.h:167
SDL_AudioStreamAvailable
#define SDL_AudioStreamAvailable
Definition: SDL_dynapi_overrides.h:647
handle
EGLImageKHR EGLint EGLint * handle
Definition: eglext.h:937
AUDIO_S32MSB
#define AUDIO_S32MSB
Definition: SDL_audio.h:104
SDL_AudioSpec::samples
Uint16 samples
Definition: SDL_audio.h:184
mode
GLenum mode
Definition: SDL_opengl_glext.h:1125
SDL_zerop
#define SDL_zerop(x)
Definition: SDL_stdinc.h:419
SDL_AUDIO_ISBIGENDIAN
#define SDL_AUDIO_ISBIGENDIAN(x)
Definition: SDL_audio.h:77
SDL_AudioSpec::format
SDL_AudioFormat format
Definition: SDL_audio.h:181
SDL_AUDIO_ISSIGNED
#define SDL_AUDIO_ISSIGNED(x)
Definition: SDL_audio.h:78
SDL_THREAD_PRIORITY_HIGH
@ SDL_THREAD_PRIORITY_HIGH
Definition: SDL_thread.h:62
stream
GLuint GLuint stream
Definition: SDL_opengl_glext.h:1779
SDL_AudioDriverImpl::OpenDevice
int(* OpenDevice)(_THIS, void *handle, const char *devname, int iscapture)
Definition: SDL_sysaudio.h:68
SDL_AudioStreamGet
#define SDL_AudioStreamGet
Definition: SDL_dynapi_overrides.h:645
SDL_NextAudioFormat
SDL_AudioFormat SDL_NextAudioFormat(void)
Definition: SDL_audio.c:1659
SDL_GetHint
#define SDL_GetHint
Definition: SDL_dynapi_overrides.h:191
SDL_OpenedAudioDeviceDisconnected
void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
Definition: SDL_audio.c:486
SDL_PrivateAudioData::iscapture
SDL_bool iscapture
Definition: SDL_qsa_audio.h:37
SDL_AudioFormat
Uint16 SDL_AudioFormat
Audio format flags.
Definition: SDL_audio.h:64
SDL_SemPost
#define SDL_SemPost
Definition: SDL_dynapi_overrides.h:269
result
GLuint64EXT * result
Definition: SDL_opengl_glext.h:9435
AudioBootStrap
Definition: SDL_sysaudio.h:177
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_AUDIO_ISFLOAT
#define SDL_AUDIO_ISFLOAT(x)
Definition: SDL_audio.h:76
COREAUDIO_bootstrap
AudioBootStrap COREAUDIO_bootstrap
SDL_strcasecmp
#define SDL_strcasecmp
Definition: SDL_dynapi_overrides.h:419
SDL_PrivateAudioData
Definition: SDL_alsa_audio.h:34
AUDIO_U8
#define AUDIO_U8
Definition: SDL_audio.h:89
len
GLenum GLsizei len
Definition: SDL_opengl_glext.h:2929
SDL_memcpy
#define SDL_memcpy
Definition: SDL_dynapi_overrides.h:387
AUDIO_F32MSB
#define AUDIO_F32MSB
Definition: SDL_audio.h:113
SDL_HINT_AUDIO_CATEGORY
#define SDL_HINT_AUDIO_CATEGORY
A variable controlling the audio category on iOS and Mac OS X.
Definition: SDL_hints.h:1147
SDL_audio.h
SDL_CreateThreadInternal
SDL_Thread * SDL_CreateThreadInternal(int(*fn)(void *), const char *name, const size_t stacksize, void *data)
Definition: SDL_thread.c:435
SDL_AudioDriverImpl
Definition: SDL_sysaudio.h:66
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
SDL_AudioDriverImpl::OnlyHasDefaultOutputDevice
int OnlyHasDefaultOutputDevice
Definition: SDL_sysaudio.h:91
name
GLuint const GLchar * name
Definition: SDL_opengl_glext.h:663
SDL_RemoveAudioDevice
void SDL_RemoveAudioDevice(const int iscapture, void *handle)
Definition: SDL_audio.c:531
SDL_assert.h
addr
GLenum const void * addr
Definition: SDL_opengl_glext.h:7948
SDL_CalculateAudioSpec
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
Definition: SDL_audio.c:1686
SDL_AudioDriverImpl::DetectDevices
void(* DetectDevices)(void)
Definition: SDL_sysaudio.h:67
_THIS
#define _THIS
Definition: SDL_alsa_audio.h:31
SDL_AudioStreamPut
#define SDL_AudioStreamPut
Definition: SDL_dynapi_overrides.h:644
SDL_AUDIO_BITSIZE
#define SDL_AUDIO_BITSIZE(x)
Definition: SDL_audio.h:75
AUDIO_F32LSB
#define AUDIO_F32LSB
Definition: SDL_audio.h:112
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_AudioSpec::freq
int freq
Definition: SDL_audio.h:180
SDL_AudioDriverImpl::OnlyHasDefaultCaptureDevice
int OnlyHasDefaultCaptureDevice
Definition: SDL_sysaudio.h:92
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:169
SDL_AudioSpec::silence
Uint8 silence
Definition: SDL_audio.h:183
AUDIO_S32LSB
#define AUDIO_S32LSB
Definition: SDL_audio.h:103
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
size
GLsizeiptr size
Definition: SDL_opengl_glext.h:540
spec
SDL_AudioSpec spec
Definition: loopwave.c:31
SDL_calloc
#define SDL_calloc
Definition: SDL_dynapi_overrides.h:375
SDL_AudioSpec::size
Uint32 size
Definition: SDL_audio.h:186
SDL_SemWait
#define SDL_SemWait
Definition: SDL_dynapi_overrides.h:266
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_hints.h
AUDIO_S16MSB
#define AUDIO_S16MSB
Definition: SDL_audio.h:94
SDL_strdup
#define SDL_strdup
Definition: SDL_dynapi_overrides.h:397
SDL_DestroySemaphore
#define SDL_DestroySemaphore
Definition: SDL_dynapi_overrides.h:265
enabled
GLenum GLenum GLsizei const GLuint GLboolean enabled
Definition: SDL_opengl_glext.h:2482
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:162
AUDIO_S16LSB
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
paused
int paused
Definition: testoverlay2.c:149
j
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
Definition: SDL_x11sym.h:50
AUDIO_S8
#define AUDIO_S8
Definition: SDL_audio.h:90
SDL_PrivateAudioData::strdesc
AudioStreamBasicDescription strdesc
Definition: SDL_coreaudio.h:54
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
SDL_AtomicSet
#define SDL_AtomicSet
Definition: SDL_dynapi_overrides.h:67
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:374
SDL_AtomicGet
#define SDL_AtomicGet
Definition: SDL_dynapi_overrides.h:68
void
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
Definition: SDL_dynapi_procs.h:89
SDL_UnlockMutex
#define SDL_UnlockMutex
Definition: SDL_dynapi_overrides.h:262
device
static SDL_AudioDeviceID device
Definition: loopwave.c:37
floor
double floor(double x)
Definition: s_floor.c:33
ptr
set set set set set set set set set set set set set set set set set set set set *set set set macro pixldst op &r &cond WK op &r &cond WK op &r &cond WK else op &m &cond &ia op &r &cond WK else op &m &cond &ia elseif elseif else error unsupported base if elseif elseif else error unsupported unaligned pixldst unaligned endm macro pixst base base else pixldst base endif endm macro PF ptr
Definition: pixman-arm-simd-asm.h:171
type
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
SDL_AudioDriverImpl::CloseDevice
void(* CloseDevice)(_THIS)
Definition: SDL_sysaudio.h:78
SDL_AddAudioDevice
void SDL_AddAudioDevice(const int iscapture, const char *name, void *handle)
Definition: SDL_audio.c:469
SDL_WaitThread
#define SDL_WaitThread
Definition: SDL_dynapi_overrides.h:478
i
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
SDL_AudioDevice
Definition: SDL_sysaudio.h:132
SDL_AudioDriverImpl::Deinitialize
void(* Deinitialize)(void)
Definition: SDL_sysaudio.h:82