zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_alsa_audio.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2013 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_config.h"
22 
23 #if SDL_AUDIO_DRIVER_ALSA
24 
25 /* Allow access to a raw mixing buffer */
26 
27 #include <sys/types.h>
28 #include <signal.h> /* For kill() */
29 #include <errno.h>
30 #include <string.h>
31 
32 #include "SDL_timer.h"
33 #include "SDL_audio.h"
34 #include "../SDL_audiomem.h"
35 #include "../SDL_audio_c.h"
36 #include "SDL_alsa_audio.h"
37 
38 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
39 #include "SDL_loadso.h"
40 #endif
41 
42 static int (*ALSA_snd_pcm_open)
43  (snd_pcm_t **, const char *, snd_pcm_stream_t, int);
44 static int (*ALSA_snd_pcm_close) (snd_pcm_t * pcm);
45 static snd_pcm_sframes_t(*ALSA_snd_pcm_writei)
46  (snd_pcm_t *, const void *, snd_pcm_uframes_t);
47 static int (*ALSA_snd_pcm_recover) (snd_pcm_t *, int, int);
48 static int (*ALSA_snd_pcm_prepare) (snd_pcm_t *);
49 static int (*ALSA_snd_pcm_drain) (snd_pcm_t *);
50 static const char *(*ALSA_snd_strerror) (int);
51 static size_t(*ALSA_snd_pcm_hw_params_sizeof) (void);
52 static size_t(*ALSA_snd_pcm_sw_params_sizeof) (void);
53 static void (*ALSA_snd_pcm_hw_params_copy)
54  (snd_pcm_hw_params_t *, const snd_pcm_hw_params_t *);
55 static int (*ALSA_snd_pcm_hw_params_any) (snd_pcm_t *, snd_pcm_hw_params_t *);
56 static int (*ALSA_snd_pcm_hw_params_set_access)
57  (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_access_t);
58 static int (*ALSA_snd_pcm_hw_params_set_format)
59  (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_format_t);
60 static int (*ALSA_snd_pcm_hw_params_set_channels)
61  (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int);
62 static int (*ALSA_snd_pcm_hw_params_get_channels)
63  (const snd_pcm_hw_params_t *, unsigned int *);
64 static int (*ALSA_snd_pcm_hw_params_set_rate_near)
65  (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *);
66 static int (*ALSA_snd_pcm_hw_params_set_period_size_near)
67  (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_uframes_t *, int *);
68 static int (*ALSA_snd_pcm_hw_params_get_period_size)
69  (const snd_pcm_hw_params_t *, snd_pcm_uframes_t *, int *);
70 static int (*ALSA_snd_pcm_hw_params_set_periods_near)
71  (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *);
72 static int (*ALSA_snd_pcm_hw_params_get_periods)
73  (const snd_pcm_hw_params_t *, unsigned int *, int *);
74 static int (*ALSA_snd_pcm_hw_params_set_buffer_size_near)
75  (snd_pcm_t *pcm, snd_pcm_hw_params_t *, snd_pcm_uframes_t *);
76 static int (*ALSA_snd_pcm_hw_params_get_buffer_size)
77  (const snd_pcm_hw_params_t *, snd_pcm_uframes_t *);
78 static int (*ALSA_snd_pcm_hw_params) (snd_pcm_t *, snd_pcm_hw_params_t *);
79 static int (*ALSA_snd_pcm_sw_params_current) (snd_pcm_t *,
80  snd_pcm_sw_params_t *);
81 static int (*ALSA_snd_pcm_sw_params_set_start_threshold)
82  (snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
83 static int (*ALSA_snd_pcm_sw_params) (snd_pcm_t *, snd_pcm_sw_params_t *);
84 static int (*ALSA_snd_pcm_nonblock) (snd_pcm_t *, int);
85 static int (*ALSA_snd_pcm_wait)(snd_pcm_t *, int);
86 static int (*ALSA_snd_pcm_sw_params_set_avail_min)
87  (snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
88 
89 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
90 #define snd_pcm_hw_params_sizeof ALSA_snd_pcm_hw_params_sizeof
91 #define snd_pcm_sw_params_sizeof ALSA_snd_pcm_sw_params_sizeof
92 
93 static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
94 static void *alsa_handle = NULL;
95 
96 static int
97 load_alsa_sym(const char *fn, void **addr)
98 {
99  *addr = SDL_LoadFunction(alsa_handle, fn);
100  if (*addr == NULL) {
101  /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
102  return 0;
103  }
104 
105  return 1;
106 }
107 
108 /* cast funcs to char* first, to please GCC's strict aliasing rules. */
109 #define SDL_ALSA_SYM(x) \
110  if (!load_alsa_sym(#x, (void **) (char *) &ALSA_##x)) return -1
111 #else
112 #define SDL_ALSA_SYM(x) ALSA_##x = x
113 #endif
114 
115 static int
116 load_alsa_syms(void)
117 {
118  SDL_ALSA_SYM(snd_pcm_open);
119  SDL_ALSA_SYM(snd_pcm_close);
120  SDL_ALSA_SYM(snd_pcm_writei);
121  SDL_ALSA_SYM(snd_pcm_recover);
122  SDL_ALSA_SYM(snd_pcm_prepare);
123  SDL_ALSA_SYM(snd_pcm_drain);
124  SDL_ALSA_SYM(snd_strerror);
125  SDL_ALSA_SYM(snd_pcm_hw_params_sizeof);
126  SDL_ALSA_SYM(snd_pcm_sw_params_sizeof);
127  SDL_ALSA_SYM(snd_pcm_hw_params_copy);
128  SDL_ALSA_SYM(snd_pcm_hw_params_any);
129  SDL_ALSA_SYM(snd_pcm_hw_params_set_access);
130  SDL_ALSA_SYM(snd_pcm_hw_params_set_format);
131  SDL_ALSA_SYM(snd_pcm_hw_params_set_channels);
132  SDL_ALSA_SYM(snd_pcm_hw_params_get_channels);
133  SDL_ALSA_SYM(snd_pcm_hw_params_set_rate_near);
134  SDL_ALSA_SYM(snd_pcm_hw_params_set_period_size_near);
135  SDL_ALSA_SYM(snd_pcm_hw_params_get_period_size);
136  SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_near);
137  SDL_ALSA_SYM(snd_pcm_hw_params_get_periods);
138  SDL_ALSA_SYM(snd_pcm_hw_params_set_buffer_size_near);
139  SDL_ALSA_SYM(snd_pcm_hw_params_get_buffer_size);
140  SDL_ALSA_SYM(snd_pcm_hw_params);
141  SDL_ALSA_SYM(snd_pcm_sw_params_current);
142  SDL_ALSA_SYM(snd_pcm_sw_params_set_start_threshold);
143  SDL_ALSA_SYM(snd_pcm_sw_params);
144  SDL_ALSA_SYM(snd_pcm_nonblock);
145  SDL_ALSA_SYM(snd_pcm_wait);
146  SDL_ALSA_SYM(snd_pcm_sw_params_set_avail_min);
147  return 0;
148 }
149 
150 #undef SDL_ALSA_SYM
151 
152 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
153 
154 static void
155 UnloadALSALibrary(void)
156 {
157  if (alsa_handle != NULL) {
158  SDL_UnloadObject(alsa_handle);
159  alsa_handle = NULL;
160  }
161 }
162 
163 static int
164 LoadALSALibrary(void)
165 {
166  int retval = 0;
167  if (alsa_handle == NULL) {
168  alsa_handle = SDL_LoadObject(alsa_library);
169  if (alsa_handle == NULL) {
170  retval = -1;
171  /* Don't call SDL_SetError(): SDL_LoadObject already did. */
172  } else {
173  retval = load_alsa_syms();
174  if (retval < 0) {
175  UnloadALSALibrary();
176  }
177  }
178  }
179  return retval;
180 }
181 
182 #else
183 
184 static void
185 UnloadALSALibrary(void)
186 {
187 }
188 
189 static int
190 LoadALSALibrary(void)
191 {
192  load_alsa_syms();
193  return 0;
194 }
195 
196 #endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */
197 
198 static const char *
199 get_audio_device(int channels)
200 {
201  const char *device;
202 
203  device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */
204  if (device == NULL) {
205  switch (channels) {
206  case 6:
207  device = "plug:surround51";
208  break;
209  case 4:
210  device = "plug:surround40";
211  break;
212  default:
213  device = "default";
214  break;
215  }
216  }
217  return device;
218 }
219 
220 
221 /* This function waits until it is possible to write a full sound buffer */
222 static void
223 ALSA_WaitDevice(_THIS)
224 {
225  /* We're in blocking mode, so there's nothing to do here */
226 }
227 
228 
229 /* !!! FIXME: is there a channel swizzler in alsalib instead? */
230 /*
231  * http://bugzilla.libsdl.org/show_bug.cgi?id=110
232  * "For Linux ALSA, this is FL-FR-RL-RR-C-LFE
233  * and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR"
234  */
235 #define SWIZ6(T) \
236  T *ptr = (T *) this->hidden->mixbuf; \
237  Uint32 i; \
238  for (i = 0; i < this->spec.samples; i++, ptr += 6) { \
239  T tmp; \
240  tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \
241  tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \
242  }
243 
244 static __inline__ void
245 swizzle_alsa_channels_6_64bit(_THIS)
246 {
247  SWIZ6(Uint64);
248 }
249 
250 static __inline__ void
251 swizzle_alsa_channels_6_32bit(_THIS)
252 {
253  SWIZ6(Uint32);
254 }
255 
256 static __inline__ void
257 swizzle_alsa_channels_6_16bit(_THIS)
258 {
259  SWIZ6(Uint16);
260 }
261 
262 static __inline__ void
263 swizzle_alsa_channels_6_8bit(_THIS)
264 {
265  SWIZ6(Uint8);
266 }
267 
268 #undef SWIZ6
269 
270 
271 /*
272  * Called right before feeding this->hidden->mixbuf to the hardware. Swizzle
273  * channels from Windows/Mac order to the format alsalib will want.
274  */
275 static __inline__ void
276 swizzle_alsa_channels(_THIS)
277 {
278  if (this->spec.channels == 6) {
279  const Uint16 fmtsize = (this->spec.format & 0xFF); /* bits/channel. */
280  if (fmtsize == 16)
281  swizzle_alsa_channels_6_16bit(this);
282  else if (fmtsize == 8)
283  swizzle_alsa_channels_6_8bit(this);
284  else if (fmtsize == 32)
285  swizzle_alsa_channels_6_32bit(this);
286  else if (fmtsize == 64)
287  swizzle_alsa_channels_6_64bit(this);
288  }
289 
290  /* !!! FIXME: update this for 7.1 if needed, later. */
291 }
292 
293 
294 static void
295 ALSA_PlayDevice(_THIS)
296 {
297  int status;
298  const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf;
299  const int frame_size = (((int) (this->spec.format & 0xFF)) / 8) *
300  this->spec.channels;
301  snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples);
302 
303  swizzle_alsa_channels(this);
304 
305  while ( frames_left > 0 && this->enabled ) {
306  /* !!! FIXME: This works, but needs more testing before going live */
307  /* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */
308  status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
309  sample_buf, frames_left);
310 
311  if (status < 0) {
312  if (status == -EAGAIN) {
313  /* Apparently snd_pcm_recover() doesn't handle this case -
314  does it assume snd_pcm_wait() above? */
315  SDL_Delay(1);
316  continue;
317  }
318  status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
319  if (status < 0) {
320  /* Hmm, not much we can do - abort */
321  fprintf(stderr, "ALSA write failed (unrecoverable): %s\n",
322  ALSA_snd_strerror(status));
323  this->enabled = 0;
324  return;
325  }
326  continue;
327  }
328  sample_buf += status * frame_size;
329  frames_left -= status;
330  }
331 }
332 
333 static Uint8 *
334 ALSA_GetDeviceBuf(_THIS)
335 {
336  return (this->hidden->mixbuf);
337 }
338 
339 static void
340 ALSA_CloseDevice(_THIS)
341 {
342  if (this->hidden != NULL) {
343  SDL_FreeAudioMem(this->hidden->mixbuf);
344  this->hidden->mixbuf = NULL;
345  if (this->hidden->pcm_handle) {
346  ALSA_snd_pcm_drain(this->hidden->pcm_handle);
347  ALSA_snd_pcm_close(this->hidden->pcm_handle);
348  this->hidden->pcm_handle = NULL;
349  }
350  SDL_free(this->hidden);
351  this->hidden = NULL;
352  }
353 }
354 
355 static int
356 ALSA_finalize_hardware(_THIS, snd_pcm_hw_params_t *hwparams, int override)
357 {
358  int status;
359  snd_pcm_uframes_t bufsize;
360 
361  /* "set" the hardware with the desired parameters */
362  status = ALSA_snd_pcm_hw_params(this->hidden->pcm_handle, hwparams);
363  if ( status < 0 ) {
364  return(-1);
365  }
366 
367  /* Get samples for the actual buffer size */
368  status = ALSA_snd_pcm_hw_params_get_buffer_size(hwparams, &bufsize);
369  if ( status < 0 ) {
370  return(-1);
371  }
372  if ( !override && bufsize != this->spec.samples * 2 ) {
373  return(-1);
374  }
375 
376  /* !!! FIXME: Is this safe to do? */
377  this->spec.samples = bufsize / 2;
378 
379  /* This is useful for debugging */
380  if ( SDL_getenv("SDL_AUDIO_ALSA_DEBUG") ) {
381  snd_pcm_uframes_t persize = 0;
382  unsigned int periods = 0;
383 
384  ALSA_snd_pcm_hw_params_get_period_size(hwparams, &persize, NULL);
385  ALSA_snd_pcm_hw_params_get_periods(hwparams, &periods, NULL);
386 
387  fprintf(stderr,
388  "ALSA: period size = %ld, periods = %u, buffer size = %lu\n",
389  persize, periods, bufsize);
390  }
391 
392  return(0);
393 }
394 
395 static int
396 ALSA_set_period_size(_THIS, snd_pcm_hw_params_t *params, int override)
397 {
398  const char *env;
399  int status;
400  snd_pcm_hw_params_t *hwparams;
401  snd_pcm_uframes_t frames;
402  unsigned int periods;
403 
404  /* Copy the hardware parameters for this setup */
405  snd_pcm_hw_params_alloca(&hwparams);
406  ALSA_snd_pcm_hw_params_copy(hwparams, params);
407 
408  if ( !override ) {
409  env = SDL_getenv("SDL_AUDIO_ALSA_SET_PERIOD_SIZE");
410  if ( env ) {
411  override = SDL_atoi(env);
412  if ( override == 0 ) {
413  return(-1);
414  }
415  }
416  }
417 
418  frames = this->spec.samples;
419  status = ALSA_snd_pcm_hw_params_set_period_size_near(
420  this->hidden->pcm_handle, hwparams, &frames, NULL);
421  if ( status < 0 ) {
422  return(-1);
423  }
424 
425  periods = 2;
426  status = ALSA_snd_pcm_hw_params_set_periods_near(
427  this->hidden->pcm_handle, hwparams, &periods, NULL);
428  if ( status < 0 ) {
429  return(-1);
430  }
431 
432  return ALSA_finalize_hardware(this, hwparams, override);
433 }
434 
435 static int
436 ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params, int override)
437 {
438  const char *env;
439  int status;
440  snd_pcm_hw_params_t *hwparams;
441  snd_pcm_uframes_t frames;
442 
443  /* Copy the hardware parameters for this setup */
444  snd_pcm_hw_params_alloca(&hwparams);
445  ALSA_snd_pcm_hw_params_copy(hwparams, params);
446 
447  if ( !override ) {
448  env = SDL_getenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE");
449  if ( env ) {
450  override = SDL_atoi(env);
451  if ( override == 0 ) {
452  return(-1);
453  }
454  }
455  }
456 
457  frames = this->spec.samples * 2;
458  status = ALSA_snd_pcm_hw_params_set_buffer_size_near(
459  this->hidden->pcm_handle, hwparams, &frames);
460  if ( status < 0 ) {
461  return(-1);
462  }
463 
464  return ALSA_finalize_hardware(this, hwparams, override);
465 }
466 
467 static int
468 ALSA_OpenDevice(_THIS, const char *devname, int iscapture)
469 {
470  int status = 0;
471  snd_pcm_t *pcm_handle = NULL;
472  snd_pcm_hw_params_t *hwparams = NULL;
473  snd_pcm_sw_params_t *swparams = NULL;
474  snd_pcm_format_t format = 0;
475  SDL_AudioFormat test_format = 0;
476  unsigned int rate = 0;
477  unsigned int channels = 0;
478 
479  /* Initialize all variables that we clean on shutdown */
480  this->hidden = (struct SDL_PrivateAudioData *)
481  SDL_malloc((sizeof *this->hidden));
482  if (this->hidden == NULL) {
483  return SDL_OutOfMemory();
484  }
485  SDL_memset(this->hidden, 0, (sizeof *this->hidden));
486 
487  /* Open the audio device */
488  /* Name of device should depend on # channels in spec */
489  status = ALSA_snd_pcm_open(&pcm_handle,
490  get_audio_device(this->spec.channels),
491  SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
492 
493  if (status < 0) {
494  ALSA_CloseDevice(this);
495  return SDL_SetError("ALSA: Couldn't open audio device: %s",
496  ALSA_snd_strerror(status));
497  }
498 
499  this->hidden->pcm_handle = pcm_handle;
500 
501  /* Figure out what the hardware is capable of */
502  snd_pcm_hw_params_alloca(&hwparams);
503  status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams);
504  if (status < 0) {
505  ALSA_CloseDevice(this);
506  return SDL_SetError("ALSA: Couldn't get hardware config: %s",
507  ALSA_snd_strerror(status));
508  }
509 
510  /* SDL only uses interleaved sample output */
511  status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
512  SND_PCM_ACCESS_RW_INTERLEAVED);
513  if (status < 0) {
514  ALSA_CloseDevice(this);
515  return SDL_SetError("ALSA: Couldn't set interleaved access: %s",
516  ALSA_snd_strerror(status));
517  }
518 
519  /* Try for a closest match on audio format */
520  status = -1;
521  for (test_format = SDL_FirstAudioFormat(this->spec.format);
522  test_format && (status < 0);) {
523  status = 0; /* if we can't support a format, it'll become -1. */
524  switch (test_format) {
525  case AUDIO_U8:
526  format = SND_PCM_FORMAT_U8;
527  break;
528  case AUDIO_S8:
529  format = SND_PCM_FORMAT_S8;
530  break;
531  case AUDIO_S16LSB:
532  format = SND_PCM_FORMAT_S16_LE;
533  break;
534  case AUDIO_S16MSB:
535  format = SND_PCM_FORMAT_S16_BE;
536  break;
537  case AUDIO_U16LSB:
538  format = SND_PCM_FORMAT_U16_LE;
539  break;
540  case AUDIO_U16MSB:
541  format = SND_PCM_FORMAT_U16_BE;
542  break;
543  case AUDIO_S32LSB:
544  format = SND_PCM_FORMAT_S32_LE;
545  break;
546  case AUDIO_S32MSB:
547  format = SND_PCM_FORMAT_S32_BE;
548  break;
549  case AUDIO_F32LSB:
550  format = SND_PCM_FORMAT_FLOAT_LE;
551  break;
552  case AUDIO_F32MSB:
553  format = SND_PCM_FORMAT_FLOAT_BE;
554  break;
555  default:
556  status = -1;
557  break;
558  }
559  if (status >= 0) {
560  status = ALSA_snd_pcm_hw_params_set_format(pcm_handle,
561  hwparams, format);
562  }
563  if (status < 0) {
564  test_format = SDL_NextAudioFormat();
565  }
566  }
567  if (status < 0) {
568  ALSA_CloseDevice(this);
569  return SDL_SetError("ALSA: Couldn't find any hardware audio formats");
570  }
571  this->spec.format = test_format;
572 
573  /* Set the number of channels */
574  status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
575  this->spec.channels);
576  channels = this->spec.channels;
577  if (status < 0) {
578  status = ALSA_snd_pcm_hw_params_get_channels(hwparams, &channels);
579  if (status < 0) {
580  ALSA_CloseDevice(this);
581  return SDL_SetError("ALSA: Couldn't set audio channels");
582  }
583  this->spec.channels = channels;
584  }
585 
586  /* Set the audio rate */
587  rate = this->spec.freq;
588  status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
589  &rate, NULL);
590  if (status < 0) {
591  ALSA_CloseDevice(this);
592  return SDL_SetError("ALSA: Couldn't set audio frequency: %s",
593  ALSA_snd_strerror(status));
594  }
595  this->spec.freq = rate;
596 
597  /* Set the buffer size, in samples */
598  if ( ALSA_set_period_size(this, hwparams, 0) < 0 &&
599  ALSA_set_buffer_size(this, hwparams, 0) < 0 ) {
600  /* Failed to set desired buffer size, do the best you can... */
601  if ( ALSA_set_period_size(this, hwparams, 1) < 0 ) {
602  ALSA_CloseDevice(this);
603  return SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status));
604  }
605  }
606  /* Set the software parameters */
607  snd_pcm_sw_params_alloca(&swparams);
608  status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
609  if (status < 0) {
610  ALSA_CloseDevice(this);
611  return SDL_SetError("ALSA: Couldn't get software config: %s",
612  ALSA_snd_strerror(status));
613  }
614  status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, this->spec.samples);
615  if (status < 0) {
616  ALSA_CloseDevice(this);
617  return SDL_SetError("Couldn't set minimum available samples: %s",
618  ALSA_snd_strerror(status));
619  }
620  status =
621  ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 1);
622  if (status < 0) {
623  ALSA_CloseDevice(this);
624  return SDL_SetError("ALSA: Couldn't set start threshold: %s",
625  ALSA_snd_strerror(status));
626  }
627  status = ALSA_snd_pcm_sw_params(pcm_handle, swparams);
628  if (status < 0) {
629  ALSA_CloseDevice(this);
630  return SDL_SetError("Couldn't set software audio parameters: %s",
631  ALSA_snd_strerror(status));
632  }
633 
634  /* Calculate the final parameters for this audio specification */
635  SDL_CalculateAudioSpec(&this->spec);
636 
637  /* Allocate mixing buffer */
638  this->hidden->mixlen = this->spec.size;
639  this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
640  if (this->hidden->mixbuf == NULL) {
641  ALSA_CloseDevice(this);
642  return SDL_OutOfMemory();
643  }
644  SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
645 
646  /* Switch to blocking mode for playback */
647  ALSA_snd_pcm_nonblock(pcm_handle, 0);
648 
649  /* We're ready to rock and roll. :-) */
650  return 0;
651 }
652 
653 static void
654 ALSA_Deinitialize(void)
655 {
656  UnloadALSALibrary();
657 }
658 
659 static int
660 ALSA_Init(SDL_AudioDriverImpl * impl)
661 {
662  if (LoadALSALibrary() < 0) {
663  return 0;
664  }
665 
666  /* Set the function pointers */
667  impl->OpenDevice = ALSA_OpenDevice;
668  impl->WaitDevice = ALSA_WaitDevice;
669  impl->GetDeviceBuf = ALSA_GetDeviceBuf;
670  impl->PlayDevice = ALSA_PlayDevice;
671  impl->CloseDevice = ALSA_CloseDevice;
672  impl->Deinitialize = ALSA_Deinitialize;
673  impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: Add device enum! */
674 
675  return 1; /* this audio target is available. */
676 }
677 
678 
680  "alsa", "ALSA PCM audio", ALSA_Init, 0
681 };
682 
683 #endif /* SDL_AUDIO_DRIVER_ALSA */
684 
685 /* vi: set ts=4 sw=4 expandtab: */
void(* CloseDevice)(_THIS)
Definition: SDL_sysaudio.h:45
#define __inline__
Definition: begin_code.h:119
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
Definition: SDL_audio.c:1226
#define AUDIO_S32MSB
Definition: SDL_audio.h:104
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
Definition: glew.h:1824
void(* WaitDevice)(_THIS)
Definition: SDL_sysaudio.h:41
#define NULL
Definition: ftobjs.h:61
#define AUDIO_U16LSB
Definition: SDL_audio.h:91
GLenum GLvoid * addr
Definition: glew.h:10667
GLenum GLsizei const GLuint GLboolean enabled
Definition: glew.h:2538
Uint8 *(* GetDeviceBuf)(_THIS)
Definition: SDL_sysaudio.h:43
#define SDL_FreeAudioMem
Definition: SDL_audiomem.h:24
DECLSPEC void SDLCALL SDL_free(void *mem)
Uint16 SDL_AudioFormat
Audio format flags.
Definition: SDL_audio.h:64
int(* OpenDevice)(_THIS, const char *devname, int iscapture)
Definition: SDL_sysaudio.h:39
SDL_AudioFormat SDL_NextAudioFormat(void)
Definition: SDL_audio.c:1238
GLenum GLvoid ** params
Definition: gl2ext.h:806
#define AUDIO_F32MSB
Definition: SDL_audio.h:113
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:145
void(* PlayDevice)(_THIS)
Definition: SDL_sysaudio.h:42
#define AUDIO_U8
Definition: SDL_audio.h:89
int
Definition: SDL_systhread.c:37
#define _THIS
uint64_t Uint64
An unsigned 64-bit integer type.
Definition: SDL_stdinc.h:154
DECLSPEC void *SDLCALL SDL_LoadObject(const char *sofile)
#define AUDIO_F32LSB
Definition: SDL_audio.h:112
DECLSPEC void SDLCALL SDL_Delay(Uint32 ms)
Wait a specified number of milliseconds before returning.
Definition: SDL_systimer.c:70
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
Definition: SDL_string.c:261
DECLSPEC void SDLCALL SDL_UnloadObject(void *handle)
#define AUDIO_S32LSB
Definition: SDL_audio.h:103
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl2ext.h:845
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
Definition: SDL_error.c:53
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
AudioBootStrap ALSA_bootstrap
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
Definition: SDL_audio.c:1247
void(* Deinitialize)(void)
Definition: SDL_sysaudio.h:48
#define SDL_AllocAudioMem
Definition: SDL_audiomem.h:23
jmp_buf env
Definition: jumphack.c:12
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define AUDIO_S16MSB
Definition: SDL_audio.h:94
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
DECLSPEC int SDLCALL SDL_atoi(const char *str)
Definition: SDL_string.c:774
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
snd_pcm_t * pcm_handle
uint16_t Uint16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:137
DECLSPEC char *SDLCALL SDL_getenv(const char *name)
Definition: SDL_getenv.c:179
DECLSPEC void *SDLCALL SDL_LoadFunction(void *handle, const char *name)
GLsizei bufsize
Definition: gl2ext.h:994
#define AUDIO_S8
Definition: SDL_audio.h:90
static SDL_AudioDevice * get_audio_device(SDL_AudioDeviceID id)
Definition: SDL_audio.c:141
unsigned int size_t
#define AUDIO_U16MSB
Definition: SDL_audio.h:93