summaryrefslogtreecommitdiffstats
path: root/audio/out
diff options
context:
space:
mode:
Diffstat (limited to 'audio/out')
-rw-r--r--audio/out/ao.c22
-rw-r--r--audio/out/ao.h3
-rw-r--r--audio/out/ao_alsa.c16
-rw-r--r--audio/out/ao_coreaudio.c5
-rw-r--r--audio/out/ao_dsound.c4
-rw-r--r--audio/out/ao_jack.c5
-rw-r--r--audio/out/ao_lavc.c8
-rw-r--r--audio/out/ao_null.c10
-rw-r--r--audio/out/ao_openal.c21
-rw-r--r--audio/out/ao_oss.c21
-rw-r--r--audio/out/ao_pcm.c2
-rw-r--r--audio/out/ao_portaudio.c9
-rw-r--r--audio/out/ao_pulse.c12
-rw-r--r--audio/out/ao_rsound.c8
-rw-r--r--audio/out/ao_sdl.c16
-rw-r--r--audio/out/ao_sndio.c2
-rw-r--r--audio/out/ao_wasapi.c4
-rw-r--r--audio/out/internal.h3
-rw-r--r--audio/out/pull.c4
-rw-r--r--audio/out/push.c18
20 files changed, 114 insertions, 79 deletions
diff --git a/audio/out/ao.c b/audio/out/ao.c
index f1e88d2a10..ee8bc2a254 100644
--- a/audio/out/ao.c
+++ b/audio/out/ao.c
@@ -235,11 +235,10 @@ done:
return ao;
}
-// Uninitialize and destroy the AO.
-// cut_audio: if false, block until all remaining audio was played.
-void ao_uninit(struct ao *ao, bool cut_audio)
+// Uninitialize and destroy the AO. Remaining audio must be dropped.
+void ao_uninit(struct ao *ao)
{
- ao->api->uninit(ao, cut_audio);
+ ao->api->uninit(ao);
talloc_free(ao);
}
@@ -315,13 +314,22 @@ void ao_resume(struct ao *ao)
ao->api->resume(ao);
}
-// Wait until the audio buffer is drained. This can be used to emulate draining
-// if native functionality is not available.
-// Only call this on uninit (otherwise, deadlock trouble ahead).
+// Be careful with locking
void ao_wait_drain(struct ao *ao)
{
// This is probably not entirely accurate, but good enough.
mp_sleep_us(ao_get_delay(ao) * 1000000);
+ ao_reset(ao);
+}
+
+// Block until the current audio buffer has played completely.
+void ao_drain(struct ao *ao)
+{
+ if (ao->api->drain) {
+ ao->api->drain(ao);
+ } else {
+ ao_wait_drain(ao);
+ }
}
bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s,
diff --git a/audio/out/ao.h b/audio/out/ao.h
index 152490aacc..e462fcf4d5 100644
--- a/audio/out/ao.h
+++ b/audio/out/ao.h
@@ -59,7 +59,7 @@ 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_uninit(struct ao *ao);
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);
@@ -71,5 +71,6 @@ int ao_get_space(struct ao *ao);
void ao_reset(struct ao *ao);
void ao_pause(struct ao *ao);
void ao_resume(struct ao *ao);
+void ao_drain(struct ao *ao);
#endif /* MPLAYER_AUDIO_OUT_H */
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c
index d50757bdfd..291c6d7c1c 100644
--- a/audio/out/ao_alsa.c
+++ b/audio/out/ao_alsa.c
@@ -79,7 +79,7 @@ struct priv {
} while (0)
static float get_delay(struct ao *ao);
-static void uninit(struct ao *ao, bool immed);
+static void uninit(struct ao *ao);
/* to set/get/query special features/parameters */
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
@@ -530,22 +530,19 @@ static int init(struct ao *ao)
return 0;
alsa_error:
- uninit(ao, true);
+ uninit(ao);
return -1;
} // end init
/* close audio device */
-static void uninit(struct ao *ao, bool immed)
+static void uninit(struct ao *ao)
{
struct priv *p = ao->priv;
if (p->alsa) {
int err;
- if (!immed)
- snd_pcm_drain(p->alsa);
-
err = snd_pcm_close(p->alsa);
CHECK_ALSA_ERROR("pcm close error");
@@ -556,6 +553,12 @@ alsa_error:
p->alsa = NULL;
}
+static void drain(struct ao *ao)
+{
+ struct priv *p = ao->priv;
+ snd_pcm_drain(p->alsa);
+}
+
static void audio_pause(struct ao *ao)
{
struct priv *p = ao->priv;
@@ -712,6 +715,7 @@ const struct ao_driver audio_out_alsa = {
.pause = audio_pause,
.resume = audio_resume,
.reset = reset,
+ .drain = drain,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.cfg_block = 1,
diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c
index 36be7c5872..e8b0179d20 100644
--- a/audio/out/ao_coreaudio.c
+++ b/audio/out/ao_coreaudio.c
@@ -626,14 +626,11 @@ static float get_delay(struct ao *ao)
return mp_ring_buffered(p->buffer) / (float)ao->bps;
}
-static void uninit(struct ao *ao, bool immed)
+static void uninit(struct ao *ao)
{
struct priv *p = ao->priv;
OSStatus err = noErr;
- if (!immed)
- mp_sleep_us(get_delay(ao) * 1000000);
-
if (!p->is_digital) {
AudioOutputUnitStop(p->audio_unit);
AudioUnitUninitialize(p->audio_unit);
diff --git a/audio/out/ao_dsound.c b/audio/out/ao_dsound.c
index ce7346fbdb..6ddf080d20 100644
--- a/audio/out/ao_dsound.c
+++ b/audio/out/ao_dsound.c
@@ -546,10 +546,8 @@ static void audio_resume(struct ao *ao)
\brief close audio device
\param immed stop playback immediately
*/
-static void uninit(struct ao *ao, bool immed)
+static void uninit(struct ao *ao)
{
- if (!immed)
- mp_sleep_us(get_delay(ao) * 1000000);
reset(ao);
DestroyBuffer(ao);
diff --git a/audio/out/ao_jack.c b/audio/out/ao_jack.c
index b3cd3fd6ef..6e9b652f2d 100644
--- a/audio/out/ao_jack.c
+++ b/audio/out/ao_jack.c
@@ -207,13 +207,10 @@ err_chmap:
}
// close audio device
-static void uninit(struct ao *ao, bool immed)
+static void uninit(struct ao *ao)
{
struct priv *p = ao->priv;
- if (!immed)
- ao_wait_drain(ao);
-
jack_client_close(p->client);
}
diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c
index afb021f7a0..073ff8ebdb 100644
--- a/audio/out/ao_lavc.c
+++ b/audio/out/ao_lavc.c
@@ -181,7 +181,7 @@ fail:
// close audio device
static int encode(struct ao *ao, double apts, void **data);
-static void uninit(struct ao *ao, bool cut_audio)
+static void uninit(struct ao *ao)
{
struct priv *ac = ao->priv;
struct encode_lavc_context *ectx = ao->encode_lavc_ctx;
@@ -462,6 +462,11 @@ static int play(struct ao *ao, void **data, int samples, int flags)
return bufpos;
}
+static void drain(struct ao *ao)
+{
+ // pretend we support it, so generic code doesn't force a wait
+}
+
const struct ao_driver audio_out_lavc = {
.encode = true,
.description = "audio encoding using libavcodec",
@@ -470,4 +475,5 @@ const struct ao_driver audio_out_lavc = {
.uninit = uninit,
.get_space = get_space,
.play = play,
+ .drain = drain,
};
diff --git a/audio/out/ao_null.c b/audio/out/ao_null.c
index a6b40fdb76..6fff65dcd9 100644
--- a/audio/out/ao_null.c
+++ b/audio/out/ao_null.c
@@ -98,10 +98,15 @@ static int init(struct ao *ao)
}
// close audio device
-static void uninit(struct ao *ao, bool cut_audio)
+static void uninit(struct ao *ao)
+{
+}
+
+static void wait_drain(struct ao *ao)
{
struct priv *priv = ao->priv;
- if (!cut_audio && !priv->paused)
+ drain(ao);
+ if (!priv->paused)
mp_sleep_us(1000000.0 * priv->buffered / ao->samplerate / priv->speed);
}
@@ -185,6 +190,7 @@ const struct ao_driver audio_out_null = {
.get_delay = get_delay,
.pause = pause,
.resume = resume,
+ .drain = wait_drain,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.bufferlen = 0.2,
diff --git a/audio/out/ao_openal.c b/audio/out/ao_openal.c
index 8cc29db689..f2cbe78e94 100644
--- a/audio/out/ao_openal.c
+++ b/audio/out/ao_openal.c
@@ -178,18 +178,10 @@ err_out:
}
// close audio device
-static void uninit(struct ao *ao, bool immed)
+static void uninit(struct ao *ao)
{
ALCcontext *ctx = alcGetCurrentContext();
ALCdevice *dev = alcGetContextsDevice(ctx);
- if (!immed) {
- ALint state;
- alGetSourcei(sources[0], AL_SOURCE_STATE, &state);
- while (state == AL_PLAYING) {
- mp_sleep_us(10000);
- alGetSourcei(sources[0], AL_SOURCE_STATE, &state);
- }
- }
reset(ao);
alcMakeContextCurrent(NULL);
alcDestroyContext(ctx);
@@ -197,6 +189,16 @@ static void uninit(struct ao *ao, bool immed)
ao_data = NULL;
}
+static void drain(struct ao *ao)
+{
+ ALint state;
+ alGetSourcei(sources[0], AL_SOURCE_STATE, &state);
+ while (state == AL_PLAYING) {
+ mp_sleep_us(10000);
+ alGetSourcei(sources[0], AL_SOURCE_STATE, &state);
+ }
+}
+
static void unqueue_buffers(void)
{
ALint p;
@@ -298,6 +300,7 @@ const struct ao_driver audio_out_openal = {
.pause = audio_pause,
.resume = audio_resume,
.reset = reset,
+ .drain = drain,
.priv_size = sizeof(struct priv),
.options = (const struct m_option[]) {
OPT_STRING_VALIDATE("device", cfg_device, 0, validate_device_opt),
diff --git a/audio/out/ao_oss.c b/audio/out/ao_oss.c
index a1bf0feefc..ca7539b590 100644
--- a/audio/out/ao_oss.c
+++ b/audio/out/ao_oss.c
@@ -427,24 +427,28 @@ ac3_retry:
}
// close audio device
-static void uninit(struct ao *ao, bool immed)
+static void uninit(struct ao *ao)
{
struct priv *p = ao->priv;
if (p->audio_fd == -1)
return;
-#ifdef SNDCTL_DSP_SYNC
- // to get the buffer played
- if (!immed)
- ioctl(p->audio_fd, SNDCTL_DSP_SYNC, NULL);
-#endif
#ifdef SNDCTL_DSP_RESET
- if (immed)
- ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL);
+ ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL);
#endif
close(p->audio_fd);
p->audio_fd = -1;
}
+static void drain(struct ao *ao)
+{
+#ifdef SNDCTL_DSP_SYNC
+ struct priv *p = ao->priv;
+ // to get the buffer played
+ if (p->audio_fd != -1)
+ ioctl(p->audio_fd, SNDCTL_DSP_SYNC, NULL);
+#endif
+}
+
#ifndef SNDCTL_DSP_RESET
static void close_device(struct ao *ao)
{
@@ -601,6 +605,7 @@ const struct ao_driver audio_out_oss = {
.pause = audio_pause,
.resume = audio_resume,
.reset = reset,
+ .drain = drain,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.audio_fd = -1,
diff --git a/audio/out/ao_pcm.c b/audio/out/ao_pcm.c
index 5824f7ce99..b14c9f4d79 100644
--- a/audio/out/ao_pcm.c
+++ b/audio/out/ao_pcm.c
@@ -166,7 +166,7 @@ static int init(struct ao *ao)
}
// close audio device
-static void uninit(struct ao *ao, bool cut_audio)
+static void uninit(struct ao *ao)
{
struct priv *priv = ao->priv;
diff --git a/audio/out/ao_portaudio.c b/audio/out/ao_portaudio.c
index 135c9224f1..ae8b76e830 100644
--- a/audio/out/ao_portaudio.c
+++ b/audio/out/ao_portaudio.c
@@ -146,16 +146,13 @@ static int stream_callback(const void *input,
return paContinue;
}
-static void uninit(struct ao *ao, bool cut_audio)
+static void uninit(struct ao *ao)
{
struct priv *priv = ao->priv;
if (priv->stream) {
- if (!cut_audio && Pa_IsStreamActive(priv->stream) == 1) {
- ao_wait_drain(ao);
-
+ if (Pa_IsStreamActive(priv->stream) == 1)
CHECK_PA_RET(Pa_StopStream(priv->stream));
- }
CHECK_PA_RET(Pa_CloseStream(priv->stream));
}
@@ -220,7 +217,7 @@ static int init(struct ao *ao)
return 0;
error_exit:
- uninit(ao, true);
+ uninit(ao);
return -1;
}
diff --git a/audio/out/ao_pulse.c b/audio/out/ao_pulse.c
index 12fca17dd6..d08ffcfc53 100644
--- a/audio/out/ao_pulse.c
+++ b/audio/out/ao_pulse.c
@@ -205,13 +205,18 @@ static bool select_chmap(struct ao *ao, pa_channel_map *dst)
chmap_pa_from_mp(dst, &ao->channels);
}
-static void uninit(struct ao *ao, bool cut_audio)
+static void drain(struct ao *ao)
{
struct priv *priv = ao->priv;
- if (priv->stream && !cut_audio) {
+ if (priv->stream) {
pa_threaded_mainloop_lock(priv->mainloop);
waitop(priv, pa_stream_drain(priv->stream, success_cb, ao));
}
+}
+
+static void uninit(struct ao *ao)
+{
+ struct priv *priv = ao->priv;
if (priv->mainloop)
pa_threaded_mainloop_stop(priv->mainloop);
@@ -366,7 +371,7 @@ fail:
if (proplist)
pa_proplist_free(proplist);
- uninit(ao, true);
+ uninit(ao);
return -1;
}
@@ -620,6 +625,7 @@ const struct ao_driver audio_out_pulse = {
.get_delay = get_delay,
.pause = pause,
.resume = resume,
+ .drain = drain,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.cfg_buffer = 250,
diff --git a/audio/out/ao_rsound.c b/audio/out/ao_rsound.c
index ef81c621da..75395c5e96 100644
--- a/audio/out/ao_rsound.c
+++ b/audio/out/ao_rsound.c
@@ -128,15 +128,9 @@ static int init(struct ao *ao)
return 0;
}
-static void uninit(struct ao *ao, bool cut_audio)
+static void uninit(struct ao *ao)
{
struct priv *priv = ao->priv;
- /* The API does not provide a direct way to explicitly wait until
- * the last byte has been played server-side as this cannot be
- * guaranteed by backend drivers, so we approximate this behavior.
- */
- if (!cut_audio)
- mp_sleep_us(rsd_delay_ms(priv->rd) * 1000);
rsd_stop(priv->rd);
rsd_free(priv->rd);
diff --git a/audio/out/ao_sdl.c b/audio/out/ao_sdl.c
index acb959b101..662eeca484 100644
--- a/audio/out/ao_sdl.c
+++ b/audio/out/ao_sdl.c
@@ -78,7 +78,7 @@ static void audio_callback(void *userdata, Uint8 *stream, int len)
SDL_UnlockMutex(priv->buffer_mutex);
}
-static void uninit(struct ao *ao, bool cut_audio)
+static void uninit(struct ao *ao)
{
struct priv *priv = ao->priv;
if (!priv)
@@ -134,14 +134,14 @@ static int init(struct ao *ao)
if (SDL_InitSubSystem(SDL_INIT_AUDIO)) {
if (!ao->probing)
MP_ERR(ao, "SDL_Init failed\n");
- uninit(ao, true);
+ uninit(ao);
return -1;
}
struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_waveext_def(&sel);
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) {
- uninit(ao, true);
+ uninit(ao);
return -1;
}
@@ -186,7 +186,7 @@ static int init(struct ao *ao)
if (SDL_OpenAudio(&desired, &obtained)) {
if (!ao->probing)
MP_ERR(ao, "could not open audio: %s\n", SDL_GetError());
- uninit(ao, true);
+ uninit(ao);
return -1;
}
@@ -217,12 +217,12 @@ static int init(struct ao *ao)
default:
if (!ao->probing)
MP_ERR(ao, "could not find matching format\n");
- uninit(ao, true);
+ uninit(ao);
return -1;
}
if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, obtained.channels)) {
- uninit(ao, true);
+ uninit(ao);
return -1;
}
@@ -231,13 +231,13 @@ static int init(struct ao *ao)
priv->buffer_mutex = SDL_CreateMutex();
if (!priv->buffer_mutex) {
MP_ERR(ao, "SDL_CreateMutex failed\n");
- uninit(ao, true);
+ uninit(ao);
return -1;
}
priv->underrun_cond = SDL_CreateCond();
if (!priv->underrun_cond) {
MP_ERR(ao, "SDL_CreateCond failed\n");
- uninit(ao, true);
+ uninit(ao);
return -1;
}
diff --git a/audio/out/ao_sndio.c b/audio/out/ao_sndio.c
index c200b906ab..286f158260 100644
--- a/audio/out/ao_sndio.c
+++ b/audio/out/ao_sndio.c
@@ -216,7 +216,7 @@ error:
/*
* close device
*/
-static void uninit(struct ao *ao, bool immed)
+static void uninit(struct ao *ao)
{
struct priv *p = ao->priv;
diff --git a/audio/out/ao_wasapi.c b/audio/out/ao_wasapi.c
index bb00849adb..a3da9fe388 100644
--- a/audio/out/ao_wasapi.c
+++ b/audio/out/ao_wasapi.c
@@ -1218,11 +1218,11 @@ static int setup_buffers(struct wasapi_state *state)
return !state->ringbuff;
}
-static void uninit(struct ao *ao, bool block)
+static void uninit(struct ao *ao)
{
MP_VERBOSE(ao, "uninit!\n");
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
- state->immed = !block;
+ state->immed = 1;
SetEvent(state->hUninit);
/* wait up to 10 seconds */
if (WaitForSingleObject(state->threadLoop, 10000) == WAIT_TIMEOUT)
diff --git a/audio/out/internal.h b/audio/out/internal.h
index 98de7e08b3..c14cdf3c68 100644
--- a/audio/out/internal.h
+++ b/audio/out/internal.h
@@ -100,13 +100,14 @@ struct ao_driver {
int (*init)(struct ao *ao);
// Optional. 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 (*uninit)(struct ao *ao);
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);
+ void (*drain)(struct ao *ao);
// For option parsing (see vo.h)
int priv_size;
diff --git a/audio/out/pull.c b/audio/out/pull.c
index a41ac714ba..01e581925d 100644
--- a/audio/out/pull.c
+++ b/audio/out/pull.c
@@ -190,9 +190,9 @@ static void resume(struct ao *ao)
ao->driver->resume(ao);
}
-static void uninit(struct ao *ao, bool cut_audio)
+static void uninit(struct ao *ao)
{
- ao->driver->uninit(ao, cut_audio);
+ ao->driver->uninit(ao);
}
static int init(struct ao *ao)
diff --git a/audio/out/push.c b/audio/out/push.c
index de093988bd..f0608dd3a4 100644
--- a/audio/out/push.c
+++ b/audio/out/push.c
@@ -106,6 +106,17 @@ static void resume(struct ao *ao)
pthread_mutex_unlock(&p->lock);
}
+static void drain(struct ao *ao)
+{
+ if (ao->driver->drain) {
+ struct ao_push_state *p = ao->api_priv;
+ pthread_mutex_lock(&p->lock);
+ ao->driver->drain(ao);
+ pthread_mutex_unlock(&p->lock);
+ } else {
+ ao_wait_drain(ao);
+ }
+}
static int get_space(struct ao *ao)
{
@@ -202,7 +213,7 @@ static void *playthread(void *arg)
return NULL;
}
-static void uninit(struct ao *ao, bool cut_audio)
+static void uninit(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
@@ -213,7 +224,7 @@ static void uninit(struct ao *ao, bool cut_audio)
pthread_join(p->thread, NULL);
- ao->driver->uninit(ao, cut_audio);
+ ao->driver->uninit(ao);
pthread_cond_destroy(&p->wakeup);
pthread_mutex_destroy(&p->lock);
@@ -231,7 +242,7 @@ static int init(struct ao *ao)
&ao->channels, ao->samplerate);
mp_audio_buffer_preallocate_min(p->buffer, ao->buffer);
if (pthread_create(&p->thread, NULL, playthread, ao)) {
- ao->driver->uninit(ao, true);
+ ao->driver->uninit(ao);
return -1;
}
return 0;
@@ -247,6 +258,7 @@ const struct ao_driver ao_api_push = {
.get_delay = get_delay,
.pause = pause,
.resume = resume,
+ .drain = drain,
.priv_size = sizeof(struct ao_push_state),
};