summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorMisaki Kasumi <misakikasumi@outlook.com>2024-03-26 21:57:12 +0800
committersfan5 <sfan5@live.de>2024-04-05 17:22:17 +0200
commitf974382ca06655ac34debce7284ce87d01e5abd1 (patch)
tree6da732c8fbe47358d4b3a9141d0a50e1fe33d5fb /audio
parent2cbb13db9edae33d8fe1b078835fd387e69946d3 (diff)
downloadmpv-f974382ca06655ac34debce7284ce87d01e5abd1.tar.bz2
mpv-f974382ca06655ac34debce7284ce87d01e5abd1.tar.xz
ao_pipewire: fix delay calculation
A figure from pipewire documentation: ``` stream time domain graph time domain /-----------------------\/-----------------------------\ queue +-+ +-+ +-----------+ +--------+ ----> | | | |->| converter | -> graph -> | kernel | -> speaker <---- +-+ +-+ +-----------+ +--------+ dequeue buffers \-------------------/\--------/ graph internal latency latency \--------/\-------------/\-----------------------------/ queued buffered delay ``` We calculate `end_time` in the following steps: 1. get current timestamp in mpv ``` int64_t end_time = mp_time_ns(); ``` 2. add duration of samples to enqueue ``` end_time += MP_TIME_S_TO_NS(nframes) / ao->samplerate; ``` 3. add delay of the pipewire graph ``` end_time += MP_TIME_S_TO_NS(time.delay) * time.rate.num / time.rate.denom; ``` 4. add duration of queued and buffered samples. ``` end_time += MP_TIME_S_TO_NS(time.queued) / ao->samplerate; end_time += MP_TIME_S_TO_NS(time.buffered) / ao->samplerate; ``` New in this commit. `time.queued` is usually zero as `SPA_PARAM_BUFFERS_buffers` is default to 1; however it is not always. `time.buffered` is non-zero if there is a resampler involved. 5. add elapsed duration from when `time` is captured ``` end_time -= pw_stream_get_nsec(p->stream) - time.now; ``` New in this commit. `time` is captured at `time.now`. From then, time has passed so we need to exclude the elapsed time, by calculating the diff of `pw_stream_get_nsec()` and `time.now`.
Diffstat (limited to 'audio')
-rw-r--r--audio/out/ao_pipewire.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/audio/out/ao_pipewire.c b/audio/out/ao_pipewire.c
index 9e08ddc626..94d393a26d 100644
--- a/audio/out/ao_pipewire.c
+++ b/audio/out/ao_pipewire.c
@@ -47,6 +47,15 @@ static inline int pw_stream_get_time_n(struct pw_stream *stream, struct pw_time
#define spa_hook_remove(hook) if ((hook)->link.prev) spa_hook_remove(hook)
#endif
+#if !PW_CHECK_VERSION(1, 0, 4)
+static uint64_t pw_stream_get_nsec(struct pw_stream *stream)
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return SPA_TIMESPEC_TO_NSEC(&ts);
+}
+#endif
+
enum init_state {
INIT_STATE_NONE,
INIT_STATE_SUCCESS,
@@ -189,9 +198,13 @@ static void on_process(void *userdata)
time.rate.num = 1;
int64_t end_time = mp_time_ns();
- /* time.queued is always going to be 0, so we don't need to care */
- end_time += (nframes * 1e9 / ao->samplerate) +
- ((double) time.delay * SPA_NSEC_PER_SEC * time.rate.num / time.rate.denom);
+ end_time += MP_TIME_S_TO_NS(nframes) / ao->samplerate;
+ end_time += MP_TIME_S_TO_NS(time.delay) * time.rate.num / time.rate.denom;
+ end_time += MP_TIME_S_TO_NS(time.queued) / ao->samplerate;
+#if PW_CHECK_VERSION(0, 3, 50)
+ end_time += MP_TIME_S_TO_NS(time.buffered) / ao->samplerate;
+#endif
+ end_time -= pw_stream_get_nsec(p->stream) - time.now;
int samples = ao_read_data_nonblocking(ao, data, nframes, end_time);
b->size = samples;