Пример #1
0
/**
 * Start recording
 *
 * We request the default format used by pulse here because the data will be
 * converted and possibly re-sampled by obs anyway.
 *
 * For now we request a buffer length of 25ms although pulse seems to ignore
 * this setting for monitor streams. For "real" input streams this should work
 * fine though.
 */
static int_fast32_t pulse_start_recording(struct pulse_data *data)
{
	if (pulse_get_server_info(pulse_server_info, (void *) data) < 0) {
		blog(LOG_ERROR, "Unable to get server info !");
		return -1;
	}

	if (pulse_get_source_info(pulse_source_info, data->device,
			(void *) data) < 0) {
		blog(LOG_ERROR, "Unable to get source info !");
		return -1;
	}

	pa_sample_spec spec;
	spec.format   = data->format;
	spec.rate     = data->samples_per_sec;
	spec.channels = data->channels;

	if (!pa_sample_spec_valid(&spec)) {
		blog(LOG_ERROR, "Sample spec is not valid");
		return -1;
	}

	data->speakers = pulse_channels_to_obs_speakers(spec.channels);
	data->bytes_per_frame = pa_frame_size(&spec);

	data->stream = pulse_stream_new(obs_source_get_name(data->source),
		&spec, NULL);
	if (!data->stream) {
		blog(LOG_ERROR, "Unable to create stream");
		return -1;
	}

	pulse_lock();
	pa_stream_set_read_callback(data->stream, pulse_stream_read,
		(void *) data);
	pulse_unlock();

	pa_buffer_attr attr;
	attr.fragsize  = pa_usec_to_bytes(25000, &spec);
	attr.maxlength = (uint32_t) -1;
	attr.minreq    = (uint32_t) -1;
	attr.prebuf    = (uint32_t) -1;
	attr.tlength   = (uint32_t) -1;

	pa_stream_flags_t flags = PA_STREAM_ADJUST_LATENCY;

	pulse_lock();
	int_fast32_t ret = pa_stream_connect_record(data->stream, data->device,
		&attr, flags);
	pulse_unlock();
	if (ret < 0) {
		pulse_stop_recording(data);
		blog(LOG_ERROR, "Unable to connect to stream");
		return -1;
	}

	blog(LOG_INFO, "Started recording from '%s'", data->device);
	return 0;
}
Пример #2
0
/*
 * start recording
 */
static int_fast32_t pulse_start_recording(struct pulse_data *data)
{
	if (pulse_get_server_info(pulse_server_info, (void *) data) < 0) {
		blog(LOG_ERROR, "pulse-input: Unable to get server info !");
		return -1;
	}

	pa_sample_spec spec;
	spec.format   = data->format;
	spec.rate     = data->samples_per_sec;
	spec.channels = data->channels;

	if (!pa_sample_spec_valid(&spec)) {
		blog(LOG_ERROR, "pulse-input: Sample spec is not valid");
		return -1;
	}

	data->bytes_per_frame = pa_frame_size(&spec);
	blog(LOG_DEBUG, "pulse-input: %u bytes per frame",
	     (unsigned int) data->bytes_per_frame);

	data->stream = pulse_stream_new(obs_source_getname(data->source),
		&spec, NULL);
	if (!data->stream) {
		blog(LOG_ERROR, "pulse-input: Unable to create stream");
		return -1;
	}

	pulse_lock();
	pa_stream_set_read_callback(data->stream, pulse_stream_read,
		(void *) data);
	pulse_unlock();

	pa_buffer_attr attr;
	attr.fragsize  = get_buffer_size(data, 250);
	attr.maxlength = (uint32_t) -1;
	attr.minreq    = (uint32_t) -1;
	attr.prebuf    = (uint32_t) -1;
	attr.tlength   = (uint32_t) -1;

	pa_stream_flags_t flags =
		PA_STREAM_INTERPOLATE_TIMING
		| PA_STREAM_AUTO_TIMING_UPDATE
		| PA_STREAM_ADJUST_LATENCY;

	pulse_lock();
	int_fast32_t ret = pa_stream_connect_record(data->stream, data->device,
		&attr, flags);
	pulse_unlock();
	if (ret < 0) {
		blog(LOG_ERROR, "pulse-input: Unable to connect to stream");
		return -1;
	}

	blog(LOG_DEBUG, "pulse-input: Recording started");
	return 0;
}
Пример #3
0
/**
 * wait for context to be ready
 */
static int_fast32_t pulse_context_ready()
{
	pulse_lock();

	if (!PA_CONTEXT_IS_GOOD(pa_context_get_state(pulse_context))) {
		pulse_unlock();
		return -1;
	}

	while (pa_context_get_state(pulse_context) != PA_CONTEXT_READY)
		pulse_wait();

	pulse_unlock();
	return 0;
}
Пример #4
0
/*
 * stop recording
 */
static void pulse_stop_recording(struct pulse_data *data)
{
	if (data->stream) {
		pulse_lock();
		pa_stream_disconnect(data->stream);
		pa_stream_unref(data->stream);
		pulse_unlock();
	}
}
Пример #5
0
/**
 * Initialize the pulse audio context with properties and callback
 */
static void pulse_init_context()
{
	pulse_lock();

	pa_proplist *p = pulse_properties();
	pulse_context = pa_context_new_with_proplist(
		pa_threaded_mainloop_get_api(pulse_mainloop), "OBS", p);

	pa_context_set_state_callback(pulse_context,
		pulse_context_state_changed, NULL);

	pa_context_connect(pulse_context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL);
	pa_proplist_free(p);

	pulse_unlock();
}
Пример #6
0
pa_stream* pulse_stream_new(const char* name, const pa_sample_spec* ss,
	const pa_channel_map* map)
{
	if (pulse_context_ready() < 0)
		return NULL;

	pulse_lock();

	pa_proplist *p = pulse_properties();
	pa_stream *s = pa_stream_new_with_proplist(
		pulse_context, name, ss, map, p);
	pa_proplist_free(p);

	pulse_unlock();
	return s;
}
Пример #7
0
int_fast32_t pulse_get_server_info(pa_server_info_cb_t cb, void* userdata)
{
	if (pulse_context_ready() < 0)
		return -1;

	pulse_lock();

	pa_operation *op = pa_context_get_server_info(
		pulse_context, cb, userdata);
	while (pa_operation_get_state(op) == PA_OPERATION_RUNNING)
		pulse_wait();
	pa_operation_unref(op);

	pulse_unlock();
	return 0;
}
Пример #8
0
/**
 * stop recording
 */
static void pulse_stop_recording(struct pulse_data *data)
{
	if (data->stream) {
		pulse_lock();
		pa_stream_disconnect(data->stream);
		pa_stream_unref(data->stream);
		data->stream = NULL;
		pulse_unlock();
	}

	blog(LOG_INFO, "Stopped recording from '%s'", data->device);
	blog(LOG_INFO, "Got %"PRIuFAST32" packets with %"PRIuFAST64" frames",
		data->packets, data->frames);

	data->first_ts = 0;
	data->packets = 0;
	data->frames = 0;
}
Пример #9
0
void pulse_unref()
{
	pthread_mutex_lock(&pulse_mutex);

	if (--pulse_refs == 0) {
		pulse_lock();
		if (pulse_context != NULL) {
			pa_context_disconnect(pulse_context);
			pa_context_unref(pulse_context);
			pulse_context = NULL;
		}
		pulse_unlock();

		if (pulse_mainloop != NULL) {
			pa_threaded_mainloop_stop(pulse_mainloop);
			pa_threaded_mainloop_free(pulse_mainloop);
			pulse_mainloop = NULL;
		}
	}

	pthread_mutex_unlock(&pulse_mutex);
}