summaryrefslogtreecommitdiffstats
path: root/audio/out/ao_alsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/out/ao_alsa.c')
-rw-r--r--audio/out/ao_alsa.c65
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)