0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 03:52:22 +02:00

audio/out: make ao struct opaque

We want to move the AO to its own thread. There's no technical reason
for making the ao struct opaque to do this. But it helps us sleep at
night, because we can control access to shared state better.
This commit is contained in:
wm4 2014-03-07 15:24:32 +01:00
parent 74b7001500
commit 41f2b26d11
26 changed files with 218 additions and 117 deletions

View File

@ -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.

View File

@ -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;
}

View File

@ -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 */

View File

@ -46,6 +46,7 @@
#include <alsa/asoundlib.h>
#include "ao.h"
#include "internal.h"
#include "audio/format.h"
#include "audio/reorder_ch.h"

View File

@ -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"

View File

@ -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

View File

@ -24,6 +24,7 @@
#include <stdbool.h>
#include "common/msg.h"
#include "audio/out/ao.h"
#include "internal.h"
#define CA_CFSTR_ENCODING kCFStringEncodingASCII

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -34,6 +34,7 @@
#include "common/msg.h"
#include "audio/format.h"
#include "ao.h"
#include "internal.h"
struct priv {
bool paused;

View File

@ -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"

View File

@ -49,6 +49,7 @@
#include "audio/format.h"
#include "ao.h"
#include "internal.h"
struct priv {
int audio_fd;

View File

@ -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__

View File

@ -31,6 +31,7 @@
#include "common/msg.h"
#include "misc/ring.h"
#include "ao.h"
#include "internal.h"
struct priv {
PaStream *stream;

View File

@ -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"

View File

@ -33,6 +33,7 @@
#include "osdep/timer.h"
#include "audio/format.h"
#include "ao.h"
#include "internal.h"
struct priv {
rsound_t *rd;

View File

@ -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"

View File

@ -27,6 +27,7 @@
#include "audio/format.h"
#include "ao.h"
#include "internal.h"
struct priv {
struct sio_hdl *hdl;

View File

@ -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

76
audio/out/internal.h Normal file
View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);

View File

@ -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) {

View File

@ -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);