SDL  2.0
SDL_alsa_audio.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2019 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_ALSA
24 
25 #ifndef SDL_ALSA_NON_BLOCKING
26 #define SDL_ALSA_NON_BLOCKING 0
27 #endif
28 
29 /* Allow access to a raw mixing buffer */
30 
31 #include <sys/types.h>
32 #include <signal.h> /* For kill() */
33 #include <string.h>
34 
35 #include "SDL_assert.h"
36 #include "SDL_timer.h"
37 #include "SDL_audio.h"
38 #include "../SDL_audio_c.h"
39 #include "SDL_alsa_audio.h"
40 
41 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
42 #include "SDL_loadso.h"
43 #endif
44 
45 static int (*ALSA_snd_pcm_open)
46  (snd_pcm_t **, const char *, snd_pcm_stream_t, int);
47 static int (*ALSA_snd_pcm_close) (snd_pcm_t * pcm);
48 static snd_pcm_sframes_t (*ALSA_snd_pcm_writei)
49  (snd_pcm_t *, const void *, snd_pcm_uframes_t);
50 static snd_pcm_sframes_t (*ALSA_snd_pcm_readi)
51  (snd_pcm_t *, void *, snd_pcm_uframes_t);
52 static int (*ALSA_snd_pcm_recover) (snd_pcm_t *, int, int);
53 static int (*ALSA_snd_pcm_prepare) (snd_pcm_t *);
54 static int (*ALSA_snd_pcm_drain) (snd_pcm_t *);
55 static const char *(*ALSA_snd_strerror) (int);
56 static size_t(*ALSA_snd_pcm_hw_params_sizeof) (void);
57 static size_t(*ALSA_snd_pcm_sw_params_sizeof) (void);
58 static void (*ALSA_snd_pcm_hw_params_copy)
59  (snd_pcm_hw_params_t *, const snd_pcm_hw_params_t *);
60 static int (*ALSA_snd_pcm_hw_params_any) (snd_pcm_t *, snd_pcm_hw_params_t *);
61 static int (*ALSA_snd_pcm_hw_params_set_access)
62  (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_access_t);
63 static int (*ALSA_snd_pcm_hw_params_set_format)
64  (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_format_t);
65 static int (*ALSA_snd_pcm_hw_params_set_channels)
66  (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int);
67 static int (*ALSA_snd_pcm_hw_params_get_channels)
68  (const snd_pcm_hw_params_t *, unsigned int *);
69 static int (*ALSA_snd_pcm_hw_params_set_rate_near)
70  (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *);
71 static int (*ALSA_snd_pcm_hw_params_set_period_size_near)
72  (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_uframes_t *, int *);
73 static int (*ALSA_snd_pcm_hw_params_get_period_size)
74  (const snd_pcm_hw_params_t *, snd_pcm_uframes_t *, int *);
75 static int (*ALSA_snd_pcm_hw_params_set_periods_min)
76  (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *);
77 static int (*ALSA_snd_pcm_hw_params_set_periods_first)
78  (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *);
79 static int (*ALSA_snd_pcm_hw_params_get_periods)
80  (const snd_pcm_hw_params_t *, unsigned int *, int *);
81 static int (*ALSA_snd_pcm_hw_params_set_buffer_size_near)
82  (snd_pcm_t *pcm, snd_pcm_hw_params_t *, snd_pcm_uframes_t *);
83 static int (*ALSA_snd_pcm_hw_params_get_buffer_size)
84  (const snd_pcm_hw_params_t *, snd_pcm_uframes_t *);
85 static int (*ALSA_snd_pcm_hw_params) (snd_pcm_t *, snd_pcm_hw_params_t *);
86 static int (*ALSA_snd_pcm_sw_params_current) (snd_pcm_t *,
87  snd_pcm_sw_params_t *);
88 static int (*ALSA_snd_pcm_sw_params_set_start_threshold)
89  (snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
90 static int (*ALSA_snd_pcm_sw_params) (snd_pcm_t *, snd_pcm_sw_params_t *);
91 static int (*ALSA_snd_pcm_nonblock) (snd_pcm_t *, int);
92 static int (*ALSA_snd_pcm_wait)(snd_pcm_t *, int);
93 static int (*ALSA_snd_pcm_sw_params_set_avail_min)
94  (snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
95 static int (*ALSA_snd_pcm_reset)(snd_pcm_t *);
96 static int (*ALSA_snd_device_name_hint) (int, const char *, void ***);
97 static char* (*ALSA_snd_device_name_get_hint) (const void *, const char *);
98 static int (*ALSA_snd_device_name_free_hint) (void **);
99 static snd_pcm_sframes_t (*ALSA_snd_pcm_avail)(snd_pcm_t *);
100 #ifdef SND_CHMAP_API_VERSION
101 static snd_pcm_chmap_t* (*ALSA_snd_pcm_get_chmap) (snd_pcm_t *);
102 static int (*ALSA_snd_pcm_chmap_print) (const snd_pcm_chmap_t *map, size_t maxlen, char *buf);
103 #endif
104 
105 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
106 #define snd_pcm_hw_params_sizeof ALSA_snd_pcm_hw_params_sizeof
107 #define snd_pcm_sw_params_sizeof ALSA_snd_pcm_sw_params_sizeof
108 
109 static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
110 static void *alsa_handle = NULL;
111 
112 static int
113 load_alsa_sym(const char *fn, void **addr)
114 {
115  *addr = SDL_LoadFunction(alsa_handle, fn);
116  if (*addr == NULL) {
117  /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
118  return 0;
119  }
120 
121  return 1;
122 }
123 
124 /* cast funcs to char* first, to please GCC's strict aliasing rules. */
125 #define SDL_ALSA_SYM(x) \
126  if (!load_alsa_sym(#x, (void **) (char *) &ALSA_##x)) return -1
127 #else
128 #define SDL_ALSA_SYM(x) ALSA_##x = x
129 #endif
130 
131 static int
132 load_alsa_syms(void)
133 {
134  SDL_ALSA_SYM(snd_pcm_open);
135  SDL_ALSA_SYM(snd_pcm_close);
136  SDL_ALSA_SYM(snd_pcm_writei);
137  SDL_ALSA_SYM(snd_pcm_readi);
138  SDL_ALSA_SYM(snd_pcm_recover);
139  SDL_ALSA_SYM(snd_pcm_prepare);
140  SDL_ALSA_SYM(snd_pcm_drain);
141  SDL_ALSA_SYM(snd_strerror);
142  SDL_ALSA_SYM(snd_pcm_hw_params_sizeof);
143  SDL_ALSA_SYM(snd_pcm_sw_params_sizeof);
144  SDL_ALSA_SYM(snd_pcm_hw_params_copy);
145  SDL_ALSA_SYM(snd_pcm_hw_params_any);
146  SDL_ALSA_SYM(snd_pcm_hw_params_set_access);
147  SDL_ALSA_SYM(snd_pcm_hw_params_set_format);
148  SDL_ALSA_SYM(snd_pcm_hw_params_set_channels);
149  SDL_ALSA_SYM(snd_pcm_hw_params_get_channels);
150  SDL_ALSA_SYM(snd_pcm_hw_params_set_rate_near);
151  SDL_ALSA_SYM(snd_pcm_hw_params_set_period_size_near);
152  SDL_ALSA_SYM(snd_pcm_hw_params_get_period_size);
153  SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_min);
154  SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_first);
155  SDL_ALSA_SYM(snd_pcm_hw_params_get_periods);
156  SDL_ALSA_SYM(snd_pcm_hw_params_set_buffer_size_near);
157  SDL_ALSA_SYM(snd_pcm_hw_params_get_buffer_size);
158  SDL_ALSA_SYM(snd_pcm_hw_params);
159  SDL_ALSA_SYM(snd_pcm_sw_params_current);
160  SDL_ALSA_SYM(snd_pcm_sw_params_set_start_threshold);
161  SDL_ALSA_SYM(snd_pcm_sw_params);
162  SDL_ALSA_SYM(snd_pcm_nonblock);
163  SDL_ALSA_SYM(snd_pcm_wait);
164  SDL_ALSA_SYM(snd_pcm_sw_params_set_avail_min);
165  SDL_ALSA_SYM(snd_pcm_reset);
166  SDL_ALSA_SYM(snd_device_name_hint);
167  SDL_ALSA_SYM(snd_device_name_get_hint);
168  SDL_ALSA_SYM(snd_device_name_free_hint);
169  SDL_ALSA_SYM(snd_pcm_avail);
170 #ifdef SND_CHMAP_API_VERSION
171  SDL_ALSA_SYM(snd_pcm_get_chmap);
172  SDL_ALSA_SYM(snd_pcm_chmap_print);
173 #endif
174 
175  return 0;
176 }
177 
178 #undef SDL_ALSA_SYM
179 
180 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
181 
182 static void
183 UnloadALSALibrary(void)
184 {
185  if (alsa_handle != NULL) {
186  SDL_UnloadObject(alsa_handle);
187  alsa_handle = NULL;
188  }
189 }
190 
191 static int
192 LoadALSALibrary(void)
193 {
194  int retval = 0;
195  if (alsa_handle == NULL) {
196  alsa_handle = SDL_LoadObject(alsa_library);
197  if (alsa_handle == NULL) {
198  retval = -1;
199  /* Don't call SDL_SetError(): SDL_LoadObject already did. */
200  } else {
201  retval = load_alsa_syms();
202  if (retval < 0) {
203  UnloadALSALibrary();
204  }
205  }
206  }
207  return retval;
208 }
209 
210 #else
211 
212 static void
213 UnloadALSALibrary(void)
214 {
215 }
216 
217 static int
218 LoadALSALibrary(void)
219 {
220  load_alsa_syms();
221  return 0;
222 }
223 
224 #endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */
225 
226 static const char *
227 get_audio_device(void *handle, const int channels)
228 {
229  const char *device;
230 
231  if (handle != NULL) {
232  return (const char *) handle;
233  }
234 
235  /* !!! FIXME: we also check "SDL_AUDIO_DEVICE_NAME" at the higher level. */
236  device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */
237  if (device != NULL) {
238  return device;
239  }
240 
241  if (channels == 6) {
242  return "plug:surround51";
243  } else if (channels == 4) {
244  return "plug:surround40";
245  }
246 
247  return "default";
248 }
249 
250 
251 /* This function waits until it is possible to write a full sound buffer */
252 static void
253 ALSA_WaitDevice(_THIS)
254 {
255 #if SDL_ALSA_NON_BLOCKING
256  const snd_pcm_sframes_t needed = (snd_pcm_sframes_t) this->spec.samples;
257  while (SDL_AtomicGet(&this->enabled)) {
258  const snd_pcm_sframes_t rc = ALSA_snd_pcm_avail(this->hidden->pcm_handle);
259  if ((rc < 0) && (rc != -EAGAIN)) {
260  /* Hmm, not much we can do - abort */
261  fprintf(stderr, "ALSA snd_pcm_avail failed (unrecoverable): %s\n",
262  ALSA_snd_strerror(rc));
264  return;
265  } else if (rc < needed) {
266  const Uint32 delay = ((needed - (SDL_max(rc, 0))) * 1000) / this->spec.freq;
267  SDL_Delay(SDL_max(delay, 10));
268  } else {
269  break; /* ready to go! */
270  }
271  }
272 #endif
273 }
274 
275 
276 /* !!! FIXME: is there a channel swizzler in alsalib instead? */
277 /*
278  * http://bugzilla.libsdl.org/show_bug.cgi?id=110
279  * "For Linux ALSA, this is FL-FR-RL-RR-C-LFE
280  * and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR"
281  */
282 #define SWIZ6(T, buf, numframes) \
283  T *ptr = (T *) buf; \
284  Uint32 i; \
285  for (i = 0; i < numframes; i++, ptr += 6) { \
286  T tmp; \
287  tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \
288  tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \
289  }
290 
291 static void
292 swizzle_alsa_channels_6_64bit(void *buffer, Uint32 bufferlen)
293 {
294  SWIZ6(Uint64, buffer, bufferlen);
295 }
296 
297 static void
298 swizzle_alsa_channels_6_32bit(void *buffer, Uint32 bufferlen)
299 {
300  SWIZ6(Uint32, buffer, bufferlen);
301 }
302 
303 static void
304 swizzle_alsa_channels_6_16bit(void *buffer, Uint32 bufferlen)
305 {
306  SWIZ6(Uint16, buffer, bufferlen);
307 }
308 
309 static void
310 swizzle_alsa_channels_6_8bit(void *buffer, Uint32 bufferlen)
311 {
312  SWIZ6(Uint8, buffer, bufferlen);
313 }
314 
315 #undef SWIZ6
316 
317 
318 /*
319  * Called right before feeding this->hidden->mixbuf to the hardware. Swizzle
320  * channels from Windows/Mac order to the format alsalib will want.
321  */
322 static void
323 swizzle_alsa_channels(_THIS, void *buffer, Uint32 bufferlen)
324 {
325  if (this->spec.channels == 6) {
326  switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
327  case 8: swizzle_alsa_channels_6_8bit(buffer, bufferlen); break;
328  case 16: swizzle_alsa_channels_6_16bit(buffer, bufferlen); break;
329  case 32: swizzle_alsa_channels_6_32bit(buffer, bufferlen); break;
330  case 64: swizzle_alsa_channels_6_64bit(buffer, bufferlen); break;
331  default: SDL_assert(!"unhandled bitsize"); break;
332  }
333  }
334 
335  /* !!! FIXME: update this for 7.1 if needed, later. */
336 }
337 
338 #ifdef SND_CHMAP_API_VERSION
339 /* Some devices have the right channel map, no swizzling necessary */
340 static void
341 no_swizzle(_THIS, void *buffer, Uint32 bufferlen)
342 {
343  return;
344 }
345 #endif /* SND_CHMAP_API_VERSION */
346 
347 
348 static void
349 ALSA_PlayDevice(_THIS)
350 {
351  const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf;
352  const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
353  this->spec.channels;
354  snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples);
355 
356  this->hidden->swizzle_func(this, this->hidden->mixbuf, frames_left);
357 
358  while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
359  int status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
360  sample_buf, frames_left);
361 
362  if (status < 0) {
363  if (status == -EAGAIN) {
364  /* Apparently snd_pcm_recover() doesn't handle this case -
365  does it assume snd_pcm_wait() above? */
366  SDL_Delay(1);
367  continue;
368  }
369  status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
370  if (status < 0) {
371  /* Hmm, not much we can do - abort */
372  fprintf(stderr, "ALSA write failed (unrecoverable): %s\n",
373  ALSA_snd_strerror(status));
375  return;
376  }
377  continue;
378  }
379  else if (status == 0) {
380  /* No frames were written (no available space in pcm device).
381  Allow other threads to catch up. */
382  Uint32 delay = (frames_left / 2 * 1000) / this->spec.freq;
383  SDL_Delay(delay);
384  }
385 
386  sample_buf += status * frame_size;
387  frames_left -= status;
388  }
389 }
390 
391 static Uint8 *
392 ALSA_GetDeviceBuf(_THIS)
393 {
394  return (this->hidden->mixbuf);
395 }
396 
397 static int
398 ALSA_CaptureFromDevice(_THIS, void *buffer, int buflen)
399 {
400  Uint8 *sample_buf = (Uint8 *) buffer;
401  const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
402  this->spec.channels;
403  const int total_frames = buflen / frame_size;
404  snd_pcm_uframes_t frames_left = total_frames;
405  snd_pcm_uframes_t wait_time = frame_size / 2;
406 
407  SDL_assert((buflen % frame_size) == 0);
408 
409  while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
410  int status;
411 
412  status = ALSA_snd_pcm_readi(this->hidden->pcm_handle,
413  sample_buf, frames_left);
414 
415  if (status == -EAGAIN) {
416  ALSA_snd_pcm_wait(this->hidden->pcm_handle, wait_time);
417  status = 0;
418  }
419  else if (status < 0) {
420  /*printf("ALSA: capture error %d\n", status);*/
421  status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
422  if (status < 0) {
423  /* Hmm, not much we can do - abort */
424  fprintf(stderr, "ALSA read failed (unrecoverable): %s\n",
425  ALSA_snd_strerror(status));
426  return -1;
427  }
428  continue;
429  }
430 
431  /*printf("ALSA: captured %d bytes\n", status * frame_size);*/
432  sample_buf += status * frame_size;
433  frames_left -= status;
434  }
435 
436  this->hidden->swizzle_func(this, buffer, total_frames - frames_left);
437 
438  return (total_frames - frames_left) * frame_size;
439 }
440 
441 static void
442 ALSA_FlushCapture(_THIS)
443 {
444  ALSA_snd_pcm_reset(this->hidden->pcm_handle);
445 }
446 
447 static void
448 ALSA_CloseDevice(_THIS)
449 {
450  if (this->hidden->pcm_handle) {
451  /* Wait for the submitted audio to drain
452  ALSA_snd_pcm_drop() can hang, so don't use that.
453  */
454  Uint32 delay = ((this->spec.samples * 1000) / this->spec.freq) * 2;
455  SDL_Delay(delay);
456 
457  ALSA_snd_pcm_close(this->hidden->pcm_handle);
458  }
459  SDL_free(this->hidden->mixbuf);
460  SDL_free(this->hidden);
461 }
462 
463 static int
464 ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params)
465 {
466  int status;
467  snd_pcm_hw_params_t *hwparams;
468  snd_pcm_uframes_t persize;
469  unsigned int periods;
470 
471  /* Copy the hardware parameters for this setup */
472  snd_pcm_hw_params_alloca(&hwparams);
473  ALSA_snd_pcm_hw_params_copy(hwparams, params);
474 
475  /* Attempt to match the period size to the requested buffer size */
476  persize = this->spec.samples;
477  status = ALSA_snd_pcm_hw_params_set_period_size_near(
478  this->hidden->pcm_handle, hwparams, &persize, NULL);
479  if ( status < 0 ) {
480  return(-1);
481  }
482 
483  /* Need to at least double buffer */
484  periods = 2;
485  status = ALSA_snd_pcm_hw_params_set_periods_min(
486  this->hidden->pcm_handle, hwparams, &periods, NULL);
487  if ( status < 0 ) {
488  return(-1);
489  }
490 
491  status = ALSA_snd_pcm_hw_params_set_periods_first(
492  this->hidden->pcm_handle, hwparams, &periods, NULL);
493  if ( status < 0 ) {
494  return(-1);
495  }
496 
497  /* "set" the hardware with the desired parameters */
498  status = ALSA_snd_pcm_hw_params(this->hidden->pcm_handle, hwparams);
499  if ( status < 0 ) {
500  return(-1);
501  }
502 
503  this->spec.samples = persize;
504 
505  /* This is useful for debugging */
506  if ( SDL_getenv("SDL_AUDIO_ALSA_DEBUG") ) {
507  snd_pcm_uframes_t bufsize;
508 
509  ALSA_snd_pcm_hw_params_get_buffer_size(hwparams, &bufsize);
510 
511  fprintf(stderr,
512  "ALSA: period size = %ld, periods = %u, buffer size = %lu\n",
513  persize, periods, bufsize);
514  }
515 
516  return(0);
517 }
518 
519 static int
520 ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
521 {
522  int status = 0;
523  snd_pcm_t *pcm_handle = NULL;
524  snd_pcm_hw_params_t *hwparams = NULL;
525  snd_pcm_sw_params_t *swparams = NULL;
526  snd_pcm_format_t format = 0;
527  SDL_AudioFormat test_format = 0;
528  unsigned int rate = 0;
529  unsigned int channels = 0;
530 #ifdef SND_CHMAP_API_VERSION
531  snd_pcm_chmap_t *chmap;
532  char chmap_str[64];
533 #endif
534 
535  /* Initialize all variables that we clean on shutdown */
536  this->hidden = (struct SDL_PrivateAudioData *)
537  SDL_malloc((sizeof *this->hidden));
538  if (this->hidden == NULL) {
539  return SDL_OutOfMemory();
540  }
541  SDL_zerop(this->hidden);
542 
543  /* Open the audio device */
544  /* Name of device should depend on # channels in spec */
545  status = ALSA_snd_pcm_open(&pcm_handle,
547  iscapture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
548  SND_PCM_NONBLOCK);
549 
550  if (status < 0) {
551  return SDL_SetError("ALSA: Couldn't open audio device: %s",
552  ALSA_snd_strerror(status));
553  }
554 
555  this->hidden->pcm_handle = pcm_handle;
556 
557  /* Figure out what the hardware is capable of */
558  snd_pcm_hw_params_alloca(&hwparams);
559  status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams);
560  if (status < 0) {
561  return SDL_SetError("ALSA: Couldn't get hardware config: %s",
562  ALSA_snd_strerror(status));
563  }
564 
565  /* SDL only uses interleaved sample output */
566  status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
567  SND_PCM_ACCESS_RW_INTERLEAVED);
568  if (status < 0) {
569  return SDL_SetError("ALSA: Couldn't set interleaved access: %s",
570  ALSA_snd_strerror(status));
571  }
572 
573  /* Try for a closest match on audio format */
574  status = -1;
575  for (test_format = SDL_FirstAudioFormat(this->spec.format);
576  test_format && (status < 0);) {
577  status = 0; /* if we can't support a format, it'll become -1. */
578  switch (test_format) {
579  case AUDIO_U8:
580  format = SND_PCM_FORMAT_U8;
581  break;
582  case AUDIO_S8:
583  format = SND_PCM_FORMAT_S8;
584  break;
585  case AUDIO_S16LSB:
586  format = SND_PCM_FORMAT_S16_LE;
587  break;
588  case AUDIO_S16MSB:
589  format = SND_PCM_FORMAT_S16_BE;
590  break;
591  case AUDIO_U16LSB:
592  format = SND_PCM_FORMAT_U16_LE;
593  break;
594  case AUDIO_U16MSB:
595  format = SND_PCM_FORMAT_U16_BE;
596  break;
597  case AUDIO_S32LSB:
598  format = SND_PCM_FORMAT_S32_LE;
599  break;
600  case AUDIO_S32MSB:
601  format = SND_PCM_FORMAT_S32_BE;
602  break;
603  case AUDIO_F32LSB:
604  format = SND_PCM_FORMAT_FLOAT_LE;
605  break;
606  case AUDIO_F32MSB:
607  format = SND_PCM_FORMAT_FLOAT_BE;
608  break;
609  default:
610  status = -1;
611  break;
612  }
613  if (status >= 0) {
614  status = ALSA_snd_pcm_hw_params_set_format(pcm_handle,
615  hwparams, format);
616  }
617  if (status < 0) {
618  test_format = SDL_NextAudioFormat();
619  }
620  }
621  if (status < 0) {
622  return SDL_SetError("ALSA: Couldn't find any hardware audio formats");
623  }
624  this->spec.format = test_format;
625 
626  /* Validate number of channels and determine if swizzling is necessary
627  * Assume original swizzling, until proven otherwise.
628  */
629  this->hidden->swizzle_func = swizzle_alsa_channels;
630 #ifdef SND_CHMAP_API_VERSION
631  chmap = ALSA_snd_pcm_get_chmap(pcm_handle);
632  if (chmap) {
633  ALSA_snd_pcm_chmap_print(chmap, sizeof(chmap_str), chmap_str);
634  if (SDL_strcmp("FL FR FC LFE RL RR", chmap_str) == 0 ||
635  SDL_strcmp("FL FR FC LFE SL SR", chmap_str) == 0) {
636  this->hidden->swizzle_func = no_swizzle;
637  }
638  free(chmap);
639  }
640 #endif /* SND_CHMAP_API_VERSION */
641 
642  /* Set the number of channels */
643  status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
644  this->spec.channels);
645  channels = this->spec.channels;
646  if (status < 0) {
647  status = ALSA_snd_pcm_hw_params_get_channels(hwparams, &channels);
648  if (status < 0) {
649  return SDL_SetError("ALSA: Couldn't set audio channels");
650  }
651  this->spec.channels = channels;
652  }
653 
654  /* Set the audio rate */
655  rate = this->spec.freq;
656  status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
657  &rate, NULL);
658  if (status < 0) {
659  return SDL_SetError("ALSA: Couldn't set audio frequency: %s",
660  ALSA_snd_strerror(status));
661  }
662  this->spec.freq = rate;
663 
664  /* Set the buffer size, in samples */
665  status = ALSA_set_buffer_size(this, hwparams);
666  if (status < 0) {
667  return SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status));
668  }
669 
670  /* Set the software parameters */
671  snd_pcm_sw_params_alloca(&swparams);
672  status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
673  if (status < 0) {
674  return SDL_SetError("ALSA: Couldn't get software config: %s",
675  ALSA_snd_strerror(status));
676  }
677  status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, this->spec.samples);
678  if (status < 0) {
679  return SDL_SetError("Couldn't set minimum available samples: %s",
680  ALSA_snd_strerror(status));
681  }
682  status =
683  ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 1);
684  if (status < 0) {
685  return SDL_SetError("ALSA: Couldn't set start threshold: %s",
686  ALSA_snd_strerror(status));
687  }
688  status = ALSA_snd_pcm_sw_params(pcm_handle, swparams);
689  if (status < 0) {
690  return SDL_SetError("Couldn't set software audio parameters: %s",
691  ALSA_snd_strerror(status));
692  }
693 
694  /* Calculate the final parameters for this audio specification */
696 
697  /* Allocate mixing buffer */
698  if (!iscapture) {
699  this->hidden->mixlen = this->spec.size;
700  this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
701  if (this->hidden->mixbuf == NULL) {
702  return SDL_OutOfMemory();
703  }
704  SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
705  }
706 
707  #if !SDL_ALSA_NON_BLOCKING
708  if (!iscapture) {
709  ALSA_snd_pcm_nonblock(pcm_handle, 0);
710  }
711  #endif
712 
713  /* We're ready to rock and roll. :-) */
714  return 0;
715 }
716 
717 typedef struct ALSA_Device
718 {
719  char *name;
720  SDL_bool iscapture;
721  struct ALSA_Device *next;
722 } ALSA_Device;
723 
724 static void
725 add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSeen)
726 {
727  ALSA_Device *dev = SDL_malloc(sizeof (ALSA_Device));
728  char *desc;
729  char *handle = NULL;
730  char *ptr;
731 
732  if (!dev) {
733  return;
734  }
735 
736  /* Not all alsa devices are enumerable via snd_device_name_get_hint
737  (i.e. bluetooth devices). Therefore if hint is passed in to this
738  function as NULL, assume name contains desc.
739  Make sure not to free the storage associated with desc in this case */
740  if (hint) {
741  desc = ALSA_snd_device_name_get_hint(hint, "DESC");
742  if (!desc) {
743  SDL_free(dev);
744  return;
745  }
746  } else {
747  desc = (char *) name;
748  }
749 
750  SDL_assert(name != NULL);
751 
752  /* some strings have newlines, like "HDA NVidia, HDMI 0\nHDMI Audio Output".
753  just chop the extra lines off, this seems to get a reasonable device
754  name without extra details. */
755  if ((ptr = strchr(desc, '\n')) != NULL) {
756  *ptr = '\0';
757  }
758 
759  /*printf("ALSA: adding %s device '%s' (%s)\n", iscapture ? "capture" : "output", name, desc);*/
760 
762  if (!handle) {
763  if (hint) {
764  free(desc);
765  }
766  SDL_free(dev);
767  return;
768  }
769 
770  SDL_AddAudioDevice(iscapture, desc, handle);
771  if (hint)
772  free(desc);
773  dev->name = handle;
774  dev->iscapture = iscapture;
775  dev->next = *pSeen;
776  *pSeen = dev;
777 }
778 
779 
780 static SDL_atomic_t ALSA_hotplug_shutdown;
781 static SDL_Thread *ALSA_hotplug_thread;
782 
783 static int SDLCALL
784 ALSA_HotplugThread(void *arg)
785 {
786  SDL_sem *first_run_semaphore = (SDL_sem *) arg;
787  ALSA_Device *devices = NULL;
788  ALSA_Device *next;
789  ALSA_Device *dev;
790  Uint32 ticks;
791 
793 
794  while (!SDL_AtomicGet(&ALSA_hotplug_shutdown)) {
795  void **hints = NULL;
796  ALSA_Device *unseen;
797  ALSA_Device *seen;
798  ALSA_Device *prev;
799 
800  if (ALSA_snd_device_name_hint(-1, "pcm", &hints) == 0) {
801  int i, j;
802  const char *match = NULL;
803  int bestmatch = 0xFFFF;
804  size_t match_len = 0;
805  int defaultdev = -1;
806  static const char * const prefixes[] = {
807  "hw:", "sysdefault:", "default:", NULL
808  };
809 
810  unseen = devices;
811  seen = NULL;
812  /* Apparently there are several different ways that ALSA lists
813  actual hardware. It could be prefixed with "hw:" or "default:"
814  or "sysdefault:" and maybe others. Go through the list and see
815  if we can find a preferred prefix for the system. */
816  for (i = 0; hints[i]; i++) {
817  char *name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
818  if (!name) {
819  continue;
820  }
821 
822  /* full name, not a prefix */
823  if ((defaultdev == -1) && (SDL_strcmp(name, "default") == 0)) {
824  defaultdev = i;
825  }
826 
827  for (j = 0; prefixes[j]; j++) {
828  const char *prefix = prefixes[j];
829  const size_t prefixlen = SDL_strlen(prefix);
830  if (SDL_strncmp(name, prefix, prefixlen) == 0) {
831  if (j < bestmatch) {
832  bestmatch = j;
833  match = prefix;
834  match_len = prefixlen;
835  }
836  }
837  }
838 
839  free(name);
840  }
841 
842  /* look through the list of device names to find matches */
843  for (i = 0; hints[i]; i++) {
844  char *name;
845 
846  /* if we didn't find a device name prefix we like at all... */
847  if ((!match) && (defaultdev != i)) {
848  continue; /* ...skip anything that isn't the default device. */
849  }
850 
851  name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
852  if (!name) {
853  continue;
854  }
855 
856  /* only want physical hardware interfaces */
857  if (!match || (SDL_strncmp(name, match, match_len) == 0)) {
858  char *ioid = ALSA_snd_device_name_get_hint(hints[i], "IOID");
859  const SDL_bool isoutput = (ioid == NULL) || (SDL_strcmp(ioid, "Output") == 0);
860  const SDL_bool isinput = (ioid == NULL) || (SDL_strcmp(ioid, "Input") == 0);
861  SDL_bool have_output = SDL_FALSE;
862  SDL_bool have_input = SDL_FALSE;
863 
864  free(ioid);
865 
866  if (!isoutput && !isinput) {
867  free(name);
868  continue;
869  }
870 
871  prev = NULL;
872  for (dev = unseen; dev; dev = next) {
873  next = dev->next;
874  if ( (SDL_strcmp(dev->name, name) == 0) && (((isinput) && dev->iscapture) || ((isoutput) && !dev->iscapture)) ) {
875  if (prev) {
876  prev->next = next;
877  } else {
878  unseen = next;
879  }
880  dev->next = seen;
881  seen = dev;
882  if (isinput) have_input = SDL_TRUE;
883  if (isoutput) have_output = SDL_TRUE;
884  } else {
885  prev = dev;
886  }
887  }
888 
889  if (isinput && !have_input) {
890  add_device(SDL_TRUE, name, hints[i], &seen);
891  }
892  if (isoutput && !have_output) {
893  add_device(SDL_FALSE, name, hints[i], &seen);
894  }
895  }
896 
897  free(name);
898  }
899 
900  ALSA_snd_device_name_free_hint(hints);
901 
902  devices = seen; /* now we have a known-good list of attached devices. */
903 
904  /* report anything still in unseen as removed. */
905  for (dev = unseen; dev; dev = next) {
906  /*printf("ALSA: removing usb %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
907  next = dev->next;
908  SDL_RemoveAudioDevice(dev->iscapture, dev->name);
909  SDL_free(dev->name);
910  SDL_free(dev);
911  }
912  }
913 
914  /* On first run, tell ALSA_DetectDevices() that we have a complete device list so it can return. */
915  if (first_run_semaphore) {
916  SDL_SemPost(first_run_semaphore);
917  first_run_semaphore = NULL; /* let other thread clean it up. */
918  }
919 
920  /* Block awhile before checking again, unless we're told to stop. */
921  ticks = SDL_GetTicks() + 5000;
922  while (!SDL_AtomicGet(&ALSA_hotplug_shutdown) && !SDL_TICKS_PASSED(SDL_GetTicks(), ticks)) {
923  SDL_Delay(100);
924  }
925  }
926 
927  /* Shutting down! Clean up any data we've gathered. */
928  for (dev = devices; dev; dev = next) {
929  /*printf("ALSA: at shutdown, removing %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
930  next = dev->next;
931  SDL_free(dev->name);
932  SDL_free(dev);
933  }
934 
935  return 0;
936 }
937 
938 static void
939 ALSA_DetectDevices(void)
940 {
941  /* Start the device detection thread here, wait for an initial iteration to complete. */
942  SDL_sem *semaphore = SDL_CreateSemaphore(0);
943  if (!semaphore) {
944  return; /* oh well. */
945  }
946 
947  SDL_AtomicSet(&ALSA_hotplug_shutdown, 0);
948 
949  ALSA_hotplug_thread = SDL_CreateThread(ALSA_HotplugThread, "SDLHotplugALSA", semaphore);
950  if (ALSA_hotplug_thread) {
951  SDL_SemWait(semaphore); /* wait for the first iteration to finish. */
952  }
953 
954  SDL_DestroySemaphore(semaphore);
955 }
956 
957 static void
958 ALSA_Deinitialize(void)
959 {
960  if (ALSA_hotplug_thread != NULL) {
961  SDL_AtomicSet(&ALSA_hotplug_shutdown, 1);
962  SDL_WaitThread(ALSA_hotplug_thread, NULL);
963  ALSA_hotplug_thread = NULL;
964  }
965 
966  UnloadALSALibrary();
967 }
968 
969 static int
970 ALSA_Init(SDL_AudioDriverImpl * impl)
971 {
972  if (LoadALSALibrary() < 0) {
973  return 0;
974  }
975 
976  /* Set the function pointers */
977  impl->DetectDevices = ALSA_DetectDevices;
978  impl->OpenDevice = ALSA_OpenDevice;
979  impl->WaitDevice = ALSA_WaitDevice;
980  impl->GetDeviceBuf = ALSA_GetDeviceBuf;
981  impl->PlayDevice = ALSA_PlayDevice;
982  impl->CloseDevice = ALSA_CloseDevice;
983  impl->Deinitialize = ALSA_Deinitialize;
984  impl->CaptureFromDevice = ALSA_CaptureFromDevice;
985  impl->FlushCapture = ALSA_FlushCapture;
986 
987  impl->HasCaptureSupport = SDL_TRUE;
988 
989  return 1; /* this audio target is available. */
990 }
991 
992 
994  "alsa", "ALSA PCM audio", ALSA_Init, 0
995 };
996 
997 #endif /* SDL_AUDIO_DRIVER_ALSA */
998 
999 /* vi: set ts=4 sw=4 expandtab: */
format
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
SDL_alsa_audio.h
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_AudioSpec::channels
Uint8 channels
Definition: SDL_audio.h:182
Uint32
uint32_t Uint32
Definition: SDL_stdinc.h:203
SDL_AudioDriverImpl::HasCaptureSupport
int HasCaptureSupport
Definition: SDL_sysaudio.h:90
AUDIO_U16LSB
#define AUDIO_U16LSB
Definition: SDL_audio.h:91
SDL_CreateSemaphore
#define SDL_CreateSemaphore
Definition: SDL_dynapi_overrides.h:264
SDL_AudioDriverImpl::FlushCapture
void(* FlushCapture)(_THIS)
Definition: SDL_sysaudio.h:76
NULL
#define NULL
Definition: begin_code.h:167
handle
EGLImageKHR EGLint EGLint * handle
Definition: eglext.h:937
SDL_timer.h
AUDIO_S32MSB
#define AUDIO_S32MSB
Definition: SDL_audio.h:104
SDL_AudioSpec::samples
Uint16 samples
Definition: SDL_audio.h:184
SDL_zerop
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
SDL_AudioSpec::format
SDL_AudioFormat format
Definition: SDL_audio.h:181
devices
EGLDeviceEXT * devices
Definition: eglext.h:621
SDLCALL
#define SDLCALL
Definition: SDL_internal.h:49
SDL_AudioDriverImpl::OpenDevice
int(* OpenDevice)(_THIS, void *handle, const char *devname, int iscapture)
Definition: SDL_sysaudio.h:68
SDL_AUDIO_DRIVER_ALSA_DYNAMIC
#define SDL_AUDIO_DRIVER_ALSA_DYNAMIC
Definition: SDL_config.h:242
params
const GLfloat * params
Definition: SDL_opengl_glext.h:371
SDL_UnloadObject
#define SDL_UnloadObject
Definition: SDL_dynapi_overrides.h:234
SDL_strncmp
#define SDL_strncmp
Definition: SDL_dynapi_overrides.h:418
SDL_Thread
Definition: SDL_thread_c.h:54
SDL_NextAudioFormat
SDL_AudioFormat SDL_NextAudioFormat(void)
Definition: SDL_audio.c:1659
SDL_THREAD_PRIORITY_LOW
@ SDL_THREAD_PRIORITY_LOW
Definition: SDL_thread.h:60
SDL_OpenedAudioDeviceDisconnected
void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
Definition: SDL_audio.c:486
map
const GLubyte GLuint GLuint GLuint GLuint alpha GLboolean GLboolean GLboolean GLboolean alpha GLint GLint GLsizei GLsizei GLenum type GLenum GLint GLenum GLint GLint GLsizei GLsizei GLint border GLenum GLint GLint GLint GLint GLint GLsizei GLsizei height GLsizei GLsizei GLenum GLenum const GLvoid *pixels GLenum GLint GLint GLint GLint j2 GLdouble GLdouble GLdouble GLdouble GLdouble GLdouble zFar GLenum GLenum GLint *params GLenum GLenum GLint *params GLenum GLenum GLint *params GLenum GLenum GLfloat *params GLenum GLint GLenum GLenum GLvoid *pixels GLenum GLint GLenum GLint *params GLenum GLenum GLint *params GLenum GLsizei const GLvoid *pointer GLenum GLenum const GLint *params GLenum GLfloat GLfloat GLint GLint const GLfloat *points GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat *points GLint GLfloat GLfloat GLint GLfloat GLfloat v2 GLenum GLenum const GLint *params GLdouble GLdouble GLdouble GLdouble GLdouble GLdouble zFar GLenum map
Definition: SDL_glfuncs.h:291
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
SDL_LoadObject
#define SDL_LoadObject
Definition: SDL_dynapi_overrides.h:232
AudioBootStrap
Definition: SDL_sysaudio.h:176
SDL_PrivateAudioData
Definition: SDL_alsa_audio.h:33
AUDIO_U8
#define AUDIO_U8
Definition: SDL_audio.h:89
SDL_AudioDriverImpl::WaitDevice
void(* WaitDevice)(_THIS)
Definition: SDL_sysaudio.h:72
buf
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: SDL_opengl_glext.h:2480
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
buffer
GLuint buffer
Definition: SDL_opengl_glext.h:533
AUDIO_F32MSB
#define AUDIO_F32MSB
Definition: SDL_audio.h:113
SDL_audio.h
retval
SDL_bool retval
Definition: testgamecontroller.c:65
ticks
static int ticks
Definition: testtimer.c:24
SDL_PrivateAudioData::pcm_handle
snd_pcm_t * pcm_handle
Definition: SDL_alsa_audio.h:36
SDL_AudioDriverImpl
Definition: SDL_sysaudio.h:65
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
SDL_max
#define SDL_max(x, y)
Definition: SDL_stdinc.h:407
name
GLuint const GLchar * name
Definition: SDL_opengl_glext.h:660
SDL_RemoveAudioDevice
void SDL_RemoveAudioDevice(const int iscapture, void *handle)
Definition: SDL_audio.c:531
Uint16
uint16_t Uint16
Definition: SDL_stdinc.h:191
bufsize
GLenum GLuint GLsizei bufsize
Definition: SDL_opengl_glext.h:1762
SDL_assert.h
SDL_GetTicks
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
addr
GLenum const void * addr
Definition: SDL_opengl_glext.h:7945
SDL_CalculateAudioSpec
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
Definition: SDL_audio.c:1668
SDL_AudioDriverImpl::DetectDevices
void(* DetectDevices)(void)
Definition: SDL_sysaudio.h:67
_THIS
#define _THIS
Definition: SDL_alsa_audio.h:31
SDL_AUDIO_BITSIZE
#define SDL_AUDIO_BITSIZE(x)
Definition: SDL_audio.h:75
AUDIO_F32LSB
#define AUDIO_F32LSB
Definition: SDL_audio.h:112
SDL_AudioDriverImpl::PlayDevice
void(* PlayDevice)(_THIS)
Definition: SDL_sysaudio.h:73
ALSA_bootstrap
AudioBootStrap ALSA_bootstrap
SDL_Delay
#define SDL_Delay
Definition: SDL_dynapi_overrides.h:486
SDL_CreateThread
#define SDL_CreateThread
Definition: SDL_dynapi_overrides.h:41
SDL_AudioSpec::freq
int freq
Definition: SDL_audio.h:180
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:169
AUDIO_S32LSB
#define AUDIO_S32LSB
Definition: SDL_audio.h:103
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
spec
SDL_AudioSpec spec
Definition: loopwave.c:31
SDL_AudioDriverImpl::CaptureFromDevice
int(* CaptureFromDevice)(_THIS, void *buffer, int buflen)
Definition: SDL_sysaudio.h:75
SDL_AudioSpec::size
Uint32 size
Definition: SDL_audio.h:186
SDL_getenv
#define SDL_getenv
Definition: SDL_dynapi_overrides.h:378
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_SemWait
#define SDL_SemWait
Definition: SDL_dynapi_overrides.h:266
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
Uint64
uint64_t Uint64
Definition: SDL_stdinc.h:216
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
SDL_LoadFunction
void * SDL_LoadFunction(void *handle, const char *name)
SDL_AudioDriverImpl::GetDeviceBuf
Uint8 *(* GetDeviceBuf)(_THIS)
Definition: SDL_sysaudio.h:74
SDL_atomic_t
A type representing an atomic integer value. It is a struct so people don't accidentally use numeric ...
Definition: SDL_atomic.h:216
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
SDL_strlen
#define SDL_strlen
Definition: SDL_dynapi_overrides.h:393
enabled
GLenum GLenum GLsizei const GLuint GLboolean enabled
Definition: SDL_opengl_glext.h:2479
SDL_TICKS_PASSED
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
Definition: SDL_timer.h:56
AUDIO_S16LSB
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
size_t
unsigned int size_t
Definition: SDL_config_windows.h:68
AUDIO_S8
#define AUDIO_S8
Definition: SDL_audio.h:90
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
SDL_strcmp
#define SDL_strcmp
Definition: SDL_dynapi_overrides.h:417
void
const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char const char const SDL_SCANF_FORMAT_STRING char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
Definition: SDL_dynapi_procs.h:89
device
static SDL_AudioDeviceID device
Definition: loopwave.c:37
free
SDL_EventEntry * free
Definition: SDL_events.c:82
SDL_loadso.h
SDL_AudioDriverImpl::CloseDevice
void(* CloseDevice)(_THIS)
Definition: SDL_sysaudio.h:78
AUDIO_U16MSB
#define AUDIO_U16MSB
Definition: SDL_audio.h:93
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_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
SDL_AudioDriverImpl::Deinitialize
void(* Deinitialize)(void)
Definition: SDL_sysaudio.h:82
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:161
get_audio_device
static SDL_AudioDevice * get_audio_device(SDL_AudioDeviceID id)
Definition: SDL_audio.c:200
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:179