static void add_audio_buffering(struct obs_core_audio *audio, size_t sample_rate, struct ts_info *ts, uint64_t min_ts) { struct ts_info new_ts; uint64_t offset; uint64_t frames; int ticks; if (audio->total_buffering_ticks == MAX_BUFFERING_TICKS) return; if (!audio->buffering_wait_ticks) audio->buffered_ts = ts->start; offset = ts->start - min_ts; frames = ns_to_audio_frames(sample_rate, offset); ticks = (int)((frames + AUDIO_OUTPUT_FRAMES - 1) / AUDIO_OUTPUT_FRAMES); audio->total_buffering_ticks += ticks; if (audio->total_buffering_ticks >= MAX_BUFFERING_TICKS) { ticks -= audio->total_buffering_ticks - MAX_BUFFERING_TICKS; audio->total_buffering_ticks = MAX_BUFFERING_TICKS; blog(LOG_WARNING, "Max audio buffering reached!"); } blog(LOG_INFO, "adding %d ticks of buffering, total buffering is " "now %d", ticks, audio->total_buffering_ticks); #if DEBUG_AUDIO == 1 blog(LOG_DEBUG, "min_ts (%"PRIu64") < start timestamp " "(%"PRIu64")", min_ts, ts->start); blog(LOG_DEBUG, "old buffered ts: %"PRIu64"-%"PRIu64, ts->start, ts->end); #endif new_ts.start = audio->buffered_ts - audio_frames_to_ns(sample_rate, audio->buffering_wait_ticks * AUDIO_OUTPUT_FRAMES); while (ticks--) { int cur_ticks = ++audio->buffering_wait_ticks; new_ts.end = new_ts.start; new_ts.start = audio->buffered_ts - audio_frames_to_ns( sample_rate, cur_ticks * AUDIO_OUTPUT_FRAMES); #if DEBUG_AUDIO == 1 blog(LOG_DEBUG, "add buffered ts: %"PRIu64"-%"PRIu64, new_ts.start, new_ts.end); #endif circlebuf_push_front(&audio->buffered_timestamps, &new_ts, sizeof(new_ts)); } *ts = new_ts; }
static void *audio_thread(void *param) { struct audio_output *audio = param; size_t rate = audio->info.samples_per_sec; 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"); const char *audio_thread_name = profile_store_name(obs_get_profiler_name_store(), "audio_thread(%s)", audio->info.name); while (os_event_try(audio->stop_event) == EAGAIN) { uint64_t cur_time; os_sleep_ms(audio_wait_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; } profile_end(audio_thread_name); profile_reenable_thread(); } return NULL; }