summaryrefslogtreecommitdiff
path: root/Source/3rdParty/SDL2/src/audio/alsa/SDL_alsa_audio.c
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-01-31 18:38:35 +0800
committerchai <chaifix@163.com>2019-01-31 18:38:35 +0800
commit2ec55fd974a63b705a4777c256d2222c874fa043 (patch)
tree48f1fea59ee9fc713a28a9aac3f05b98dc5ae66f /Source/3rdParty/SDL2/src/audio/alsa/SDL_alsa_audio.c
parentc581dfbf1e849f393861d15e82aa6446c0c1c310 (diff)
*SDL project
Diffstat (limited to 'Source/3rdParty/SDL2/src/audio/alsa/SDL_alsa_audio.c')
-rw-r--r--Source/3rdParty/SDL2/src/audio/alsa/SDL_alsa_audio.c142
1 files changed, 51 insertions, 91 deletions
diff --git a/Source/3rdParty/SDL2/src/audio/alsa/SDL_alsa_audio.c b/Source/3rdParty/SDL2/src/audio/alsa/SDL_alsa_audio.c
index 2dba1ff..eff192b 100644
--- a/Source/3rdParty/SDL2/src/audio/alsa/SDL_alsa_audio.c
+++ b/Source/3rdParty/SDL2/src/audio/alsa/SDL_alsa_audio.c
@@ -22,6 +22,10 @@
#if SDL_AUDIO_DRIVER_ALSA
+#ifndef SDL_ALSA_NON_BLOCKING
+#define SDL_ALSA_NON_BLOCKING 0
+#endif
+
/* Allow access to a raw mixing buffer */
#include <sys/types.h>
@@ -90,6 +94,7 @@ static int (*ALSA_snd_pcm_reset)(snd_pcm_t *);
static int (*ALSA_snd_device_name_hint) (int, const char *, void ***);
static char* (*ALSA_snd_device_name_get_hint) (const void *, const char *);
static int (*ALSA_snd_device_name_free_hint) (void **);
+static snd_pcm_sframes_t (*ALSA_snd_pcm_avail)(snd_pcm_t *);
#ifdef SND_CHMAP_API_VERSION
static snd_pcm_chmap_t* (*ALSA_snd_pcm_get_chmap) (snd_pcm_t *);
static int (*ALSA_snd_pcm_chmap_print) (const snd_pcm_chmap_t *map, size_t maxlen, char *buf);
@@ -158,6 +163,7 @@ load_alsa_syms(void)
SDL_ALSA_SYM(snd_device_name_hint);
SDL_ALSA_SYM(snd_device_name_get_hint);
SDL_ALSA_SYM(snd_device_name_free_hint);
+ SDL_ALSA_SYM(snd_pcm_avail);
#ifdef SND_CHMAP_API_VERSION
SDL_ALSA_SYM(snd_pcm_get_chmap);
SDL_ALSA_SYM(snd_pcm_chmap_print);
@@ -243,7 +249,24 @@ get_audio_device(void *handle, const int channels)
static void
ALSA_WaitDevice(_THIS)
{
- /* We're in blocking mode, so there's nothing to do here */
+#if SDL_ALSA_NON_BLOCKING
+ const snd_pcm_sframes_t needed = (snd_pcm_sframes_t) this->spec.samples;
+ while (SDL_AtomicGet(&this->enabled)) {
+ const snd_pcm_sframes_t rc = ALSA_snd_pcm_avail(this->hidden->pcm_handle);
+ if ((rc < 0) && (rc != -EAGAIN)) {
+ /* Hmm, not much we can do - abort */
+ fprintf(stderr, "ALSA snd_pcm_avail failed (unrecoverable): %s\n",
+ ALSA_snd_strerror(rc));
+ SDL_OpenedAudioDeviceDisconnected(this);
+ return;
+ } else if (rc < needed) {
+ const Uint32 delay = ((needed - (SDL_max(rc, 0))) * 1000) / this->spec.freq;
+ SDL_Delay(SDL_max(delay, 10));
+ } else {
+ break; /* ready to go! */
+ }
+ }
+#endif
}
@@ -422,7 +445,7 @@ static void
ALSA_CloseDevice(_THIS)
{
if (this->hidden->pcm_handle) {
- /* Wait for the submitted audio to drain
+ /* Wait for the submitted audio to drain
ALSA_snd_pcm_drop() can hang, so don't use that.
*/
Uint32 delay = ((this->spec.samples * 1000) / this->spec.freq) * 2;
@@ -435,35 +458,45 @@ ALSA_CloseDevice(_THIS)
}
static int
-ALSA_finalize_hardware(_THIS, snd_pcm_hw_params_t *hwparams, int override)
+ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params)
{
int status;
+ snd_pcm_hw_params_t *hwparams;
snd_pcm_uframes_t bufsize;
+ snd_pcm_uframes_t persize;
- /* "set" the hardware with the desired parameters */
- status = ALSA_snd_pcm_hw_params(this->hidden->pcm_handle, hwparams);
+ /* Copy the hardware parameters for this setup */
+ snd_pcm_hw_params_alloca(&hwparams);
+ ALSA_snd_pcm_hw_params_copy(hwparams, params);
+
+ /* Prioritize matching the period size to the requested buffer size */
+ persize = this->spec.samples;
+ status = ALSA_snd_pcm_hw_params_set_period_size_near(
+ this->hidden->pcm_handle, hwparams, &persize, NULL);
if ( status < 0 ) {
return(-1);
}
- /* Get samples for the actual buffer size */
- status = ALSA_snd_pcm_hw_params_get_buffer_size(hwparams, &bufsize);
+ /* Next try to restrict the parameters to having only two periods */
+ bufsize = this->spec.samples * 2;
+ status = ALSA_snd_pcm_hw_params_set_buffer_size_near(
+ this->hidden->pcm_handle, hwparams, &bufsize);
if ( status < 0 ) {
return(-1);
}
- if ( !override && bufsize != this->spec.samples * 2 ) {
+
+ /* "set" the hardware with the desired parameters */
+ status = ALSA_snd_pcm_hw_params(this->hidden->pcm_handle, hwparams);
+ if ( status < 0 ) {
return(-1);
}
- /* !!! FIXME: Is this safe to do? */
- this->spec.samples = bufsize / 2;
+ this->spec.samples = persize;
/* This is useful for debugging */
if ( SDL_getenv("SDL_AUDIO_ALSA_DEBUG") ) {
- snd_pcm_uframes_t persize = 0;
unsigned int periods = 0;
- ALSA_snd_pcm_hw_params_get_period_size(hwparams, &persize, NULL);
ALSA_snd_pcm_hw_params_get_periods(hwparams, &periods, NULL);
fprintf(stderr,
@@ -475,78 +508,6 @@ ALSA_finalize_hardware(_THIS, snd_pcm_hw_params_t *hwparams, int override)
}
static int
-ALSA_set_period_size(_THIS, snd_pcm_hw_params_t *params, int override)
-{
- const char *env;
- int status;
- snd_pcm_hw_params_t *hwparams;
- snd_pcm_uframes_t frames;
- unsigned int periods;
-
- /* Copy the hardware parameters for this setup */
- snd_pcm_hw_params_alloca(&hwparams);
- ALSA_snd_pcm_hw_params_copy(hwparams, params);
-
- if ( !override ) {
- env = SDL_getenv("SDL_AUDIO_ALSA_SET_PERIOD_SIZE");
- if ( env ) {
- override = SDL_atoi(env);
- if ( override == 0 ) {
- return(-1);
- }
- }
- }
-
- frames = this->spec.samples;
- status = ALSA_snd_pcm_hw_params_set_period_size_near(
- this->hidden->pcm_handle, hwparams, &frames, NULL);
- if ( status < 0 ) {
- return(-1);
- }
-
- periods = 2;
- status = ALSA_snd_pcm_hw_params_set_periods_near(
- this->hidden->pcm_handle, hwparams, &periods, NULL);
- if ( status < 0 ) {
- return(-1);
- }
-
- return ALSA_finalize_hardware(this, hwparams, override);
-}
-
-static int
-ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params, int override)
-{
- const char *env;
- int status;
- snd_pcm_hw_params_t *hwparams;
- snd_pcm_uframes_t frames;
-
- /* Copy the hardware parameters for this setup */
- snd_pcm_hw_params_alloca(&hwparams);
- ALSA_snd_pcm_hw_params_copy(hwparams, params);
-
- if ( !override ) {
- env = SDL_getenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE");
- if ( env ) {
- override = SDL_atoi(env);
- if ( override == 0 ) {
- return(-1);
- }
- }
- }
-
- frames = this->spec.samples * 2;
- status = ALSA_snd_pcm_hw_params_set_buffer_size_near(
- this->hidden->pcm_handle, hwparams, &frames);
- if ( status < 0 ) {
- return(-1);
- }
-
- return ALSA_finalize_hardware(this, hwparams, override);
-}
-
-static int
ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
int status = 0;
@@ -692,14 +653,11 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
this->spec.freq = rate;
/* Set the buffer size, in samples */
- if ( ALSA_set_period_size(this, hwparams, 0) < 0 &&
- ALSA_set_buffer_size(this, hwparams, 0) < 0 ) {
- /* Failed to set desired buffer size, do the best you can... */
- status = ALSA_set_period_size(this, hwparams, 1);
- if (status < 0) {
- return SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status));
- }
+ status = ALSA_set_buffer_size(this, hwparams);
+ if (status < 0) {
+ return SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status));
}
+
/* Set the software parameters */
snd_pcm_sw_params_alloca(&swparams);
status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
@@ -737,9 +695,11 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
}
+ #if !SDL_ALSA_NON_BLOCKING
if (!iscapture) {
ALSA_snd_pcm_nonblock(pcm_handle, 0);
}
+ #endif
/* We're ready to rock and roll. :-) */
return 0;