From 296531ad0050fbc38fb1cf7823f6e22f97d502b1 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 19 Sep 2013 14:31:43 +0200 Subject: mixer: minor refactoring Let struct mixer access access MPOpts to simplify some things. Rename some variables and functions. There should be no functional changes. --- audio/mixer.c | 44 +++++++++++++++++++++++--------------------- audio/mixer.h | 9 ++++----- mpvcore/mplayer.c | 11 ++++------- 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/audio/mixer.c b/audio/mixer.c index d3762628ae..6b68ee2e58 100644 --- a/audio/mixer.c +++ b/audio/mixer.c @@ -42,16 +42,16 @@ static void checkvolume(struct mixer *mixer) if (mixer->softvol || CONTROL_OK != ao_control(mixer->ao, AOCONTROL_GET_VOLUME, &vol)) { mixer->softvol = SOFTVOL_YES; - if (!mixer->afilter) + if (!mixer->af) return; float db_vals[AF_NCH]; - if (!af_control_any_rev(mixer->afilter, + if (!af_control_any_rev(mixer->af, 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; + vol.left = (db_vals[0] / (mixer->opts->softvol_max / 100.0)) * 100.0; + vol.right = (db_vals[1] / (mixer->opts->softvol_max / 100.0)) * 100.0; } float l = mixer->vol_l; float r = mixer->vol_r; @@ -97,24 +97,24 @@ static void setvolume_internal(mixer_t *mixer, float l, float r) return; } mixer->restore_volume = "softvol"; - if (!mixer->afilter) + if (!mixer->af) 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); + db_vals[0] = (l / 100.0) * (mixer->opts->softvol_max / 100.0); + db_vals[1] = (r / 100.0) * (mixer->opts->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; + db_vals[i] = ((l + r) / 100.0) * (mixer->opts->softvol_max / 100.0) / 2.0; af_to_dB(AF_NCH, db_vals, db_vals, 20.0); - if (!af_control_any_rev(mixer->afilter, + if (!af_control_any_rev(mixer->af, AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, db_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, + if (!(af_add(mixer->af, "volume", NULL) + && af_control_any_rev(mixer->af, AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, db_vals))) mp_tmsg(MSGT_GLOBAL, MSGL_ERR, @@ -173,18 +173,18 @@ static void addvolume(struct mixer *mixer, float d) void mixer_incvolume(mixer_t *mixer) { - addvolume(mixer, mixer->volstep); + addvolume(mixer, mixer->opts->volstep); } void mixer_decvolume(mixer_t *mixer) { - addvolume(mixer, -mixer->volstep); + addvolume(mixer, -mixer->opts->volstep); } void mixer_getbalance(mixer_t *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; @@ -210,23 +210,23 @@ 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); + af_init(mixer->af); /* make all other channels pass thru since by default pan blocks all */ memset(level, 0, sizeof(level)); for (i = 2; i < AF_NCH; i++) { @@ -243,9 +243,11 @@ void mixer_setbalance(mixer_t *mixer, float val) } // Called after the audio filter chain is built or rebuilt. -void mixer_reinit(struct mixer *mixer, struct ao *ao) +void mixer_reinit_audio(struct mixer *mixer, struct ao *ao, struct af_stream *af) { mixer->ao = ao; + mixer->af = af; + mixer->softvol = mixer->opts->softvol; /* 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; @@ -274,7 +276,7 @@ void mixer_reinit(struct mixer *mixer, struct ao *ao) * 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; diff --git a/audio/mixer.h b/audio/mixer.h index 3160c20cfe..b22bba0310 100644 --- a/audio/mixer.h +++ b/audio/mixer.h @@ -28,11 +28,10 @@ enum { }; typedef struct mixer { + struct MPOpts *opts; struct ao *ao; - struct af_stream *afilter; - int volstep; + struct af_stream *af; int softvol; - float softvol_max; bool muted; bool muted_by_us; bool muted_using_volume; @@ -45,8 +44,8 @@ typedef struct mixer { bool user_set_volume; } mixer_t; -void mixer_reinit(struct mixer *mixer, struct ao *ao); -void mixer_uninit(struct mixer *mixer); +void mixer_reinit_audio(struct mixer *mixer, struct ao *ao, struct af_stream *af); +void mixer_uninit_audio(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); diff --git a/mpvcore/mplayer.c b/mpvcore/mplayer.c index d9715e447f..a2c96bb270 100644 --- a/mpvcore/mplayer.c +++ b/mpvcore/mplayer.c @@ -454,7 +454,7 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) if (mpctx->sh_audio) uninit_audio(mpctx->sh_audio); cleanup_demux_stream(mpctx, STREAM_AUDIO); - mpctx->mixer.afilter = NULL; + mpctx->mixer.af = NULL; } if (mask & INITIALIZED_SUB) { @@ -542,7 +542,7 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) if (mask & INITIALIZED_AO) { mpctx->initialized_flags &= ~INITIALIZED_AO; if (mpctx->mixer.ao) - mixer_uninit(&mpctx->mixer); + mixer_uninit_audio(&mpctx->mixer); mpctx->mixer.ao = NULL; if (mpctx->ao) ao_uninit(mpctx->ao, mpctx->stop_play != AT_END_OF_FILE); @@ -1628,11 +1628,7 @@ static int recreate_audio_filters(struct MPContext *mpctx) return -1; } - mpctx->mixer.afilter = mpctx->sh_audio->afilter; - mpctx->mixer.volstep = opts->volstep; - mpctx->mixer.softvol = opts->softvol; - mpctx->mixer.softvol_max = opts->softvol_max; - mixer_reinit(&mpctx->mixer, mpctx->ao); + mixer_reinit_audio(&mpctx->mixer, mpctx->ao, mpctx->sh_audio->afilter); if (!(mpctx->initialized_flags & INITIALIZED_VOL)) { if (opts->mixer_init_volume >= 0) { mixer_setvolume(&mpctx->mixer, opts->mixer_init_volume, @@ -4859,6 +4855,7 @@ static int mpv_main(int argc, char *argv[]) init_libav(); GetCpuCaps(&gCpuCaps); screenshot_init(mpctx); + mpctx->mixer.opts = opts; // Preparse the command line m_config_preparse_command_line(mpctx->mconfig, argc, argv); -- cgit v1.2.3 From 4ba52a9e821486d9d9b076a5187583af144b8cec Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 19 Sep 2013 14:31:55 +0200 Subject: mixer, af_volume: use linear values instead of dB Softvol always used a linear multiplier for volume control. This was converted to dB, and then back to linear in af_volume. Remove this non- sense. We still try to keep the command line argument to af_volume in dB, though. --- audio/filter/af_volume.c | 13 +++++++++---- audio/mixer.c | 29 ++++++++++++----------------- 2 files changed, 21 insertions(+), 21 deletions(-) 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;ilevel,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 6b68ee2e58..97e9417fc1 100644 --- a/audio/mixer.c +++ b/audio/mixer.c @@ -44,14 +44,12 @@ static void checkvolume(struct mixer *mixer) mixer->softvol = SOFTVOL_YES; if (!mixer->af) return; - float db_vals[AF_NCH]; + float vals[AF_NCH]; if (!af_control_any_rev(mixer->af, - 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->opts->softvol_max / 100.0)) * 100.0; - vol.right = (db_vals[1] / (mixer->opts->softvol_max / 100.0)) * 100.0; + 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; } float l = mixer->vol_l; float r = mixer->vol_r; @@ -99,24 +97,21 @@ static void setvolume_internal(mixer_t *mixer, float l, float r) mixer->restore_volume = "softvol"; if (!mixer->af) return; - // af_volume uses values in dB - float db_vals[AF_NCH]; - int i; - db_vals[0] = (l / 100.0) * (mixer->opts->softvol_max / 100.0); - db_vals[1] = (r / 100.0) * (mixer->opts->softvol_max / 100.0); - for (i = 2; i < AF_NCH; i++) - db_vals[i] = ((l + r) / 100.0) * (mixer->opts->softvol_max / 100.0) / 2.0; - af_to_dB(AF_NCH, db_vals, db_vals, 20.0); + 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->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"); } -- cgit v1.2.3 From 38b2c97fd6b59b923ad309c19c457cbc0210da17 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 19 Sep 2013 14:32:09 +0200 Subject: mixer: refactor, fix some aspects of --volume handling Refactor how mixer.c does volume/mute restoration and initialization. Move to handling of --volume and --mute to mixer.c. Simplify the implementation of these and hopefully fix bugs/strange behavior related to using them as file-local options (this uses a somewhat dirty trick: the option values are reverted to "auto" after initialization). Put most code related to initialization and volume restoring in probe_softvol() and restore_volume(). Having this code all in one place is less confusing. Instead of trying to detect whether to use softvol at runtime, detect it at initialization time using AOCONTROL_GET_VOLUME (same with mute, AOCONTROL_GET_MUTE). This implies we expect SET_VOLUME/SET_MUTE to work if the GET variants work. Hopefully this is always the case. This is also preparation for being able to change volume/mute settings if audio is disabled, and for allowing restoring value with playback resume. --- audio/mixer.c | 176 +++++++++++++++++++++++++++++++++++------------------- audio/mixer.h | 16 +++-- mpvcore/mp_core.h | 1 - mpvcore/mplayer.c | 42 +++---------- 4 files changed, 131 insertions(+), 104 deletions(-) diff --git a/audio/mixer.c b/audio/mixer.c index 97e9417fc1..38c93032a1 100644 --- a/audio/mixer.c +++ b/audio/mixer.c @@ -26,34 +26,34 @@ #include "mpvcore/mp_msg.h" #include "mixer.h" +void mixer_init(struct mixer *mixer, struct MPOpts *opts) +{ + mixer->opts = opts; + mixer->vol_l = mixer->vol_r = 100; + mixer->driver = ""; +} 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->af) - return; + 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). @@ -65,14 +65,10 @@ 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) @@ -86,17 +82,11 @@ static void setvolume_internal(mixer_t *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->af) - return; 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; @@ -106,8 +96,7 @@ static void setvolume_internal(mixer_t *mixer, float l, float r) AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, vals)) { - mp_tmsg(MSGT_GLOBAL, mixer->softvol ? MSGL_V : MSGL_WARN, - "[Mixer] No hardware mixing, inserting volume filter.\n"); + 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, @@ -119,13 +108,13 @@ static void setvolume_internal(mixer_t *mixer, float l, float r) void mixer_setvolume(mixer_t *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) @@ -138,17 +127,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; } } @@ -160,8 +152,9 @@ 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); + float vol_l, vol_r; + mixer_getvolume(mixer, &vol_l, &vol_r); + mixer_setvolume(mixer, vol_l + d, vol_r + d); if (d > 0) mixer_setmute(mixer, false); } @@ -237,37 +230,95 @@ void mixer_setbalance(mixer_t *mixer, float val) AF_CONTROL_PAN_BALANCE | AF_CONTROL_SET, &val); } +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; + + // 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, these are reset to other values. + 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. +// (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; mixer->af = af; - mixer->softvol = mixer->opts->softvol; - /* 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); + + 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. */ @@ -291,4 +342,5 @@ void mixer_uninit_audio(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 b22bba0310..6761be5da4 100644 --- a/audio/mixer.h +++ b/audio/mixer.h @@ -21,6 +21,7 @@ #include +// Values of MPOpts.softvol enum { SOFTVOL_NO = 0, SOFTVOL_YES = 1, @@ -31,19 +32,22 @@ typedef struct mixer { struct MPOpts *opts; struct ao *ao; struct af_stream *af; - int softvol; + // 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; - 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; + const char *driver; + // Other stuff float balance; - bool user_set_mute; - bool user_set_volume; } mixer_t; +void mixer_init(struct mixer *mixer, 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(mixer_t *mixer, float *l, float *r); diff --git a/mpvcore/mp_core.h b/mpvcore/mp_core.h index 9f3e095110..8f57a65edf 100644 --- a/mpvcore/mp_core.h +++ b/mpvcore/mp_core.h @@ -29,7 +29,6 @@ #define INITIALIZED_VO 1 #define INITIALIZED_AO 2 -#define INITIALIZED_VOL 4 #define INITIALIZED_GETCH2 8 #define INITIALIZED_PLAYBACK 16 #define INITIALIZED_STREAM 64 diff --git a/mpvcore/mplayer.c b/mpvcore/mplayer.c index a2c96bb270..fafb88d022 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 *opts = mpctx->opts; - mask &= mpctx->initialized_flags; mp_msg(MSGT_CPLAYER, MSGL_DBG2, "\n*** uninit(0x%X)\n", mask); if (mask & INITIALIZED_ACODEC) { mpctx->initialized_flags &= ~INITIALIZED_ACODEC; + mixer_uninit_audio(&mpctx->mixer); if (mpctx->sh_audio) uninit_audio(mpctx->sh_audio); cleanup_demux_stream(mpctx, STREAM_AUDIO); - mpctx->mixer.af = NULL; } if (mask & INITIALIZED_SUB) { @@ -526,24 +524,8 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) getch2_disable(); } - if (mask & INITIALIZED_VOL) { - mpctx->initialized_flags &= ~INITIALIZED_VOL; - if (mpctx->mixer.ao) { - // Normally the mixer remembers volume, but do it even if the - // volume is set explicitly with --volume=... (so that the same - // volume is restored on reinit) - if (opts->mixer_init_volume >= 0 && mpctx->mixer.user_set_volume) - mixer_getbothvolume(&mpctx->mixer, &opts->mixer_init_volume); - if (opts->mixer_init_mute >= 0 && mpctx->mixer.user_set_mute) - opts->mixer_init_mute = mixer_getmute(&mpctx->mixer); - } - } - if (mask & INITIALIZED_AO) { mpctx->initialized_flags &= ~INITIALIZED_AO; - if (mpctx->mixer.ao) - mixer_uninit_audio(&mpctx->mixer); - mpctx->mixer.ao = NULL; if (mpctx->ao) ao_uninit(mpctx->ao, mpctx->stop_play != AT_END_OF_FILE); mpctx->ao = NULL; @@ -1618,7 +1600,6 @@ static int build_afilter_chain(struct MPContext *mpctx) static int recreate_audio_filters(struct MPContext *mpctx) { - struct MPOpts *opts = mpctx->opts; assert(mpctx->sh_audio); // init audio filters: @@ -1629,15 +1610,6 @@ static int recreate_audio_filters(struct MPContext *mpctx) } mixer_reinit_audio(&mpctx->mixer, mpctx->ao, mpctx->sh_audio->afilter); - if (!(mpctx->initialized_flags & INITIALIZED_VOL)) { - if (opts->mixer_init_volume >= 0) { - mixer_setvolume(&mpctx->mixer, opts->mixer_init_volume, - opts->mixer_init_volume); - } - if (opts->mixer_init_mute >= 0) - mixer_setmute(&mpctx->mixer, opts->mixer_init_mute); - mpctx->initialized_flags |= INITIALIZED_VOL; - } return 0; } @@ -1662,7 +1634,7 @@ void reinit_audio_chain(struct MPContext *mpctx) struct MPOpts *opts = mpctx->opts; init_demux_stream(mpctx, STREAM_AUDIO); if (!mpctx->sh_audio) { - uninit_player(mpctx, INITIALIZED_VOL | INITIALIZED_AO); + uninit_player(mpctx, INITIALIZED_AO); goto no_audio; } @@ -1733,7 +1705,7 @@ void reinit_audio_chain(struct MPContext *mpctx) return; init_error: - uninit_player(mpctx, INITIALIZED_ACODEC | INITIALIZED_AO | INITIALIZED_VOL); + uninit_player(mpctx, INITIALIZED_ACODEC | INITIALIZED_AO); cleanup_demux_stream(mpctx, STREAM_AUDIO); no_audio: mpctx->current_track[STREAM_AUDIO] = NULL; @@ -2040,7 +2012,7 @@ void mp_switch_track(struct MPContext *mpctx, enum stream_type type, uninit_player(mpctx, INITIALIZED_VCODEC | (mpctx->opts->fixed_vo && track ? 0 : INITIALIZED_VO)); } else if (type == STREAM_AUDIO) { - uninit_player(mpctx, INITIALIZED_AO | INITIALIZED_ACODEC | INITIALIZED_VOL); + uninit_player(mpctx, INITIALIZED_AO | INITIALIZED_ACODEC); } else if (type == STREAM_SUB) { uninit_player(mpctx, INITIALIZED_SUB); } @@ -2280,7 +2252,7 @@ static int fill_audio_out_buffers(struct MPContext *mpctx, double endpts) * while displaying video, then doing the output format switch. */ if (!mpctx->opts->gapless_audio) - uninit_player(mpctx, INITIALIZED_AO | INITIALIZED_VOL); + uninit_player(mpctx, INITIALIZED_AO); reinit_audio_chain(mpctx); return -1; } else if (res == ASYNC_PLAY_DONE) @@ -2909,7 +2881,7 @@ static bool timeline_set_part(struct MPContext *mpctx, int i, bool force) enum stop_play_reason orig_stop_play = mpctx->stop_play; if (!mpctx->sh_video && mpctx->stop_play == KEEP_PLAYING) mpctx->stop_play = AT_END_OF_FILE; // let audio uninit drain data - uninit_player(mpctx, INITIALIZED_VCODEC | (mpctx->opts->fixed_vo ? 0 : INITIALIZED_VO) | (mpctx->opts->gapless_audio ? 0 : INITIALIZED_AO) | INITIALIZED_VOL | INITIALIZED_ACODEC | INITIALIZED_SUB); + uninit_player(mpctx, INITIALIZED_VCODEC | (mpctx->opts->fixed_vo ? 0 : INITIALIZED_VO) | (mpctx->opts->gapless_audio ? 0 : INITIALIZED_AO) | INITIALIZED_ACODEC | INITIALIZED_SUB); mpctx->stop_play = orig_stop_play; mpctx->demuxer = n->source; @@ -4855,7 +4827,7 @@ static int mpv_main(int argc, char *argv[]) init_libav(); GetCpuCaps(&gCpuCaps); screenshot_init(mpctx); - mpctx->mixer.opts = opts; + mixer_init(&mpctx->mixer, opts); // Preparse the command line m_config_preparse_command_line(mpctx->mconfig, argc, argv); -- cgit v1.2.3 From 234d967bed3784657279052e23fdfa751ae1e7fc Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 19 Sep 2013 14:32:25 +0200 Subject: mixer: don't unmute audio when raising volume This is rather strange behavior, away with it. --- audio/mixer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/audio/mixer.c b/audio/mixer.c index 38c93032a1..4407e8969f 100644 --- a/audio/mixer.c +++ b/audio/mixer.c @@ -155,8 +155,6 @@ static void addvolume(struct mixer *mixer, float d) float vol_l, vol_r; mixer_getvolume(mixer, &vol_l, &vol_r); mixer_setvolume(mixer, vol_l + d, vol_r + d); - if (d > 0) - mixer_setmute(mixer, false); } void mixer_incvolume(mixer_t *mixer) -- cgit v1.2.3 From b8e42ae13c511855fcba0b6b795d55b37e461665 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 19 Sep 2013 14:32:47 +0200 Subject: mixer: restore volume with playback resume Note that this is intentionally never done if the AO or softvolume is different, or if the current volume control method is thought to control system wide volume (such as ALSA) or otherwise user controllable (such as PulseAudio). The intention is to keep things robust and to avoid messing with the user's audio settings as far as possible, while still providing the ability to resume volume if it makes sense. --- DOCS/man/en/options.rst | 12 ++++++++++++ audio/mixer.c | 30 +++++++++++++++++++++++++++++- audio/mixer.h | 1 + mpvcore/command.c | 16 ++++++++++++++++ mpvcore/mplayer.c | 3 +-- mpvcore/options.c | 1 + mpvcore/options.h | 1 + 7 files changed, 61 insertions(+), 3 deletions(-) diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst index f9a75779f7..ac07a9a1ba 100644 --- a/DOCS/man/en/options.rst +++ b/DOCS/man/en/options.rst @@ -2596,6 +2596,18 @@ Set the startup volume. A value of -1 (the default) will not change the volume. See also ``--softvol``. +``--volume-restore-data=`` + 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=`` (X11 and Windows only) This tells mpv to attach to an existing window. The ID is interpreted as diff --git a/audio/mixer.c b/audio/mixer.c index 4407e8969f..3e16ce5f8e 100644 --- a/audio/mixer.c +++ b/audio/mixer.c @@ -17,6 +17,7 @@ */ #include +#include #include @@ -24,6 +25,7 @@ #include "audio/out/ao.h" #include "audio/filter/af.h" #include "mpvcore/mp_msg.h" +#include "talloc.h" #include "mixer.h" void mixer_init(struct mixer *mixer, struct MPOpts *opts) @@ -228,6 +230,14 @@ 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) { @@ -286,10 +296,28 @@ static void restore_volume(struct mixer *mixer) 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, these are reset to other values. + // 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; diff --git a/audio/mixer.h b/audio/mixer.h index 6761be5da4..a636a2b418 100644 --- a/audio/mixer.h +++ b/audio/mixer.h @@ -59,5 +59,6 @@ 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); +char *mixer_get_volume_restore_data(struct mixer *mixer); #endif /* MPLAYER_MIXER_H */ diff --git a/mpvcore/command.c b/mpvcore/command.c index dedac9dc10..ea71b9e082 100644 --- a/mpvcore/command.c +++ b/mpvcore/command.c @@ -804,6 +804,21 @@ static int mp_property_mute(m_option_t *prop, int action, void *arg, 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) @@ -1806,6 +1821,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/mplayer.c b/mpvcore/mplayer.c index fafb88d022..00229364e6 100644 --- a/mpvcore/mplayer.c +++ b/mpvcore/mplayer.c @@ -809,8 +809,7 @@ static const char *backup_properties[] = { "speed", "edition", "pause", - //"volume", - //"mute", + "volume-restore-data", "audio-delay", //"balance", "fullscreen", diff --git a/mpvcore/options.c b/mpvcore/options.c index a09a28856f..e3b3137aed 100644 --- a/mpvcore/options.c +++ b/mpvcore/options.c @@ -565,6 +565,7 @@ const m_option_t mp_opts[] = { ({"auto", -1}, {"no", 0}, {"yes", 1}, {"", 1})), + OPT_STRING("volume-restore-data", mixer_restore_volume_data, 0), OPT_FLAG("gapless-audio", gapless_audio, 0), // set screen dimensions (when not detectable or virtual!=visible) diff --git a/mpvcore/options.h b/mpvcore/options.h index 67074de241..d425d0789b 100644 --- a/mpvcore/options.h +++ b/mpvcore/options.h @@ -51,6 +51,7 @@ typedef struct MPOpts { int softvol; float mixer_init_volume; int mixer_init_mute; + char *mixer_restore_volume_data; int volstep; float softvol_max; int gapless_audio; -- cgit v1.2.3 From 7623c94ddce304ac045a86d4b70c1519d672107d Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 19 Sep 2013 14:33:01 +0200 Subject: manpage: af_volnorm was renamed --- DOCS/man/en/af.rst | 2 +- DOCS/man/en/changes.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) 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``.) ```` 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:: -- cgit v1.2.3 From 327a779a81098b39823f7036eba816b8b4c7245f Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 19 Sep 2013 14:33:12 +0200 Subject: mixer: allow accessing volume and mute property on disabled audio The volume is set as soon as the audio chain is created again. This works only in softvol mode. For system wide volume or otherwise externally user controllable volume, this code is intentionally disabled. It would be extremely weird if changing volume (while audio is not initialized) would do nothing, and then suddenly change it when the audio chain is created. There's another odd corner case: the user-set volume will be thrown away if it's set before the _first_ audio chain initialization. This is because the volume restore logic recognizes a change from nothing to softvol or an AO, and circumventing that would require additional code. Also, we don't even know the start volume before that point. Forcing the volume with --volume will can override the volume set during no-audio mode, depending on the situation. --- mpvcore/command.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/mpvcore/command.c b/mpvcore/command.c index ea71b9e082..cb1bdd9678 100644 --- a/mpvcore/command.c +++ b/mpvcore/command.c @@ -762,10 +762,6 @@ 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); @@ -789,10 +785,6 @@ 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); -- cgit v1.2.3 From 01622717257673d424debfa762536f998d97a4dd Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 19 Sep 2013 14:33:26 +0200 Subject: mixer: make struct opaque Also remove stray include statements from ao_alsa and ao_oss. --- audio/mixer.c | 48 ++++++++++++++++++++++++++++++++++++------------ audio/mixer.h | 42 ++++++++++++++---------------------------- audio/out/ao_alsa.c | 1 - audio/out/ao_oss.c | 1 - mpvcore/command.c | 20 ++++++++++---------- mpvcore/mp_core.h | 3 +-- mpvcore/mplayer.c | 6 +++--- 7 files changed, 64 insertions(+), 57 deletions(-) diff --git a/audio/mixer.c b/audio/mixer.c index 3e16ce5f8e..0bc650c7e8 100644 --- a/audio/mixer.c +++ b/audio/mixer.c @@ -28,11 +28,35 @@ #include "talloc.h" #include "mixer.h" -void mixer_init(struct mixer *mixer, struct MPOpts *opts) +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) { - mixer->opts = opts; - mixer->vol_l = mixer->vol_r = 100; - mixer->driver = ""; + 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) @@ -73,14 +97,14 @@ static void checkvolume(struct mixer *mixer) mixer->muted_by_us &= 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) { @@ -108,7 +132,7 @@ static void setvolume_internal(mixer_t *mixer, float l, float r) } } -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 if (mixer->vol_l == l && mixer->vol_r == r) @@ -119,7 +143,7 @@ void mixer_setvolume(mixer_t *mixer, float l, float r) 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); @@ -159,17 +183,17 @@ static void addvolume(struct mixer *mixer, float d) mixer_setvolume(mixer, vol_l + d, vol_r + d); } -void mixer_incvolume(mixer_t *mixer) +void mixer_incvolume(struct mixer *mixer) { addvolume(mixer, mixer->opts->volstep); } -void mixer_decvolume(mixer_t *mixer) +void mixer_decvolume(struct mixer *mixer) { addvolume(mixer, -mixer->opts->volstep); } -void mixer_getbalance(mixer_t *mixer, float *val) +void mixer_getbalance(struct mixer *mixer, float *val) { if (mixer->af) af_control_any_rev(mixer->af, @@ -189,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; diff --git a/audio/mixer.h b/audio/mixer.h index a636a2b418..9fbb4bcdca 100644 --- a/audio/mixer.h +++ b/audio/mixer.h @@ -28,37 +28,23 @@ enum { SOFTVOL_AUTO = 2, }; -typedef 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; -} mixer_t; +struct MPOpts; +struct ao; +struct af_stream; +struct mixer; -void mixer_init(struct mixer *mixer, struct MPOpts *opts); +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(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); +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 diff --git a/mpvcore/command.c b/mpvcore/command.c index cb1bdd9678..a2de363b3d 100644 --- a/mpvcore/command.c +++ b/mpvcore/command.c @@ -764,17 +764,17 @@ static int mp_property_volume(m_option_t *prop, int action, void *arg, { 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; } } @@ -787,10 +787,10 @@ static int mp_property_mute(m_option_t *prop, int action, void *arg, { 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; @@ -801,7 +801,7 @@ static int mp_property_volrestore(m_option_t *prop, int action, { switch (action) { case M_PROPERTY_GET: { - char *s = mixer_get_volume_restore_data(&mpctx->mixer); + char *s = mixer_get_volume_restore_data(mpctx->mixer); *(char **)arg = s; return s ? M_PROPERTY_OK : M_PROPERTY_UNAVAILABLE; } @@ -906,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) @@ -925,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; diff --git a/mpvcore/mp_core.h b/mpvcore/mp_core.h index 8f57a65edf..98096aa5fe 100644 --- a/mpvcore/mp_core.h +++ b/mpvcore/mp_core.h @@ -22,7 +22,6 @@ #include #include "mpvcore/options.h" -#include "audio/mixer.h" #include "demux/demux.h" // definitions used internally by the core player code @@ -179,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 00229364e6..dc4322d4e3 100644 --- a/mpvcore/mplayer.c +++ b/mpvcore/mplayer.c @@ -449,7 +449,7 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) if (mask & INITIALIZED_ACODEC) { mpctx->initialized_flags &= ~INITIALIZED_ACODEC; - mixer_uninit_audio(&mpctx->mixer); + mixer_uninit_audio(mpctx->mixer); if (mpctx->sh_audio) uninit_audio(mpctx->sh_audio); cleanup_demux_stream(mpctx, STREAM_AUDIO); @@ -1608,7 +1608,7 @@ static int recreate_audio_filters(struct MPContext *mpctx) return -1; } - mixer_reinit_audio(&mpctx->mixer, mpctx->ao, mpctx->sh_audio->afilter); + mixer_reinit_audio(mpctx->mixer, mpctx->ao, mpctx->sh_audio->afilter); return 0; } @@ -4826,7 +4826,7 @@ static int mpv_main(int argc, char *argv[]) init_libav(); GetCpuCaps(&gCpuCaps); screenshot_init(mpctx); - mixer_init(&mpctx->mixer, opts); + mpctx->mixer = mixer_init(mpctx, opts); // Preparse the command line m_config_preparse_command_line(mpctx->mconfig, argc, argv); -- cgit v1.2.3 From 542086dd4537b852b61974f9bee4eabebde8505f Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 20 Sep 2013 13:25:53 +0200 Subject: af: merge af_reinit() and fix_output_format() Calling them separately doesn't really make sense, and all existing calls to them usually combined them. One subtitle difference was that af_init() didn't wipe the filter chain if initialization of the chain itself failed, but that didn't really make sense anyway. Also remove af_init() from the code for setting balance in mixer.c. The mixer should be in the initialized state only if audio is fully initialized, so the af_init() call made no sense. Note that the filter "editing" code in command.c doesn't really do a nice job of handling errors in case recreating an _old_ (known to work) filter chain unexpectedly fails, and this obscure/rare case might be differently handled after this change. --- audio/filter/af.c | 41 ++++++++++++----------------------------- audio/mixer.c | 1 - 2 files changed, 12 insertions(+), 30 deletions(-) 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/mixer.c b/audio/mixer.c index 0bc650c7e8..07ce229f73 100644 --- a/audio/mixer.c +++ b/audio/mixer.c @@ -238,7 +238,6 @@ void mixer_setbalance(struct mixer *mixer, float val) return; } - af_init(mixer->af); /* make all other channels pass thru since by default pan blocks all */ memset(level, 0, sizeof(level)); for (i = 2; i < AF_NCH; i++) { -- cgit v1.2.3