diff options
Diffstat (limited to 'audio/out/ao_alsa.c')
-rw-r--r-- | audio/out/ao_alsa.c | 65 |
1 files changed, 35 insertions, 30 deletions
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index 24f3355047..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 @@ -915,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) { @@ -933,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) @@ -983,19 +990,20 @@ 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; @@ -1004,10 +1012,7 @@ static bool recover_and_get_state(struct ao *ao, struct mp_pcm_state *state) 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) |