summaryrefslogtreecommitdiffstats
path: root/audio/out
diff options
context:
space:
mode:
Diffstat (limited to 'audio/out')
-rw-r--r--audio/out/ao.c2
-rw-r--r--audio/out/ao_audiotrack.c2
-rw-r--r--audio/out/ao_audiounit.m2
-rw-r--r--audio/out/ao_avfoundation.m11
-rw-r--r--audio/out/ao_coreaudio.c4
-rw-r--r--audio/out/ao_coreaudio_exclusive.c2
-rw-r--r--audio/out/ao_coreaudio_utils.c28
-rw-r--r--audio/out/ao_jack.c3
-rw-r--r--audio/out/ao_opensles.c2
-rw-r--r--audio/out/ao_oss.c3
-rw-r--r--audio/out/ao_pcm.c4
-rw-r--r--audio/out/ao_pipewire.c4
-rw-r--r--audio/out/ao_pulse.c38
-rw-r--r--audio/out/ao_sdl.c2
-rw-r--r--audio/out/ao_wasapi_changenotify.c5
-rw-r--r--audio/out/ao_wasapi_utils.c44
-rw-r--r--audio/out/buffer.c57
-rw-r--r--audio/out/internal.h8
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