1 /******************************************************************************
2     Copyright (C) 2015 by Hugh Bailey <obs.jim@gmail.com>
3 
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation, either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
17 
18 #include <inttypes.h>
19 #include "obs-internal.h"
20 #include "util/util_uint64.h"
21 
22 struct ts_info {
23 	uint64_t start;
24 	uint64_t end;
25 };
26 
27 #define DEBUG_AUDIO 0
28 #define DEBUG_LAGGED_AUDIO 0
29 #define MAX_BUFFERING_TICKS 45
30 
push_audio_tree(obs_source_t * parent,obs_source_t * source,void * p)31 static void push_audio_tree(obs_source_t *parent, obs_source_t *source, void *p)
32 {
33 	struct obs_core_audio *audio = p;
34 
35 	if (da_find(audio->render_order, &source, 0) == DARRAY_INVALID) {
36 		obs_source_t *s = obs_source_get_ref(source);
37 		if (s)
38 			da_push_back(audio->render_order, &s);
39 	}
40 
41 	UNUSED_PARAMETER(parent);
42 }
43 
convert_time_to_frames(size_t sample_rate,uint64_t t)44 static inline size_t convert_time_to_frames(size_t sample_rate, uint64_t t)
45 {
46 	return (size_t)util_mul_div64(t, sample_rate, 1000000000ULL);
47 }
48 
mix_audio(struct audio_output_data * mixes,obs_source_t * source,size_t channels,size_t sample_rate,struct ts_info * ts)49 static inline void mix_audio(struct audio_output_data *mixes,
50 			     obs_source_t *source, size_t channels,
51 			     size_t sample_rate, struct ts_info *ts)
52 {
53 	size_t total_floats = AUDIO_OUTPUT_FRAMES;
54 	size_t start_point = 0;
55 
56 	if (source->audio_ts < ts->start || ts->end <= source->audio_ts)
57 		return;
58 
59 	if (source->audio_ts != ts->start) {
60 		start_point = convert_time_to_frames(
61 			sample_rate, source->audio_ts - ts->start);
62 		if (start_point == AUDIO_OUTPUT_FRAMES)
63 			return;
64 
65 		total_floats -= start_point;
66 	}
67 
68 	for (size_t mix_idx = 0; mix_idx < MAX_AUDIO_MIXES; mix_idx++) {
69 		for (size_t ch = 0; ch < channels; ch++) {
70 			register float *mix = mixes[mix_idx].data[ch];
71 			register float *aud =
72 				source->audio_output_buf[mix_idx][ch];
73 			register float *end;
74 
75 			mix += start_point;
76 			end = aud + total_floats;
77 
78 			while (aud < end)
79 				*(mix++) += *(aud++);
80 		}
81 	}
82 }
83 
ignore_audio(obs_source_t * source,size_t channels,size_t sample_rate,uint64_t start_ts)84 static bool ignore_audio(obs_source_t *source, size_t channels,
85 			 size_t sample_rate, uint64_t start_ts)
86 {
87 	size_t num_floats = source->audio_input_buf[0].size / sizeof(float);
88 	const char *name = obs_source_get_name(source);
89 
90 	if (!source->audio_ts && num_floats) {
91 #if DEBUG_LAGGED_AUDIO == 1
92 		blog(LOG_DEBUG, "[src: %s] no timestamp, but audio available?",
93 		     name);
94 #endif
95 		for (size_t ch = 0; ch < channels; ch++)
96 			circlebuf_pop_front(&source->audio_input_buf[ch], NULL,
97 					    source->audio_input_buf[0].size);
98 		source->last_audio_input_buf_size = 0;
99 		return false;
100 	}
101 
102 	if (num_floats) {
103 		/* round up the number of samples to drop */
104 		size_t drop =
105 			(size_t)util_mul_div64(start_ts - source->audio_ts - 1,
106 					       sample_rate, 1000000000ULL) +
107 			1;
108 		if (drop > num_floats)
109 			drop = num_floats;
110 
111 #if DEBUG_LAGGED_AUDIO == 1
112 		blog(LOG_DEBUG,
113 		     "[src: %s] ignored %" PRIu64 "/%" PRIu64 " samples", name,
114 		     (uint64_t)drop, (uint64_t)num_floats);
115 #endif
116 		for (size_t ch = 0; ch < channels; ch++)
117 			circlebuf_pop_front(&source->audio_input_buf[ch], NULL,
118 					    drop * sizeof(float));
119 
120 		source->last_audio_input_buf_size = 0;
121 		source->audio_ts +=
122 			util_mul_div64(drop, 1000000000ULL, sample_rate);
123 		blog(LOG_DEBUG, "[src: %s] ts lag after ignoring: %" PRIu64,
124 		     name, start_ts - source->audio_ts);
125 
126 		/* rounding error, adjust */
127 		if (source->audio_ts == (start_ts - 1))
128 			source->audio_ts = start_ts;
129 
130 		/* source is back in sync */
131 		if (source->audio_ts >= start_ts)
132 			return true;
133 	} else {
134 #if DEBUG_LAGGED_AUDIO == 1
135 		blog(LOG_DEBUG, "[src: %s] no samples to ignore! ts = %" PRIu64,
136 		     name, source->audio_ts);
137 #endif
138 	}
139 
140 	if (!source->audio_pending || num_floats) {
141 		blog(LOG_WARNING,
142 		     "Source %s audio is lagging (over by %.02f ms) "
143 		     "at max audio buffering. Restarting source audio.",
144 		     name, (start_ts - source->audio_ts) / 1000000.);
145 	}
146 
147 	source->audio_pending = true;
148 	source->audio_ts = 0;
149 	/* tell the timestamp adjustment code in source_output_audio_data to
150 	 * reset everything, and hopefully fix the timestamps */
151 	source->timing_set = false;
152 	return false;
153 }
154 
discard_if_stopped(obs_source_t * source,size_t channels)155 static bool discard_if_stopped(obs_source_t *source, size_t channels)
156 {
157 	size_t last_size;
158 	size_t size;
159 
160 	last_size = source->last_audio_input_buf_size;
161 	size = source->audio_input_buf[0].size;
162 
163 	if (!size)
164 		return false;
165 
166 	/* if perpetually pending data, it means the audio has stopped,
167 	 * so clear the audio data */
168 	if (last_size == size) {
169 		if (!source->pending_stop) {
170 			source->pending_stop = true;
171 #if DEBUG_AUDIO == 1
172 			blog(LOG_DEBUG, "doing pending stop trick: '%s'",
173 			     source->context.name);
174 #endif
175 			return false;
176 		}
177 
178 		for (size_t ch = 0; ch < channels; ch++)
179 			circlebuf_pop_front(&source->audio_input_buf[ch], NULL,
180 					    source->audio_input_buf[ch].size);
181 
182 		source->pending_stop = false;
183 		source->audio_ts = 0;
184 		source->last_audio_input_buf_size = 0;
185 #if DEBUG_AUDIO == 1
186 		blog(LOG_DEBUG, "source audio data appears to have "
187 				"stopped, clearing");
188 #endif
189 		return true;
190 	} else {
191 		source->last_audio_input_buf_size = size;
192 		return false;
193 	}
194 }
195 
196 #define MAX_AUDIO_SIZE (AUDIO_OUTPUT_FRAMES * sizeof(float))
197 
discard_audio(struct obs_core_audio * audio,obs_source_t * source,size_t channels,size_t sample_rate,struct ts_info * ts)198 static inline void discard_audio(struct obs_core_audio *audio,
199 				 obs_source_t *source, size_t channels,
200 				 size_t sample_rate, struct ts_info *ts)
201 {
202 	size_t total_floats = AUDIO_OUTPUT_FRAMES;
203 	size_t size;
204 	/* debug assert only */
205 	UNUSED_PARAMETER(audio);
206 
207 #if DEBUG_AUDIO == 1
208 	bool is_audio_source = source->info.output_flags & OBS_SOURCE_AUDIO;
209 #endif
210 
211 	if (source->info.audio_render) {
212 		source->audio_ts = 0;
213 		return;
214 	}
215 
216 	if (ts->end <= source->audio_ts) {
217 #if DEBUG_AUDIO == 1
218 		blog(LOG_DEBUG,
219 		     "can't discard, source "
220 		     "timestamp (%" PRIu64 ") >= "
221 		     "end timestamp (%" PRIu64 ")",
222 		     source->audio_ts, ts->end);
223 #endif
224 		return;
225 	}
226 
227 	if (source->audio_ts < (ts->start - 1)) {
228 		if (source->audio_pending &&
229 		    source->audio_input_buf[0].size < MAX_AUDIO_SIZE &&
230 		    discard_if_stopped(source, channels))
231 			return;
232 
233 #if DEBUG_AUDIO == 1
234 		if (is_audio_source) {
235 			blog(LOG_DEBUG,
236 			     "can't discard, source "
237 			     "timestamp (%" PRIu64 ") < "
238 			     "start timestamp (%" PRIu64 ")",
239 			     source->audio_ts, ts->start);
240 		}
241 
242 		/* ignore_audio should have already run and marked this source
243 		 * pending, unless we *just* added buffering */
244 		assert(audio->total_buffering_ticks < MAX_BUFFERING_TICKS ||
245 		       source->audio_pending || !source->audio_ts ||
246 		       audio->buffering_wait_ticks);
247 #endif
248 		return;
249 	}
250 
251 	if (source->audio_ts != ts->start &&
252 	    source->audio_ts != (ts->start - 1)) {
253 		size_t start_point = convert_time_to_frames(
254 			sample_rate, source->audio_ts - ts->start);
255 		if (start_point == AUDIO_OUTPUT_FRAMES) {
256 #if DEBUG_AUDIO == 1
257 			if (is_audio_source)
258 				blog(LOG_DEBUG, "can't discard, start point is "
259 						"at audio frame count");
260 #endif
261 			return;
262 		}
263 
264 		total_floats -= start_point;
265 	}
266 
267 	size = total_floats * sizeof(float);
268 
269 	if (source->audio_input_buf[0].size < size) {
270 		if (discard_if_stopped(source, channels))
271 			return;
272 
273 #if DEBUG_AUDIO == 1
274 		if (is_audio_source)
275 			blog(LOG_DEBUG, "can't discard, data still pending");
276 #endif
277 		source->audio_ts = ts->end;
278 		return;
279 	}
280 
281 	for (size_t ch = 0; ch < channels; ch++)
282 		circlebuf_pop_front(&source->audio_input_buf[ch], NULL, size);
283 
284 	source->last_audio_input_buf_size = 0;
285 
286 #if DEBUG_AUDIO == 1
287 	if (is_audio_source)
288 		blog(LOG_DEBUG, "audio discarded, new ts: %" PRIu64, ts->end);
289 #endif
290 
291 	source->pending_stop = false;
292 	source->audio_ts = ts->end;
293 }
294 
add_audio_buffering(struct obs_core_audio * audio,size_t sample_rate,struct ts_info * ts,uint64_t min_ts,const char * buffering_name)295 static void add_audio_buffering(struct obs_core_audio *audio,
296 				size_t sample_rate, struct ts_info *ts,
297 				uint64_t min_ts, const char *buffering_name)
298 {
299 	struct ts_info new_ts;
300 	uint64_t offset;
301 	uint64_t frames;
302 	size_t total_ms;
303 	size_t ms;
304 	int ticks;
305 
306 	if (audio->total_buffering_ticks == MAX_BUFFERING_TICKS)
307 		return;
308 
309 	if (!audio->buffering_wait_ticks)
310 		audio->buffered_ts = ts->start;
311 
312 	offset = ts->start - min_ts;
313 	frames = ns_to_audio_frames(sample_rate, offset);
314 	ticks = (int)((frames + AUDIO_OUTPUT_FRAMES - 1) / AUDIO_OUTPUT_FRAMES);
315 
316 	audio->total_buffering_ticks += ticks;
317 
318 	if (audio->total_buffering_ticks >= MAX_BUFFERING_TICKS) {
319 		ticks -= audio->total_buffering_ticks - MAX_BUFFERING_TICKS;
320 		audio->total_buffering_ticks = MAX_BUFFERING_TICKS;
321 		blog(LOG_WARNING, "Max audio buffering reached!");
322 	}
323 
324 	ms = ticks * AUDIO_OUTPUT_FRAMES * 1000 / sample_rate;
325 	total_ms = audio->total_buffering_ticks * AUDIO_OUTPUT_FRAMES * 1000 /
326 		   sample_rate;
327 
328 	blog(LOG_INFO,
329 	     "adding %d milliseconds of audio buffering, total "
330 	     "audio buffering is now %d milliseconds"
331 	     " (source: %s)\n",
332 	     (int)ms, (int)total_ms, buffering_name);
333 #if DEBUG_AUDIO == 1
334 	blog(LOG_DEBUG,
335 	     "min_ts (%" PRIu64 ") < start timestamp "
336 	     "(%" PRIu64 ")",
337 	     min_ts, ts->start);
338 	blog(LOG_DEBUG, "old buffered ts: %" PRIu64 "-%" PRIu64, ts->start,
339 	     ts->end);
340 #endif
341 
342 	new_ts.start =
343 		audio->buffered_ts -
344 		audio_frames_to_ns(sample_rate, audio->buffering_wait_ticks *
345 							AUDIO_OUTPUT_FRAMES);
346 
347 	while (ticks--) {
348 		const uint64_t cur_ticks = ++audio->buffering_wait_ticks;
349 
350 		new_ts.end = new_ts.start;
351 		new_ts.start =
352 			audio->buffered_ts -
353 			audio_frames_to_ns(sample_rate,
354 					   cur_ticks * AUDIO_OUTPUT_FRAMES);
355 
356 #if DEBUG_AUDIO == 1
357 		blog(LOG_DEBUG, "add buffered ts: %" PRIu64 "-%" PRIu64,
358 		     new_ts.start, new_ts.end);
359 #endif
360 
361 		circlebuf_push_front(&audio->buffered_timestamps, &new_ts,
362 				     sizeof(new_ts));
363 	}
364 
365 	*ts = new_ts;
366 }
367 
audio_buffer_insuffient(struct obs_source * source,size_t sample_rate,uint64_t min_ts)368 static bool audio_buffer_insuffient(struct obs_source *source,
369 				    size_t sample_rate, uint64_t min_ts)
370 {
371 	size_t total_floats = AUDIO_OUTPUT_FRAMES;
372 	size_t size;
373 
374 	if (source->info.audio_render || source->audio_pending ||
375 	    !source->audio_ts) {
376 		return false;
377 	}
378 
379 	if (source->audio_ts != min_ts && source->audio_ts != (min_ts - 1)) {
380 		size_t start_point = convert_time_to_frames(
381 			sample_rate, source->audio_ts - min_ts);
382 		if (start_point >= AUDIO_OUTPUT_FRAMES)
383 			return false;
384 
385 		total_floats -= start_point;
386 	}
387 
388 	size = total_floats * sizeof(float);
389 
390 	if (source->audio_input_buf[0].size < size) {
391 		source->audio_pending = true;
392 		return true;
393 	}
394 
395 	return false;
396 }
397 
find_min_ts(struct obs_core_data * data,uint64_t * min_ts)398 static inline const char *find_min_ts(struct obs_core_data *data,
399 				      uint64_t *min_ts)
400 {
401 	obs_source_t *buffering_source = NULL;
402 	struct obs_source *source = data->first_audio_source;
403 	while (source) {
404 		if (!source->audio_pending && source->audio_ts &&
405 		    source->audio_ts < *min_ts) {
406 			*min_ts = source->audio_ts;
407 			buffering_source = source;
408 		}
409 
410 		source = (struct obs_source *)source->next_audio_source;
411 	}
412 	return buffering_source ? obs_source_get_name(buffering_source) : NULL;
413 }
414 
mark_invalid_sources(struct obs_core_data * data,size_t sample_rate,uint64_t min_ts)415 static inline bool mark_invalid_sources(struct obs_core_data *data,
416 					size_t sample_rate, uint64_t min_ts)
417 {
418 	bool recalculate = false;
419 
420 	struct obs_source *source = data->first_audio_source;
421 	while (source) {
422 		recalculate |=
423 			audio_buffer_insuffient(source, sample_rate, min_ts);
424 		source = (struct obs_source *)source->next_audio_source;
425 	}
426 
427 	return recalculate;
428 }
429 
calc_min_ts(struct obs_core_data * data,size_t sample_rate,uint64_t * min_ts)430 static inline const char *calc_min_ts(struct obs_core_data *data,
431 				      size_t sample_rate, uint64_t *min_ts)
432 {
433 	const char *buffering_name = find_min_ts(data, min_ts);
434 	if (mark_invalid_sources(data, sample_rate, *min_ts))
435 		buffering_name = find_min_ts(data, min_ts);
436 	return buffering_name;
437 }
438 
release_audio_sources(struct obs_core_audio * audio)439 static inline void release_audio_sources(struct obs_core_audio *audio)
440 {
441 	for (size_t i = 0; i < audio->render_order.num; i++)
442 		obs_source_release(audio->render_order.array[i]);
443 }
444 
audio_callback(void * param,uint64_t start_ts_in,uint64_t end_ts_in,uint64_t * out_ts,uint32_t mixers,struct audio_output_data * mixes)445 bool audio_callback(void *param, uint64_t start_ts_in, uint64_t end_ts_in,
446 		    uint64_t *out_ts, uint32_t mixers,
447 		    struct audio_output_data *mixes)
448 {
449 	struct obs_core_data *data = &obs->data;
450 	struct obs_core_audio *audio = &obs->audio;
451 	struct obs_source *source;
452 	size_t sample_rate = audio_output_get_sample_rate(audio->audio);
453 	size_t channels = audio_output_get_channels(audio->audio);
454 	struct ts_info ts = {start_ts_in, end_ts_in};
455 	size_t audio_size;
456 	uint64_t min_ts;
457 
458 	da_resize(audio->render_order, 0);
459 	da_resize(audio->root_nodes, 0);
460 
461 	circlebuf_push_back(&audio->buffered_timestamps, &ts, sizeof(ts));
462 	circlebuf_peek_front(&audio->buffered_timestamps, &ts, sizeof(ts));
463 	min_ts = ts.start;
464 
465 	audio_size = AUDIO_OUTPUT_FRAMES * sizeof(float);
466 
467 #if DEBUG_AUDIO == 1
468 	blog(LOG_DEBUG, "ts %llu-%llu", ts.start, ts.end);
469 #endif
470 
471 	/* ------------------------------------------------ */
472 	/* build audio render order
473 	 * NOTE: these are source channels, not audio channels */
474 	for (uint32_t i = 0; i < MAX_CHANNELS; i++) {
475 		obs_source_t *source = obs_get_output_source(i);
476 		if (source) {
477 			obs_source_enum_active_tree(source, push_audio_tree,
478 						    audio);
479 			push_audio_tree(NULL, source, audio);
480 			da_push_back(audio->root_nodes, &source);
481 			obs_source_release(source);
482 		}
483 	}
484 
485 	pthread_mutex_lock(&data->audio_sources_mutex);
486 
487 	source = data->first_audio_source;
488 	while (source) {
489 		push_audio_tree(NULL, source, audio);
490 		source = (struct obs_source *)source->next_audio_source;
491 	}
492 
493 	pthread_mutex_unlock(&data->audio_sources_mutex);
494 
495 	/* ------------------------------------------------ */
496 	/* render audio data */
497 	for (size_t i = 0; i < audio->render_order.num; i++) {
498 		obs_source_t *source = audio->render_order.array[i];
499 		obs_source_audio_render(source, mixers, channels, sample_rate,
500 					audio_size);
501 
502 		/* if a source has gone backward in time and we can no
503 		 * longer buffer, drop some or all of its audio */
504 		if (audio->total_buffering_ticks == MAX_BUFFERING_TICKS &&
505 		    source->audio_ts < ts.start) {
506 			if (source->info.audio_render) {
507 				blog(LOG_DEBUG,
508 				     "render audio source %s timestamp has "
509 				     "gone backwards",
510 				     obs_source_get_name(source));
511 
512 				/* just avoid further damage */
513 				source->audio_pending = true;
514 #if DEBUG_AUDIO == 1
515 				/* this should really be fixed */
516 				assert(false);
517 #endif
518 			} else {
519 				pthread_mutex_lock(&source->audio_buf_mutex);
520 				bool rerender = ignore_audio(source, channels,
521 							     sample_rate,
522 							     ts.start);
523 				pthread_mutex_unlock(&source->audio_buf_mutex);
524 
525 				/* if we (potentially) recovered, re-render */
526 				if (rerender)
527 					obs_source_audio_render(source, mixers,
528 								channels,
529 								sample_rate,
530 								audio_size);
531 			}
532 		}
533 	}
534 
535 	/* ------------------------------------------------ */
536 	/* get minimum audio timestamp */
537 	pthread_mutex_lock(&data->audio_sources_mutex);
538 	const char *buffering_name = calc_min_ts(data, sample_rate, &min_ts);
539 	pthread_mutex_unlock(&data->audio_sources_mutex);
540 
541 	/* ------------------------------------------------ */
542 	/* if a source has gone backward in time, buffer */
543 	if (min_ts < ts.start)
544 		add_audio_buffering(audio, sample_rate, &ts, min_ts,
545 				    buffering_name);
546 
547 	/* ------------------------------------------------ */
548 	/* mix audio */
549 	if (!audio->buffering_wait_ticks) {
550 		for (size_t i = 0; i < audio->root_nodes.num; i++) {
551 			obs_source_t *source = audio->root_nodes.array[i];
552 
553 			if (source->audio_pending)
554 				continue;
555 
556 			pthread_mutex_lock(&source->audio_buf_mutex);
557 
558 			if (source->audio_output_buf[0][0] && source->audio_ts)
559 				mix_audio(mixes, source, channels, sample_rate,
560 					  &ts);
561 
562 			pthread_mutex_unlock(&source->audio_buf_mutex);
563 		}
564 	}
565 
566 	/* ------------------------------------------------ */
567 	/* discard audio */
568 	pthread_mutex_lock(&data->audio_sources_mutex);
569 
570 	source = data->first_audio_source;
571 	while (source) {
572 		pthread_mutex_lock(&source->audio_buf_mutex);
573 		discard_audio(audio, source, channels, sample_rate, &ts);
574 		pthread_mutex_unlock(&source->audio_buf_mutex);
575 
576 		source = (struct obs_source *)source->next_audio_source;
577 	}
578 
579 	pthread_mutex_unlock(&data->audio_sources_mutex);
580 
581 	/* ------------------------------------------------ */
582 	/* release audio sources */
583 	release_audio_sources(audio);
584 
585 	circlebuf_pop_front(&audio->buffered_timestamps, NULL, sizeof(ts));
586 
587 	*out_ts = ts.start;
588 
589 	if (audio->buffering_wait_ticks) {
590 		audio->buffering_wait_ticks--;
591 		return false;
592 	}
593 
594 	UNUSED_PARAMETER(param);
595 	return true;
596 }
597