mirror of
https://github.com/mpv-player/mpv
synced 2024-10-02 16:25:33 +02:00
mixer, libao: add proper mute control
The mixer frontend code can now make use of a proper system mixer mute toggle, if the audio output driver supports it. The consequence is that, if support is available, mplayer will no longer temporarily set the system volume to 0 if mute is enabled. Generally, the code now deals with the following combinations of available AO features: - software volume control forced by user (--softvol / soft_vol flag) => if enabled, never touch the "hardware" controls - "hardware"/driver volume control available (whether AOCONTROL_GET/SET_VOLUME works) => if not available, enable volume controls by enabling softvol - "hardware"/driver mute control (AOCONTROL_GET/SET_MUTE) => if not available, emulate by setting volume to 0 - whether the volume+mute controls are kept or not when the AO is closed (indicated by ao->no_persistent_volume) => if not persistent, restore the volume/mute next time the AO is opened
This commit is contained in:
parent
56c1ab1c62
commit
06b1de2687
@ -97,10 +97,19 @@ void list_audio_out(void);
|
||||
#define AOCONTROL_SET_DEVICE 1
|
||||
#define AOCONTROL_GET_DEVICE 2
|
||||
#define AOCONTROL_QUERY_FORMAT 3 /* test for availabilty of a format */
|
||||
// Uses ao_control_vol_t* as arg.
|
||||
// If the volume controls are joint, the average of both volumes should be used.
|
||||
#define AOCONTROL_GET_VOLUME 4
|
||||
#define AOCONTROL_SET_VOLUME 5
|
||||
#define AOCONTROL_SET_PLUGIN_DRIVER 6
|
||||
#define AOCONTROL_SET_PLUGIN_LIST 7
|
||||
// Uses ao_control_vol_t* as arg.
|
||||
// left==0.0f means muted, left==1.0f means not muted (right likewise)
|
||||
// Other values between are invalid.
|
||||
// If the mtue controls are joint, the output should be muted if either of the
|
||||
// two channels are muted.
|
||||
#define AOCONTROL_GET_MUTE 6
|
||||
#define AOCONTROL_SET_MUTE 7
|
||||
#define AOCONTROL_SET_PLUGIN_DRIVER 8
|
||||
#define AOCONTROL_SET_PLUGIN_LIST 9
|
||||
|
||||
#define AOPLAY_FINAL_CHUNK 1
|
||||
|
||||
|
74
mixer.c
74
mixer.c
@ -35,22 +35,31 @@ char *mixer_channel = NULL;
|
||||
int soft_vol = 0;
|
||||
float soft_vol_max = 110.0;
|
||||
|
||||
static void internal_setvolume(mixer_t *mixer, float l, float r);
|
||||
|
||||
|
||||
// Called after the audio filter chain is built or rebuilt.
|
||||
void mixer_reinit(mixer_t *mixer)
|
||||
{
|
||||
if (!mixer->ao)
|
||||
return;
|
||||
// Some of this might be incorrect when the AO behavior changes (e.g.
|
||||
// different AO due to file specific -ao options), but we assume this
|
||||
// doesn't happen. We could attempt to handle this by trying to detect
|
||||
// whether a system mixer or mute is supported, but it would probably add
|
||||
// even more bugs to the code.
|
||||
if (mixer->restore_volume) {
|
||||
int muted = mixer->muted;
|
||||
mixer_setvolume(mixer, mixer->restore_vol_l, mixer->restore_vol_r);
|
||||
mixer->muted = muted;
|
||||
// restore previous volume (softvol, or no persistent AO volume)
|
||||
internal_setvolume(mixer, mixer->restore_vol_l, mixer->restore_vol_r);
|
||||
}
|
||||
if (mixer->muted) {
|
||||
// undo mixer_uninit()
|
||||
mixer_setvolume(mixer, 0, 0);
|
||||
mixer->muted = true;
|
||||
if (mixer->muted &&
|
||||
(mixer->mute_emulation || mixer->ao->no_persistent_volume))
|
||||
{
|
||||
// undo mixer_uninit(), or restore mute state
|
||||
mixer_setmuted(mixer, true);
|
||||
}
|
||||
if (mixer->restore_balance) {
|
||||
// balance control always uses af_pan, it always needs to be restored
|
||||
mixer_setbalance(mixer, mixer->balance);
|
||||
}
|
||||
}
|
||||
@ -62,12 +71,14 @@ void mixer_uninit(mixer_t *mixer)
|
||||
{
|
||||
if (!mixer->ao)
|
||||
return;
|
||||
// The player is supposed to turn off the mute state when the player
|
||||
// terminates. No other attempts at restoring the volume are done.
|
||||
// The player is supposed to restore the volume, when mute was enabled, and
|
||||
// the player terminates. No other attempts at restoring anything are done.
|
||||
// One complication is that the mute state should survive audio
|
||||
// reinitialization (e.g. when switching to a new file), so we have to be
|
||||
// sure mixer_reinit() will restore the mute state.
|
||||
if (mixer_getmuted(mixer)) {
|
||||
// This is only needed when a global system mixer without mute control is
|
||||
// used, i.e. we emulate mute by setting the volume to 0.
|
||||
if (mixer->mute_emulation && mixer_getmuted(mixer)) {
|
||||
// avoid playing the rest of the audio buffer at restored volume
|
||||
ao_reset(mixer->ao);
|
||||
mixer_setmuted(mixer, false);
|
||||
@ -107,7 +118,7 @@ static float clip_vol(float v)
|
||||
return v > 100 ? 100 : (v < 0 ? 0 : v);
|
||||
}
|
||||
|
||||
void mixer_setvolume(mixer_t *mixer, float l, float r)
|
||||
static void internal_setvolume(mixer_t *mixer, float l, float r)
|
||||
{
|
||||
l = clip_vol(l);
|
||||
r = clip_vol(r);
|
||||
@ -156,7 +167,15 @@ void mixer_setvolume(mixer_t *mixer, float l, float r)
|
||||
mixer->restore_vol_r = r;
|
||||
}
|
||||
}
|
||||
mixer->muted = false;
|
||||
}
|
||||
|
||||
void mixer_setvolume(mixer_t *mixer, float l, float r)
|
||||
{
|
||||
internal_setvolume(mixer, l, r);
|
||||
// Changing the volume clears mute; these are mplayer semantics. (If this
|
||||
// is not desired, this would be removed, and code for restoring the softvol
|
||||
// volume had to be added.)
|
||||
mixer_setmuted(mixer, false);
|
||||
}
|
||||
|
||||
void mixer_getvolume(mixer_t *mixer, float *l, float *r)
|
||||
@ -210,9 +229,15 @@ void mixer_mute(mixer_t *mixer)
|
||||
|
||||
bool mixer_getmuted(mixer_t *mixer)
|
||||
{
|
||||
// this call will also check whether mute is still active, and "fix" it
|
||||
float l, r;
|
||||
mixer_getvolume(mixer, &l, &r);
|
||||
ao_control_vol_t vol = {0};
|
||||
if (!soft_vol &&
|
||||
CONTROL_OK == ao_control(mixer->ao, AOCONTROL_GET_MUTE, &vol))
|
||||
{
|
||||
mixer->muted = vol.left == 0.0f || vol.right == 0.0f;
|
||||
} else {
|
||||
float l, r;
|
||||
mixer_getvolume(mixer, &l, &r); // updates mixer->muted
|
||||
}
|
||||
return mixer->muted;
|
||||
}
|
||||
|
||||
@ -221,13 +246,20 @@ void mixer_setmuted(mixer_t *mixer, bool mute)
|
||||
bool muted = mixer_getmuted(mixer);
|
||||
if (mute == muted)
|
||||
return;
|
||||
if (muted) {
|
||||
mixer_setvolume(mixer, mixer->last_l, mixer->last_r);
|
||||
} else {
|
||||
mixer_getvolume(mixer, &mixer->last_l, &mixer->last_r);
|
||||
mixer_setvolume(mixer, 0, 0);
|
||||
mixer->muted = true;
|
||||
ao_control_vol_t vol;
|
||||
vol.left = vol.right = mute ? 0.0f : 1.0f;
|
||||
mixer->mute_emulation = soft_vol ||
|
||||
CONTROL_OK != ao_control(mixer->ao, AOCONTROL_SET_MUTE, &vol);
|
||||
if (mixer->mute_emulation) {
|
||||
// mute is emulated by setting volume to 0
|
||||
if (!mute) {
|
||||
internal_setvolume(mixer, mixer->last_l, mixer->last_r);
|
||||
} else {
|
||||
mixer_getvolume(mixer, &mixer->last_l, &mixer->last_r);
|
||||
internal_setvolume(mixer, 0, 0);
|
||||
}
|
||||
}
|
||||
mixer->muted = mute;
|
||||
}
|
||||
|
||||
void mixer_getbalance(mixer_t *mixer, float *val)
|
||||
|
Loading…
Reference in New Issue
Block a user