summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-09-20 13:48:36 +0200
committerwm4 <wm4@nowhere>2013-09-20 13:48:36 +0200
commit3e5b632559a9198c0ede739622529d8df7909ca7 (patch)
tree0b66c871c6b670313da1dcedb9582db2a856cf51
parented2d67b6d7585a5db5411f230fc8dcd27f9e85fc (diff)
parent542086dd4537b852b61974f9bee4eabebde8505f (diff)
downloadmpv-3e5b632559a9198c0ede739622529d8df7909ca7.tar.bz2
mpv-3e5b632559a9198c0ede739622529d8df7909ca7.tar.xz
Merge branch 'volume_restore'
-rw-r--r--DOCS/man/en/af.rst2
-rw-r--r--DOCS/man/en/changes.rst1
-rw-r--r--DOCS/man/en/options.rst12
-rw-r--r--audio/filter/af.c41
-rw-r--r--audio/filter/af_volume.c13
-rw-r--r--audio/mixer.c302
-rw-r--r--audio/mixer.h46
-rw-r--r--audio/out/ao_alsa.c1
-rw-r--r--audio/out/ao_oss.c1
-rw-r--r--mpvcore/command.c42
-rw-r--r--mpvcore/mp_core.h4
-rw-r--r--mpvcore/mplayer.c50
-rw-r--r--mpvcore/options.c1
-rw-r--r--mpvcore/options.h1
14 files changed, 290 insertions, 227 deletions
diff --git a/DOCS/man/en/af.rst b/DOCS/man/en/af.rst
index a6ad32989c..8844077781 100644
--- a/DOCS/man/en/af.rst
+++ b/DOCS/man/en/af.rst
@@ -438,7 +438,7 @@ Available filters are:
``drc[=method:target]``
Applies dynamic range compression. This maximizes the volume by compressing
- the audio signal's dynamic range.
+ the audio signal's dynamic range. (Formerly called ``volnorm``.)
``<method>``
Sets the used method.
diff --git a/DOCS/man/en/changes.rst b/DOCS/man/en/changes.rst
index 8996a90336..489fadd36c 100644
--- a/DOCS/man/en/changes.rst
+++ b/DOCS/man/en/changes.rst
@@ -172,6 +172,7 @@ Command Line Switches
``--mixer`` AO suboptions (``alsa``, ``oss``)
``--mixer-channel`` AO suboptions (``alsa``, ``oss``)
``--ao=alsa:device=hw=0.3`` ``--ao=alsa:device=[hw:0,3]``
+ ``-af volnorm`` ``--af=drc`` (renamed)
=========================== ========================================
.. note::
diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst
index 1c07403ea7..766118e4c6 100644
--- a/DOCS/man/en/options.rst
+++ b/DOCS/man/en/options.rst
@@ -2589,6 +2589,18 @@
Set the startup volume. A value of -1 (the default) will not change the
volume. See also ``--softvol``.
+``--volume-restore-data=<string>``
+ Used internally for use by playback resume (e.g. with ``quit_watch_later``).
+ Restoring value has to be done carefully, because different AOs as well as
+ softvol can have different value ranges, and we don't want to restore
+ volume if setting the volume changes it system wide. The normal options
+ (like ``--volume``) would always set the volume. This option was added for
+ restoring volume in a safer way (by storing the method used to set the
+ volume), and is not generally useful. Its semantics are considered private
+ to mpv.
+
+ Do not use.
+
``--wid=<ID>``
(X11 and Windows only)
This tells mpv to attach to an existing window. The ID is interpreted as
diff --git a/audio/filter/af.c b/audio/filter/af.c
index 7a8dc406cf..00eb2346f9 100644
--- a/audio/filter/af.c
+++ b/audio/filter/af.c
@@ -437,8 +437,6 @@ static int af_fix_rate(struct af_stream *s, struct af_instance **p_af,
// state (for example, format filters that were tentatively inserted stay
// inserted).
// In that case, you should always rebuild the filter chain, or abort.
-// Also, note that for complete reinit, fixup_output_format() may have to be
-// called after this function.
static int af_reinit(struct af_stream *s)
{
// Start with the second filter, as the first filter is the special input
@@ -496,7 +494,12 @@ static int af_reinit(struct af_stream *s)
af_print_filter_chain(s, NULL, MSGL_V);
- return AF_OK;
+ /* Set previously unset fields in s->output to those of the filter chain
+ * output. This is used to make the output format fixed, and even if you
+ * insert new filters or change the input format, the output format won't
+ * change. (Audio outputs generally can't change format at runtime.) */
+ af_copy_unset_fields(&s->output, &s->filter_output);
+ return af_config_equals(&s->output, &s->filter_output) ? AF_OK : AF_ERROR;
negotiate_error:
mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Unable to correct audio format. "
@@ -547,21 +550,6 @@ void af_destroy(struct af_stream *s)
talloc_free(s);
}
-/*
- * Set previously unset fields in s->output to those of the filter chain
- * output. This is used to make the output format fixed, and even if you insert
- * new filters or change the input format, the output format won't change.
- * \return AF_ERROR on error, AF_OK if successful.
- */
-static int fixup_output_format(struct af_stream *s)
-{
- if (AF_OK != af_reinit(s))
- return AF_ERROR;
-
- af_copy_unset_fields(&s->output, &s->filter_output);
- return af_config_equals(&s->output, &s->filter_output) ? AF_OK : AF_ERROR;
-}
-
/* Initialize the stream "s". This function creates a new filter list
if necessary according to the values set in input and output. Input
and output should contain the format of the current movie and the
@@ -586,23 +574,18 @@ int af_init(struct af_stream *s)
// Add all filters in the list (if there are any)
struct m_obj_settings *list = s->opts->af_settings;
for (int i = 0; list && list[i].name; i++) {
- if (!af_prepend(s, s->last, list[i].name, list[i].attribs))
+ if (!af_prepend(s, s->last, list[i].name, list[i].attribs)) {
+ af_uninit(s);
return -1;
+ }
}
}
remove_auto_inserted_filters(s);
- // Init filters
- if (AF_OK != af_reinit(s))
- return -1;
-
- if (AF_OK != fixup_output_format(s)) {
+ if (af_reinit(s) != AF_OK) {
// Something is stuffed audio out will not work
- mp_msg(
- MSGT_AFILTER, MSGL_ERR,
- "[libaf] Unable to setup filter system can not"
- " meet sound-card demands, please send a bug report. \n");
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "Could not create audio filter chain.\n");
af_uninit(s);
return -1;
}
@@ -628,7 +611,7 @@ struct af_instance *af_add(struct af_stream *s, char *name, char **args)
return NULL;
// Reinitalize the filter list
- if (af_reinit(s) != AF_OK || fixup_output_format(s) != AF_OK) {
+ if (af_reinit(s) != AF_OK) {
af_uninit(s);
af_init(s);
return NULL;
diff --git a/audio/filter/af_volume.c b/audio/filter/af_volume.c
index 82c31eaa12..a766b97ec6 100644
--- a/audio/filter/af_volume.c
+++ b/audio/filter/af_volume.c
@@ -81,17 +81,22 @@ static int control(struct af_instance* af, int cmd, void* arg)
}
return af_test_output(af,(struct mp_audio*)arg);
case AF_CONTROL_COMMAND_LINE:{
- float v=0.0;
+ float v=1000.0;
float vol[AF_NCH];
int i;
sscanf((char*)arg,"%f:%i:%i", &v, &s->soft, &s->fast);
- for(i=0;i<AF_NCH;i++) vol[i]=v;
+ float dest = 0.0;
+ if (v < 1000)
+ af_from_dB(1,&v,&dest,20.0,-200.0,60.0);
+ for(i=0;i<AF_NCH;i++) vol[i]=dest;
return control(af,AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, vol);
}
case AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET:
- return af_from_dB(AF_NCH,(float*)arg,s->level,20.0,-200.0,60.0);
+ memcpy(s->level, arg, sizeof(float) * AF_NCH);
+ return AF_OK;
case AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_GET:
- return af_to_dB(AF_NCH,s->level,(float*)arg,20.0);
+ memcpy(arg, s->level, sizeof(float) * AF_NCH);
+ return AF_OK;
case AF_CONTROL_PRE_DESTROY:{
float m = 0.0;
int i;
diff --git a/audio/mixer.c b/audio/mixer.c
index d3762628ae..07ce229f73 100644
--- a/audio/mixer.c
+++ b/audio/mixer.c
@@ -17,6 +17,7 @@
*/
#include <string.h>
+#include <stdio.h>
#include <libavutil/common.h>
@@ -24,38 +25,61 @@
#include "audio/out/ao.h"
#include "audio/filter/af.h"
#include "mpvcore/mp_msg.h"
+#include "talloc.h"
#include "mixer.h"
+struct mixer {
+ struct MPOpts *opts;
+ struct ao *ao;
+ struct af_stream *af;
+ // Static, dependent on ao/softvol settings
+ bool softvol; // use AO (true) or af_volume (false)
+ 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;
+};
+
+struct mixer *mixer_init(void *talloc_ctx, struct MPOpts *opts)
+{
+ struct mixer *mixer = talloc_ptrtype(talloc_ctx, mixer);
+ *mixer = (struct mixer) {
+ .opts = opts,
+ .vol_l = 100,
+ .vol_r = 100,
+ .driver = "",
+ };
+ return mixer;
+}
static void checkvolume(struct mixer *mixer)
{
if (!mixer->ao)
return;
- if (mixer->softvol == SOFTVOL_AUTO) {
- mixer->softvol = mixer->ao->per_application_mixer
- || mixer->ao->no_persistent_volume
- ? SOFTVOL_NO : SOFTVOL_YES;
- }
-
- ao_control_vol_t vol;
- if (mixer->softvol || CONTROL_OK != ao_control(mixer->ao,
- AOCONTROL_GET_VOLUME, &vol)) {
- mixer->softvol = SOFTVOL_YES;
- if (!mixer->afilter)
- return;
- float db_vals[AF_NCH];
- if (!af_control_any_rev(mixer->afilter,
- AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_GET, db_vals))
- db_vals[0] = db_vals[1] = 1.0;
- else
- af_from_dB(2, db_vals, db_vals, 20.0, -200.0, 60.0);
- vol.left = (db_vals[0] / (mixer->softvol_max / 100.0)) * 100.0;
- vol.right = (db_vals[1] / (mixer->softvol_max / 100.0)) * 100.0;
+ ao_control_vol_t vol = {mixer->vol_l, mixer->vol_r};
+ if (mixer->softvol) {
+ float vals[AF_NCH];
+ if (!af_control_any_rev(mixer->af,
+ AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_GET, vals))
+ vals[0] = vals[1] = 1.0;
+ vol.left = (vals[0] / (mixer->opts->softvol_max / 100.0)) * 100.0;
+ vol.right = (vals[1] / (mixer->opts->softvol_max / 100.0)) * 100.0;
+ } else {
+ // 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->muted_using_volume)
+ 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).
@@ -67,73 +91,59 @@ static void checkvolume(struct mixer *mixer)
if (FFABS(vol.left - l) >= 3 || FFABS(vol.right - r) >= 3) {
mixer->vol_l = vol.left;
mixer->vol_r = vol.right;
- if (mixer->muted_using_volume)
+ if (mixer->emulate_mute)
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(struct mixer *mixer, float *l, float *r)
{
checkvolume(mixer);
*l = mixer->vol_l;
*r = mixer->vol_r;
}
-static void setvolume_internal(mixer_t *mixer, float l, float r)
+static void setvolume_internal(struct mixer *mixer, float l, float r)
{
struct ao_control_vol vol = {.left = l, .right = r};
if (!mixer->softvol) {
- // relies on the driver data being permanent (so ptr stays valid)
- mixer->restore_volume = mixer->ao->no_persistent_volume ?
- mixer->ao->driver->info->short_name : NULL;
if (ao_control(mixer->ao, AOCONTROL_SET_VOLUME, &vol) != CONTROL_OK)
mp_tmsg(MSGT_GLOBAL, MSGL_ERR,
"[Mixer] Failed to change audio output volume.\n");
return;
}
- mixer->restore_volume = "softvol";
- if (!mixer->afilter)
- return;
- // af_volume uses values in dB
- float db_vals[AF_NCH];
- int i;
- db_vals[0] = (l / 100.0) * (mixer->softvol_max / 100.0);
- db_vals[1] = (r / 100.0) * (mixer->softvol_max / 100.0);
- for (i = 2; i < AF_NCH; i++)
- db_vals[i] = ((l + r) / 100.0) * (mixer->softvol_max / 100.0) / 2.0;
- af_to_dB(AF_NCH, db_vals, db_vals, 20.0);
- if (!af_control_any_rev(mixer->afilter,
+ float vals[AF_NCH];
+ vals[0] = l / 100.0 * mixer->opts->softvol_max / 100.0;
+ vals[1] = r / 100.0 * mixer->opts->softvol_max / 100.0;
+ for (int i = 2; i < AF_NCH; i++)
+ vals[i] = (vals[0] + vals[1]) / 2.0;
+ if (!af_control_any_rev(mixer->af,
AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET,
- db_vals))
+ vals))
{
- mp_tmsg(MSGT_GLOBAL, mixer->softvol ? MSGL_V : MSGL_WARN,
- "[Mixer] No hardware mixing, inserting volume filter.\n");
- if (!(af_add(mixer->afilter, "volume", NULL)
- && af_control_any_rev(mixer->afilter,
+ mp_tmsg(MSGT_GLOBAL, MSGL_V, "[Mixer] Inserting volume filter.\n");
+ if (!(af_add(mixer->af, "volume", NULL)
+ && af_control_any_rev(mixer->af,
AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET,
- db_vals)))
+ vals)))
mp_tmsg(MSGT_GLOBAL, MSGL_ERR,
"[Mixer] No volume control available.\n");
}
}
-void mixer_setvolume(mixer_t *mixer, float l, float r)
+void mixer_setvolume(struct mixer *mixer, float l, float r)
{
- checkvolume(mixer); // to check mute status and AO support for volume
+ checkvolume(mixer); // to check mute status
+ if (mixer->vol_l == l && mixer->vol_r == r)
+ return; // just prevent af_volume insertion when not needed
mixer->vol_l = av_clipf(l, 0, 100);
mixer->vol_r = av_clipf(r, 0, 100);
- if (!mixer->ao || mixer->muted_using_volume)
- return;
- setvolume_internal(mixer, mixer->vol_l, mixer->vol_r);
- mixer->user_set_volume = true;
+ if (mixer->ao && !(mixer->emulate_mute && mixer->muted))
+ setvolume_internal(mixer, mixer->vol_l, mixer->vol_r);
}
-void mixer_getbothvolume(mixer_t *mixer, float *b)
+void mixer_getbothvolume(struct mixer *mixer, float *b)
{
float mixer_l, mixer_r;
mixer_getvolume(mixer, &mixer_l, &mixer_r);
@@ -143,17 +153,20 @@ void mixer_getbothvolume(mixer_t *mixer, float *b)
void mixer_setmute(struct mixer *mixer, bool mute)
{
checkvolume(mixer);
- 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 {
+ if (mute == mixer->muted)
+ return;
+ if (mixer->ao) {
+ mixer->muted = mute;
+ mixer->muted_by_us = mute;
+ if (mixer->emulate_mute) {
setvolume_internal(mixer, mixer->vol_l*!mute, mixer->vol_r*!mute);
- mixer->muted_using_volume = mute;
+ } else {
+ ao_control(mixer->ao, AOCONTROL_SET_MUTE, &mute);
}
+ checkvolume(mixer);
+ } else {
mixer->muted = mute;
mixer->muted_by_us = mute;
- mixer->user_set_mute = true;
}
}
@@ -165,26 +178,25 @@ bool mixer_getmute(struct mixer *mixer)
static void addvolume(struct mixer *mixer, float d)
{
- checkvolume(mixer);
- mixer_setvolume(mixer, mixer->vol_l + d, mixer->vol_r + d);
- if (d > 0)
- mixer_setmute(mixer, false);
+ float vol_l, vol_r;
+ mixer_getvolume(mixer, &vol_l, &vol_r);
+ mixer_setvolume(mixer, vol_l + d, vol_r + d);
}
-void mixer_incvolume(mixer_t *mixer)
+void mixer_incvolume(struct mixer *mixer)
{
- addvolume(mixer, mixer->volstep);
+ addvolume(mixer, mixer->opts->volstep);
}
-void mixer_decvolume(mixer_t *mixer)
+void mixer_decvolume(struct mixer *mixer)
{
- addvolume(mixer, -mixer->volstep);
+ addvolume(mixer, -mixer->opts->volstep);
}
-void mixer_getbalance(mixer_t *mixer, float *val)
+void mixer_getbalance(struct mixer *mixer, float *val)
{
- if (mixer->afilter)
- af_control_any_rev(mixer->afilter,
+ if (mixer->af)
+ af_control_any_rev(mixer->af,
AF_CONTROL_PAN_BALANCE | AF_CONTROL_GET,
&mixer->balance);
*val = mixer->balance;
@@ -201,7 +213,7 @@ void mixer_getbalance(mixer_t *mixer, float *val)
* are significantly below 1 will be overwritten with much higher values.
*/
-void mixer_setbalance(mixer_t *mixer, float val)
+void mixer_setbalance(struct mixer *mixer, float val)
{
float level[AF_NCH];
int i;
@@ -210,23 +222,22 @@ void mixer_setbalance(mixer_t *mixer, float val)
mixer->balance = val;
- if (!mixer->afilter)
+ if (!mixer->af)
return;
- if (af_control_any_rev(mixer->afilter,
+ if (af_control_any_rev(mixer->af,
AF_CONTROL_PAN_BALANCE | AF_CONTROL_SET, &val))
return;
if (val == 0 || mixer->ao->channels.num < 2)
return;
- if (!(af_pan_balance = af_add(mixer->afilter, "pan", NULL))) {
+ if (!(af_pan_balance = af_add(mixer->af, "pan", NULL))) {
mp_tmsg(MSGT_GLOBAL, MSGL_ERR,
"[Mixer] No balance control available.\n");
return;
}
- af_init(mixer->afilter);
/* make all other channels pass thru since by default pan blocks all */
memset(level, 0, sizeof(level));
for (i = 2; i < AF_NCH; i++) {
@@ -242,39 +253,125 @@ void mixer_setbalance(mixer_t *mixer, float val)
AF_CONTROL_PAN_BALANCE | AF_CONTROL_SET, &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)
+{
+ if (mixer->opts->softvol == SOFTVOL_AUTO) {
+ // No system-wide volume => fine with AO volume control.
+ mixer->softvol = !(mixer->ao->per_application_mixer ||
+ mixer->ao->no_persistent_volume);
+ } else {
+ mixer->softvol = mixer->opts->softvol == SOFTVOL_YES;
+ }
+
+ // 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_tmsg(MSGT_GLOBAL, MSGL_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->driver->info->short_name;
+
+ bool restore = mixer->softvol || ao->no_persistent_volume;
+
+ // Restore old parameters if volume won't survive reinitialization.
+ // But not if volume scale is possibly different.
+ if (restore && 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 *restore_data = mixer->opts->mixer_restore_volume_data;
+ if (restore && restore_data && restore_data[0]) {
+ char drv[40];
+ float v_l, v_r;
+ int m;
+ if (sscanf(restore_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;
+ }
+ }
+ talloc_free(restore_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)
+ mixer_setvolume(mixer, force_vol_l, force_vol_r);
+ if (force_mute >= 0)
+ mixer_setmute(mixer, force_mute);
+}
+
// Called after the audio filter chain is built or rebuilt.
-void mixer_reinit(struct mixer *mixer, struct ao *ao)
+// (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)
{
+ if (!ao || !af)
+ return;
mixer->ao = ao;
- /* Use checkvolume() to see if softvol needs to be enabled because of
- * lacking AO support, but first store values it could overwrite. */
- float left = mixer->vol_l, right = mixer->vol_r;
- bool muted = mixer->muted_by_us;
- checkvolume(mixer);
- /* Try to avoid restoring volume stored from one control method with
- * another. Especially, restoring softvol volume (typically high) on
- * system mixer could have very nasty effects. */
- const char *restore_reason = mixer->softvol ? "softvol" :
- mixer->ao->driver->info->short_name;
- if (mixer->restore_volume && !strcmp(mixer->restore_volume,
- restore_reason))
- mixer_setvolume(mixer, left, right);
- /* 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);
+ mixer->af = af;
+
+ probe_softvol(mixer);
+ restore_volume(mixer);
+
if (mixer->balance != 0)
mixer_setbalance(mixer, mixer->balance);
- mixer->user_set_mute = false;
- mixer->user_set_volume = false;
}
-/* Called before uninitializing the audio output. The main purpose is to
+/* Called before uninitializing the audio filter chain. The main purpose is to
* turn off mute, in case it's a global/persistent setting which might
* otherwise be left enabled even after this player instance exits.
*/
-void mixer_uninit(struct mixer *mixer)
+void mixer_uninit_audio(struct mixer *mixer)
{
if (!mixer->ao)
return;
@@ -294,4 +391,5 @@ void mixer_uninit(struct mixer *mixer)
mixer->muted_by_us = true;
}
mixer->ao = NULL;
+ mixer->af = NULL;
}
diff --git a/audio/mixer.h b/audio/mixer.h
index 3160c20cfe..9fbb4bcdca 100644
--- a/audio/mixer.h
+++ b/audio/mixer.h
@@ -21,40 +21,30 @@
#include <stdbool.h>
+// Values of MPOpts.softvol
enum {
SOFTVOL_NO = 0,
SOFTVOL_YES = 1,
SOFTVOL_AUTO = 2,
};
-typedef struct mixer {
- struct ao *ao;
- struct af_stream *afilter;
- int volstep;
- int softvol;
- float softvol_max;
- bool muted;
- bool muted_by_us;
- bool muted_using_volume;
- float vol_l, vol_r;
- /* Contains ao driver name or "softvol" if volume is not persistent
- * and needs to be restored after the driver is reinitialized. */
- const char *restore_volume;
- float balance;
- bool user_set_mute;
- bool user_set_volume;
-} mixer_t;
+struct MPOpts;
+struct ao;
+struct af_stream;
+struct mixer;
-void mixer_reinit(struct mixer *mixer, struct ao *ao);
-void mixer_uninit(struct mixer *mixer);
-void mixer_getvolume(mixer_t *mixer, float *l, float *r);
-void mixer_setvolume(mixer_t *mixer, float l, float r);
-void mixer_incvolume(mixer_t *mixer);
-void mixer_decvolume(mixer_t *mixer);
-void mixer_getbothvolume(mixer_t *mixer, float *b);
-void mixer_setmute(mixer_t *mixer, bool mute);
-bool mixer_getmute(mixer_t *mixer);
-void mixer_getbalance(mixer_t *mixer, float *bal);
-void mixer_setbalance(mixer_t *mixer, float bal);
+struct mixer *mixer_init(void *talloc_ctx, struct MPOpts *opts);
+void mixer_reinit_audio(struct mixer *mixer, struct ao *ao, struct af_stream *af);
+void mixer_uninit_audio(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_incvolume(struct mixer *mixer);
+void mixer_decvolume(struct mixer *mixer);
+void mixer_getbothvolume(struct mixer *mixer, float *b);
+void mixer_setmute(struct mixer *mixer, bool mute);
+bool mixer_getmute(struct mixer *mixer);
+void mixer_getbalance(struct mixer *mixer, float *bal);
+void mixer_setbalance(struct mixer *mixer, float bal);
+char *mixer_get_volume_restore_data(struct mixer *mixer);
#endif /* MPLAYER_MIXER_H */
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c
index 2db5041b95..ff931e2a0b 100644
--- a/audio/out/ao_alsa.c
+++ b/audio/out/ao_alsa.c
@@ -38,7 +38,6 @@
#include "config.h"
#include "mpvcore/options.h"
#include "mpvcore/m_option.h"
-#include "audio/mixer.h"
#include "mpvcore/mp_msg.h"
#define ALSA_PCM_NEW_HW_PARAMS_API
diff --git a/audio/out/ao_oss.c b/audio/out/ao_oss.c
index 79b96c7bc1..0890f11e0a 100644
--- a/audio/out/ao_oss.c
+++ b/audio/out/ao_oss.c
@@ -36,7 +36,6 @@
#include "config.h"
#include "mpvcore/options.h"
#include "mpvcore/mp_msg.h"
-#include "audio/mixer.h"
#ifdef HAVE_SYS_SOUNDCARD_H
#include <sys/soundcard.h>
diff --git a/mpvcore/command.c b/mpvcore/command.c
index dedac9dc10..a2de363b3d 100644
--- a/mpvcore/command.c
+++ b/mpvcore/command.c
@@ -762,23 +762,19 @@ static int mp_property_clock(m_option_t *prop, int action, void *arg,
static int mp_property_volume(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
-
- if (!mpctx->sh_audio)
- return M_PROPERTY_UNAVAILABLE;
-
switch (action) {
case M_PROPERTY_GET:
- mixer_getbothvolume(&mpctx->mixer, arg);
+ mixer_getbothvolume(mpctx->mixer, arg);
return M_PROPERTY_OK;
case M_PROPERTY_SET:
- mixer_setvolume(&mpctx->mixer, *(float *) arg, *(float *) arg);
+ mixer_setvolume(mpctx->mixer, *(float *) arg, *(float *) arg);
return M_PROPERTY_OK;
case M_PROPERTY_SWITCH: {
struct m_property_switch_arg *sarg = arg;
if (sarg->inc <= 0)
- mixer_decvolume(&mpctx->mixer);
+ mixer_decvolume(mpctx->mixer);
else
- mixer_incvolume(&mpctx->mixer);
+ mixer_incvolume(mpctx->mixer);
return M_PROPERTY_OK;
}
}
@@ -789,21 +785,32 @@ static int mp_property_volume(m_option_t *prop, int action, void *arg,
static int mp_property_mute(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
-
- if (!mpctx->sh_audio)
- return M_PROPERTY_UNAVAILABLE;
-
switch (action) {
case M_PROPERTY_SET:
- mixer_setmute(&mpctx->mixer, *(int *) arg);
+ mixer_setmute(mpctx->mixer, *(int *) arg);
return M_PROPERTY_OK;
case M_PROPERTY_GET:
- *(int *)arg = mixer_getmute(&mpctx->mixer);
+ *(int *)arg = mixer_getmute(mpctx->mixer);
return M_PROPERTY_OK;
}
return M_PROPERTY_NOT_IMPLEMENTED;
}
+static int mp_property_volrestore(m_option_t *prop, int action,
+ void *arg, MPContext *mpctx)
+{
+ switch (action) {
+ case M_PROPERTY_GET: {
+ char *s = mixer_get_volume_restore_data(mpctx->mixer);
+ *(char **)arg = s;
+ return s ? M_PROPERTY_OK : M_PROPERTY_UNAVAILABLE;
+ }
+ case M_PROPERTY_SET:
+ return M_PROPERTY_NOT_IMPLEMENTED;
+ }
+ return mp_property_generic_option(prop, action, arg, mpctx);
+}
+
/// Audio delay (RW)
static int mp_property_audio_delay(m_option_t *prop, int action,
void *arg, MPContext *mpctx)
@@ -899,11 +906,11 @@ static int mp_property_balance(m_option_t *prop, int action, void *arg,
switch (action) {
case M_PROPERTY_GET:
- mixer_getbalance(&mpctx->mixer, arg);
+ mixer_getbalance(mpctx->mixer, arg);
return M_PROPERTY_OK;
case M_PROPERTY_PRINT: {
char **str = arg;
- mixer_getbalance(&mpctx->mixer, &bal);
+ mixer_getbalance(mpctx->mixer, &bal);
if (bal == 0.f)
*str = talloc_strdup(NULL, "center");
else if (bal == -1.f)
@@ -918,7 +925,7 @@ static int mp_property_balance(m_option_t *prop, int action, void *arg,
return M_PROPERTY_OK;
}
case M_PROPERTY_SET:
- mixer_setbalance(&mpctx->mixer, *(float *)arg);
+ mixer_setbalance(mpctx->mixer, *(float *)arg);
return M_PROPERTY_OK;
}
return M_PROPERTY_NOT_IMPLEMENTED;
@@ -1806,6 +1813,7 @@ static const m_option_t mp_properties[] = {
M_OPTION_PROPERTY_CUSTOM("aid", mp_property_audio),
{ "balance", mp_property_balance, CONF_TYPE_FLOAT,
M_OPT_RANGE, -1, 1, NULL },
+ M_OPTION_PROPERTY_CUSTOM("volume-restore-data", mp_property_volrestore),
// Video
M_OPTION_PROPERTY_CUSTOM("fullscreen", mp_property_fullscreen),
diff --git a/mpvcore/mp_core.h b/mpvcore/mp_core.h
index 9f3e095110..98096aa5fe 100644
--- a/mpvcore/mp_core.h
+++ b/mpvcore/mp_core.h
@@ -22,14 +22,12 @@
#include <stdbool.h>
#include "mpvcore/options.h"
-#include "audio/mixer.h"
#include "demux/demux.h"
// definitions used internally by the core player code
#define INITIALIZED_VO 1
#define INITIALIZED_AO 2
-#define INITIALIZED_VOL 4
#define INITIALIZED_GETCH2 8
#define INITIALIZED_PLAYBACK 16
#define INITIALIZED_STREAM 64
@@ -180,7 +178,7 @@ typedef struct MPContext {
// demuxer defines metadata), or special purpose demuxers like TV.
struct demuxer *master_demuxer;
- mixer_t mixer;
+ struct mixer *mixer;
struct ao *ao;
struct vo *video_out;
diff --git a/mpvcore/mplayer.c b/mpvcore/mplayer.c
index e4566c56ff..f4bf6c9316 100644
--- a/mpvcore/mplayer.c
+++ b/mpvcore/mplayer.c
@@ -443,18 +443,16 @@ static void uninit_subs(struct demuxer *demuxer)
void uninit_player(struct MPContext *mpctx, unsigned int mask)
{
- struct MPOpts *o