static void process_audio(obs_source_t *transition, obs_source_t *child,
                          struct obs_source_audio_mix *audio, uint64_t min_ts,
                          uint32_t mixers, size_t channels, size_t sample_rate,
                          obs_transition_audio_mix_callback_t mix)
{
    bool valid = child && !child->audio_pending;
    struct obs_source_audio_mix child_audio;
    uint64_t ts;
    size_t pos;

    if (!valid)
        return;

    ts = child->audio_ts;
    obs_source_get_audio_mix(child, &child_audio);

    for (size_t mix_idx = 0; mix_idx < MAX_AUDIO_MIXES; mix_idx++) {
        struct audio_output_data *output = &audio->output[mix_idx];
        struct audio_output_data *input = &child_audio.output[mix_idx];

        if ((mixers & (1 << mix_idx)) == 0)
            continue;

        pos = (size_t)ns_to_audio_frames(sample_rate, ts - min_ts);

        for (size_t ch = 0; ch < channels; ch++) {
            float *out = output->data[ch];
            float *in = input->data[ch];

            mix_child(transition, out + pos, in,
                      AUDIO_OUTPUT_FRAMES - pos,
                      sample_rate, ts, mix);
        }
    }
}
示例#2
0
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;
}
示例#3
0
static bool scene_audio_render(void *data, uint64_t *ts_out,
		struct obs_source_audio_mix *audio_output, uint32_t mixers,
		size_t channels, size_t sample_rate)
{
	uint64_t timestamp = 0;
	float *buf = NULL;
	struct obs_source_audio_mix child_audio;
	struct obs_scene *scene = data;
	struct obs_scene_item *item;

	audio_lock(scene);

	item = scene->first_item;
	while (item) {
		if (!obs_source_audio_pending(item->source)) {
			uint64_t source_ts =
				obs_source_get_audio_timestamp(item->source);

			if (!timestamp || source_ts < timestamp)
				timestamp = source_ts;
		}

		item = item->next;
	}

	if (!timestamp) {
		/* just process all pending audio actions if no audio playing,
		 * otherwise audio actions will just never be processed */
		item = scene->first_item;
		while (item) {
			process_all_audio_actions(item, sample_rate);
			item = item->next;
		}

		audio_unlock(scene);
		return false;
	}

	item = scene->first_item;
	while (item) {
		uint64_t source_ts;
		size_t pos, count;
		bool apply_buf;

		apply_buf = apply_scene_item_volume(item, &buf, timestamp,
				sample_rate);

		if (obs_source_audio_pending(item->source)) {
			item = item->next;
			continue;
		}

		source_ts = obs_source_get_audio_timestamp(item->source);
		pos = (size_t)ns_to_audio_frames(sample_rate,
				source_ts - timestamp);
		count = AUDIO_OUTPUT_FRAMES - pos;

		if (!apply_buf && !item->visible) {
			item = item->next;
			continue;
		}

		obs_source_get_audio_mix(item->source, &child_audio);
		for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
			if ((mixers & (1 << mix)) == 0)
				continue;

			for (size_t ch = 0; ch < channels; ch++) {
				float *out = audio_output->output[mix].data[ch];
				float *in = child_audio.output[mix].data[ch];

				if (apply_buf)
					mix_audio_with_buf(out, in, buf, pos,
							count);
				else
					mix_audio(out, in, pos, count);
			}
		}

		item = item->next;
	}

	*ts_out = timestamp;
	audio_unlock(scene);

	free(buf);
	return true;
}