コード例 #1
0
bool obs_transition_audio_render(obs_source_t *transition,
                                 uint64_t *ts_out, struct obs_source_audio_mix *audio,
                                 uint32_t mixers, size_t channels, size_t sample_rate,
                                 obs_transition_audio_mix_callback_t mix_a,
                                 obs_transition_audio_mix_callback_t mix_b)
{
    obs_source_t *sources[2];
    struct transition_state state = {0};
    bool stopped = false;
    uint64_t min_ts;
    float t;

    if (!transition_valid(transition, "obs_transition_audio_render"))
        return false;

    lock_transition(transition);

    sources[0] = transition->transition_sources[0];
    sources[1] = transition->transition_sources[1];

    min_ts = calc_min_ts(sources);

    if (min_ts) {
        t = calc_time(transition, min_ts);

        if (t >= 1.0f && transition->transitioning_audio)
            stopped = stop_audio(transition);

        sources[0] = transition->transition_sources[0];
        sources[1] = transition->transition_sources[1];
        min_ts = calc_min_ts(sources);
        if (min_ts)
            copy_transition_state(transition, &state);

    } else if (transition->transitioning_audio) {
        stopped = stop_audio(transition);
    }

    unlock_transition(transition);

    if (min_ts) {
        if (state.transitioning_audio) {
            if (state.s[0])
                process_audio(transition, state.s[0], audio,
                              min_ts, mixers, channels,
                              sample_rate, mix_a);
            if (state.s[1])
                process_audio(transition, state.s[1], audio,
                              min_ts, mixers, channels,
                              sample_rate, mix_b);
        } else if (state.s[0]) {
            memcpy(audio->output[0].data[0],
                   state.s[0]->audio_output_buf[0][0],
                   TOTAL_AUDIO_SIZE);
        }

        obs_source_release(state.s[0]);
        obs_source_release(state.s[1]);
    }

    if (stopped)
        obs_source_dosignal(transition, "source_transition_stop",
                            "transition_stop");

    *ts_out = min_ts;
    return !!min_ts;
}
コード例 #2
0
ファイル: obs-audio.c プロジェクト: ab22/obs-studio
bool 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)
{
	struct obs_core_data *data = &obs->data;
	struct obs_core_audio *audio = &obs->audio;
	struct obs_source *source;
	size_t sample_rate = audio_output_get_sample_rate(audio->audio);
	size_t channels = audio_output_get_channels(audio->audio);
	struct ts_info ts = {start_ts_in, end_ts_in};
	size_t audio_size;
	uint64_t min_ts;

	da_resize(audio->render_order, 0);
	da_resize(audio->root_nodes, 0);

	circlebuf_push_back(&audio->buffered_timestamps, &ts, sizeof(ts));
	circlebuf_peek_front(&audio->buffered_timestamps, &ts, sizeof(ts));
	min_ts = ts.start;

	audio_size = AUDIO_OUTPUT_FRAMES * sizeof(float);

#if DEBUG_AUDIO == 1
	blog(LOG_DEBUG, "ts %llu-%llu", ts.start, ts.end);
#endif

	/* ------------------------------------------------ */
	/* build audio render order
	 * NOTE: these are source channels, not audio channels */
	for (uint32_t i = 0; i < MAX_CHANNELS; i++) {
		obs_source_t *source = obs_get_output_source(i);
		if (source) {
			obs_source_enum_active_tree(source, push_audio_tree,
					audio);
			push_audio_tree(NULL, source, audio);
			da_push_back(audio->root_nodes, &source);
			obs_source_release(source);
		}
	}

	pthread_mutex_lock(&data->audio_sources_mutex);

	source = data->first_audio_source;
	while (source) {
		push_audio_tree(NULL, source, audio);
		source = (struct obs_source*)source->next_audio_source;
	}

	pthread_mutex_unlock(&data->audio_sources_mutex);

	/* ------------------------------------------------ */
	/* render audio data */
	for (size_t i = 0; i < audio->render_order.num; i++) {
		obs_source_t *source = audio->render_order.array[i];
		obs_source_audio_render(source, mixers, channels, sample_rate,
				audio_size);
	}

	/* ------------------------------------------------ */
	/* get minimum audio timestamp */
	pthread_mutex_lock(&data->audio_sources_mutex);
	calc_min_ts(data, sample_rate, &min_ts);
	pthread_mutex_unlock(&data->audio_sources_mutex);

	/* ------------------------------------------------ */
	/* if a source has gone backward in time, buffer */
	if (min_ts < ts.start)
		add_audio_buffering(audio, sample_rate, &ts, min_ts);

	/* ------------------------------------------------ */
	/* mix audio */
	if (!audio->buffering_wait_ticks) {
		for (size_t i = 0; i < audio->root_nodes.num; i++) {
			obs_source_t *source = audio->root_nodes.array[i];

			if (source->audio_pending)
				continue;

			pthread_mutex_lock(&source->audio_buf_mutex);

			if (source->audio_output_buf[0][0] && source->audio_ts)
				mix_audio(mixes, source, channels, sample_rate,
						&ts);

			pthread_mutex_unlock(&source->audio_buf_mutex);
		}
	}

	/* ------------------------------------------------ */
	/* discard audio */
	pthread_mutex_lock(&data->audio_sources_mutex);

	source = data->first_audio_source;
	while (source) {
		pthread_mutex_lock(&source->audio_buf_mutex);
		discard_audio(audio, source, channels, sample_rate, &ts);
		pthread_mutex_unlock(&source->audio_buf_mutex);

		source = (struct obs_source*)source->next_audio_source;
	}

	pthread_mutex_unlock(&data->audio_sources_mutex);

	/* ------------------------------------------------ */
	/* release audio sources */
	release_audio_sources(audio);

	circlebuf_pop_front(&audio->buffered_timestamps, NULL, sizeof(ts));

	*out_ts = ts.start;

	if (audio->buffering_wait_ticks) {
		audio->buffering_wait_ticks--;
		return false;
	}

	UNUSED_PARAMETER(param);
	return true;
}