diff options
Diffstat (limited to 'audio/out/ao_alsa.c')
-rw-r--r-- | audio/out/ao_alsa.c | 74 |
1 files changed, 41 insertions, 33 deletions
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index 0380162eb4..92ea0db237 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -34,7 +34,6 @@ #include <math.h> #include <string.h> -#include "config.h" #include "options/options.h" #include "options/m_config.h" #include "options/m_option.h" @@ -57,9 +56,9 @@ struct ao_alsa_opts { char *mixer_device; char *mixer_name; int mixer_index; - int resample; - int ni; - int ignore_chmap; + bool resample; + bool ni; + bool ignore_chmap; int buffer_time; int frags; }; @@ -67,12 +66,12 @@ struct ao_alsa_opts { #define OPT_BASE_STRUCT struct ao_alsa_opts static const struct m_sub_options ao_alsa_conf = { .opts = (const struct m_option[]) { - {"alsa-resample", OPT_FLAG(resample)}, + {"alsa-resample", OPT_BOOL(resample)}, {"alsa-mixer-device", OPT_STRING(mixer_device)}, {"alsa-mixer-name", OPT_STRING(mixer_name)}, {"alsa-mixer-index", OPT_INT(mixer_index), M_RANGE(0, 99)}, - {"alsa-non-interleaved", OPT_FLAG(ni)}, - {"alsa-ignore-chmap", OPT_FLAG(ignore_chmap)}, + {"alsa-non-interleaved", OPT_BOOL(ni)}, + {"alsa-ignore-chmap", OPT_BOOL(ignore_chmap)}, {"alsa-buffer-time", OPT_INT(buffer_time), M_RANGE(0, INT_MAX)}, {"alsa-periods", OPT_INT(frags), M_RANGE(0, INT_MAX)}, {0} @@ -80,8 +79,6 @@ static const struct m_sub_options ao_alsa_conf = { .defaults = &(const struct ao_alsa_opts) { .mixer_device = "default", .mixer_name = "Master", - .mixer_index = 0, - .ni = 0, .buffer_time = 100000, .frags = 4, }, @@ -168,15 +165,13 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg) switch (cmd) { case AOCONTROL_SET_VOLUME: { - ao_control_vol_t *vol = arg; - set_vol = vol->left / f_multi + pmin + 0.5; + float *vol = arg; + set_vol = *vol / f_multi + pmin + 0.5; err = snd_mixer_selem_set_playback_volume(elem, 0, set_vol); CHECK_ALSA_ERROR("Error setting left channel"); MP_DBG(ao, "left=%li, ", set_vol); - set_vol = vol->right / f_multi + pmin + 0.5; - err = snd_mixer_selem_set_playback_volume(elem, 1, set_vol); CHECK_ALSA_ERROR("Error setting right channel"); MP_DBG(ao, "right=%li, pmin=%li, pmax=%li, mult=%f\n", @@ -184,12 +179,14 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg) break; } case AOCONTROL_GET_VOLUME: { - ao_control_vol_t *vol = arg; + float *vol = arg; + float left, right; snd_mixer_selem_get_playback_volume(elem, 0, &get_vol); - vol->left = (get_vol - pmin) * f_multi; + left = (get_vol - pmin) * f_multi; snd_mixer_selem_get_playback_volume(elem, 1, &get_vol); - vol->right = (get_vol - pmin) * f_multi; - MP_DBG(ao, "left=%f, right=%f\n", vol->left, vol->right); + right = (get_vol - pmin) * f_multi; + *vol = (left + right) / 2.0; + MP_DBG(ao, "vol=%f\n", *vol); break; } case AOCONTROL_SET_MUTE: { @@ -563,7 +560,7 @@ static char *append_params(void *ta_parent, const char *device, const char *p) /* a simple list of parameters: add it at the end of the list */ return talloc_asprintf(ta_parent, "%s,%s", device, p); } - abort(); + MP_ASSERT_UNREACHABLE(); } static int try_open_device(struct ao *ao, const char *device, int mode) @@ -626,7 +623,8 @@ static void uninit(struct ao *ao) CHECK_ALSA_ERROR("pcm close error"); } -alsa_error: ; +alsa_error: + snd_config_update_free_global(); } #define INIT_DEVICE_ERR_GENERIC -1 @@ -850,7 +848,6 @@ static int init_device(struct ao *ao, int mode) MP_VERBOSE(ao, "period size: %d samples\n", (int)p->outburst); ao->device_buffer = p->buffersize; - ao->period_size = p->outburst; p->convert.channels = ao->channels.num; @@ -916,7 +913,7 @@ static int init(struct ao *ao) // Function for dealing with playback state. This attempts to recover the ALSA // state (bring it into SND_PCM_STATE_{PREPARED,RUNNING,PAUSED,UNDERRUN}). If -// state!=NULL, fill it after recovery. +// state!=NULL, fill it after recovery is attempted. // Returns true if PCM is in one the expected states. static bool recover_and_get_state(struct ao *ao, struct mp_pcm_state *state) { @@ -934,9 +931,18 @@ static bool recover_and_get_state(struct ao *ao, struct mp_pcm_state *state) // (where things were retried in a loop). for (int n = 0; n < 10; n++) { err = snd_pcm_status(p->alsa, st); - CHECK_ALSA_ERROR("snd_pcm_status"); + if (err == -EPIPE) { + // ALSA APIs can return -EPIPE when an XRUN happens, + // we skip right to handling it by setting pcmst + // manually. + pcmst = SND_PCM_STATE_XRUN; + } else { + // Otherwise do error checking and query the PCM state properly. + CHECK_ALSA_ERROR("snd_pcm_status"); + + pcmst = snd_pcm_status_get_state(st); + } - pcmst = snd_pcm_status_get_state(st); if (pcmst == SND_PCM_STATE_PREPARED || pcmst == SND_PCM_STATE_RUNNING || pcmst == SND_PCM_STATE_PAUSED) @@ -984,29 +990,29 @@ static bool recover_and_get_state(struct ao *ao, struct mp_pcm_state *state) ao_request_reload(ao); p->device_lost = true; } - return false; + goto alsa_error; } } if (!state_ok) { MP_ERR(ao, "could not recover\n"); - return false; } +alsa_error: + if (state) { - snd_pcm_sframes_t del = snd_pcm_status_get_delay(st); + snd_pcm_sframes_t del = state_ok ? snd_pcm_status_get_delay(st) : 0; state->delay = MPMAX(del, 0) / (double)ao->samplerate; - state->free_samples = snd_pcm_status_get_avail(st); + state->free_samples = state_ok ? snd_pcm_status_get_avail(st) : 0; state->free_samples = MPCLAMP(state->free_samples, 0, ao->device_buffer); + // Align to period size. + state->free_samples = state->free_samples / p->outburst * p->outburst; state->queued_samples = ao->device_buffer - state->free_samples; state->playing = pcmst == SND_PCM_STATE_RUNNING || pcmst == SND_PCM_STATE_PAUSED; } - return true; - -alsa_error: - return false; + return state_ok; } static void audio_get_state(struct ao *ao, struct mp_pcm_state *state) @@ -1084,8 +1090,10 @@ static bool audio_write(struct ao *ao, void **data, int samples) } CHECK_ALSA_ERROR("pcm write error"); - if (err != samples) - MP_WARN(ao, "unexpected short write\n"); + if (err >= 0 && err != samples) { + MP_ERR(ao, "unexpected partial write (%d of %d frames), dropping audio\n", + (int)err, samples); + } return true; |