diff options
author | chai <chaifix@163.com> | 2019-01-31 18:38:35 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2019-01-31 18:38:35 +0800 |
commit | 2ec55fd974a63b705a4777c256d2222c874fa043 (patch) | |
tree | 48f1fea59ee9fc713a28a9aac3f05b98dc5ae66f /Source/3rdParty/SDL2/src/audio/alsa/SDL_alsa_audio.c | |
parent | c581dfbf1e849f393861d15e82aa6446c0c1c310 (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.c | 142 |
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; |