summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio/mixer.c12
-rw-r--r--audio/out/ao.c38
-rw-r--r--audio/out/ao.h69
-rw-r--r--audio/out/ao_alsa.c1
-rw-r--r--audio/out/ao_coreaudio.c1
-rw-r--r--audio/out/ao_coreaudio_properties.h2
-rw-r--r--audio/out/ao_coreaudio_utils.h1
-rw-r--r--audio/out/ao_dsound.c1
-rw-r--r--audio/out/ao_jack.c1
-rw-r--r--audio/out/ao_lavc.c1
-rw-r--r--audio/out/ao_null.c1
-rw-r--r--audio/out/ao_openal.c1
-rw-r--r--audio/out/ao_oss.c1
-rw-r--r--audio/out/ao_pcm.c1
-rw-r--r--audio/out/ao_portaudio.c1
-rw-r--r--audio/out/ao_pulse.c1
-rw-r--r--audio/out/ao_rsound.c1
-rw-r--r--audio/out/ao_sdl.c1
-rw-r--r--audio/out/ao_sndio.c1
-rw-r--r--audio/out/ao_wasapi.c1
-rw-r--r--audio/out/internal.h76
-rw-r--r--player/audio.c98
-rw-r--r--player/core.h5
-rw-r--r--player/loadfile.c6
-rw-r--r--player/playloop.c11
-rw-r--r--player/video.c2
26 files changed, 218 insertions, 117 deletions
diff --git a/audio/mixer.c b/audio/mixer.c
index a9759976a2..34a1722c80 100644
--- a/audio/mixer.c
+++ b/audio/mixer.c
@@ -210,7 +210,7 @@ void mixer_setbalance(struct mixer *mixer, float val)
if (af_control_any_rev(mixer->af, AF_CONTROL_SET_PAN_BALANCE, &val))
return;
- if (val == 0 || mixer->ao->channels.num < 2)
+ if (val == 0)
return;
if (!(af_pan_balance = af_add(mixer->af, "pan", NULL))) {
@@ -243,8 +243,9 @@ 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);
+ mixer->softvol =
+ ao_control(mixer->ao, AOCONTROL_HAS_TEMP_VOLUME, 0) != 1 &&
+ ao_control(mixer->ao, AOCONTROL_HAS_PER_APP_VOLUME, 0) != 1;
} else {
mixer->softvol = mixer->opts->softvol == SOFTVOL_YES;
}
@@ -275,9 +276,10 @@ static void restore_volume(struct mixer *mixer)
int force_mute = -1;
const char *prev_driver = mixer->driver;
- mixer->driver = mixer->softvol ? "softvol" : ao->driver->name;
+ mixer->driver = mixer->softvol ? "softvol" : ao_get_name(ao);
- bool restore = mixer->softvol || ao->no_persistent_volume;
+ bool restore
+ = mixer->softvol || ao_control(ao, AOCONTROL_HAS_TEMP_VOLUME, 0) == 1;
// Restore old parameters if volume won't survive reinitialization.
// But not if volume scale is possibly different.
diff --git a/audio/out/ao.c b/audio/out/ao.c
index 02415b0f2d..b77d401d64 100644
--- a/audio/out/ao.c
+++ b/audio/out/ao.c
@@ -25,7 +25,9 @@
#include "config.h"
#include "ao.h"
+#include "internal.h"
#include "audio/format.h"
+#include "audio/audio.h"
#include "options/options.h"
#include "options/m_config.h"
@@ -231,8 +233,15 @@ int ao_play(struct ao *ao, void **data, int samples, int flags)
int ao_control(struct ao *ao, enum aocontrol cmd, void *arg)
{
- if (ao->driver->control)
- return ao->driver->control(ao, cmd, arg);
+ switch (cmd) {
+ case AOCONTROL_HAS_TEMP_VOLUME:
+ return !ao->no_persistent_volume;
+ case AOCONTROL_HAS_PER_APP_VOLUME:
+ return !!ao->per_application_mixer;
+ default:
+ if (ao->driver->control)
+ return ao->driver->control(ao, cmd, arg);
+ }
return CONTROL_UNKNOWN;
}
@@ -307,3 +316,28 @@ bool ao_chmap_sel_get_def(struct ao *ao, const struct mp_chmap_sel *s,
{
return mp_chmap_sel_get_def(s, map, num);
}
+
+// --- The following functions just return immutable information.
+
+void ao_get_format(struct ao *ao, struct mp_audio *format)
+{
+ *format = (struct mp_audio){0};
+ mp_audio_set_format(format, ao->format);
+ mp_audio_set_channels(format, &ao->channels);
+ format->rate = ao->samplerate;
+}
+
+const char *ao_get_name(struct ao *ao)
+{
+ return ao->driver->name;
+}
+
+const char *ao_get_description(struct ao *ao)
+{
+ return ao->driver->description;
+}
+
+bool ao_untimed(struct ao *ao)
+{
+ return ao->untimed;
+}
diff --git a/audio/out/ao.h b/audio/out/ao.h
index 73a7cdfa61..152490aacc 100644
--- a/audio/out/ao.h
+++ b/audio/out/ao.h
@@ -36,6 +36,8 @@ enum aocontrol {
AOCONTROL_SET_MUTE,
// Has char* as argument, which contains the desired stream title.
AOCONTROL_UPDATE_STREAM_TITLE,
+ AOCONTROL_HAS_TEMP_VOLUME,
+ AOCONTROL_HAS_PER_APP_VOLUME,
};
// If set, then the queued audio data is the last. Note that after a while, new
@@ -48,64 +50,20 @@ typedef struct ao_control_vol {
} ao_control_vol_t;
struct ao;
-
-struct ao_driver {
- // If true, use with encoding only.
- bool encode;
- // Name used for --ao.
- const char *name;
- // Description shown with --ao=help.
- const char *description;
- // Init the device using ao->format/ao->channels/ao->samplerate. If the
- // device doesn't accept these parameters, you can attempt to negotiate
- // fallback parameters, and set the ao format fields accordingly.
- int (*init)(struct ao *ao);
- // See ao_control() etc. in ao.c
- int (*control)(struct ao *ao, enum aocontrol cmd, void *arg);
- void (*uninit)(struct ao *ao, bool cut_audio);
- void (*reset)(struct ao*ao);
- int (*get_space)(struct ao *ao);
- int (*play)(struct ao *ao, void **data, int samples, int flags);
- float (*get_delay)(struct ao *ao);
- void (*pause)(struct ao *ao);
- void (*resume)(struct ao *ao);
-
- // For option parsing (see vo.h)
- int priv_size;
- const void *priv_defaults;
- const struct m_option *options;
-};
-
-/* global data used by mplayer and plugins */
-struct ao {
- int samplerate;
- struct mp_chmap channels;
- int format; // one of AF_FORMAT_...
- int bps; // bytes per second
- int sstride; // size of a sample on each plane
- // (format_size*num_channels/num_planes)
- double pts; // some mplayer.c state (why is this here?)
- struct mp_audio_buffer *buffer; // queued audio; passed to play() later
- int buffer_playable_samples;// part of the part of the buffer the AO hasn't
- // accepted yet with play()
- bool probing; // if true, don't fail loudly on init
- bool untimed; // don't assume realtime playback
- bool no_persistent_volume; // the AO does the equivalent of af_volume
- bool per_application_mixer; // like above, but volume persists (per app)
- const struct ao_driver *driver;
- void *priv;
- struct encode_lavc_context *encode_lavc_ctx;
- struct MPOpts *opts;
- struct input_ctx *input_ctx;
- struct mp_log *log; // Using e.g. "[ao/coreaudio]" as prefix
-};
-
struct mpv_global;
+struct input_ctx;
+struct encode_lavc_context;
+struct mp_audio;
+
struct ao *ao_init_best(struct mpv_global *global,
struct input_ctx *input_ctx,
struct encode_lavc_context *encode_lavc_ctx,
int samplerate, int format, struct mp_chmap channels);
void ao_uninit(struct ao *ao, bool cut_audio);
+void ao_get_format(struct ao *ao, struct mp_audio *format);
+const char *ao_get_name(struct ao *ao);
+const char *ao_get_description(struct ao *ao);
+bool ao_untimed(struct ao *ao);
int ao_play(struct ao *ao, void **data, int samples, int flags);
int ao_control(struct ao *ao, enum aocontrol cmd, void *arg);
double ao_get_delay(struct ao *ao);
@@ -114,11 +72,4 @@ void ao_reset(struct ao *ao);
void ao_pause(struct ao *ao);
void ao_resume(struct ao *ao);
-int ao_play_silence(struct ao *ao, int samples);
-
-bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s,
- struct mp_chmap *map);
-bool ao_chmap_sel_get_def(struct ao *ao, const struct mp_chmap_sel *s,
- struct mp_chmap *map, int num);
-
#endif /* MPLAYER_AUDIO_OUT_H */
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c
index 2237c4dd59..d50757bdfd 100644
--- a/audio/out/ao_alsa.c
+++ b/audio/out/ao_alsa.c
@@ -46,6 +46,7 @@
#include <alsa/asoundlib.h>
#include "ao.h"
+#include "internal.h"
#include "audio/format.h"
#include "audio/reorder_ch.h"
diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c
index ba95fa728d..36be7c5872 100644
--- a/audio/out/ao_coreaudio.c
+++ b/audio/out/ao_coreaudio.c
@@ -37,6 +37,7 @@
#include "config.h"
#include "ao.h"
+#include "internal.h"
#include "audio/format.h"
#include "osdep/timer.h"
#include "options/m_option.h"
diff --git a/audio/out/ao_coreaudio_properties.h b/audio/out/ao_coreaudio_properties.h
index ee7f83e6b7..e48b75871e 100644
--- a/audio/out/ao_coreaudio_properties.h
+++ b/audio/out/ao_coreaudio_properties.h
@@ -21,6 +21,8 @@
#include <AudioToolbox/AudioToolbox.h>
+#include "internal.h"
+
// CoreAudio names are way too verbose
#define ca_sel AudioObjectPropertySelector
#define ca_scope AudioObjectPropertyScope
diff --git a/audio/out/ao_coreaudio_utils.h b/audio/out/ao_coreaudio_utils.h
index cf69248b47..0aca2f7c62 100644
--- a/audio/out/ao_coreaudio_utils.h
+++ b/audio/out/ao_coreaudio_utils.h
@@ -24,6 +24,7 @@
#include <stdbool.h>
#include "common/msg.h"
#include "audio/out/ao.h"
+#include "internal.h"
#define CA_CFSTR_ENCODING kCFStringEncodingASCII
diff --git a/audio/out/ao_dsound.c b/audio/out/ao_dsound.c
index 26c7bb83ed..ce7346fbdb 100644
--- a/audio/out/ao_dsound.c
+++ b/audio/out/ao_dsound.c
@@ -38,6 +38,7 @@
#include "config.h"
#include "audio/format.h"
#include "ao.h"
+#include "internal.h"
#include "audio/reorder_ch.h"
#include "common/msg.h"
#include "osdep/timer.h"
diff --git a/audio/out/ao_jack.c b/audio/out/ao_jack.c
index 72235a2d48..5b142f2d06 100644
--- a/audio/out/ao_jack.c
+++ b/audio/out/ao_jack.c
@@ -32,6 +32,7 @@
#include "common/msg.h"
#include "ao.h"
+#include "internal.h"
#include "audio/format.h"
#include "osdep/timer.h"
#include "options/m_option.h"
diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c
index 9a2df7be22..7d31f63ec9 100644
--- a/audio/out/ao_lavc.c
+++ b/audio/out/ao_lavc.c
@@ -36,6 +36,7 @@
#include "audio/fmt-conversion.h"
#include "talloc.h"
#include "ao.h"
+#include "internal.h"
#include "common/msg.h"
#include "common/encode_lavc.h"
diff --git a/audio/out/ao_null.c b/audio/out/ao_null.c
index 7c912d94a4..7caee039e0 100644
--- a/audio/out/ao_null.c
+++ b/audio/out/ao_null.c
@@ -34,6 +34,7 @@
#include "common/msg.h"
#include "audio/format.h"
#include "ao.h"
+#include "internal.h"
struct priv {
bool paused;
diff --git a/audio/out/ao_openal.c b/audio/out/ao_openal.c
index 3cb8ba5149..8cc29db689 100644
--- a/audio/out/ao_openal.c
+++ b/audio/out/ao_openal.c
@@ -38,6 +38,7 @@
#include "common/msg.h"
#include "ao.h"
+#include "internal.h"
#include "audio/format.h"
#include "osdep/timer.h"
#include "options/m_option.h"
diff --git a/audio/out/ao_oss.c b/audio/out/ao_oss.c
index 574fcf6beb..a1bf0feefc 100644
--- a/audio/out/ao_oss.c
+++ b/audio/out/ao_oss.c
@@ -49,6 +49,7 @@
#include "audio/format.h"
#include "ao.h"
+#include "internal.h"
struct priv {
int audio_fd;
diff --git a/audio/out/ao_pcm.c b/audio/out/ao_pcm.c
index 14548d3be3..5824f7ce99 100644
--- a/audio/out/ao_pcm.c
+++ b/audio/out/ao_pcm.c
@@ -34,6 +34,7 @@
#include "audio/format.h"
#include "audio/reorder_ch.h"
#include "ao.h"
+#include "internal.h"
#include "common/msg.h"
#ifdef __MINGW32__
diff --git a/audio/out/ao_portaudio.c b/audio/out/ao_portaudio.c
index 8b7e3041cd..c3ba343485 100644
--- a/audio/out/ao_portaudio.c
+++ b/audio/out/ao_portaudio.c
@@ -31,6 +31,7 @@
#include "common/msg.h"
#include "misc/ring.h"
#include "ao.h"
+#include "internal.h"
struct priv {
PaStream *stream;
diff --git a/audio/out/ao_pulse.c b/audio/out/ao_pulse.c
index fc93c40871..12fca17dd6 100644
--- a/audio/out/ao_pulse.c
+++ b/audio/out/ao_pulse.c
@@ -31,6 +31,7 @@
#include "audio/format.h"
#include "common/msg.h"
#include "ao.h"
+#include "internal.h"
#include "input/input.h"
#define PULSE_CLIENT_NAME "mpv"
diff --git a/audio/out/ao_rsound.c b/audio/out/ao_rsound.c
index 6bd99030a1..ef81c621da 100644
--- a/audio/out/ao_rsound.c
+++ b/audio/out/ao_rsound.c
@@ -33,6 +33,7 @@
#include "osdep/timer.h"
#include "audio/format.h"
#include "ao.h"
+#include "internal.h"
struct priv {
rsound_t *rd;
diff --git a/audio/out/ao_sdl.c b/audio/out/ao_sdl.c
index ac1fd6febb..acb959b101 100644
--- a/audio/out/ao_sdl.c
+++ b/audio/out/ao_sdl.c
@@ -23,6 +23,7 @@
#include "audio/format.h"
#include "talloc.h"
#include "ao.h"
+#include "internal.h"
#include "common/msg.h"
#include "options/m_option.h"
#include "osdep/timer.h"
diff --git a/audio/out/ao_sndio.c b/audio/out/ao_sndio.c
index 75ea5d095b..c200b906ab 100644
--- a/audio/out/ao_sndio.c
+++ b/audio/out/ao_sndio.c
@@ -27,6 +27,7 @@
#include "audio/format.h"
#include "ao.h"
+#include "internal.h"
struct priv {
struct sio_hdl *hdl;
diff --git a/audio/out/ao_wasapi.c b/audio/out/ao_wasapi.c
index 39199159b3..bb00849adb 100644
--- a/audio/out/ao_wasapi.c
+++ b/audio/out/ao_wasapi.c
@@ -35,6 +35,7 @@
#include "common/msg.h"
#include "misc/ring.h"
#include "ao.h"
+#include "internal.h"
#include "compat/atomics.h"
#ifndef PKEY_Device_FriendlyName
diff --git a/audio/out/internal.h b/audio/out/internal.h
new file mode 100644
index 0000000000..5cb12886a7
--- /dev/null
+++ b/audio/out/internal.h
@@ -0,0 +1,76 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MP_AO_INTERNAL_H_
+#define MP_AO_INTERNAL_H_
+
+/* global data used by ao.c and ao drivers */
+struct ao {
+ int samplerate;
+ struct mp_chmap channels;
+ int format; // one of AF_FORMAT_...
+ int bps; // bytes per second
+ int sstride; // size of a sample on each plane
+ // (format_size*num_channels/num_planes)
+ bool probing; // if true, don't fail loudly on init
+ bool untimed; // don't assume realtime playback
+ bool no_persistent_volume; // the AO does the equivalent of af_volume
+ bool per_application_mixer; // like above, but volume persists (per app)
+ const struct ao_driver *driver;
+ void *priv;
+ struct encode_lavc_context *encode_lavc_ctx;
+ struct MPOpts *opts;
+ struct input_ctx *input_ctx;
+ struct mp_log *log; // Using e.g. "[ao/coreaudio]" as prefix
+};
+
+struct ao_driver {
+ // If true, use with encoding only.
+ bool encode;
+ // Name used for --ao.
+ const char *name;
+ // Description shown with --ao=help.
+ const char *description;
+ // Init the device using ao->format/ao->channels/ao->samplerate. If the
+ // device doesn't accept these parameters, you can attempt to negotiate
+ // fallback parameters, and set the ao format fields accordingly.
+ int (*init)(struct ao *ao);
+ // See ao_control() etc. in ao.c
+ int (*control)(struct ao *ao, enum aocontrol cmd, void *arg);
+ void (*uninit)(struct ao *ao, bool cut_audio);
+ void (*reset)(struct ao*ao);
+ int (*get_space)(struct ao *ao);
+ int (*play)(struct ao *ao, void **data, int samples, int flags);
+ float (*get_delay)(struct ao *ao);
+ void (*pause)(struct ao *ao);
+ void (*resume)(struct ao *ao);
+
+ // For option parsing (see vo.h)
+ int priv_size;
+ const void *priv_defaults;
+ const struct m_option *options;
+};
+
+// These functions can be called by AOs. They don't lock the AO.
+int ao_play_silence(struct ao *ao, int samples);
+bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s,
+ struct mp_chmap *map);
+bool ao_chmap_sel_get_def(struct ao *ao, const struct mp_chmap_sel *s,
+ struct mp_chmap *map, int num);
+
+#endif
diff --git a/player/audio.c b/player/audio.c
index 984243b639..c6e7411e2a 100644
--- a/player/audio.c
+++ b/player/audio.c
@@ -45,7 +45,6 @@
static int build_afilter_chain(struct MPContext *mpctx)
{
struct dec_audio *d_audio = mpctx->d_audio;
- struct ao *ao = mpctx->ao;
struct MPOpts *opts = mpctx->opts;
if (!d_audio)
@@ -54,13 +53,16 @@ static int build_afilter_chain(struct MPContext *mpctx)
struct mp_audio in_format;
mp_audio_buffer_get_format(d_audio->decode_buffer, &in_format);
+ struct mp_audio out_format;
+ ao_get_format(mpctx->ao, &out_format);
+
int new_srate;
if (af_control_any_rev(d_audio->afilter, AF_CONTROL_SET_PLAYBACK_SPEED,
&opts->playback_speed))
new_srate = in_format.rate;
else {
new_srate = in_format.rate * opts->playback_speed;
- if (new_srate != ao->samplerate) {
+ if (new_srate != out_format.rate) {
// limits are taken from libaf/af_resample.c
if (new_srate < 8000)
new_srate = 8000;
@@ -70,7 +72,7 @@ static int build_afilter_chain(struct MPContext *mpctx)
}
}
return audio_init_filters(d_audio, new_srate,
- &ao->samplerate, &ao->channels, &ao->format);
+ &out_format.rate, &out_format.channels, &out_format.format);
}
static int recreate_audio_filters(struct MPContext *mpctx)
@@ -135,9 +137,11 @@ void reinit_audio_chain(struct MPContext *mpctx)
int ao_format = opts->audio_output_format;
struct mp_chmap ao_channels = {0};
if (mpctx->initialized_flags & INITIALIZED_AO) {
- ao_srate = mpctx->ao->samplerate;
- ao_format = mpctx->ao->format;
- ao_channels = mpctx->ao->channels;
+ struct mp_audio out_format;
+ ao_get_format(mpctx->ao, &out_format);
+ ao_srate = out_format.rate;
+ ao_format = out_format.format;
+ ao_channels = out_format.channels;
} else {
// Automatic downmix
if (mp_chmap_is_stereo(&opts->audio_output_channels) &&
@@ -172,14 +176,16 @@ void reinit_audio_chain(struct MPContext *mpctx)
goto init_error;
}
- ao->buffer = mp_audio_buffer_create(ao);
- mp_audio_buffer_reinit_fmt(ao->buffer, ao->format, &ao->channels,
- ao->samplerate);
+ struct mp_audio fmt;
+ ao_get_format(ao, &fmt);
- char *s = mp_audio_fmt_to_str(ao->samplerate, &ao->channels, ao->format);
- MP_INFO(mpctx, "AO: [%s] %s\n", ao->driver->name, s);
+ mpctx->ao_buffer = mp_audio_buffer_create(ao);
+ mp_audio_buffer_reinit(mpctx->ao_buffer, &fmt);
+
+ char *s = mp_audio_config_to_str(&fmt);
+ MP_INFO(mpctx, "AO: [%s] %s\n", ao_get_name(ao), s);
talloc_free(s);
- MP_VERBOSE(mpctx, "AO: Description: %s\n", ao->driver->description);
+ MP_VERBOSE(mpctx, "AO: Description: %s\n", ao_get_description(ao));
update_window_title(mpctx, true);
}
@@ -228,7 +234,7 @@ double written_audio_pts(struct MPContext *mpctx)
// Data that was ready for ao but was buffered because ao didn't fully
// accept everything to internal buffers yet
- buffered_output += mp_audio_buffer_seconds(mpctx->ao->buffer);
+ buffered_output += mp_audio_buffer_seconds(mpctx->ao_buffer);
// Filters divide audio length by playback_speed, so multiply by it
// to get the length in original units without speedup or slowdown
@@ -252,11 +258,13 @@ static int write_to_ao(struct MPContext *mpctx, struct mp_audio *data, int flags
if (mpctx->paused)
return 0;
struct ao *ao = mpctx->ao;
- ao->pts = pts;
+ struct mp_audio out_format;
+ ao_get_format(ao, &out_format);
+ mpctx->ao_pts = pts;
#if HAVE_ENCODING
- encode_lavc_set_audio_pts(mpctx->encode_lavc_ctx, ao->pts);
+ encode_lavc_set_audio_pts(mpctx->encode_lavc_ctx, mpctx->ao_pts);
#endif
- double real_samplerate = ao->samplerate / mpctx->opts->playback_speed;
+ double real_samplerate = out_format.rate / mpctx->opts->playback_speed;
int played = ao_play(mpctx->ao, data->planes, data->samples, flags);
assert(played <= data->samples);
if (played > 0) {
@@ -264,7 +272,7 @@ static int write_to_ao(struct MPContext *mpctx, struct mp_audio *data, int flags
mpctx->delay += played / real_samplerate;
// Keep correct pts for remaining data - could be used to flush
// remaining buffer when closing ao.
- ao->pts += played / real_samplerate;
+ mpctx->ao_pts += played / real_samplerate;
return played;
}
return 0;
@@ -274,7 +282,7 @@ static int write_silence_to_ao(struct MPContext *mpctx, int samples, int flags,
double pts)
{
struct mp_audio tmp = {0};
- mp_audio_buffer_get_format(mpctx->ao->buffer, &tmp);
+ mp_audio_buffer_get_format(mpctx->ao_buffer, &tmp);
tmp.samples = samples;
char *p = talloc_size(NULL, tmp.samples * tmp.sstride);
for (int n = 0; n < tmp.num_planes; n++)
@@ -295,15 +303,18 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize)
assert(d_audio);
+ struct mp_audio out_format;
+ ao_get_format(ao, &out_format);
+
// Timing info may not be set without
- res = audio_decode(d_audio, ao->buffer, 1);
+ res = audio_decode(d_audio, mpctx->ao_buffer, 1);
if (res < 0)
return res;
int samples;
bool did_retry = false;
double written_pts;
- double real_samplerate = ao->samplerate / opts->playback_speed;
+ double real_samplerate = out_format.rate / opts->playback_speed;
bool hrseek = mpctx->hrseek_active; // audio only hrseek
mpctx->hrseek_active = false;
while (1) {
@@ -320,7 +331,7 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize)
if (written_pts <= 1 && d_audio->pts == MP_NOPTS_VALUE) {
if (!did_retry) {
// Try to read more data to see packets that have pts
- res = audio_decode(d_audio, ao->buffer, ao->samplerate);
+ res = audio_decode(d_audio, mpctx->ao_buffer, out_format.rate);
if (res < 0)
return res;
did_retry = true;
@@ -338,16 +349,16 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize)
mpctx->syncing_audio = false;
int skip_samples = -samples;
int a = MPMIN(skip_samples, MPMAX(playsize, 2500));
- res = audio_decode(d_audio, ao->buffer, a);
- if (skip_samples <= mp_audio_buffer_samples(ao->buffer)) {
- mp_audio_buffer_skip(ao->buffer, skip_samples);
- ao->buffer_playable_samples = 0;
+ res = audio_decode(d_audio, mpctx->ao_buffer, a);
+ if (skip_samples <= mp_audio_buffer_samples(mpctx->ao_buffer)) {
+ mp_audio_buffer_skip(mpctx->ao_buffer, skip_samples);
+ mpctx->ao_buffer_playable_samples = 0;
if (res < 0)
return res;
- return audio_decode(d_audio, ao->buffer, playsize);
+ return audio_decode(d_audio, mpctx->ao_buffer, playsize);
}
- mp_audio_buffer_clear(ao->buffer);
- ao->buffer_playable_samples = 0;
+ mp_audio_buffer_clear(mpctx->ao_buffer);
+ mpctx->ao_buffer_playable_samples = 0;
if (res < 0)
return res;
}
@@ -357,15 +368,15 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize)
if (samples >= playsize) {
/* This case could fall back to the one below with
* samples = playsize, but then silence would keep accumulating
- * in ao->buffer if the AO accepts less data than it asks for
+ * in ao_buffer if the AO accepts less data than it asks for
* in playsize. */
write_silence_to_ao(mpctx, playsize, 0,
written_pts - samples / real_samplerate);
return ASYNC_PLAY_DONE;
}
mpctx->syncing_audio = false;
- mp_audio_buffer_prepend_silence(ao->buffer, samples);
- return audio_decode(d_audio, ao->buffer, playsize);
+ mp_audio_buffer_prepend_silence(mpctx->ao_buffer, samples);
+ return audio_decode(d_audio, mpctx->ao_buffer, playsize);
}
int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
@@ -378,8 +389,10 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
bool signal_eof = false;
bool partial_fill = false;
struct dec_audio *d_audio = mpctx->d_audio;
+ struct mp_audio out_format;
+ ao_get_format(ao, &out_format);
// Can't adjust the start of audio with spdif pass-through.
- bool modifiable_audio_format = !(ao->format & AF_FORMAT_SPECIAL_MASK);
+ bool modifiable_audio_format = !(out_format.format & AF_FORMAT_SPECIAL_MASK);
assert(d_audio);
@@ -400,7 +413,7 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
if (mpctx->syncing_audio || mpctx->hrseek_active)
res = audio_start_sync(mpctx, playsize);
else
- res = audio_decode(d_audio, ao->buffer, playsize);
+ res = audio_decode(d_audio, mpctx->ao_buffer, playsize);
if (res < 0) { // EOF, error or format change
if (res == -2) {
@@ -420,7 +433,7 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
if (endpts != MP_NOPTS_VALUE) {
double samples = (endpts - written_audio_pts(mpctx) - mpctx->audio_delay)
- * ao->samplerate / opts->playback_speed;
+ * out_format.rate / opts->playback_speed;
if (playsize > samples) {
playsize = MPMAX(samples, 0);
audio_eof = true;
@@ -428,8 +441,8 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
}
}
- if (playsize > mp_audio_buffer_samples(ao->buffer)) {
- playsize = mp_audio_buffer_samples(ao->buffer);
+ if (playsize > mp_audio_buffer_samples(mpctx->ao_buffer)) {
+ playsize = mp_audio_buffer_samples(mpctx->ao_buffer);
partial_fill = true;
}
if (!playsize)
@@ -445,17 +458,18 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
}
}
- assert(ao->buffer_playable_samples <= mp_audio_buffer_samples(ao->buffer));
+ assert(mpctx->ao_buffer_playable_samples <=
+ mp_audio_buffer_samples(mpctx->ao_buffer));
struct mp_audio data;
- mp_audio_buffer_peek(ao->buffer, &data);
+ mp_audio_buffer_peek(mpctx->ao_buffer, &data);
data.samples = MPMIN(data.samples, playsize);
int played = write_to_ao(mpctx, &data, playflags, written_audio_pts(mpctx));
assert(played >= 0 && played <= data.samples);
- ao->buffer_playable_samples = playsize - played;
+ mpctx->ao_buffer_playable_samples = playsize - played;
if (played > 0) {
- mp_audio_buffer_skip(ao->buffer, played);
+ mp_audio_buffer_skip(mpctx->ao_buffer, played);
} else if (!mpctx->paused && audio_eof && ao_get_delay(ao) < .04) {
// Sanity check to avoid hanging in case current ao doesn't output
// partial chunks and doesn't check for AOPLAY_FINAL_CHUNK
@@ -470,8 +484,8 @@ void clear_audio_output_buffers(struct MPContext *mpctx)
{
if (mpctx->ao) {
ao_reset(mpctx->ao);
- mp_audio_buffer_clear(mpctx->ao->buffer);
- mpctx->ao->buffer_playable_samples = 0;
+ mp_audio_buffer_clear(mpctx->ao_buffer);
+ mpctx->ao_buffer_playable_samples = 0;
}
}
diff --git a/player/core.h b/player/core.h
index fd9be5bcd4..5e60568c97 100644
--- a/player/core.h
+++ b/player/core.h
@@ -223,6 +223,11 @@ typedef struct MPContext {
struct mixer *mixer;
struct ao *ao;
+ double ao_pts;
+ struct mp_audio_buffer *ao_buffer; // queued audio; passed to ao_play() later
+ int ao_buffer_playable_samples; // part of the part of the buffer the AO
+ // hasn't accepted yet with play()
+
struct vo *video_out;
/* We're starting playback from scratch or after a seek. Show first
diff --git a/player/loadfile.c b/player/loadfile.c
index 7cfaf67978..657c950f32 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -178,14 +178,14 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask)
if (opts->gapless_audio || mpctx->stop_play == AT_END_OF_FILE) {
drain = true;
struct mp_audio data;
- mp_audio_buffer_peek(ao->buffer, &data);
- int samples = ao->buffer_playable_samples;
+ mp_audio_buffer_peek(mpctx->ao_buffer, &data);
+ int samples = mpctx->ao_buffer_playable_samples;
assert(samples <= data.samples);
if (samples > 0) {
int played = ao_play(ao, data.planes, samples,
AOPLAY_FINAL_CHUNK);
if (played < samples)
- MP_WARN(ao, "Audio output truncated at end.\n");
+ MP_WARN(mpctx, "Audio output truncated at end.\n");
}
}
ao_uninit(ao, drain);
diff --git a/player/playloop.c b/player/playloop.c
index 0b926cae36..c5dd55e396 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -982,7 +982,7 @@ void run_playloop(struct MPContext *mpctx)
mpctx->stop_play = PT_NEXT_ENTRY;
}
- if (mpctx->d_audio && !mpctx->restart_playback && !mpctx->ao->untimed) {
+ if (mpctx->d_audio && !mpctx->restart_playback && !ao_untimed(mpctx->ao)) {
int status = fill_audio_out_buffers(mpctx, endpts);
full_audio_buffers = status >= 0;
// Not at audio stream EOF yet
@@ -1193,10 +1193,11 @@ void run_playloop(struct MPContext *mpctx)
video_left &= mpctx->sync_audio_to_video; // force no-video semantics
if (mpctx->d_audio && (mpctx->restart_playback ? !video_left :
- mpctx->ao->untimed && (mpctx->delay <= 0 ||
- !video_left))) {
+ ao_untimed(mpctx->ao) && (mpctx->delay <= 0 ||
+ !video_left)))
+ {
int status = fill_audio_out_buffers(mpctx, endpts);
- full_audio_buffers = status >= 0 && !mpctx->ao->untimed;
+ full_audio_buffers = status >= 0 && !ao_untimed(mpctx->ao);
// Not at audio stream EOF yet
audio_left = status > -2;
}
@@ -1286,7 +1287,7 @@ void run_playloop(struct MPContext *mpctx)
if (mpctx->restart_playback)
sleeptime = 0;
if (mpctx->d_audio && !mpctx->paused) {
- if (mpctx->ao->untimed) {
+ if (ao_untimed(mpctx->ao)) {
if (!video_left)
audio_sleep = 0;
} else if (full_audio_buffers) {
diff --git a/player/video.c b/player/video.c
index 348954c855..39a5b55a2a 100644
--- a/player/video.c
+++ b/player/video.c
@@ -340,7 +340,7 @@ static int check_framedrop(struct MPContext *mpctx, double frame_time)
struct track *t_audio = mpctx->current_track[0][STREAM_AUDIO];
struct sh_stream *sh_audio = t_audio ? t_audio->stream : NULL;
// check for frame-drop:
- if (mpctx->d_audio && !mpctx->ao->untimed && sh_audio &&
+ if (mpctx->d_audio && !ao_untimed(mpctx->ao) && sh_audio &&
!demux_stream_eof(sh_audio))
{
float delay = opts->playback_speed * ao_get_delay(mpctx->ao);