SDL  2.0
SDL_alsa_audio.c
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_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 }
344 #endif /* SND_CHMAP_API_VERSION */
345 
346 
347 static void
348 ALSA_PlayDevice(_THIS)
349 {
350  const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf;
351  const int frame_size = ((SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
352  this->spec.channels;
353  snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples);
354 
355  this->hidden->swizzle_func(this, this->hidden->mixbuf, frames_left);
356 
357  while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
358  int status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
359  sample_buf, frames_left);
360 
361  if (status < 0) {
362  if (status == -EAGAIN) {
363  /* Apparently snd_pcm_recover() doesn't handle this case -
364  does it assume snd_pcm_wait() above? */
365  SDL_Delay(1);
366  continue;
367  }
368  status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
369  if (status < 0) {
370  /* Hmm, not much we can do - abort */
371  fprintf(stderr, "ALSA write failed (unrecoverable): %s\n",
372  ALSA_snd_strerror(status));
374  return;
375  }
376  continue;
377  }
378  else if (status == 0) {
379  /* No frames were written (no available space in pcm device).
380  Allow other threads to catch up. */
381  Uint32 delay = (frames_left / 2 * 1000) / this->spec.freq;
382  SDL_Delay(delay);
383  }
384 
385  sample_buf += status * frame_size;
386  frames_left -= status;
387  }
388 }
389 
390 static Uint8 *
391 ALSA_GetDeviceBuf(_THIS)
392 {
393  return (this->hidden->mixbuf);
394 }
395 
396 static int
397 ALSA_CaptureFromDevice(_THIS, void *buffer, int buflen)
398 {
399  Uint8 *sample_buf = (Uint8 *) buffer;
400  const int frame_size = ((SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
401  this->spec.channels;
402  const int total_frames = buflen / frame_size;
403  snd_pcm_uframes_t frames_left = total_frames;
404  snd_pcm_uframes_t wait_time = frame_size / 2;
405 
406  SDL_assert((buflen % frame_size) == 0);
407 
408  while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
409  int status;
410 
411  status = ALSA_snd_pcm_readi(this->hidden->pcm_handle,
412  sample_buf, frames_left);
413 
414  if (status == -EAGAIN) {
415  ALSA_snd_pcm_wait(this->hidden->pcm_handle, wait_time);
416  status = 0;
417  }
418  else if (status < 0) {
419  /*printf("ALSA: capture error %d\n", status);*/
420  status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
421  if (status < 0) {
422  /* Hmm, not much we can do - abort */
423  fprintf(stderr, "ALSA read failed (unrecoverable): %s\n",
424  ALSA_snd_strerror(status));
425  return -1;
426  }
427  continue;
428  }
429 
430  /*printf("ALSA: captured %d bytes\n", status * frame_size);*/
431  sample_buf += status * frame_size;
432  frames_left -= status;
433  }
434 
435  this->hidden->swizzle_func(this, buffer, total_frames - frames_left);
436 
437  return (total_frames - frames_left) * frame_size;
438 }
439 
440 static void
441 ALSA_FlushCapture(_THIS)
442 {
443  ALSA_snd_pcm_reset(this->hidden->pcm_handle);
444 }
445 
446 static void
447 ALSA_CloseDevice(_THIS)
448 {
449  if (this->hidden->pcm_handle) {
450  /* Wait for the submitted audio to drain
451  ALSA_snd_pcm_drop() can hang, so don't use that.
452  */
453  Uint32 delay = ((this->spec.samples * 1000) / this->spec.freq) * 2;
454  SDL_Delay(delay);
455 
456  ALSA_snd_pcm_close(this->hidden->pcm_handle);
457  }
458  SDL_free(this->hidden->mixbuf);
459  SDL_free(this->hidden);
460 }
461 
462 static int
463 ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params)
464 {
465  int status;
466  snd_pcm_hw_params_t *hwparams;
467  snd_pcm_uframes_t persize;
468  unsigned int periods;
469 
470  /* Copy the hardware parameters for this setup */
471  snd_pcm_hw_params_alloca(&hwparams);
472  ALSA_snd_pcm_hw_params_copy(hwparams, params);
473 
474  /* Attempt to match the period size to the requested buffer size */
475  persize = this->spec.samples;
476  status = ALSA_snd_pcm_hw_params_set_period_size_near(
477  this->hidden->pcm_handle, hwparams, &persize, NULL);
478  if ( status < 0 ) {
479  return(-1);
480  }
481 
482  /* Need to at least double buffer */
483  periods = 2;
484  status = ALSA_snd_pcm_hw_params_set_periods_min(
485  this->hidden->pcm_handle, hwparams, &periods, NULL);
486  if ( status < 0 ) {
487  return(-1);
488  }
489 
490  status = ALSA_snd_pcm_hw_params_set_periods_first(
491  this->hidden->pcm_handle, hwparams, &periods, NULL);
492  if ( status < 0 ) {
493  return(-1);
494  }
495 
496  /* "set" the hardware with the desired parameters */
497  status = ALSA_snd_pcm_hw_params(this->hidden->pcm_handle, hwparams);
498  if ( status < 0 ) {
499  return(-1);
500  }
501 
502  this->spec.samples = persize;
503 
504  /* This is useful for debugging */
505  if ( SDL_getenv("SDL_AUDIO_ALSA_DEBUG") ) {
506  snd_pcm_uframes_t bufsize;
507 
508  ALSA_snd_pcm_hw_params_get_buffer_size(hwparams, &bufsize);
509 
510  fprintf(stderr,
511  "ALSA: period size = %ld, periods = %u, buffer size = %lu\n",
512  persize, periods, bufsize);
513  }
514 
515  return(0);
516 }
517 
518 static int
519 ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
520 {
521  int status = 0;
522  snd_pcm_t *pcm_handle = NULL;
523  snd_pcm_hw_params_t *hwparams = NULL;
524  snd_pcm_sw_params_t *swparams = NULL;
525  snd_pcm_format_t format = 0;
526  SDL_AudioFormat test_format = 0;
527  unsigned int rate = 0;
528  unsigned int channels = 0;
529 #ifdef SND_CHMAP_API_VERSION
530  snd_pcm_chmap_t *chmap;
531  char chmap_str[64];
532 #endif
533 
534  /* Initialize all variables that we clean on shutdown */
535  this->hidden = (struct SDL_PrivateAudioData *)
536  SDL_malloc((sizeof *this->hidden));
537  if (this->hidden == NULL) {
538  return SDL_OutOfMemory();
539  }
540  SDL_zerop(this->hidden);
541 
542  /* Open the audio device */
543  /* Name of device should depend on # channels in spec */
544  status = ALSA_snd_pcm_open(&pcm_handle,
546  iscapture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
547  SND_PCM_NONBLOCK);
548 
549  if (status < 0) {
550  return SDL_SetError("ALSA: Couldn't open audio device: %s",
551  ALSA_snd_strerror(status));
552  }
553 
554  this->hidden->pcm_handle = pcm_handle;
555 
556  /* Figure out what the hardware is capable of */
557  snd_pcm_hw_params_alloca(&hwparams);
558  status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams);
559  if (status < 0) {
560  return SDL_SetError("ALSA: Couldn't get hardware config: %s",
561  ALSA_snd_strerror(status));
562  }
563 
564  /* SDL only uses interleaved sample output */
565  status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
566  SND_PCM_ACCESS_RW_INTERLEAVED);
567  if (status < 0) {
568  return SDL_SetError("ALSA: Couldn't set interleaved access: %s",
569  ALSA_snd_strerror(status));
570  }
571 
572  /* Try for a closest match on audio format */
573  status = -1;
574  for (test_format = SDL_FirstAudioFormat(this->spec.format);
575  test_format && (status < 0);) {
576  status = 0; /* if we can't support a format, it'll become -1. */
577  switch (test_format) {
578  case AUDIO_U8:
579  format = SND_PCM_FORMAT_U8;
580  break;
581  case AUDIO_S8:
582  format = SND_PCM_FORMAT_S8;
583  break;
584  case AUDIO_S16LSB:
585  format = SND_PCM_FORMAT_S16_LE;
586  break;
587  case AUDIO_S16MSB:
588  format = SND_PCM_FORMAT_S16_BE;
589  break;
590  case AUDIO_U16LSB:
591  format = SND_PCM_FORMAT_U16_LE;
592  break;
593  case AUDIO_U16MSB:
594  format = SND_PCM_FORMAT_U16_BE;
595  break;
596  case AUDIO_S32LSB:
597  format = SND_PCM_FORMAT_S32_LE;
598  break;
599  case AUDIO_S32MSB:
600  format = SND_PCM_FORMAT_S32_BE;
601  break;
602  case AUDIO_F32LSB:
603  format = SND_PCM_FORMAT_FLOAT_LE;
604  break;
605  case AUDIO_F32MSB:
606  format = SND_PCM_FORMAT_FLOAT_BE;
607  break;
608  default:
609  status = -1;
610  break;
611  }
612  if (status >= 0) {
613  status = ALSA_snd_pcm_hw_params_set_format(pcm_handle,
614  hwparams, format);
615  }
616  if (status < 0) {
617  test_format = SDL_NextAudioFormat();
618  }
619  }
620  if (status < 0) {
621  return SDL_SetError("ALSA: Couldn't find any hardware audio formats");
622  }
623  this->spec.format = test_format;
624 
625  /* Validate number of channels and determine if swizzling is necessary
626  * Assume original swizzling, until proven otherwise.
627  */
628  this->hidden->swizzle_func = swizzle_alsa_channels;
629 #ifdef SND_CHMAP_API_VERSION
630  chmap = ALSA_snd_pcm_get_chmap(pcm_handle);
631  if (chmap) {
632  ALSA_snd_pcm_chmap_print(chmap, sizeof(chmap_str), chmap_str);
633  if (SDL_strcmp("FL FR FC LFE RL RR", chmap_str) == 0 ||
634  SDL_strcmp("FL FR FC LFE SL SR", chmap_str) == 0) {
635  this->hidden->swizzle_func = no_swizzle;
636  }
637  free(chmap);
638  }
639 #endif /* SND_CHMAP_API_VERSION */
640 
641  /* Set the number of channels */
642  status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
643  this->spec.channels);
644  channels = this->spec.channels;
645  if (status < 0) {
646  status = ALSA_snd_pcm_hw_params_get_channels(hwparams, &channels);
647  if (status < 0) {
648  return SDL_SetError("ALSA: Couldn't set audio channels");
649  }
650  this->spec.channels = channels;
651  }
652 
653  /* Set the audio rate */
654  rate = this->spec.freq;
655  status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
656  &rate, NULL);
657  if (status < 0) {
658  return SDL_SetError("ALSA: Couldn't set audio frequency: %s",
659  ALSA_snd_strerror(status));
660  }
661  this->spec.freq = rate;
662 
663  /* Set the buffer size, in samples */
664  status = ALSA_set_buffer_size(this, hwparams);
665  if (status < 0) {
666  return SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status));
667  }
668 
669  /* Set the software parameters */
670  snd_pcm_sw_params_alloca(&swparams);
671  status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
672  if (status < 0) {
673  return SDL_SetError("ALSA: Couldn't get software config: %s",
674  ALSA_snd_strerror(status));
675  }
676  status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, this->spec.samples);
677  if (status < 0) {
678  return SDL_SetError("Couldn't set minimum available samples: %s",
679  ALSA_snd_strerror(status));
680  }
681  status =
682  ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 1);
683  if (status < 0) {
684  return SDL_SetError("ALSA: Couldn't set start threshold: %s",
685  ALSA_snd_strerror(status));
686  }
687  status = ALSA_snd_pcm_sw_params(pcm_handle, swparams);
688  if (status < 0) {
689  return SDL_SetError("Couldn't set software audio parameters: %s",
690  ALSA_snd_strerror(status));
691  }
692 
693  /* Calculate the final parameters for this audio specification */
695 
696  /* Allocate mixing buffer */
697  if (!iscapture) {
698  this->hidden->mixlen = this->spec.size;
699  this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
700  if (this->hidden->mixbuf == NULL) {
701  return SDL_OutOfMemory();
702  }
703  SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
704  }
705 
706  #if !SDL_ALSA_NON_BLOCKING
707  if (!iscapture) {
708  ALSA_snd_pcm_nonblock(pcm_handle, 0);
709  }
710  #endif
711 
712  /* We're ready to rock and roll. :-) */
713  return 0;
714 }
715 
716 typedef struct ALSA_Device
717 {
718  char *name;
719  SDL_bool iscapture;
720  struct ALSA_Device *next;
721 } ALSA_Device;
722 
723 static void
724 add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSeen)
725 {
726  ALSA_Device *dev = SDL_malloc(sizeof (ALSA_Device));
727  char *desc;
728  char *handle = NULL;
729  char *ptr;
730 
731  if (!dev) {
732  return;
733  }
734 
735  /* Not all alsa devices are enumerable via snd_device_name_get_hint
736  (i.e. bluetooth devices). Therefore if hint is passed in to this
737  function as NULL, assume name contains desc.
738  Make sure not to free the storage associated with desc in this case */
739  if (hint) {
740  desc = ALSA_snd_device_name_get_hint(hint, "DESC");
741  if (!desc) {
742  SDL_free(dev);
743  return;
744  }
745  } else {
746  desc = (char *) name;
747  }
748 
749  SDL_assert(name != NULL);
750 
751  /* some strings have newlines, like "HDA NVidia, HDMI 0\nHDMI Audio Output".
752  just chop the extra lines off, this seems to get a reasonable device
753  name without extra details. */
754  if ((ptr = strchr(desc, '\n')) != NULL) {
755  *ptr = '\0';
756  }
757 
758  /*printf("ALSA: adding %s device '%s' (%s)\n", iscapture ? "capture" : "output", name, desc);*/
759 
761  if (!handle) {
762  if (hint) {
763  free(desc);
764  }
765  SDL_free(dev);
766  return;
767  }
768 
769  SDL_AddAudioDevice(iscapture, desc, handle);
770  if (hint)
771  free(desc);
772  dev->name = handle;
773  dev->iscapture = iscapture;
774  dev->next = *pSeen;
775  *pSeen = dev;
776 }
777 
778 
779 static SDL_atomic_t ALSA_hotplug_shutdown;
780 static SDL_Thread *ALSA_hotplug_thread;
781 
782 static int SDLCALL
783 ALSA_HotplugThread(void *arg)
784 {
785  SDL_sem *first_run_semaphore = (SDL_sem *) arg;
786  ALSA_Device *devices = NULL;
787  ALSA_Device *next;
788  ALSA_Device *dev;
789  Uint32 ticks;
790 
792 
793  while (!SDL_AtomicGet(&ALSA_hotplug_shutdown)) {
794  void **hints = NULL;
795  ALSA_Device *unseen;
796  ALSA_Device *seen;
797  ALSA_Device *prev;
798 
799  if (ALSA_snd_device_name_hint(-1, "pcm", &hints) == 0) {
800  int i, j;
801  const char *match = NULL;
802  int bestmatch = 0xFFFF;
803  size_t match_len = 0;
804  int defaultdev = -1;
805  static const char * const prefixes[] = {
806  "hw:", "sysdefault:", "default:", NULL
807  };
808 
809  unseen = devices;
810  seen = NULL;
811  /* Apparently there are several different ways that ALSA lists
812  actual hardware. It could be prefixed with "hw:" or "default:"
813  or "sysdefault:" and maybe others. Go through the list and see
814  if we can find a preferred prefix for the system. */
815  for (i = 0; hints[i]; i++) {
816  char *name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
817  if (!name) {
818  continue;
819  }
820 
821  /* full name, not a prefix */
822  if ((defaultdev == -1) && (SDL_strcmp(name, "default") == 0)) {
823  defaultdev = i;
824  }
825 
826  for (j = 0; prefixes[j]; j++) {
827  const char *prefix = prefixes[j];
828  const size_t prefixlen = SDL_strlen(prefix);
829  if (SDL_strncmp(name, prefix, prefixlen) == 0) {
830  if (j < bestmatch) {
831  bestmatch = j;
832  match = prefix;
833  match_len = prefixlen;
834  }
835  }
836  }
837 
838  free(name);
839  }
840 
841  /* look through the list of device names to find matches */
842  for (i = 0; hints[i]; i++) {
843  char *name;
844 
845  /* if we didn't find a device name prefix we like at all... */
846  if ((!match) && (defaultdev != i)) {
847  continue; /* ...skip anything that isn't the default device. */
848  }
849 
850  name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
851  if (!name) {
852  continue;
853  }
854 
855  /* only want physical hardware interfaces */
856  if (!match || (SDL_strncmp(name, match, match_len) == 0)) {
857  char *ioid = ALSA_snd_device_name_get_hint(hints[i], "IOID");
858  const SDL_bool isoutput = (ioid == NULL) || (SDL_strcmp(ioid, "Output") == 0);
859  const SDL_bool isinput = (ioid == NULL) || (SDL_strcmp(ioid, "Input") == 0);
860  SDL_bool have_output = SDL_FALSE;
861  SDL_bool have_input = SDL_FALSE;
862 
863  free(ioid);
864 
865  if (!isoutput && !isinput) {
866  free(name);
867  continue;
868  }
869 
870  prev = NULL;
871  for (dev = unseen; dev; dev = next) {
872  next = dev->next;
873  if ( (SDL_strcmp(dev->name, name) == 0) && (((isinput) && dev->iscapture) || ((isoutput) && !dev->iscapture)) ) {
874  if (prev) {
875  prev->next = next;
876  } else {
877  unseen = next;
878  }
879  dev->next = seen;
880  seen = dev;
881  if (isinput) have_input = SDL_TRUE;
882  if (isoutput) have_output = SDL_TRUE;
883  } else {
884  prev = dev;
885  }
886  }
887 
888  if (isinput && !have_input) {
889  add_device(SDL_TRUE, name, hints[i], &seen);
890  }
891  if (isoutput && !have_output) {
892  add_device(SDL_FALSE, name, hints[i], &seen);
893  }
894  }
895 
896  free(name);
897  }
898 
899  ALSA_snd_device_name_free_hint(hints);
900 
901  devices = seen; /* now we have a known-good list of attached devices. */
902 
903  /* report anything still in unseen as removed. */
904  for (dev = unseen; dev; dev = next) {
905  /*printf("ALSA: removing usb %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
906  next = dev->next;
907  SDL_RemoveAudioDevice(dev->iscapture, dev->name);
908  SDL_free(dev->name);
909  SDL_free(dev);
910  }
911  }
912 
913  /* On first run, tell ALSA_DetectDevices() that we have a complete device list so it can return. */
914  if (first_run_semaphore) {
915  SDL_SemPost(first_run_semaphore);
916  first_run_semaphore = NULL; /* let other thread clean it up. */
917  }
918 
919  /* Block awhile before checking again, unless we're told to stop. */
920  ticks = SDL_GetTicks() + 5000;
921  while (!SDL_AtomicGet(&ALSA_hotplug_shutdown) && !SDL_TICKS_PASSED(SDL_GetTicks(), ticks)) {
922  SDL_Delay(100);
923  }
924  }
925 
926  /* Shutting down! Clean up any data we've gathered. */
927  for (dev = devices; dev; dev = next) {
928  /*printf("ALSA: at shutdown, removing %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
929  next = dev->next;
930  SDL_free(dev->name);
931  SDL_free(dev);
932  }
933 
934  return 0;
935 }
936 
937 static void
938 ALSA_DetectDevices(void)
939 {
940  /* Start the device detection thread here, wait for an initial iteration to complete. */
941  SDL_sem *semaphore = SDL_CreateSemaphore(0);
942  if (!semaphore) {
943  return; /* oh well. */
944  }
945 
946  SDL_AtomicSet(&ALSA_hotplug_shutdown, 0);
947 
948  ALSA_hotplug_thread = SDL_CreateThread(ALSA_HotplugThread, "SDLHotplugALSA", semaphore);
949  if (ALSA_hotplug_thread) {
950  SDL_SemWait(semaphore); /* wait for the first iteration to finish. */
951  }
952 
953  SDL_DestroySemaphore(semaphore);
954 }
955 
956 static void
957 ALSA_Deinitialize(void)
958 {
959  if (ALSA_hotplug_thread != NULL) {
960  SDL_AtomicSet(&ALSA_hotplug_shutdown, 1);
961  SDL_WaitThread(ALSA_hotplug_thread, NULL);
962  ALSA_hotplug_thread = NULL;
963  }
964 
965  UnloadALSALibrary();
966 }
967 
968 static int
969 ALSA_Init(SDL_AudioDriverImpl * impl)
970 {
971  if (LoadALSALibrary() < 0) {
972  return 0;
973  }
974 
975  /* Set the function pointers */
976  impl->DetectDevices = ALSA_DetectDevices;
977  impl->OpenDevice = ALSA_OpenDevice;
978  impl->WaitDevice = ALSA_WaitDevice;
979  impl->GetDeviceBuf = ALSA_GetDeviceBuf;
980  impl->PlayDevice = ALSA_PlayDevice;
981  impl->CloseDevice = ALSA_CloseDevice;
982  impl->Deinitialize = ALSA_Deinitialize;
983  impl->CaptureFromDevice = ALSA_CaptureFromDevice;
984  impl->FlushCapture = ALSA_FlushCapture;
985 
986  impl->HasCaptureSupport = SDL_TRUE;
987 
988  return 1; /* this audio target is available. */
989 }
990 
991 
993  "alsa", "ALSA PCM audio", ALSA_Init, 0
994 };
995 
996 #endif /* SDL_AUDIO_DRIVER_ALSA */
997 
998 /* 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
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_CreateThread
#define SDL_CreateThread(fn, name, data)
Definition: SDL_thread.h:132
SDL_AudioSpec::channels
Uint8 channels
Definition: SDL_audio.h:182
SDL_AudioDriverImpl::HasCaptureSupport
int HasCaptureSupport
Definition: SDL_sysaudio.h:90
Uint16
uint16_t Uint16
Definition: SDL_stdinc.h:191
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
size_t
unsigned int size_t
Definition: SDL_config_windows.h:68
SDL_zerop
#define SDL_zerop(x)
Definition: SDL_stdinc.h:419
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
params
const GLfloat * params
Definition: SDL_opengl_glext.h:374
SDL_UnloadObject
#define SDL_UnloadObject
Definition: SDL_dynapi_overrides.h:234
Uint32
uint32_t Uint32
Definition: SDL_stdinc.h:203
SDL_strncmp
#define SDL_strncmp
Definition: SDL_dynapi_overrides.h:418
SDL_Thread
Definition: SDL_thread_c.h:55
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:177
SDL_PrivateAudioData
Definition: SDL_alsa_audio.h:34
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:2483
buffer
GLuint buffer
Definition: SDL_opengl_glext.h:536
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:66
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:663
SDL_RemoveAudioDevice
void SDL_RemoveAudioDevice(const int iscapture, void *handle)
Definition: SDL_audio.c:531
bufsize
GLenum GLuint GLsizei bufsize
Definition: SDL_opengl_glext.h:1765
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: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_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_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_Delay
#define SDL_Delay
Definition: SDL_dynapi_overrides.h:486
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_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
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:2482
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
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:162
AUDIO_S16LSB
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
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_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
SDL_strcmp
#define SDL_strcmp
Definition: SDL_dynapi_overrides.h:417
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
device
static SDL_AudioDeviceID device
Definition: loopwave.c:37
free
SDL_EventEntry * free
Definition: SDL_events.c:89
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
SDL_loadso.h
SDL_AudioDriverImpl::CloseDevice
void(* CloseDevice)(_THIS)
Definition: SDL_sysaudio.h:78
AUDIO_U16MSB
#define AUDIO_U16MSB
Definition: SDL_audio.h:93
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_AudioDriverImpl::Deinitialize
void(* Deinitialize)(void)
Definition: SDL_sysaudio.h:82
get_audio_device
static SDL_AudioDevice * get_audio_device(SDL_AudioDeviceID id)
Definition: SDL_audio.c:200