mixer: support native audio driver mute

Make mixer support setting the mute attribute at audio driver level,
if one exists separately from volume. As of this commit, no libao2
driver exposes such an attribute yet; that will be added in later
commits.

Since the mute status can now be set externally, it's no longer
completely obvious when the player should automatically disable mute
when uninitializing an audio output. The implemented behavior is to
turn mute off at uninitialization if we turned it on and haven't
noticed it turn off (by external means) since.
This commit is contained in:
Uoti Urpala 2012-04-10 04:45:53 +03:00
parent 9624f10aa8
commit 39aa7d9846
3 changed files with 29 additions and 7 deletions

View File

@ -35,6 +35,9 @@ enum aocontrol {
// If there's only one volume, SET should use average of left/right. // If there's only one volume, SET should use average of left/right.
AOCONTROL_GET_VOLUME, AOCONTROL_GET_VOLUME,
AOCONTROL_SET_VOLUME, AOCONTROL_SET_VOLUME,
// _MUTE commands take a pointer to bool
AOCONTROL_GET_MUTE,
AOCONTROL_SET_MUTE,
}; };
#define AOPLAY_FINAL_CHUNK 1 #define AOPLAY_FINAL_CHUNK 1

31
mixer.c
View File

@ -49,7 +49,7 @@ static void checkvolume(struct mixer *mixer)
} }
float l = mixer->vol_l; float l = mixer->vol_l;
float r = mixer->vol_r; float r = mixer->vol_r;
if (mixer->muted) if (mixer->muted_using_volume)
l = r = 0; l = r = 0;
/* Try to detect cases where the volume has been changed by some external /* Try to detect cases where the volume has been changed by some external
* action (such as something else changing a shared system-wide volume). * action (such as something else changing a shared system-wide volume).
@ -61,8 +61,14 @@ static void checkvolume(struct mixer *mixer)
if (FFABS(vol.left - l) >= 3 || FFABS(vol.right - r) >= 3) { if (FFABS(vol.left - l) >= 3 || FFABS(vol.right - r) >= 3) {
mixer->vol_l = vol.left; mixer->vol_l = vol.left;
mixer->vol_r = vol.right; mixer->vol_r = vol.right;
mixer->muted = false; if (mixer->muted_using_volume)
mixer->muted = false;
} }
if (!mixer->softvol)
// Rely on the value not changing if the query is not supported
ao_control(mixer->ao, AOCONTROL_GET_MUTE, &mixer->muted);
mixer->muted_by_us &= mixer->muted;
mixer->muted_using_volume &= mixer->muted;
} }
void mixer_getvolume(mixer_t *mixer, float *l, float *r) void mixer_getvolume(mixer_t *mixer, float *l, float *r)
@ -130,8 +136,15 @@ void mixer_setmute(struct mixer *mixer, bool mute)
{ {
checkvolume(mixer); checkvolume(mixer);
if (mute != mixer->muted) { if (mute != mixer->muted) {
if (!mixer->softvol && !mixer->muted_using_volume && ao_control(
mixer->ao, AOCONTROL_SET_MUTE, &mute) == CONTROL_OK) {
mixer->muted_using_volume = false;
} else {
setvolume_internal(mixer, mixer->vol_l*!mute, mixer->vol_r*!mute);
mixer->muted_using_volume = mute;
}
mixer->muted = mute; mixer->muted = mute;
setvolume_internal(mixer, mixer->vol_l * !mute, mixer->vol_r * !mute); mixer->muted_by_us = mute;
} }
} }
@ -227,7 +240,7 @@ void mixer_reinit(struct mixer *mixer, struct ao *ao)
/* Use checkvolume() to see if softvol needs to be enabled because of /* Use checkvolume() to see if softvol needs to be enabled because of
* lacking AO support, but first store values it could overwrite. */ * lacking AO support, but first store values it could overwrite. */
float left = mixer->vol_l, right = mixer->vol_r; float left = mixer->vol_l, right = mixer->vol_r;
bool muted = mixer->muted; bool muted = mixer->muted_by_us;
checkvolume(mixer); checkvolume(mixer);
/* Try to avoid restoring volume stored from one control method with /* Try to avoid restoring volume stored from one control method with
* another. Especially, restoring softvol volume (typically high) on * another. Especially, restoring softvol volume (typically high) on
@ -237,7 +250,11 @@ void mixer_reinit(struct mixer *mixer, struct ao *ao)
if (mixer->restore_volume && !strcmp(mixer->restore_volume, if (mixer->restore_volume && !strcmp(mixer->restore_volume,
restore_reason)) restore_reason))
mixer_setvolume(mixer, left, right); mixer_setvolume(mixer, left, right);
mixer_setmute(mixer, muted); /* We turn mute off at AO uninit, so it has to be restored (unless
* we're reinitializing filter chain while keeping AO); but we only
* enable mute, not turn external mute off. */
if (muted)
mixer_setmute(mixer, true);
if (mixer->balance != 0) if (mixer->balance != 0)
mixer_setbalance(mixer, mixer->balance); mixer_setbalance(mixer, mixer->balance);
} }
@ -249,7 +266,7 @@ void mixer_reinit(struct mixer *mixer, struct ao *ao)
void mixer_uninit(struct mixer *mixer) void mixer_uninit(struct mixer *mixer)
{ {
checkvolume(mixer); checkvolume(mixer);
if (mixer->muted) { if (mixer->muted_by_us) {
/* Current audio output API combines playing the remaining buffered /* Current audio output API combines playing the remaining buffered
* audio and uninitializing the AO into one operation, even though * audio and uninitializing the AO into one operation, even though
* ideally unmute would happen between those two steps. We can't do * ideally unmute would happen between those two steps. We can't do
@ -260,7 +277,7 @@ void mixer_uninit(struct mixer *mixer)
mixer_setmute(mixer, false); mixer_setmute(mixer, false);
/* We remember mute status and re-enable it if we play more audio /* We remember mute status and re-enable it if we play more audio
* in the same process. */ * in the same process. */
mixer->muted = true; mixer->muted_by_us = true;
} }
mixer->ao = NULL; mixer->ao = NULL;
} }

View File

@ -31,6 +31,8 @@ typedef struct mixer {
bool softvol; bool softvol;
float softvol_max; float softvol_max;
bool muted; bool muted;
bool muted_by_us;
bool muted_using_volume;
float vol_l, vol_r; float vol_l, vol_r;
/* Contains ao driver name or "softvol" if volume is not persistent /* Contains ao driver name or "softvol" if volume is not persistent
* and needs to be restored after the driver is reinitialized. */ * and needs to be restored after the driver is reinitialized. */