diff --git a/libobs/obs-source.c b/libobs/obs-source.c index e7175f29b..525fd3de9 100644 --- a/libobs/obs-source.c +++ b/libobs/obs-source.c @@ -324,8 +324,23 @@ void obs_source_video_tick(obs_source_t source, float seconds) source->callbacks.video_tick(source->data, seconds); } +static inline uint64_t conv_frames_to_time(obs_source_t source, size_t frames) +{ + const struct audio_info *info = audio_output_getinfo(obs->audio.audio); + double sps_to_ns = 1000000000.0 / (double)info->samples_per_sec; + return (uint64_t)((double)frames * sps_to_ns); +} + /* maximum "direct" timestamp variance in nanoseconds */ -#define MAX_VARIANCE 2000000000ULL +#define MAX_TS_VAR 2000000000ULL +/* maximum time that timestamp can jump in nanoseconds */ +#define MAX_TIMESTAMP_JUMP 500000000ULL + +static inline void reset_audio_timing(obs_source_t source, uint64_t timetamp) +{ + source->timing_set = true; + source->timing_adjust = os_gettime_ns() - timetamp; +} static void source_output_audio_line(obs_source_t source, const struct audio_data *data) @@ -333,15 +348,29 @@ static void source_output_audio_line(obs_source_t source, struct audio_data in = *data; if (!source->timing_set) { - source->timing_set = true; - source->timing_adjust = os_gettime_ns() - in.timestamp; + reset_audio_timing(source, in.timestamp); /* detects 'directly' set timestamps as long as they're within * a certain threshold */ - if ((source->timing_adjust+MAX_VARIANCE) < MAX_VARIANCE*2) + if ((source->timing_adjust + MAX_TS_VAR) < MAX_TS_VAR * 2) source->timing_adjust = 0; + } else { + uint64_t time_diff = + data->timestamp - source->next_audio_timestamp_min; + + /* don't need signed because negative will trigger it + * regardless, which is what we want */ + if (time_diff > MAX_TIMESTAMP_JUMP) { + blog(LOG_DEBUG, "Audio timestamp for source '%s' " + "jumped by '%lld', resetting audio " + "timing", source->name, time_diff); + reset_audio_timing(source, in.timestamp); + } } + source->next_audio_timestamp_min = in.timestamp + + conv_frames_to_time(source, in.frames); + in.timestamp += source->timing_adjust; in.volume = source->volume; audio_line_output(source->audio_line, &in); diff --git a/libobs/obs-source.h b/libobs/obs-source.h index 825aafc33..ed0ef9bb6 100644 --- a/libobs/obs-source.h +++ b/libobs/obs-source.h @@ -223,6 +223,7 @@ struct obs_source { /* timing (if video is present, is based upon video) */ bool timing_set; uint64_t timing_adjust; + uint64_t next_audio_timestamp_min; uint64_t last_frame_timestamp; uint64_t last_sys_timestamp;