summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@mplayer2.org>2012-01-17 07:54:11 +0100
committerwm4 <wm4@mplayer2.org>2012-01-18 04:21:46 +0100
commit06b1de26875dded600ac5771d4c0bd87f1d6e802 (patch)
treeadf08f344f280f633ab78c49c88704038b0381db
parent56c1ab1c62e4e35c7b62d2b8143f6e9247f4c96c (diff)
downloadmpv-06b1de26875dded600ac5771d4c0bd87f1d6e802.tar.bz2
mpv-06b1de26875dded600ac5771d4c0bd87f1d6e802.tar.xz
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
-rw-r--r--libao2/audio_out.h13
-rw-r--r--mixer.c74
-rw-r--r--mixer.h1
3 files changed, 65 insertions, 23 deletions
diff --git a/libao2/audio_out.h b/libao2/audio_out.h
index a8efc92069..c5ddb5bf60 100644
--- a/libao2/audio_out.h
+++ b/libao2/audio_out.h
@@ -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
diff --git a/mixer.c b/mixer.c
index 61dc1dcb13..dfa52e6b28 100644
--- a/mixer.c
+++ b/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)
diff --git a/mixer.h b/mixer.h
index f99e860ff3..6619783a58 100644
--- a/mixer.h
+++ b/mixer.h
@@ -34,6 +34,7 @@ typedef struct mixer_s {
af_stream_t *afilter;
int volstep;
bool muted;
+ bool mute_emulation;
float last_l, last_r;
float restore_vol_l, restore_vol_r;
bool restore_volume;