2
0
Эх сурвалжийг харах

Added support for single channel inputs for PulseAudio

Marcelo Fernandez 7 жил өмнө
parent
commit
913eec5b04

+ 61 - 19
drivers/pulseaudio/audio_driver_pulseaudio.cpp

@@ -64,18 +64,32 @@ void AudioDriverPulseAudio::pa_sink_info_cb(pa_context *c, const pa_sink_info *l
 	ad->pa_status++;
 	ad->pa_status++;
 }
 }
 
 
+void AudioDriverPulseAudio::pa_source_info_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata) {
+	AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata;
+
+	// If eol is set to a positive number, you're at the end of the list
+	if (eol > 0) {
+		return;
+	}
+
+	ad->pa_rec_map = l->channel_map;
+	ad->pa_status++;
+}
+
 void AudioDriverPulseAudio::pa_server_info_cb(pa_context *c, const pa_server_info *i, void *userdata) {
 void AudioDriverPulseAudio::pa_server_info_cb(pa_context *c, const pa_server_info *i, void *userdata) {
 	AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata;
 	AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata;
 
 
+	ad->capture_default_device = i->default_source_name;
 	ad->default_device = i->default_sink_name;
 	ad->default_device = i->default_sink_name;
 	ad->pa_status++;
 	ad->pa_status++;
 }
 }
 
 
-void AudioDriverPulseAudio::detect_channels() {
+void AudioDriverPulseAudio::detect_channels(bool capture) {
 
 
-	pa_channel_map_init_stereo(&pa_map);
+	pa_channel_map_init_stereo(capture ? &pa_rec_map : &pa_map);
 
 
-	if (device_name == "Default") {
+	String device = capture ? capture_device_name : device_name;
+	if (device == "Default") {
 		// Get the default output device name
 		// Get the default output device name
 		pa_status = 0;
 		pa_status = 0;
 		pa_operation *pa_op = pa_context_get_server_info(pa_ctx, &AudioDriverPulseAudio::pa_server_info_cb, (void *)this);
 		pa_operation *pa_op = pa_context_get_server_info(pa_ctx, &AudioDriverPulseAudio::pa_server_info_cb, (void *)this);
@@ -93,16 +107,22 @@ void AudioDriverPulseAudio::detect_channels() {
 		}
 		}
 	}
 	}
 
 
-	char device[1024];
-	if (device_name == "Default") {
-		strcpy(device, default_device.utf8().get_data());
+	char dev[1024];
+	if (device == "Default") {
+		strcpy(dev, capture ? capture_default_device.utf8().get_data() : default_device.utf8().get_data());
 	} else {
 	} else {
-		strcpy(device, device_name.utf8().get_data());
+		strcpy(dev, device.utf8().get_data());
 	}
 	}
 
 
 	// Now using the device name get the amount of channels
 	// Now using the device name get the amount of channels
 	pa_status = 0;
 	pa_status = 0;
-	pa_operation *pa_op = pa_context_get_sink_info_by_name(pa_ctx, device, &AudioDriverPulseAudio::pa_sink_info_cb, (void *)this);
+	pa_operation *pa_op;
+	if (capture) {
+		pa_op = pa_context_get_source_info_by_name(pa_ctx, dev, &AudioDriverPulseAudio::pa_source_info_cb, (void *)this);
+	} else {
+		pa_op = pa_context_get_sink_info_by_name(pa_ctx, dev, &AudioDriverPulseAudio::pa_sink_info_cb, (void *)this);
+	}
+
 	if (pa_op) {
 	if (pa_op) {
 		while (pa_status == 0) {
 		while (pa_status == 0) {
 			int ret = pa_mainloop_iterate(pa_ml, 1, NULL);
 			int ret = pa_mainloop_iterate(pa_ml, 1, NULL);
@@ -113,7 +133,11 @@ void AudioDriverPulseAudio::detect_channels() {
 
 
 		pa_operation_unref(pa_op);
 		pa_operation_unref(pa_op);
 	} else {
 	} else {
-		ERR_PRINT("pa_context_get_sink_info_by_name error");
+		if (capture) {
+			ERR_PRINT("pa_context_get_source_info_by_name error");
+		} else {
+			ERR_PRINT("pa_context_get_sink_info_by_name error");
+		}
 	}
 	}
 }
 }
 
 
@@ -195,6 +219,10 @@ Error AudioDriverPulseAudio::init_device() {
 	samples_in.resize(buffer_frames * channels);
 	samples_in.resize(buffer_frames * channels);
 	samples_out.resize(pa_buffer_size);
 	samples_out.resize(pa_buffer_size);
 
 
+	// Reset audio input to keep synchronisation.
+	input_position = 0;
+	input_size = 0;
+
 	return OK;
 	return OK;
 }
 }
 
 
@@ -389,9 +417,12 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
 				} else {
 				} else {
 					int16_t *srcptr = (int16_t *)ptr;
 					int16_t *srcptr = (int16_t *)ptr;
 					for (size_t i = bytes >> 1; i > 0; i--) {
 					for (size_t i = bytes >> 1; i > 0; i--) {
-						ad->input_buffer.write[ad->input_position++] = int32_t(*srcptr++) << 16;
-						if (ad->input_position >= ad->input_buffer.size()) {
-							ad->input_position = 0;
+						int32_t sample = int32_t(*srcptr++) << 16;
+						ad->input_buffer_write(sample);
+
+						if (ad->pa_rec_map.channels == 1) {
+							// In case input device is single channel convert it to Stereo
+							ad->input_buffer_write(sample);
 						}
 						}
 					}
 					}
 
 
@@ -571,10 +602,26 @@ Error AudioDriverPulseAudio::capture_init_device() {
 		}
 		}
 	}
 	}
 
 
+	detect_channels(true);
+	switch (pa_rec_map.channels) {
+		case 1: // Mono
+		case 2: // Stereo
+			break;
+
+		default:
+			WARN_PRINTS("PulseAudio: Unsupported number of input channels: " + itos(pa_rec_map.channels));
+			pa_channel_map_init_stereo(&pa_rec_map);
+			break;
+	}
+
+	if (OS::get_singleton()->is_stdout_verbose()) {
+		print_line("PulseAudio: detected " + itos(pa_rec_map.channels) + " input channels");
+	}
+
 	pa_sample_spec spec;
 	pa_sample_spec spec;
 
 
 	spec.format = PA_SAMPLE_S16LE;
 	spec.format = PA_SAMPLE_S16LE;
-	spec.channels = 2;
+	spec.channels = pa_rec_map.channels;
 	spec.rate = mix_rate;
 	spec.rate = mix_rate;
 
 
 	int latency = 30;
 	int latency = 30;
@@ -584,9 +631,6 @@ Error AudioDriverPulseAudio::capture_init_device() {
 	pa_buffer_attr attr;
 	pa_buffer_attr attr;
 	attr.fragsize = buffer_size * sizeof(int16_t);
 	attr.fragsize = buffer_size * sizeof(int16_t);
 
 
-	pa_channel_map pa_rec_map;
-	pa_channel_map_init_stereo(&pa_rec_map);
-
 	pa_rec_str = pa_stream_new(pa_ctx, "Record", &spec, &pa_rec_map);
 	pa_rec_str = pa_stream_new(pa_ctx, "Record", &spec, &pa_rec_map);
 	if (pa_rec_str == NULL) {
 	if (pa_rec_str == NULL) {
 		ERR_PRINTS("PulseAudio: pa_stream_new error: " + String(pa_strerror(pa_context_errno(pa_ctx))));
 		ERR_PRINTS("PulseAudio: pa_stream_new error: " + String(pa_strerror(pa_context_errno(pa_ctx))));
@@ -602,10 +646,8 @@ Error AudioDriverPulseAudio::capture_init_device() {
 	}
 	}
 
 
 	input_buffer.resize(input_buffer_frames * 8);
 	input_buffer.resize(input_buffer_frames * 8);
-	for (int i = 0; i < input_buffer.size(); i++) {
-		input_buffer.write[i] = 0;
-	}
 	input_position = 0;
 	input_position = 0;
+	input_size = 0;
 
 
 	return OK;
 	return OK;
 }
 }

+ 3 - 1
drivers/pulseaudio/audio_driver_pulseaudio.h

@@ -49,6 +49,7 @@ class AudioDriverPulseAudio : public AudioDriver {
 	pa_stream *pa_str;
 	pa_stream *pa_str;
 	pa_stream *pa_rec_str;
 	pa_stream *pa_rec_str;
 	pa_channel_map pa_map;
 	pa_channel_map pa_map;
+	pa_channel_map pa_rec_map;
 
 
 	String device_name;
 	String device_name;
 	String new_device;
 	String new_device;
@@ -79,6 +80,7 @@ class AudioDriverPulseAudio : public AudioDriver {
 
 
 	static void pa_state_cb(pa_context *c, void *userdata);
 	static void pa_state_cb(pa_context *c, void *userdata);
 	static void pa_sink_info_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata);
 	static void pa_sink_info_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata);
+	static void pa_source_info_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata);
 	static void pa_server_info_cb(pa_context *c, const pa_server_info *i, void *userdata);
 	static void pa_server_info_cb(pa_context *c, const pa_server_info *i, void *userdata);
 	static void pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata);
 	static void pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata);
 	static void pa_sourcelist_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata);
 	static void pa_sourcelist_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata);
@@ -89,7 +91,7 @@ class AudioDriverPulseAudio : public AudioDriver {
 	Error capture_init_device();
 	Error capture_init_device();
 	void capture_finish_device();
 	void capture_finish_device();
 
 
-	void detect_channels();
+	void detect_channels(bool capture = false);
 
 
 	static void thread_func(void *p_udata);
 	static void thread_func(void *p_udata);