diff --git a/docs/sphinx/reference-libobs-util-platform.rst b/docs/sphinx/reference-libobs-util-platform.rst index 5b857fdb708ccb..54103fd2f24423 100644 --- a/docs/sphinx/reference-libobs-util-platform.rst +++ b/docs/sphinx/reference-libobs-util-platform.rst @@ -194,6 +194,13 @@ Sleep/Time Functions --------------------- +.. function:: bool os_sleepto_ns_fast(uint64_t time_target) + + Sleeps to a specific time without high precision, in nanoseconds. + The function won't return until reaching the specific time. + +--------------------- + .. function:: void os_sleep_ms(uint32_t duration) Sleeps for a specific number of milliseconds. diff --git a/libobs/media-io/audio-io.c b/libobs/media-io/audio-io.c index dc93bfeaf36653..df88a4c24f01b8 100644 --- a/libobs/media-io/audio-io.c +++ b/libobs/media-io/audio-io.c @@ -213,10 +213,6 @@ static void *audio_thread(void *param) uint64_t samples = 0; uint64_t start_time = os_gettime_ns(); uint64_t prev_time = start_time; - uint64_t audio_time = prev_time; - uint32_t audio_wait_time = - (uint32_t)(audio_frames_to_ns(rate, AUDIO_OUTPUT_FRAMES) / - 1000000); os_set_thread_name("audio-io: audio thread"); @@ -225,21 +221,16 @@ static void *audio_thread(void *param) "audio_thread(%s)", audio->info.name); while (os_event_try(audio->stop_event) == EAGAIN) { - uint64_t cur_time; + samples += AUDIO_OUTPUT_FRAMES; + uint64_t audio_time = + start_time + audio_frames_to_ns(rate, samples); - os_sleep_ms(audio_wait_time); + os_sleepto_ns_fast(audio_time); profile_start(audio_thread_name); - cur_time = os_gettime_ns(); - while (audio_time <= cur_time) { - samples += AUDIO_OUTPUT_FRAMES; - audio_time = - start_time + audio_frames_to_ns(rate, samples); - - input_and_output(audio, audio_time, prev_time); - prev_time = audio_time; - } + input_and_output(audio, audio_time, prev_time); + prev_time = audio_time; profile_end(audio_thread_name); diff --git a/libobs/util/platform-nix.c b/libobs/util/platform-nix.c index b266bfdb0fa08f..7646299942d026 100644 --- a/libobs/util/platform-nix.c +++ b/libobs/util/platform-nix.c @@ -180,6 +180,23 @@ bool os_sleepto_ns(uint64_t time_target) return true; } +bool os_sleepto_ns_fast(uint64_t time_target) +{ + uint64_t current = os_gettime_ns(); + if (time_target < current) + return false; + + do { + uint64_t remain_us = (time_target - current + 999) / 1000; + useconds_t us = remain_us >= 1000000 ? 999999 : remain_us; + usleep(us); + + current = os_gettime_ns(); + } while (time_target > current); + + return true; +} + void os_sleep_ms(uint32_t duration) { usleep(duration * 1000); diff --git a/libobs/util/platform-windows.c b/libobs/util/platform-windows.c index b3f66e828fc1dc..bc61c307c4aeb8 100644 --- a/libobs/util/platform-windows.c +++ b/libobs/util/platform-windows.c @@ -360,6 +360,24 @@ bool os_sleepto_ns(uint64_t time_target) return stall; } +bool os_sleepto_ns_fast(uint64_t time_target) +{ + uint64_t current = os_gettime_ns(); + if (time_target < current) + return false; + + do { + uint64_t remain_ms = (time_target - current) / 1000000; + if (!remain_ms) + remain_ms = 1; + Sleep((DWORD)remain_ms); + + current = os_gettime_ns(); + } while (time_target > current); + + return true; +} + void os_sleep_ms(uint32_t duration) { /* windows 8+ appears to have decreased sleep precision */ diff --git a/libobs/util/platform.h b/libobs/util/platform.h index 4759e60d56ebbb..9e5328de9b66e0 100644 --- a/libobs/util/platform.h +++ b/libobs/util/platform.h @@ -103,6 +103,7 @@ EXPORT void os_end_high_performance(os_performance_token_t *); * Returns false if already at or past target time. */ EXPORT bool os_sleepto_ns(uint64_t time_target); +EXPORT bool os_sleepto_ns_fast(uint64_t time_target); EXPORT void os_sleep_ms(uint32_t duration); EXPORT uint64_t os_gettime_ns(void);