diff options
Diffstat (limited to 'audio/out')
-rw-r--r-- | audio/out/ao.c | 22 | ||||
-rw-r--r-- | audio/out/ao.h | 3 | ||||
-rw-r--r-- | audio/out/ao_alsa.c | 16 | ||||
-rw-r--r-- | audio/out/ao_coreaudio.c | 5 | ||||
-rw-r--r-- | audio/out/ao_dsound.c | 4 | ||||
-rw-r--r-- | audio/out/ao_jack.c | 5 | ||||
-rw-r--r-- | audio/out/ao_lavc.c | 8 | ||||
-rw-r--r-- | audio/out/ao_null.c | 10 | ||||
-rw-r--r-- | audio/out/ao_openal.c | 21 | ||||
-rw-r--r-- | audio/out/ao_oss.c | 21 | ||||
-rw-r--r-- | audio/out/ao_pcm.c | 2 | ||||
-rw-r--r-- | audio/out/ao_portaudio.c | 9 | ||||
-rw-r--r-- | audio/out/ao_pulse.c | 12 | ||||
-rw-r--r-- | audio/out/ao_rsound.c | 8 | ||||
-rw-r--r-- | audio/out/ao_sdl.c | 16 | ||||
-rw-r--r-- | audio/out/ao_sndio.c | 2 | ||||
-rw-r--r-- | audio/out/ao_wasapi.c | 4 | ||||
-rw-r--r-- | audio/out/internal.h | 3 | ||||
-rw-r--r-- | audio/out/pull.c | 4 | ||||
-rw-r--r-- | audio/out/push.c | 18 |
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), }; |