23 #if SDL_AUDIO_DRIVER_ALSA
34 #include "../SDL_audiomem.h"
35 #include "../SDL_audio_c.h"
38 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
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);
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
93 static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
94 static void *alsa_handle =
NULL;
97 load_alsa_sym(
const char *fn,
void **
addr)
109 #define SDL_ALSA_SYM(x) \
110 if (!load_alsa_sym(#x, (void **) (char *) &ALSA_##x)) return -1
112 #define SDL_ALSA_SYM(x) ALSA_##x = x
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);
152 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
155 UnloadALSALibrary(
void)
157 if (alsa_handle !=
NULL) {
164 LoadALSALibrary(
void)
167 if (alsa_handle ==
NULL) {
169 if (alsa_handle ==
NULL) {
173 retval = load_alsa_syms();
185 UnloadALSALibrary(
void)
190 LoadALSALibrary(
void)
204 if (device ==
NULL) {
207 device =
"plug:surround51";
210 device =
"plug:surround40";
223 ALSA_WaitDevice(
_THIS)
236 T *ptr = (T *) this->hidden->mixbuf; \
238 for (i = 0; i < this->spec.samples; i++, ptr += 6) { \
240 tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \
241 tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \
245 swizzle_alsa_channels_6_64bit(
_THIS)
251 swizzle_alsa_channels_6_32bit(
_THIS)
257 swizzle_alsa_channels_6_16bit(
_THIS)
263 swizzle_alsa_channels_6_8bit(
_THIS)
276 swizzle_alsa_channels(
_THIS)
278 if (this->spec.channels == 6) {
279 const Uint16 fmtsize = (this->spec.format & 0xFF);
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);
295 ALSA_PlayDevice(
_THIS)
298 const Uint8 *sample_buf = (
const Uint8 *) this->hidden->mixbuf;
299 const int frame_size = (((
int) (this->spec.format & 0xFF)) / 8) *
301 snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples);
303 swizzle_alsa_channels(
this);
305 while ( frames_left > 0 && this->
enabled ) {
308 status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
309 sample_buf, frames_left);
312 if (status == -EAGAIN) {
318 status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
321 fprintf(stderr,
"ALSA write failed (unrecoverable): %s\n",
322 ALSA_snd_strerror(status));
328 sample_buf += status * frame_size;
329 frames_left -= status;
334 ALSA_GetDeviceBuf(
_THIS)
336 return (this->hidden->mixbuf);
340 ALSA_CloseDevice(
_THIS)
342 if (this->hidden !=
NULL) {
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;
356 ALSA_finalize_hardware(
_THIS, snd_pcm_hw_params_t *hwparams,
int override)
362 status = ALSA_snd_pcm_hw_params(this->hidden->pcm_handle, hwparams);
368 status = ALSA_snd_pcm_hw_params_get_buffer_size(hwparams, &bufsize);
372 if ( !
override && bufsize != this->spec.samples * 2 ) {
377 this->spec.samples = bufsize / 2;
381 snd_pcm_uframes_t persize = 0;
382 unsigned int periods = 0;
384 ALSA_snd_pcm_hw_params_get_period_size(hwparams, &persize,
NULL);
385 ALSA_snd_pcm_hw_params_get_periods(hwparams, &periods,
NULL);
388 "ALSA: period size = %ld, periods = %u, buffer size = %lu\n",
389 persize, periods, bufsize);
396 ALSA_set_period_size(
_THIS, snd_pcm_hw_params_t *
params,
int override)
400 snd_pcm_hw_params_t *hwparams;
401 snd_pcm_uframes_t frames;
402 unsigned int periods;
405 snd_pcm_hw_params_alloca(&hwparams);
406 ALSA_snd_pcm_hw_params_copy(hwparams, params);
409 env =
SDL_getenv(
"SDL_AUDIO_ALSA_SET_PERIOD_SIZE");
412 if (
override == 0 ) {
418 frames = this->spec.samples;
419 status = ALSA_snd_pcm_hw_params_set_period_size_near(
420 this->hidden->pcm_handle, hwparams, &frames,
NULL);
426 status = ALSA_snd_pcm_hw_params_set_periods_near(
427 this->hidden->pcm_handle, hwparams, &periods,
NULL);
432 return ALSA_finalize_hardware(
this, hwparams,
override);
436 ALSA_set_buffer_size(
_THIS, snd_pcm_hw_params_t *params,
int override)
440 snd_pcm_hw_params_t *hwparams;
441 snd_pcm_uframes_t frames;
444 snd_pcm_hw_params_alloca(&hwparams);
445 ALSA_snd_pcm_hw_params_copy(hwparams, params);
448 env =
SDL_getenv(
"SDL_AUDIO_ALSA_SET_BUFFER_SIZE");
451 if (
override == 0 ) {
457 frames = this->spec.samples * 2;
458 status = ALSA_snd_pcm_hw_params_set_buffer_size_near(
459 this->hidden->pcm_handle, hwparams, &frames);
464 return ALSA_finalize_hardware(
this, hwparams,
override);
468 ALSA_OpenDevice(
_THIS,
const char *devname,
int iscapture)
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;
476 unsigned int rate = 0;
477 unsigned int channels = 0;
482 if (this->hidden ==
NULL) {
485 SDL_memset(this->hidden, 0, (
sizeof *this->hidden));
489 status = ALSA_snd_pcm_open(&pcm_handle,
491 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
494 ALSA_CloseDevice(
this);
495 return SDL_SetError(
"ALSA: Couldn't open audio device: %s",
496 ALSA_snd_strerror(status));
502 snd_pcm_hw_params_alloca(&hwparams);
503 status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams);
505 ALSA_CloseDevice(
this);
506 return SDL_SetError(
"ALSA: Couldn't get hardware config: %s",
507 ALSA_snd_strerror(status));
511 status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
512 SND_PCM_ACCESS_RW_INTERLEAVED);
514 ALSA_CloseDevice(
this);
515 return SDL_SetError(
"ALSA: Couldn't set interleaved access: %s",
516 ALSA_snd_strerror(status));
522 test_format && (status < 0);) {
524 switch (test_format) {
526 format = SND_PCM_FORMAT_U8;
529 format = SND_PCM_FORMAT_S8;
532 format = SND_PCM_FORMAT_S16_LE;
535 format = SND_PCM_FORMAT_S16_BE;
538 format = SND_PCM_FORMAT_U16_LE;
541 format = SND_PCM_FORMAT_U16_BE;
544 format = SND_PCM_FORMAT_S32_LE;
547 format = SND_PCM_FORMAT_S32_BE;
550 format = SND_PCM_FORMAT_FLOAT_LE;
553 format = SND_PCM_FORMAT_FLOAT_BE;
560 status = ALSA_snd_pcm_hw_params_set_format(pcm_handle,
568 ALSA_CloseDevice(
this);
569 return SDL_SetError(
"ALSA: Couldn't find any hardware audio formats");
571 this->spec.format = test_format;
574 status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
575 this->spec.channels);
576 channels = this->spec.channels;
578 status = ALSA_snd_pcm_hw_params_get_channels(hwparams, &channels);
580 ALSA_CloseDevice(
this);
581 return SDL_SetError(
"ALSA: Couldn't set audio channels");
583 this->spec.channels = channels;
587 rate = this->spec.freq;
588 status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
591 ALSA_CloseDevice(
this);
592 return SDL_SetError(
"ALSA: Couldn't set audio frequency: %s",
593 ALSA_snd_strerror(status));
595 this->spec.freq = rate;
598 if ( ALSA_set_period_size(
this, hwparams, 0) < 0 &&
599 ALSA_set_buffer_size(
this, hwparams, 0) < 0 ) {
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));
607 snd_pcm_sw_params_alloca(&swparams);
608 status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
610 ALSA_CloseDevice(
this);
611 return SDL_SetError(
"ALSA: Couldn't get software config: %s",
612 ALSA_snd_strerror(status));
614 status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, this->spec.samples);
616 ALSA_CloseDevice(
this);
617 return SDL_SetError(
"Couldn't set minimum available samples: %s",
618 ALSA_snd_strerror(status));
621 ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 1);
623 ALSA_CloseDevice(
this);
624 return SDL_SetError(
"ALSA: Couldn't set start threshold: %s",
625 ALSA_snd_strerror(status));
627 status = ALSA_snd_pcm_sw_params(pcm_handle, swparams);
629 ALSA_CloseDevice(
this);
630 return SDL_SetError(
"Couldn't set software audio parameters: %s",
631 ALSA_snd_strerror(status));
638 this->hidden->mixlen = this->spec.size;
640 if (this->hidden->mixbuf ==
NULL) {
641 ALSA_CloseDevice(
this);
644 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
647 ALSA_snd_pcm_nonblock(pcm_handle, 0);
654 ALSA_Deinitialize(
void)
662 if (LoadALSALibrary() < 0) {
680 "alsa",
"ALSA PCM audio", ALSA_Init, 0
void(* CloseDevice)(_THIS)
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
void(* WaitDevice)(_THIS)
GLenum GLsizei const GLuint GLboolean enabled
Uint8 *(* GetDeviceBuf)(_THIS)
DECLSPEC void SDLCALL SDL_free(void *mem)
Uint16 SDL_AudioFormat
Audio format flags.
int(* OpenDevice)(_THIS, const char *devname, int iscapture)
SDL_AudioFormat SDL_NextAudioFormat(void)
uint32_t Uint32
An unsigned 32-bit integer type.
void(* PlayDevice)(_THIS)
int OnlyHasDefaultOutputDevice
uint64_t Uint64
An unsigned 64-bit integer type.
DECLSPEC void *SDLCALL SDL_LoadObject(const char *sofile)
DECLSPEC void SDLCALL SDL_Delay(Uint32 ms)
Wait a specified number of milliseconds before returning.
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
DECLSPEC void SDLCALL SDL_UnloadObject(void *handle)
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum format
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
AudioBootStrap ALSA_bootstrap
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
void(* Deinitialize)(void)
#define SDL_AllocAudioMem
#define SDL_OutOfMemory()
uint8_t Uint8
An unsigned 8-bit integer type.
DECLSPEC int SDLCALL SDL_atoi(const char *str)
uint16_t Uint16
An unsigned 16-bit integer type.
DECLSPEC char *SDLCALL SDL_getenv(const char *name)
DECLSPEC void *SDLCALL SDL_LoadFunction(void *handle, const char *name)
static SDL_AudioDevice * get_audio_device(SDL_AudioDeviceID id)