diff options
Diffstat (limited to 'audio')
-rw-r--r-- | audio/mixer.c | 278 | ||||
-rw-r--r-- | audio/mixer.h | 11 |
2 files changed, 14 insertions, 275 deletions
diff --git a/audio/mixer.c b/audio/mixer.c index 01bb4d5088..a251a5aa60 100644 --- a/audio/mixer.c +++ b/audio/mixer.c @@ -35,18 +35,6 @@ struct mixer { struct MPOpts *opts; struct ao *ao; struct af_stream *af; - // Static, dependent on ao/softvol settings - bool softvol; // use AO (false) or af_volume (true) - bool persistent_volume; // volume does not need to be restored - bool emulate_mute; // if true, emulate mute with volume=0 - // Last known values (possibly out of sync with reality) - float vol_l, vol_r; - bool muted; - // Used to decide whether we should unmute on uninit - bool muted_by_us; - /* Contains ao driver name or "softvol" if volume is not persistent - * and needs to be restored after the driver is reinitialized. */ - const char *driver; // Other stuff float balance; }; @@ -57,82 +45,22 @@ struct mixer *mixer_init(void *talloc_ctx, struct mpv_global *global) *mixer = (struct mixer) { .log = mp_log_new(mixer, global->log, "mixer"), .opts = global->opts, - .vol_l = 100, - .vol_r = 100, - .driver = "", }; return mixer; } bool mixer_audio_initialized(struct mixer *mixer) { - return !!mixer->ao; + return !!mixer->af; } -float mixer_getmaxvolume(struct mixer *mixer) +// Called when opts->softvol_volume or opts->softvol_mute were changed. +void mixer_update_volume(struct mixer *mixer) { - // gain == 1 - return mixer->softvol ? mixer->opts->softvol_max : 100; -} - -static void checkvolume(struct mixer *mixer) -{ - if (!mixer->ao) - return; - - ao_control_vol_t vol = {mixer->vol_l, mixer->vol_r}; - if (mixer->softvol) { - float gain; - if (!af_control_any_rev(mixer->af, AF_CONTROL_GET_VOLUME, &gain)) - gain = 1.0; - vol.left = gain * 100.0; - vol.right = gain * 100.0; - } else { - MP_DBG(mixer, "Reading volume from AO.\n"); - // Rely on the values not changing if the query is not supported - ao_control(mixer->ao, AOCONTROL_GET_VOLUME, &vol); - ao_control(mixer->ao, AOCONTROL_GET_MUTE, &mixer->muted); - } - float l = mixer->vol_l; - float r = mixer->vol_r; - if (mixer->emulate_mute && mixer->muted) - l = r = 0; - /* Try to detect cases where the volume has been changed by some external - * action (such as something else changing a shared system-wide volume). - * We don't test for exact equality, as some AOs may round the value - * we last set to some nearby supported value. 3 has been the default - * volume step for increase/decrease keys, and is apparently big enough - * to step to the next possible value in most setups. - */ - if (FFABS(vol.left - l) >= 3 || FFABS(vol.right - r) >= 3) { - mixer->vol_l = vol.left; - mixer->vol_r = vol.right; - if (mixer->emulate_mute) - mixer->muted = false; - } - mixer->muted_by_us &= mixer->muted; -} + float gain = MPMAX(mixer->opts->softvol_volume / 100.0, 0); + if (mixer->opts->softvol_mute == 1) + gain = 0.0; -void mixer_getvolume(struct mixer *mixer, float *l, float *r) -{ - checkvolume(mixer); - *l = mixer->vol_l; - *r = mixer->vol_r; -} - -static void setvolume_internal(struct mixer *mixer) -{ - float l = mixer->vol_l, r = mixer->vol_r; - if (mixer->emulate_mute && mixer->muted) - l = r = 0; - if (!mixer->softvol) { - MP_DBG(mixer, "Setting volume on AO.\n"); - struct ao_control_vol vol = {.left = l, .right = r}; - if (ao_control(mixer->ao, AOCONTROL_SET_VOLUME, &vol) != CONTROL_OK) - MP_ERR(mixer, "Failed to change audio output volume.\n"); - return; - } - float gain = (l + r) / 2.0 / 100.0; if (!af_control_any_rev(mixer->af, AF_CONTROL_SET_VOLUME, &gain)) { if (gain == 1.0) return; @@ -143,57 +71,6 @@ static void setvolume_internal(struct mixer *mixer) } } -void mixer_setvolume(struct mixer *mixer, float l, float r) -{ - checkvolume(mixer); // to check mute status - - float max = mixer_getmaxvolume(mixer); - mixer->vol_l = MPCLAMP(l, 0, max); - mixer->vol_r = MPCLAMP(r, 0, max); - if (mixer->ao) - setvolume_internal(mixer); -} - -void mixer_getbothvolume(struct mixer *mixer, float *b) -{ - float mixer_l, mixer_r; - mixer_getvolume(mixer, &mixer_l, &mixer_r); - *b = (mixer_l + mixer_r) / 2; -} - -void mixer_setmute(struct mixer *mixer, bool mute) -{ - checkvolume(mixer); - if (mute == mixer->muted) - return; - if (mixer->ao) { - mixer->muted = mute; - mixer->muted_by_us = mute; - if (mixer->emulate_mute) { - setvolume_internal(mixer); - } else { - ao_control(mixer->ao, AOCONTROL_SET_MUTE, &mute); - } - checkvolume(mixer); - } else { - mixer->muted = mute; - mixer->muted_by_us = mute; - } -} - -bool mixer_getmute(struct mixer *mixer) -{ - checkvolume(mixer); - return mixer->muted; -} - -void mixer_addvolume(struct mixer *mixer, float step) -{ - float vol_l, vol_r; - mixer_getvolume(mixer, &vol_l, &vol_r); - mixer_setvolume(mixer, vol_l + step, vol_r + step); -} - void mixer_getbalance(struct mixer *mixer, float *val) { if (mixer->af) @@ -242,130 +119,18 @@ void mixer_setbalance(struct mixer *mixer, float val) af_pan_balance->control(af_pan_balance, AF_CONTROL_SET_PAN_BALANCE, &val); } -char *mixer_get_volume_restore_data(struct mixer *mixer) -{ - if (!mixer->driver[0]) - return NULL; - return talloc_asprintf(NULL, "%s:%f:%f:%d", mixer->driver, mixer->vol_l, - mixer->vol_r, mixer->muted_by_us); -} - -static void probe_softvol(struct mixer *mixer) -{ - bool ao_perapp = ao_control(mixer->ao, AOCONTROL_HAS_PER_APP_VOLUME, 0) == 1; - bool ao_softvol = ao_control(mixer->ao, AOCONTROL_HAS_SOFT_VOLUME, 0) == 1; - assert(!(ao_perapp && ao_softvol)); - mixer->persistent_volume = !ao_softvol; - - if (mixer->opts->softvol == SOFTVOL_AUTO) { - // No system-wide volume => fine with AO volume control. - mixer->softvol = !ao_softvol && !ao_perapp; - } else { - mixer->softvol = mixer->opts->softvol == SOFTVOL_YES; - } - - if (mixer->softvol) - mixer->persistent_volume = false; - - MP_DBG(mixer, "Will use af_volume: %s\n", mixer->softvol ? "yes" : "no"); - - // If we can't use real volume control => force softvol. - if (!mixer->softvol) { - ao_control_vol_t vol; - if (ao_control(mixer->ao, AOCONTROL_GET_VOLUME, &vol) != CONTROL_OK) { - mixer->softvol = true; - MP_WARN(mixer, "Hardware volume control unavailable.\n"); - } - } - - // Probe native mute support. - mixer->emulate_mute = true; - if (!mixer->softvol) { - if (ao_control(mixer->ao, AOCONTROL_GET_MUTE, &(bool){0}) == CONTROL_OK) - mixer->emulate_mute = false; - } -} - -static void restore_volume(struct mixer *mixer) -{ - struct MPOpts *opts = mixer->opts; - struct ao *ao = mixer->ao; - - float force_vol_l = -1, force_vol_r = -1; - int force_mute = -1; - - const char *prev_driver = mixer->driver; - mixer->driver = mixer->softvol ? "softvol" : ao_get_name(ao); - if (!prev_driver[0]) - prev_driver = mixer->driver; - - // Restore old parameters if volume won't survive reinitialization. - // But not if volume scale is possibly different. - if (!mixer->persistent_volume && strcmp(mixer->driver, prev_driver) == 0) { - force_vol_l = mixer->vol_l; - force_vol_r = mixer->vol_r; - } - - // Set mute if we disabled it on uninit last time. - if (mixer->muted_by_us) - force_mute = 1; - - // Set parameters from command line. - if (opts->mixer_init_volume >= 0) - force_vol_l = force_vol_r = opts->mixer_init_volume; - if (opts->mixer_init_mute >= 0) - force_mute = opts->mixer_init_mute; - - // Set parameters from playback resume. - char *data = mixer->opts->mixer_restore_volume_data; - if (!mixer->persistent_volume && data && data[0]) { - char drv[40]; - float v_l, v_r; - int m; - if (sscanf(data, "%39[^:]:%f:%f:%d", drv, &v_l, &v_r, &m) == 4) { - if (strcmp(mixer->driver, drv) == 0) { - force_vol_l = v_l; - force_vol_r = v_r; - force_mute = !!m; - MP_DBG(mixer, "Restoring volume from resume config.\n"); - } - } - talloc_free(mixer->opts->mixer_restore_volume_data); - mixer->opts->mixer_restore_volume_data = NULL; - } - - // Using --volume should not reset the volume on every file (i.e. reinit), - // OTOH mpv --{ --volume 10 f1.mkv --} --{ --volume 20 f2.mkv --} must work. - // Resetting the option volumes to "auto" (-1) is easiest. If file local - // options (as shown above) are used, the option handler code will reset - // them to other values, and force the volume to be reset as well. - opts->mixer_init_volume = -1; - opts->mixer_init_mute = -1; - - checkvolume(mixer); - if (force_vol_l >= 0 && force_vol_r >= 0) { - MP_DBG(mixer, "Restoring previous volume.\n"); - mixer_setvolume(mixer, force_vol_l, force_vol_r); - } - if (force_mute >= 0) { - MP_DBG(mixer, "Restoring previous mute toggle.\n"); - mixer_setmute(mixer, force_mute); - } -} - // Called after the audio filter chain is built or rebuilt. // (Can be called multiple times, even without mixer_uninit() in-between.) -void mixer_reinit_audio(struct mixer *mixer, struct ao *ao, struct af_stream *af) +void mixer_reinit_audio(struct mixer *mixer, struct af_stream *af) { - if (!ao || !af) - return; - mixer->ao = ao; mixer->af = af; + if (!af) + return; - MP_DBG(mixer, "Reinit...\n"); + if (mixer->opts->softvol == SOFTVOL_NO) + MP_ERR(mixer, "--softvol=no is not supported anymore.\n"); - probe_softvol(mixer); - restore_volume(mixer); + mixer_update_volume(mixer); if (mixer->balance != 0) mixer_setbalance(mixer, mixer->balance); @@ -380,24 +145,5 @@ void mixer_uninit_audio(struct mixer *mixer) if (!mixer->ao) return; - MP_DBG(mixer, "Uninit...\n"); - - checkvolume(mixer); - if (mixer->muted_by_us && mixer->persistent_volume) { - MP_DBG(mixer, "Draining.\n"); - /* Current audio output API combines playing the remaining buffered - * audio and uninitializing the AO into one operation, even though - * ideally unmute would happen between those two steps. We can't do - * volume changes after uninitialization, but we don't want the - * remaining audio to play at full volume either. Thus this - * workaround to drop remaining audio first. */ - ao_reset(mixer->ao); - mixer_setmute(mixer, false); - /* We remember mute status and re-enable it if we play more audio - * in the same process. */ - mixer->muted_by_us = true; - } - mixer->ao = NULL; mixer->af = NULL; - mixer->softvol = false; } diff --git a/audio/mixer.h b/audio/mixer.h index 4e2ff350ff..b475c12700 100644 --- a/audio/mixer.h +++ b/audio/mixer.h @@ -33,18 +33,11 @@ struct af_stream; struct mixer; struct mixer *mixer_init(void *talloc_ctx, struct mpv_global *global); -void mixer_reinit_audio(struct mixer *mixer, struct ao *ao, struct af_stream *af); +void mixer_reinit_audio(struct mixer *mixer, struct af_stream *af); void mixer_uninit_audio(struct mixer *mixer); bool mixer_audio_initialized(struct mixer *mixer); -void mixer_getvolume(struct mixer *mixer, float *l, float *r); -void mixer_setvolume(struct mixer *mixer, float l, float r); -void mixer_addvolume(struct mixer *mixer, float step); -void mixer_getbothvolume(struct mixer *mixer, float *b); -void mixer_setmute(struct mixer *mixer, bool mute); -bool mixer_getmute(struct mixer *mixer); +void mixer_update_volume(struct mixer *mixer); void mixer_getbalance(struct mixer *mixer, float *bal); void mixer_setbalance(struct mixer *mixer, float bal); -float mixer_getmaxvolume(struct mixer *mixer); -char *mixer_get_volume_restore_data(struct mixer *mixer); #endif /* MPLAYER_MIXER_H */ |