summaryrefslogtreecommitdiffstats
path: root/player/audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'player/audio.c')
-rw-r--r--player/audio.c87
1 files changed, 61 insertions, 26 deletions
diff --git a/player/audio.c b/player/audio.c
index 50c0faaf09..da91dd4340 100644
--- a/player/audio.c
+++ b/player/audio.c
@@ -22,7 +22,6 @@
#include <math.h>
#include <assert.h>
-#include "config.h"
#include "mpv_talloc.h"
#include "common/msg.h"
@@ -64,9 +63,17 @@ static void update_speed_filters(struct MPContext *mpctx)
speed = 1.0;
}
- if (mpctx->display_sync_active && mpctx->opts->video_sync == VS_DISP_ADROP) {
- drop *= speed * resample;
- resample = speed = 1.0;
+ if (mpctx->display_sync_active) {
+ switch (mpctx->video_out->opts->video_sync) {
+ case VS_DISP_ADROP:
+ drop *= speed * resample;
+ resample = speed = 1.0;
+ break;
+ case VS_DISP_TEMPO:
+ speed = mpctx->audio_speed;
+ resample = 1.0;
+ break;
+ }
}
mp_output_chain_set_audio_speed(ao_c->filter, speed, resample, drop);
@@ -168,6 +175,7 @@ void audio_update_volume(struct MPContext *mpctx)
float gain = MPMAX(opts->softvol_volume / 100.0, 0);
gain = pow(gain, 3);
gain *= compute_replaygain(mpctx);
+ gain *= db_gain(opts->softvol_gain);
if (opts->softvol_mute == 1)
gain = 0.0;
@@ -183,11 +191,24 @@ void update_playback_speed(struct MPContext *mpctx)
update_speed_filters(mpctx);
}
+static bool has_video_track(struct MPContext *mpctx)
+{
+ if (mpctx->vo_chain && mpctx->vo_chain->is_coverart)
+ return false;
+
+ for (int n = 0; n < mpctx->num_tracks; n++) {
+ struct track *track = mpctx->tracks[n];
+ if (track->type == STREAM_VIDEO && !track->attached_picture && !track->image)
+ return true;
+ }
+
+ return false;
+}
+
static void ao_chain_reset_state(struct ao_chain *ao_c)
{
ao_c->last_out_pts = MP_NOPTS_VALUE;
ao_c->out_eof = false;
- ao_c->underrun = false;
ao_c->start_pts_known = false;
ao_c->start_pts = MP_NOPTS_VALUE;
ao_c->untimed_throttle = false;
@@ -281,8 +302,7 @@ static bool keep_weak_gapless_format(struct mp_aframe *old, struct mp_aframe* ne
{
bool res = false;
struct mp_aframe *new_mod = mp_aframe_new_ref(new);
- if (!new_mod)
- abort();
+ MP_HANDLE_OOM(new_mod);
// If the sample formats are compatible (== libswresample generally can
// convert them), keep the AO. On other changes, recreate it.
@@ -314,6 +334,7 @@ static void ao_chain_set_ao(struct ao_chain *ao_c, struct ao *ao)
mp_async_queue_set_notifier(ao_c->queue_filter, ao_c->ao_filter);
// Make sure filtering never stops with frames stuck in access filter.
mp_filter_set_high_priority(ao_c->queue_filter, true);
+ audio_update_volume(ao_c->mpctx);
}
if (ao_c->filter->ao_needs_update)
@@ -322,7 +343,7 @@ static void ao_chain_set_ao(struct ao_chain *ao_c, struct ao *ao)
mp_filter_wakeup(ao_c->ao_filter);
}
-static void reinit_audio_filters_and_output(struct MPContext *mpctx)
+static int reinit_audio_filters_and_output(struct MPContext *mpctx)
{
struct MPOpts *opts = mpctx->opts;
struct ao_chain *ao_c = mpctx->ao_chain;
@@ -333,8 +354,7 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
// The "ideal" filter output format
struct mp_aframe *out_fmt = mp_aframe_new_ref(ao_c->filter->output_aformat);
- if (!out_fmt)
- abort();
+ MP_HANDLE_OOM(out_fmt);
if (!mp_aframe_config_is_valid(out_fmt)) {
talloc_free(out_fmt);
@@ -359,13 +379,13 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
{
ao_chain_set_ao(ao_c, mpctx->ao);
talloc_free(out_fmt);
- return;
+ return 0;
}
// Wait until all played.
if (mpctx->ao && ao_is_playing(mpctx->ao)) {
talloc_free(out_fmt);
- return;
+ return 0;
}
// Format change during syncing. Force playback start early, then wait.
if (ao_c->ao_queue && mp_async_queue_get_frames(ao_c->ao_queue) &&
@@ -374,11 +394,11 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
mpctx->audio_status = STATUS_READY;
mp_wakeup_core(mpctx);
talloc_free(out_fmt);
- return;
+ return 0;
}
if (mpctx->audio_status == STATUS_READY) {
talloc_free(out_fmt);
- return;
+ return 0;
}
uninit_audio_out(mpctx);
@@ -411,6 +431,9 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
opts->audio_output_channels.num_chmaps);
}
+ if (!has_video_track(mpctx))
+ ao_flags |= AO_INIT_MEDIA_ROLE_MUSIC;
+
mpctx->ao_filter_fmt = out_fmt;
mpctx->ao = ao_init_best(mpctx->global, ao_flags, mp_wakeup_core_cb,
@@ -446,7 +469,7 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
reset_audio_state(mpctx);
mp_output_chain_reset_harder(ao_c->filter);
mp_wakeup_core(mpctx); // reinit with new format next time
- return;
+ return 0;
}
MP_ERR(mpctx, "Could not open/initialize audio device -> no sound.\n");
@@ -464,7 +487,8 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
ao_c->ao_resume_time =
opts->audio_wait_open > 0 ? mp_time_sec() + opts->audio_wait_open : 0;
- ao_set_paused(mpctx->ao, get_internal_paused(mpctx));
+ bool eof = mpctx->audio_status == STATUS_EOF;
+ ao_set_paused(mpctx->ao, get_internal_paused(mpctx), eof);
ao_chain_set_ao(ao_c, mpctx->ao);
@@ -477,12 +501,13 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
mp_wakeup_core(mpctx);
mp_notify(mpctx, MPV_EVENT_AUDIO_RECONFIG, NULL);
- return;
+ return 0;
init_error:
uninit_audio_chain(mpctx);
uninit_audio_out(mpctx);
error_on_track(mpctx, track);
+ return -1;
}
int init_audio_decoder(struct MPContext *mpctx, struct track *track)
@@ -516,7 +541,8 @@ void reinit_audio_chain(struct MPContext *mpctx)
struct track *track = NULL;
track = mpctx->current_track[0][STREAM_AUDIO];
if (!track || !track->stream) {
- uninit_audio_out(mpctx);
+ if (!mpctx->encode_lavc_ctx)
+ uninit_audio_out(mpctx);
error_on_track(mpctx, track);
return;
}
@@ -592,7 +618,7 @@ double playing_audio_pts(struct MPContext *mpctx)
double pts = written_audio_pts(mpctx);
if (pts == MP_NOPTS_VALUE || !mpctx->ao)
return pts;
- return pts - mpctx->audio_speed * ao_get_delay(mpctx->ao);
+ return pts - ao_get_delay(mpctx->ao);
}
// This garbage is needed for untimed AOs. These consume audio infinitely fast,
@@ -634,7 +660,7 @@ static void ao_process(struct mp_filter *f)
return;
}
- // Due to mp_async_queue_set_notifier() thhis function is called when the
+ // Due to mp_async_queue_set_notifier() this function is called when the
// queue becomes full. This affects state changes in the normal playloop,
// so wake it up. But avoid redundant wakeups during normal playback.
if (mpctx->audio_status != STATUS_PLAYING &&
@@ -698,7 +724,8 @@ static void ao_process(struct mp_filter *f)
mpctx->shown_aframes += samples;
double real_samplerate = mp_aframe_get_rate(af) / mpctx->audio_speed;
- mpctx->delay += samples / real_samplerate;
+ if (mpctx->video_status != STATUS_EOF)
+ mpctx->delay += samples / real_samplerate;
ao_c->last_out_pts = mp_aframe_end_pts(af);
update_throttle(mpctx);
@@ -802,7 +829,8 @@ void audio_start_ao(struct MPContext *mpctx)
double pts = MP_NOPTS_VALUE;
if (!get_sync_pts(mpctx, &pts))
return;
- double apts = playing_audio_pts(mpctx); // (basically including mpctx->delay)
+ double apts = written_audio_pts(mpctx);
+ apts -= apts != MP_NOPTS_VALUE ? mpctx->audio_speed * ao_get_delay(mpctx->ao) : 0;
if (pts != MP_NOPTS_VALUE && apts != MP_NOPTS_VALUE && pts < apts &&
mpctx->video_status != STATUS_EOF)
{
@@ -818,10 +846,13 @@ void audio_start_ao(struct MPContext *mpctx)
}
MP_VERBOSE(mpctx, "starting audio playback\n");
+ ao_c->audio_started = true;
ao_start(ao_c->ao);
mpctx->audio_status = STATUS_PLAYING;
- if (ao_c->out_eof)
+ if (ao_c->out_eof) {
mpctx->audio_status = STATUS_DRAINING;
+ MP_VERBOSE(mpctx, "audio draining\n");
+ }
ao_c->underrun = false;
mpctx->logged_async_diff = -1;
mp_wakeup_core(mpctx);
@@ -849,8 +880,10 @@ void fill_audio_out_buffers(struct MPContext *mpctx)
return;
}
- if (ao_c->filter->ao_needs_update)
- reinit_audio_filters_and_output(mpctx);
+ if (ao_c->filter->ao_needs_update) {
+ if (reinit_audio_filters_and_output(mpctx) < 0)
+ return;
+ }
if (mpctx->vo_chain && ao_c->track && ao_c->track->dec &&
mp_decoder_wrapper_get_pts_reset(ao_c->track->dec))
@@ -870,8 +903,10 @@ void fill_audio_out_buffers(struct MPContext *mpctx)
// until the old audio is fully played.
// (Buggy if AO underruns.)
if (mpctx->ao && ao_is_playing(mpctx->ao) &&
- mpctx->video_status != STATUS_EOF)
+ mpctx->video_status != STATUS_EOF) {
+ MP_VERBOSE(mpctx, "blocked, waiting for old audio to play\n");
ok = false;
+ }
if (ao_c->start_pts_known != ok || ao_c->start_pts != pts) {
ao_c->start_pts_known = ok;