diff options
Diffstat (limited to 'audio/out')
-rw-r--r-- | audio/out/ao.c | 2 | ||||
-rw-r--r-- | audio/out/ao_audiotrack.c | 2 | ||||
-rw-r--r-- | audio/out/ao_audiounit.m | 2 | ||||
-rw-r--r-- | audio/out/ao_avfoundation.m | 11 | ||||
-rw-r--r-- | audio/out/ao_coreaudio.c | 4 | ||||
-rw-r--r-- | audio/out/ao_coreaudio_exclusive.c | 2 | ||||
-rw-r--r-- | audio/out/ao_coreaudio_utils.c | 28 | ||||
-rw-r--r-- | audio/out/ao_jack.c | 3 | ||||
-rw-r--r-- | audio/out/ao_opensles.c | 2 | ||||
-rw-r--r-- | audio/out/ao_oss.c | 3 | ||||
-rw-r--r-- | audio/out/ao_pcm.c | 4 | ||||
-rw-r--r-- | audio/out/ao_pipewire.c | 4 | ||||
-rw-r--r-- | audio/out/ao_pulse.c | 38 | ||||
-rw-r--r-- | audio/out/ao_sdl.c | 2 | ||||
-rw-r--r-- | audio/out/ao_wasapi_changenotify.c | 5 | ||||
-rw-r--r-- | audio/out/ao_wasapi_utils.c | 44 | ||||
-rw-r--r-- | audio/out/buffer.c | 57 | ||||
-rw-r--r-- | audio/out/internal.h | 8 |
18 files changed, 139 insertions, 82 deletions
diff --git a/audio/out/ao.c b/audio/out/ao.c index 75fcbac6fa..ee20b736a3 100644 --- a/audio/out/ao.c +++ b/audio/out/ao.c @@ -241,7 +241,7 @@ static struct ao *ao_init(bool probing, struct mpv_global *global, } else { ao->sstride *= ao->channels.num; } - ao->bps = ao->samplerate * ao->sstride; + ao->bps = (int64_t)ao->samplerate * ao->sstride; if (ao->device_buffer <= 0 && ao->driver->write) { MP_ERR(ao, "Device buffer size not set.\n"); diff --git a/audio/out/ao_audiotrack.c b/audio/out/ao_audiotrack.c index db1da9c407..940bffbec9 100644 --- a/audio/out/ao_audiotrack.c +++ b/audio/out/ao_audiotrack.c @@ -564,7 +564,7 @@ static MP_THREAD_VOID ao_thread(void *arg) int64_t ts = mp_time_ns(); ts += MP_TIME_S_TO_NS(read_samples / (double)(ao->samplerate)); ts += MP_TIME_S_TO_NS(AudioTrack_getLatency(ao)); - int samples = ao_read_data_nonblocking(ao, &p->chunk, read_samples, ts); + int samples = ao_read_data(ao, &p->chunk, read_samples, ts, NULL, false, false); int ret = AudioTrack_write(ao, samples * ao->sstride); if (ret >= 0) { p->written_frames += ret / ao->sstride; diff --git a/audio/out/ao_audiounit.m b/audio/out/ao_audiounit.m index 85b1226dc9..d35912ceb8 100644 --- a/audio/out/ao_audiounit.m +++ b/audio/out/ao_audiounit.m @@ -97,7 +97,7 @@ static OSStatus render_cb_lpcm(void *ctx, AudioUnitRenderActionFlags *aflags, int64_t end = mp_time_ns(); end += MP_TIME_S_TO_NS(p->device_latency); end += ca_get_latency(ts) + ca_frames_to_ns(ao, frames); - ao_read_data(ao, planes, frames, end); + ao_read_data(ao, planes, frames, end, NULL, true, true); return noErr; } diff --git a/audio/out/ao_avfoundation.m b/audio/out/ao_avfoundation.m index 7654916519..2e7d194b25 100644 --- a/audio/out/ao_avfoundation.m +++ b/audio/out/ao_avfoundation.m @@ -76,11 +76,14 @@ static void feed(struct ao *ao) int64_t cur_time_mp = mp_time_ns(); int64_t end_time_av = MPMAX(p->end_time_av, cur_time_av); int64_t time_delta = CMTimeGetNanoseconds(CMTimeMake(request_sample_count, samplerate)); - int real_sample_count = ao_read_data_nonblocking(ao, data, request_sample_count, end_time_av - cur_time_av + cur_time_mp + time_delta); + bool eof; + int real_sample_count = ao_read_data(ao, data, request_sample_count, end_time_av - cur_time_av + cur_time_mp + time_delta, &eof, false, true); + if (eof) { + [p->renderer stopRequestingMediaData]; + ao_stop_streaming(ao); + } if (real_sample_count == 0) { - // avoid spinning by blocking the thread - mp_sleep_ns(10000000); - goto finish; + return; } if ((err = CMBlockBufferCreateWithMemoryBlock( diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c index 4abfac38ee..1b0f99a9d1 100644 --- a/audio/out/ao_coreaudio.c +++ b/audio/out/ao_coreaudio.c @@ -16,6 +16,7 @@ */ #include <CoreAudio/HostTime.h> +#include <libavutil/mathematics.h> #include "ao.h" #include "internal.h" @@ -90,7 +91,7 @@ static OSStatus render_cb_lpcm(void *ctx, AudioUnitRenderActionFlags *aflags, int64_t end = mp_time_ns(); end += p->hw_latency_ns + ca_get_latency(ts) + ca_frames_to_ns(ao, frames); // don't use the returned sample count since CoreAudio always expects full frames - ao_read_data(ao, planes, frames, end); + ao_read_data(ao, planes, frames, end, NULL, true, true); return noErr; } @@ -178,6 +179,7 @@ static int init(struct ao *ao) goto coreaudio_error; reinit_latency(ao); + ao->device_buffer = av_rescale(p->hw_latency_ns, ao->samplerate, 1000000000) * 2; p->queue = dispatch_queue_create("io.mpv.coreaudio_stop_during_idle", DISPATCH_QUEUE_SERIAL); diff --git a/audio/out/ao_coreaudio_exclusive.c b/audio/out/ao_coreaudio_exclusive.c index 5e0ec3b19f..dbe7b94ed7 100644 --- a/audio/out/ao_coreaudio_exclusive.c +++ b/audio/out/ao_coreaudio_exclusive.c @@ -181,7 +181,7 @@ static OSStatus render_cb_compressed( end += p->hw_latency_ns + ca_get_latency(ts) + ca_frames_to_ns(ao, pseudo_frames); - ao_read_data(ao, &buf.mData, pseudo_frames, end); + ao_read_data(ao, &buf.mData, pseudo_frames, end, NULL, true, true); if (p->spdif_hack) bad_hack_mygodwhy(buf.mData, pseudo_frames * ao->channels.num); diff --git a/audio/out/ao_coreaudio_utils.c b/audio/out/ao_coreaudio_utils.c index 44604e6df2..78cdcad393 100644 --- a/audio/out/ao_coreaudio_utils.c +++ b/audio/out/ao_coreaudio_utils.c @@ -236,20 +236,20 @@ void ca_print_asbd(struct ao *ao, const char *description, int mpfmt = ca_asbd_to_mp_format(asbd); MP_VERBOSE(ao, - "%s %7.1fHz %" PRIu32 "bit %s " - "[%" PRIu32 "][%" PRIu32 "bpp][%" PRIu32 "fbp]" - "[%" PRIu32 "bpf][%" PRIu32 "ch] " - "%s %s %s%s%s%s (%s)\n", - description, asbd->mSampleRate, asbd->mBitsPerChannel, format, - asbd->mFormatFlags, asbd->mBytesPerPacket, asbd->mFramesPerPacket, - asbd->mBytesPerFrame, asbd->mChannelsPerFrame, - (flags & kAudioFormatFlagIsFloat) ? "float" : "int", - (flags & kAudioFormatFlagIsBigEndian) ? "BE" : "LE", - (flags & kAudioFormatFlagIsSignedInteger) ? "S" : "U", - (flags & kAudioFormatFlagIsPacked) ? " packed" : "", - (flags & kAudioFormatFlagIsAlignedHigh) ? " aligned" : "", - (flags & kAudioFormatFlagIsNonInterleaved) ? " P" : "", - mpfmt ? af_fmt_to_str(mpfmt) : "-"); + "%s %7.1fHz %" PRIu32 "bit %s " + "[%" PRIu32 "][%" PRIu32 "bpp][%" PRIu32 "fbp]" + "[%" PRIu32 "bpf][%" PRIu32 "ch] " + "%s %s %s%s%s%s (%s)\n", + description, asbd->mSampleRate, asbd->mBitsPerChannel, format, + asbd->mFormatFlags, asbd->mBytesPerPacket, asbd->mFramesPerPacket, + asbd->mBytesPerFrame, asbd->mChannelsPerFrame, + (flags & kAudioFormatFlagIsFloat) ? "float" : "int", + (flags & kAudioFormatFlagIsBigEndian) ? "BE" : "LE", + (flags & kAudioFormatFlagIsSignedInteger) ? "S" : "U", + (flags & kAudioFormatFlagIsPacked) ? " packed" : "", + (flags & kAudioFormatFlagIsAlignedHigh) ? " aligned" : "", + (flags & kAudioFormatFlagIsNonInterleaved) ? " P" : "", + mpfmt ? af_fmt_to_str(mpfmt) : "-"); } // Return whether new is an improvement over old. Assume a higher value means diff --git a/audio/out/ao_jack.c b/audio/out/ao_jack.c index 412e91d626..bd1a19e67a 100644 --- a/audio/out/ao_jack.c +++ b/audio/out/ao_jack.c @@ -26,7 +26,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <unistd.h> #include "config.h" #include "common/msg.h" @@ -125,7 +124,7 @@ static int process(jack_nframes_t nframes, void *arg) int64_t end_time = mp_time_ns(); end_time += MP_TIME_S_TO_NS((jack_latency + nframes) / (double)ao->samplerate); - ao_read_data(ao, buffers, nframes, end_time); + ao_read_data(ao, buffers, nframes, end_time, NULL, true, true); return 0; } diff --git a/audio/out/ao_opensles.c b/audio/out/ao_opensles.c index ddcff1904a..6d4b6a78db 100644 --- a/audio/out/ao_opensles.c +++ b/audio/out/ao_opensles.c @@ -81,7 +81,7 @@ static void buffer_callback(SLBufferQueueItf buffer_queue, void *context) delay = p->frames_per_enqueue / (double)ao->samplerate; delay += p->audio_latency; ao_read_data(ao, &p->buf, p->frames_per_enqueue, - mp_time_ns() + MP_TIME_S_TO_NS(delay)); + mp_time_ns() + MP_TIME_S_TO_NS(delay), NULL, true, true); res = (*buffer_queue)->Enqueue(buffer_queue, p->buf, p->bytes_per_enqueue); if (res != SL_RESULT_SUCCESS) diff --git a/audio/out/ao_oss.c b/audio/out/ao_oss.c index afe5839dd5..31e4700b40 100644 --- a/audio/out/ao_oss.c +++ b/audio/out/ao_oss.c @@ -25,7 +25,6 @@ #include <errno.h> #include <fcntl.h> #include <stdio.h> -#include <unistd.h> #include <sys/ioctl.h> #include <sys/soundcard.h> @@ -328,7 +327,7 @@ static bool audio_write(struct ao *ao, void **data, int samples) while ((rc = write(p->dsp_fd, data[0], size)) == -1) { if (errno == EINTR) - continue; + continue; MP_WARN(ao, "audio_write: write() fail, err = %i: %s.\n", errno, mp_strerror(errno)); return false; diff --git a/audio/out/ao_pcm.c b/audio/out/ao_pcm.c index 4097aa3bd6..71650c39e3 100644 --- a/audio/out/ao_pcm.c +++ b/audio/out/ao_pcm.c @@ -86,7 +86,7 @@ static void write_wave_header(struct ao *ao, FILE *fp, uint64_t data_length) fput16le(WAV_ID_FORMAT_EXTENSIBLE, fp); fput16le(ao->channels.num, fp); fput32le(ao->samplerate, fp); - fput32le(ao->bps, fp); + fput32le(MPCLAMP(ao->bps, 0, UINT32_MAX), fp); fput16le(ao->channels.num * (bits / 8), fp); fput16le(bits, fp); @@ -145,7 +145,7 @@ static int init(struct ao *ao) if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) return -1; - ao->bps = ao->channels.num * ao->samplerate * af_fmt_to_bytes(ao->format); + ao->bps = ao->channels.num * (int64_t)ao->samplerate * af_fmt_to_bytes(ao->format); MP_INFO(ao, "File: %s (%s)\nPCM: Samplerate: %d Hz Channels: %d Format: %s\n", outputfilename, diff --git a/audio/out/ao_pipewire.c b/audio/out/ao_pipewire.c index 94d393a26d..a04ae9d3d0 100644 --- a/audio/out/ao_pipewire.c +++ b/audio/out/ao_pipewire.c @@ -38,7 +38,7 @@ #if !PW_CHECK_VERSION(0, 3, 50) static inline int pw_stream_get_time_n(struct pw_stream *stream, struct pw_time *time, size_t size) { - return pw_stream_get_time(stream, time); + return pw_stream_get_time(stream, time); } #endif @@ -206,7 +206,7 @@ static void on_process(void *userdata) #endif end_time -= pw_stream_get_nsec(p->stream) - time.now; - int samples = ao_read_data_nonblocking(ao, data, nframes, end_time); + int samples = ao_read_data(ao, data, nframes, end_time, NULL, false, false); b->size = samples; for (int i = 0; i < buf->n_datas; i++) { diff --git a/audio/out/ao_pulse.c b/audio/out/ao_pulse.c index 5c86855d71..95a7fb0ea8 100644 --- a/audio/out/ao_pulse.c +++ b/audio/out/ao_pulse.c @@ -209,25 +209,25 @@ static pa_encoding_t map_digital_format(int format) } static const int speaker_map[][2] = { - {PA_CHANNEL_POSITION_FRONT_LEFT, MP_SPEAKER_ID_FL}, - {PA_CHANNEL_POSITION_FRONT_RIGHT, MP_SPEAKER_ID_FR}, - {PA_CHANNEL_POSITION_FRONT_CENTER, MP_SPEAKER_ID_FC}, - {PA_CHANNEL_POSITION_REAR_CENTER, MP_SPEAKER_ID_BC}, - {PA_CHANNEL_POSITION_REAR_LEFT, MP_SPEAKER_ID_BL}, - {PA_CHANNEL_POSITION_REAR_RIGHT, MP_SPEAKER_ID_BR}, - {PA_CHANNEL_POSITION_LFE, MP_SPEAKER_ID_LFE}, - {PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, MP_SPEAKER_ID_FLC}, - {PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, MP_SPEAKER_ID_FRC}, - {PA_CHANNEL_POSITION_SIDE_LEFT, MP_SPEAKER_ID_SL}, - {PA_CHANNEL_POSITION_SIDE_RIGHT, MP_SPEAKER_ID_SR}, - {PA_CHANNEL_POSITION_TOP_CENTER, MP_SPEAKER_ID_TC}, - {PA_CHANNEL_POSITION_TOP_FRONT_LEFT, MP_SPEAKER_ID_TFL}, - {PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, MP_SPEAKER_ID_TFR}, - {PA_CHANNEL_POSITION_TOP_FRONT_CENTER, MP_SPEAKER_ID_TFC}, - {PA_CHANNEL_POSITION_TOP_REAR_LEFT, MP_SPEAKER_ID_TBL}, - {PA_CHANNEL_POSITION_TOP_REAR_RIGHT, MP_SPEAKER_ID_TBR}, - {PA_CHANNEL_POSITION_TOP_REAR_CENTER, MP_SPEAKER_ID_TBC}, - {PA_CHANNEL_POSITION_INVALID, -1} + {PA_CHANNEL_POSITION_FRONT_LEFT, MP_SPEAKER_ID_FL}, + {PA_CHANNEL_POSITION_FRONT_RIGHT, MP_SPEAKER_ID_FR}, + {PA_CHANNEL_POSITION_FRONT_CENTER, MP_SPEAKER_ID_FC}, + {PA_CHANNEL_POSITION_REAR_CENTER, MP_SPEAKER_ID_BC}, + {PA_CHANNEL_POSITION_REAR_LEFT, MP_SPEAKER_ID_BL}, + {PA_CHANNEL_POSITION_REAR_RIGHT, MP_SPEAKER_ID_BR}, + {PA_CHANNEL_POSITION_LFE, MP_SPEAKER_ID_LFE}, + {PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, MP_SPEAKER_ID_FLC}, + {PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, MP_SPEAKER_ID_FRC}, + {PA_CHANNEL_POSITION_SIDE_LEFT, MP_SPEAKER_ID_SL}, + {PA_CHANNEL_POSITION_SIDE_RIGHT, MP_SPEAKER_ID_SR}, + {PA_CHANNEL_POSITION_TOP_CENTER, MP_SPEAKER_ID_TC}, + {PA_CHANNEL_POSITION_TOP_FRONT_LEFT, MP_SPEAKER_ID_TFL}, + {PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, MP_SPEAKER_ID_TFR}, + {PA_CHANNEL_POSITION_TOP_FRONT_CENTER, MP_SPEAKER_ID_TFC}, + {PA_CHANNEL_POSITION_TOP_REAR_LEFT, MP_SPEAKER_ID_TBL}, + {PA_CHANNEL_POSITION_TOP_REAR_RIGHT, MP_SPEAKER_ID_TBR}, + {PA_CHANNEL_POSITION_TOP_REAR_CENTER, MP_SPEAKER_ID_TBC}, + {PA_CHANNEL_POSITION_INVALID, -1} }; static bool chmap_pa_from_mp(pa_channel_map *dst, struct mp_chmap *src) diff --git a/audio/out/ao_sdl.c b/audio/out/ao_sdl.c index 5a6a58b124..5fa8ebbd56 100644 --- a/audio/out/ao_sdl.c +++ b/audio/out/ao_sdl.c @@ -61,7 +61,7 @@ static void audio_callback(void *userdata, Uint8 *stream, int len) // fixed latency. double delay = 2 * len / (double)ao->bps; - ao_read_data(ao, data, len / ao->sstride, mp_time_ns() + MP_TIME_S_TO_NS(delay)); + ao_read_data(ao, data, len / ao->sstride, mp_time_ns() + MP_TIME_S_TO_NS(delay), NULL, true, true); } static void uninit(struct ao *ao) diff --git a/audio/out/ao_wasapi_changenotify.c b/audio/out/ao_wasapi_changenotify.c index f0e1895305..7f1c16794f 100644 --- a/audio/out/ao_wasapi_changenotify.c +++ b/audio/out/ao_wasapi_changenotify.c @@ -155,6 +155,11 @@ static HRESULT STDMETHODCALLTYPE sIMMNotificationClient_OnDefaultDeviceChanged( return S_OK; } +// IsEqualIID in Windows SDK passes GUID as REFGUID (reference) in C++, but in +// C is has to get pointers... +#undef IsEqualPropertyKey +#define IsEqualPropertyKey(a, b) (((a).pid == (b).pid) && IsEqualIID(&(a).fmtid, &(b).fmtid)) + static HRESULT STDMETHODCALLTYPE sIMMNotificationClient_OnPropertyValueChanged( IMMNotificationClient *This, LPCWSTR pwstrDeviceId, diff --git a/audio/out/ao_wasapi_utils.c b/audio/out/ao_wasapi_utils.c index 2614872b91..7d4c536e78 100644 --- a/audio/out/ao_wasapi_utils.c +++ b/audio/out/ao_wasapi_utils.c @@ -20,9 +20,17 @@ #include <math.h> #include <windows.h> -#include <mmsystem.h> +// Workaround for redefinition of some guids in mingw. ks.h has to be included +// before other ks*.h headers, but mingw fails then. +#ifdef __MINGW32__ #include <mmreg.h> #include <ksguid.h> +#else +#include <ks.h> +#include <ksguid.h> +#include <mmreg.h> +#endif +#include <mmsystem.h> #include <ksmedia.h> #include <avrt.h> #include <propsys.h> @@ -34,6 +42,40 @@ #include "osdep/strnlen.h" #include "ao_wasapi.h" +#ifdef _MSC_VER +// Define some GUIDs that are defined only in C++ interfaces. +DEFINE_GUID(KSDATAFORMAT_SPECIFIER_NONE, + 0xf6417d6, 0xc318, 0x11d0, 0xa4, 0x3f, + 0, 0xa0, 0xc9, 0x22, 0x31, 0x96); +DEFINE_GUID(CLSID_MMDeviceEnumerator, + 0xbcde0395, 0xe52f, 0x467c, 0x8e, 0x3d, + 0xc4, 0x57, 0x92, 0x91, 0x69, 0x2e); +DEFINE_GUID(IID_IAudioClient, + 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1, 0x78, 0xc2, + 0xf5, 0x68, 0xa7, 0x03, 0xb2); +DEFINE_GUID(IID_IAudioClock, + 0xcd63314f, 0x3fba, 0x4a1b, 0x81, 0x2c, 0xef, 0x96, + 0x35, 0x87, 0x28, 0xe7); +DEFINE_GUID(IID_IAudioEndpointVolume, + 0x5cdf2c82, 0x841e, 0x4546, 0x97, 0x22, + 0x0c, 0xf7, 0x40, 0x78, 0x22, 0x9a); +DEFINE_GUID(IID_IAudioRenderClient, + 0xf294acfc, 0x3146, 0x4483, 0xa7, 0xbf, + 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2); +DEFINE_GUID(IID_IAudioSessionControl, + 0xf4b1a599, 0x7266, 0x4319, 0xa8, 0xca, + 0xe7, 0x0a, 0xcb, 0x11, 0xe8, 0xcd); +DEFINE_GUID(IID_IMMDeviceEnumerator, + 0xa95664d2, 0x9614, 0x4f35, 0xa7, 0x46, + 0xde, 0x8d, 0xb6, 0x36, 0x17, 0xe6); +DEFINE_GUID(IID_IMMNotificationClient, + 0x7991eec9, 0x7e89, 0x4d85, 0x83, 0x90, + 0x6c, 0x70, 0x3c, 0xec, 0x60, 0xc0); +DEFINE_GUID(IID_ISimpleAudioVolume, + 0x87ce5498, 0x68d6, 0x44e5, 0x92, 0x15, + 0x6d, 0xa4, 0x7e, 0xf8, 0x83, 0xd8); +#endif + #ifndef KSDATAFORMAT_SUBTYPE_IEC61937_DTS DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEC61937_DTS, WAVE_FORMAT_DTS, 0x0000, 0x0010, 0x80, 0x00, diff --git a/audio/out/buffer.c b/audio/out/buffer.c index 97f7ea147e..e06d67e12a 100644 --- a/audio/out/buffer.c +++ b/audio/out/buffer.c @@ -18,7 +18,6 @@ #include <stddef.h> #include <inttypes.h> #include <math.h> -#include <unistd.h> #include <errno.h> #include <assert.h> @@ -60,6 +59,7 @@ struct buffer_state { bool streaming; // AO streaming active bool playing; // logically playing audio from buffer bool paused; // logically paused + bool hw_paused; // driver->set_pause() was used successfully int64_t end_time_ns; // absolute output time of last played sample int64_t queued_time_ns; // duration of samples that have been queued to @@ -71,7 +71,6 @@ struct buffer_state { bool initial_unblocked; // "Push" AOs only (AOs with driver->write). - bool hw_paused; // driver->set_pause() was used successfully bool recover_pause; // non-hw_paused: needs to recover delay struct mp_pcm_state prepause_state; mp_thread thread; // thread shoveling data to AO @@ -179,12 +178,12 @@ static int read_buffer(struct ao *ao, void **data, int samples, bool *eof, } static int ao_read_data_locked(struct ao *ao, void **data, int samples, - int64_t out_time_ns, bool pad_silence) + int64_t out_time_ns, bool *eof, bool pad_silence) { struct buffer_state *p = ao->buffer_state; assert(!ao->driver->write); - int pos = read_buffer(ao, data, samples, &(bool){0}, pad_silence); + int pos = read_buffer(ao, data, samples, eof, pad_silence); if (pos > 0) p->end_time_ns = out_time_ns; @@ -207,29 +206,23 @@ static int ao_read_data_locked(struct ao *ao, void **data, int samples, // If this is called in paused mode, it will always return 0. // The caller should set out_time_ns to the expected delay until the last sample // reaches the speakers, in nanoseconds, using mp_time_ns() as reference. -int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_ns) +int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_ns, bool *eof, bool pad_silence, bool blocking) { struct buffer_state *p = ao->buffer_state; - mp_mutex_lock(&p->lock); - - int pos = ao_read_data_locked(ao, data, samples, out_time_ns, true); - - mp_mutex_unlock(&p->lock); - - return pos; -} - -// Like ao_read_data() but does not block and also may return partial data. -// Callers have to check the return value. -int ao_read_data_nonblocking(struct ao *ao, void **data, int samples, int64_t out_time_ns) -{ - struct buffer_state *p = ao->buffer_state; + if (blocking) { + mp_mutex_lock(&p->lock); + } else if (mp_mutex_trylock(&p->lock)) { + return 0; + } - if (mp_mutex_trylock(&p->lock)) - return 0; + bool eof_buf; + if (eof == NULL) { + // This is a public API. We want to reduce the cognitive burden of the caller. + eof = &eof_buf; + } - int pos = ao_read_data_locked(ao, data, samples, out_time_ns, false); + int pos = ao_read_data_locked(ao, data, samples, out_time_ns, eof, pad_silence); mp_mutex_unlock(&p->lock); @@ -245,7 +238,7 @@ int ao_read_data_converted(struct ao *ao, struct ao_convert_fmt *fmt, void *ndata[MP_NUM_CHANNELS] = {0}; if (!ao_need_conversion(fmt)) - return ao_read_data(ao, data, samples, out_time_ns); + return ao_read_data(ao, data, samples, out_time_ns, NULL, true, true); assert(ao->format == fmt->src_fmt); assert(ao->channels.num == fmt->channels); @@ -265,7 +258,7 @@ int ao_read_data_converted(struct ao *ao, struct ao_convert_fmt *fmt, for (int n = 0; n < planes; n++) ndata[n] = p->convert_buffer + n * src_plane_size; - int res = ao_read_data(ao, ndata, samples, out_time_ns); + int res = ao_read_data(ao, ndata, samples, out_time_ns, NULL, true, true); ao_convert_inplace(fmt, ndata, samples); for (int n = 0; n < planes; n++) @@ -274,6 +267,16 @@ int ao_read_data_converted(struct ao *ao, struct ao_convert_fmt *fmt, return res; } +// Called by pull-based AO to indicate the AO has stopped requesting more data, +// usually when EOF is got from ao_read_data(). +// After this function is called, the core will call ao->driver->start() again +// when more audio data after EOF arrives. +void ao_stop_streaming(struct ao *ao) +{ + struct buffer_state *p = ao->buffer_state; + p->streaming = false; +} + int ao_control(struct ao *ao, enum aocontrol cmd, void *arg) { struct buffer_state *p = ao->buffer_state; @@ -387,6 +390,7 @@ void ao_set_paused(struct ao *ao, bool paused, bool eof) struct buffer_state *p = ao->buffer_state; bool wakeup = false; bool do_change_state = false; + bool is_hw_paused; // If we are going to pause on eof and ao is still playing, // be sure to drain the ao first for gapless. @@ -411,6 +415,7 @@ void ao_set_paused(struct ao *ao, bool paused, bool eof) // See ao_reset() why this is done outside of the lock. do_change_state = true; p->streaming = false; + is_hw_paused = p->hw_paused = !!ao->driver->set_pause; } } wakeup = true; @@ -423,6 +428,8 @@ void ao_set_paused(struct ao *ao, bool paused, bool eof) if (!p->streaming) do_change_state = true; p->streaming = true; + is_hw_paused = p->hw_paused; + p->hw_paused = false; } wakeup = true; } @@ -431,7 +438,7 @@ void ao_set_paused(struct ao *ao, bool paused, bool eof) mp_mutex_unlock(&p->lock); if (do_change_state) { - if (ao->driver->set_pause) { + if (is_hw_paused) { if (paused) { ao->driver->set_pause(ao, true); p->queued_time_ns = p->end_time_ns - mp_time_ns(); diff --git a/audio/out/internal.h b/audio/out/internal.h index 51429b9c06..18445f6e69 100644 --- a/audio/out/internal.h +++ b/audio/out/internal.h @@ -28,7 +28,7 @@ struct ao { int samplerate; struct mp_chmap channels; int format; // one of AF_FORMAT_... - int bps; // bytes per second (per plane) + int64_t bps; // bytes per second (per plane) int sstride; // size of a sample on each plane // (format_size*num_channels/num_planes) int num_planes; @@ -201,9 +201,7 @@ struct ao_driver { // These functions can be called by AOs. -int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_ns); -MP_WARN_UNUSED_RESULT -int ao_read_data_nonblocking(struct ao *ao, void **data, int samples, int64_t out_time_ns); +int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_ns, bool *eof, bool pad_silence, bool blocking); bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s, struct mp_chmap *map); @@ -236,4 +234,6 @@ void ao_wakeup(struct ao *ao); int ao_read_data_converted(struct ao *ao, struct ao_convert_fmt *fmt, void **data, int samples, int64_t out_time_ns); +void ao_stop_streaming(struct ao *ao); + #endif |