21 #include "../../SDL_internal.h" 23 #if SDL_AUDIO_DRIVER_ALSA 27 #include <sys/types.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 snd_pcm_sframes_t (*ALSA_snd_pcm_readi)
48 (snd_pcm_t *,
void *, snd_pcm_uframes_t);
49 static int (*ALSA_snd_pcm_recover) (snd_pcm_t *, int, int);
50 static int (*ALSA_snd_pcm_prepare) (snd_pcm_t *);
51 static int (*ALSA_snd_pcm_drain) (snd_pcm_t *);
52 static const char *(*ALSA_snd_strerror) (int);
53 static size_t(*ALSA_snd_pcm_hw_params_sizeof) (
void);
54 static size_t(*ALSA_snd_pcm_sw_params_sizeof) (
void);
55 static void (*ALSA_snd_pcm_hw_params_copy)
56 (snd_pcm_hw_params_t *,
const snd_pcm_hw_params_t *);
57 static int (*ALSA_snd_pcm_hw_params_any) (snd_pcm_t *, snd_pcm_hw_params_t *);
58 static int (*ALSA_snd_pcm_hw_params_set_access)
59 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_access_t);
60 static int (*ALSA_snd_pcm_hw_params_set_format)
61 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_format_t);
62 static int (*ALSA_snd_pcm_hw_params_set_channels)
63 (snd_pcm_t *, snd_pcm_hw_params_t *,
unsigned int);
64 static int (*ALSA_snd_pcm_hw_params_get_channels)
65 (
const snd_pcm_hw_params_t *,
unsigned int *);
66 static int (*ALSA_snd_pcm_hw_params_set_rate_near)
67 (snd_pcm_t *, snd_pcm_hw_params_t *,
unsigned int *,
int *);
68 static int (*ALSA_snd_pcm_hw_params_set_period_size_near)
69 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_uframes_t *,
int *);
70 static int (*ALSA_snd_pcm_hw_params_get_period_size)
71 (
const snd_pcm_hw_params_t *, snd_pcm_uframes_t *,
int *);
72 static int (*ALSA_snd_pcm_hw_params_set_periods_near)
73 (snd_pcm_t *, snd_pcm_hw_params_t *,
unsigned int *,
int *);
74 static int (*ALSA_snd_pcm_hw_params_get_periods)
75 (
const snd_pcm_hw_params_t *,
unsigned int *,
int *);
76 static int (*ALSA_snd_pcm_hw_params_set_buffer_size_near)
77 (snd_pcm_t *pcm, snd_pcm_hw_params_t *, snd_pcm_uframes_t *);
78 static int (*ALSA_snd_pcm_hw_params_get_buffer_size)
79 (
const snd_pcm_hw_params_t *, snd_pcm_uframes_t *);
80 static int (*ALSA_snd_pcm_hw_params) (snd_pcm_t *, snd_pcm_hw_params_t *);
81 static int (*ALSA_snd_pcm_sw_params_current) (snd_pcm_t *,
82 snd_pcm_sw_params_t *);
83 static int (*ALSA_snd_pcm_sw_params_set_start_threshold)
84 (snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
85 static int (*ALSA_snd_pcm_sw_params) (snd_pcm_t *, snd_pcm_sw_params_t *);
86 static int (*ALSA_snd_pcm_nonblock) (snd_pcm_t *, int);
87 static int (*ALSA_snd_pcm_wait)(snd_pcm_t *, int);
88 static int (*ALSA_snd_pcm_sw_params_set_avail_min)
89 (snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
90 static int (*ALSA_snd_pcm_reset)(snd_pcm_t *);
91 static int (*ALSA_snd_device_name_hint) (int,
const char *,
void ***);
92 static char* (*ALSA_snd_device_name_get_hint) (
const void *,
const char *);
93 static int (*ALSA_snd_device_name_free_hint) (
void **);
95 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC 96 #define snd_pcm_hw_params_sizeof ALSA_snd_pcm_hw_params_sizeof 97 #define snd_pcm_sw_params_sizeof ALSA_snd_pcm_sw_params_sizeof 99 static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
100 static void *alsa_handle =
NULL;
103 load_alsa_sym(
const char *fn,
void **
addr)
115 #define SDL_ALSA_SYM(x) \ 116 if (!load_alsa_sym(#x, (void **) (char *) &ALSA_##x)) return -1 118 #define SDL_ALSA_SYM(x) ALSA_##x = x 124 SDL_ALSA_SYM(snd_pcm_open);
125 SDL_ALSA_SYM(snd_pcm_close);
126 SDL_ALSA_SYM(snd_pcm_writei);
127 SDL_ALSA_SYM(snd_pcm_readi);
128 SDL_ALSA_SYM(snd_pcm_recover);
129 SDL_ALSA_SYM(snd_pcm_prepare);
130 SDL_ALSA_SYM(snd_pcm_drain);
131 SDL_ALSA_SYM(snd_strerror);
132 SDL_ALSA_SYM(snd_pcm_hw_params_sizeof);
133 SDL_ALSA_SYM(snd_pcm_sw_params_sizeof);
134 SDL_ALSA_SYM(snd_pcm_hw_params_copy);
135 SDL_ALSA_SYM(snd_pcm_hw_params_any);
136 SDL_ALSA_SYM(snd_pcm_hw_params_set_access);
137 SDL_ALSA_SYM(snd_pcm_hw_params_set_format);
138 SDL_ALSA_SYM(snd_pcm_hw_params_set_channels);
139 SDL_ALSA_SYM(snd_pcm_hw_params_get_channels);
140 SDL_ALSA_SYM(snd_pcm_hw_params_set_rate_near);
141 SDL_ALSA_SYM(snd_pcm_hw_params_set_period_size_near);
142 SDL_ALSA_SYM(snd_pcm_hw_params_get_period_size);
143 SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_near);
144 SDL_ALSA_SYM(snd_pcm_hw_params_get_periods);
145 SDL_ALSA_SYM(snd_pcm_hw_params_set_buffer_size_near);
146 SDL_ALSA_SYM(snd_pcm_hw_params_get_buffer_size);
147 SDL_ALSA_SYM(snd_pcm_hw_params);
148 SDL_ALSA_SYM(snd_pcm_sw_params_current);
149 SDL_ALSA_SYM(snd_pcm_sw_params_set_start_threshold);
150 SDL_ALSA_SYM(snd_pcm_sw_params);
151 SDL_ALSA_SYM(snd_pcm_nonblock);
152 SDL_ALSA_SYM(snd_pcm_wait);
153 SDL_ALSA_SYM(snd_pcm_sw_params_set_avail_min);
154 SDL_ALSA_SYM(snd_pcm_reset);
155 SDL_ALSA_SYM(snd_device_name_hint);
156 SDL_ALSA_SYM(snd_device_name_get_hint);
157 SDL_ALSA_SYM(snd_device_name_free_hint);
164 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC 167 UnloadALSALibrary(
void)
169 if (alsa_handle !=
NULL) {
176 LoadALSALibrary(
void)
179 if (alsa_handle ==
NULL) {
181 if (alsa_handle ==
NULL) {
185 retval = load_alsa_syms();
197 UnloadALSALibrary(
void)
202 LoadALSALibrary(
void)
215 if (handle !=
NULL) {
216 return (
const char *) handle;
221 if (device !=
NULL) {
226 return "plug:surround51";
227 }
else if (channels == 4) {
228 return "plug:surround40";
237 ALSA_WaitDevice(
_THIS)
249 #define SWIZ6(T, buf, numframes) \ 250 T *ptr = (T *) buf; \ 252 for (i = 0; i < numframes; i++, ptr += 6) { \ 254 tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \ 255 tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \ 259 swizzle_alsa_channels_6_64bit(
void *
buffer,
Uint32 bufferlen)
261 SWIZ6(
Uint64, buffer, bufferlen);
265 swizzle_alsa_channels_6_32bit(
void *
buffer,
Uint32 bufferlen)
267 SWIZ6(
Uint32, buffer, bufferlen);
271 swizzle_alsa_channels_6_16bit(
void *
buffer,
Uint32 bufferlen)
273 SWIZ6(
Uint16, buffer, bufferlen);
277 swizzle_alsa_channels_6_8bit(
void *
buffer,
Uint32 bufferlen)
279 SWIZ6(
Uint8, buffer, bufferlen);
294 case 8: swizzle_alsa_channels_6_8bit(buffer, bufferlen);
break;
295 case 16: swizzle_alsa_channels_6_16bit(buffer, bufferlen);
break;
296 case 32: swizzle_alsa_channels_6_32bit(buffer, bufferlen);
break;
297 case 64: swizzle_alsa_channels_6_64bit(buffer, bufferlen);
break;
298 default:
SDL_assert(!
"unhandled bitsize");
break;
307 ALSA_PlayDevice(
_THIS)
309 const Uint8 *sample_buf = (
const Uint8 *) this->hidden->mixbuf;
312 snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->
spec.
samples);
314 swizzle_alsa_channels(
this, this->hidden->mixbuf, frames_left);
323 status = ALSA_snd_pcm_wait(this->hidden->pcm_handle, 1000);
330 status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
331 sample_buf, frames_left);
334 if (status == -EAGAIN) {
340 status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
343 fprintf(stderr,
"ALSA write failed (unrecoverable): %s\n",
344 ALSA_snd_strerror(status));
350 sample_buf += status * frame_size;
351 frames_left -= status;
356 ALSA_GetDeviceBuf(
_THIS)
358 return (this->hidden->mixbuf);
362 ALSA_CaptureFromDevice(
_THIS,
void *buffer,
int buflen)
367 const int total_frames = buflen / frame_size;
368 snd_pcm_uframes_t frames_left = total_frames;
375 int status = ALSA_snd_pcm_readi(this->hidden->pcm_handle,
376 sample_buf, frames_left);
380 if (status == -EAGAIN) {
386 status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
389 fprintf(stderr,
"ALSA read failed (unrecoverable): %s\n",
390 ALSA_snd_strerror(status));
397 sample_buf += status * frame_size;
398 frames_left -= status;
401 swizzle_alsa_channels(
this, buffer, total_frames - frames_left);
403 return (total_frames - frames_left) * frame_size;
407 ALSA_FlushCapture(
_THIS)
409 ALSA_snd_pcm_reset(this->hidden->pcm_handle);
413 ALSA_CloseDevice(
_THIS)
415 if (this->hidden->pcm_handle) {
422 ALSA_snd_pcm_close(this->hidden->pcm_handle);
429 ALSA_finalize_hardware(
_THIS, snd_pcm_hw_params_t *hwparams,
int override)
435 status = ALSA_snd_pcm_hw_params(this->hidden->pcm_handle, hwparams);
441 status = ALSA_snd_pcm_hw_params_get_buffer_size(hwparams, &bufsize);
445 if ( !
override && bufsize != this->
spec.
samples * 2 ) {
454 snd_pcm_uframes_t persize = 0;
455 unsigned int periods = 0;
457 ALSA_snd_pcm_hw_params_get_period_size(hwparams, &persize,
NULL);
458 ALSA_snd_pcm_hw_params_get_periods(hwparams, &periods,
NULL);
461 "ALSA: period size = %ld, periods = %u, buffer size = %lu\n",
462 persize, periods, bufsize);
469 ALSA_set_period_size(
_THIS, snd_pcm_hw_params_t *
params,
int override)
473 snd_pcm_hw_params_t *hwparams;
474 snd_pcm_uframes_t frames;
475 unsigned int periods;
478 snd_pcm_hw_params_alloca(&hwparams);
479 ALSA_snd_pcm_hw_params_copy(hwparams, params);
482 env =
SDL_getenv(
"SDL_AUDIO_ALSA_SET_PERIOD_SIZE");
485 if (
override == 0 ) {
492 status = ALSA_snd_pcm_hw_params_set_period_size_near(
493 this->hidden->pcm_handle, hwparams, &frames,
NULL);
499 status = ALSA_snd_pcm_hw_params_set_periods_near(
500 this->hidden->pcm_handle, hwparams, &periods,
NULL);
505 return ALSA_finalize_hardware(
this, hwparams,
override);
509 ALSA_set_buffer_size(
_THIS, snd_pcm_hw_params_t *params,
int override)
513 snd_pcm_hw_params_t *hwparams;
514 snd_pcm_uframes_t frames;
517 snd_pcm_hw_params_alloca(&hwparams);
518 ALSA_snd_pcm_hw_params_copy(hwparams, params);
521 env =
SDL_getenv(
"SDL_AUDIO_ALSA_SET_BUFFER_SIZE");
524 if (
override == 0 ) {
531 status = ALSA_snd_pcm_hw_params_set_buffer_size_near(
532 this->hidden->pcm_handle, hwparams, &frames);
537 return ALSA_finalize_hardware(
this, hwparams,
override);
541 ALSA_OpenDevice(
_THIS,
void *handle,
const char *devname,
int iscapture)
544 snd_pcm_t *pcm_handle =
NULL;
545 snd_pcm_hw_params_t *hwparams =
NULL;
546 snd_pcm_sw_params_t *swparams =
NULL;
547 snd_pcm_format_t
format = 0;
549 unsigned int rate = 0;
550 unsigned int channels = 0;
555 if (this->hidden ==
NULL) {
562 status = ALSA_snd_pcm_open(&pcm_handle,
564 iscapture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
568 return SDL_SetError(
"ALSA: Couldn't open audio device: %s",
569 ALSA_snd_strerror(status));
575 snd_pcm_hw_params_alloca(&hwparams);
576 status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams);
578 return SDL_SetError(
"ALSA: Couldn't get hardware config: %s",
579 ALSA_snd_strerror(status));
583 status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
584 SND_PCM_ACCESS_RW_INTERLEAVED);
586 return SDL_SetError(
"ALSA: Couldn't set interleaved access: %s",
587 ALSA_snd_strerror(status));
593 test_format && (status < 0);) {
595 switch (test_format) {
597 format = SND_PCM_FORMAT_U8;
600 format = SND_PCM_FORMAT_S8;
603 format = SND_PCM_FORMAT_S16_LE;
606 format = SND_PCM_FORMAT_S16_BE;
609 format = SND_PCM_FORMAT_U16_LE;
612 format = SND_PCM_FORMAT_U16_BE;
615 format = SND_PCM_FORMAT_S32_LE;
618 format = SND_PCM_FORMAT_S32_BE;
621 format = SND_PCM_FORMAT_FLOAT_LE;
624 format = SND_PCM_FORMAT_FLOAT_BE;
631 status = ALSA_snd_pcm_hw_params_set_format(pcm_handle,
639 return SDL_SetError(
"ALSA: Couldn't find any hardware audio formats");
644 status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
648 status = ALSA_snd_pcm_hw_params_get_channels(hwparams, &channels);
650 return SDL_SetError(
"ALSA: Couldn't set audio channels");
657 status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
660 return SDL_SetError(
"ALSA: Couldn't set audio frequency: %s",
661 ALSA_snd_strerror(status));
666 if ( ALSA_set_period_size(
this, hwparams, 0) < 0 &&
667 ALSA_set_buffer_size(
this, hwparams, 0) < 0 ) {
669 status = ALSA_set_period_size(
this, hwparams, 1);
671 return SDL_SetError(
"Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status));
675 snd_pcm_sw_params_alloca(&swparams);
676 status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
678 return SDL_SetError(
"ALSA: Couldn't get software config: %s",
679 ALSA_snd_strerror(status));
681 status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, this->
spec.
samples);
683 return SDL_SetError(
"Couldn't set minimum available samples: %s",
684 ALSA_snd_strerror(status));
687 ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 1);
689 return SDL_SetError(
"ALSA: Couldn't set start threshold: %s",
690 ALSA_snd_strerror(status));
692 status = ALSA_snd_pcm_sw_params(pcm_handle, swparams);
694 return SDL_SetError(
"Couldn't set software audio parameters: %s",
695 ALSA_snd_strerror(status));
703 this->hidden->mixlen = this->
spec.
size;
705 if (this->hidden->mixbuf ==
NULL) {
708 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
712 ALSA_snd_pcm_nonblock(pcm_handle, 0);
718 typedef struct ALSA_Device
722 struct ALSA_Device *next;
726 add_device(
const int iscapture,
const char *
name,
void *hint, ALSA_Device **pSeen)
728 ALSA_Device *dev =
SDL_malloc(
sizeof (ALSA_Device));
729 char *desc = ALSA_snd_device_name_get_hint(hint,
"DESC");
746 if ((ptr = strchr(desc,
'\n')) !=
NULL) {
763 dev->iscapture = iscapture;
773 ALSA_HotplugThread(
void *arg)
775 SDL_sem *first_run_semaphore = (SDL_sem *) arg;
776 ALSA_Device *devices =
NULL;
783 if (ALSA_snd_device_name_hint(-1,
"pcm", &hints) != -1) {
784 ALSA_Device *unseen = devices;
785 ALSA_Device *seen =
NULL;
788 const char *match =
NULL;
789 int bestmatch = 0xFFFF;
790 size_t match_len = 0;
792 static const char *
const prefixes[] = {
793 "hw:",
"sysdefault:",
"default:",
NULL 800 for (i = 0; hints[
i]; i++) {
801 char *name = ALSA_snd_device_name_get_hint(hints[i],
"NAME");
807 if ((defaultdev == -1) && (
SDL_strcmp(name,
"default") == 0)) {
811 for (j = 0; prefixes[
j]; j++) {
812 const char *prefix = prefixes[
j];
818 match_len = prefixlen;
827 for (i = 0; hints[
i]; i++) {
831 if ((!match) && (defaultdev != i)) {
835 name = ALSA_snd_device_name_get_hint(hints[i],
"NAME");
841 if (!match || (
SDL_strncmp(name, match, match_len) == 0)) {
842 char *ioid = ALSA_snd_device_name_get_hint(hints[i],
"IOID");
850 if (!isoutput && !isinput) {
856 for (dev = unseen; dev; dev = next) {
858 if ( (
SDL_strcmp(dev->name, name) == 0) && (((isinput) && dev->iscapture) || ((isoutput) && !dev->iscapture)) ) {
867 if (isoutput) have_output =
SDL_TRUE;
873 if (isinput && !have_input) {
874 add_device(
SDL_TRUE, name, hints[i], &seen);
876 if (isoutput && !have_output) {
877 add_device(
SDL_FALSE, name, hints[i], &seen);
884 ALSA_snd_device_name_free_hint(hints);
889 for (dev = unseen; dev; dev = next) {
899 if (first_run_semaphore) {
901 first_run_semaphore =
NULL;
912 for (dev = devices; dev; dev = next) {
923 ALSA_DetectDevices(
void)
933 ALSA_hotplug_thread =
SDL_CreateThread(ALSA_HotplugThread,
"SDLHotplugALSA", semaphore);
934 if (ALSA_hotplug_thread) {
942 ALSA_Deinitialize(
void)
944 if (ALSA_hotplug_thread !=
NULL) {
947 ALSA_hotplug_thread =
NULL;
956 if (LoadALSALibrary() < 0) {
978 "alsa",
"ALSA PCM audio", ALSA_Init, 0
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
void(* DetectDevices)(void)
A type representing an atomic integer value. It is a struct so people don't accidentally use numeric ...
#define SDL_CreateSemaphore
void(* PlayDevice)(_THIS)
void(* WaitDevice)(_THIS)
void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
Uint16 SDL_AudioFormat
Audio format flags.
GLuint const GLchar * name
uint32_t Uint32
An unsigned 32-bit integer type.
uint64_t Uint64
An unsigned 64-bit integer type.
SDL_AudioFormat SDL_NextAudioFormat(void)
GLenum GLuint GLsizei bufsize
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
void SDL_RemoveAudioDevice(const int iscapture, void *handle)
uint8_t Uint8
An unsigned 8-bit integer type.
#define SDL_AUDIO_BITSIZE(x)
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)
void(* Deinitialize)(void)
AudioBootStrap ALSA_bootstrap
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
GLenum GLenum GLsizei const GLuint GLboolean enabled
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)
#define SDL_assert(condition)
int(* OpenDevice)(_THIS, void *handle, const char *devname, int iscapture)
#define SDL_OutOfMemory()
int(* CaptureFromDevice)(_THIS, void *buffer, int buflen)
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
void(* CloseDevice)(_THIS)
void(* FlushCapture)(_THIS)
#define SDL_DestroySemaphore
Uint8 *(* GetDeviceBuf)(_THIS)
uint16_t Uint16
An unsigned 16-bit integer type.
void * SDL_LoadFunction(void *handle, const char *name)
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
static SDL_AudioDevice * get_audio_device(SDL_AudioDeviceID id)
void SDL_AddAudioDevice(const int iscapture, const char *name, void *handle)