Browse Source

Implemented capture device selection for PulseAudio (marcelofg55)

Saracen 7 years ago
parent
commit
09eafaba62

+ 117 - 11
drivers/pulseaudio/audio_driver_pulseaudio.cpp

@@ -402,6 +402,26 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
 					}
 					}
 				}
 				}
 			}
 			}
+
+			// User selected a new device, finish the current one so we'll init the new device
+			if (ad->capture_device_name != ad->capture_new_device) {
+				ad->capture_device_name = ad->capture_new_device;
+				ad->capture_finish_device();
+
+				Error err = ad->capture_init_device();
+				if (err != OK) {
+					ERR_PRINT("PulseAudio: capture_init_device error");
+					ad->capture_device_name = "Default";
+					ad->capture_new_device = "Default";
+
+					err = ad->capture_init_device();
+					if (err != OK) {
+						ad->active = false;
+						ad->exit_thread = true;
+						break;
+					}
+				}
+			}
 		}
 		}
 
 
 		ad->stop_counting_ticks();
 		ad->stop_counting_ticks();
@@ -540,11 +560,16 @@ void AudioDriverPulseAudio::finish() {
 	thread = NULL;
 	thread = NULL;
 }
 }
 
 
-Error AudioDriverPulseAudio::capture_start() {
-
-	Error err = OK;
+Error AudioDriverPulseAudio::capture_init_device() {
 
 
-	lock();
+	// If there is a specified device check that it is really present
+	if (capture_device_name != "Default") {
+		Array list = capture_get_device_list();
+		if (list.find(capture_device_name) == -1) {
+			capture_device_name = "Default";
+			capture_new_device = "Default";
+		}
+	}
 
 
 	pa_sample_spec spec;
 	pa_sample_spec spec;
 
 
@@ -568,11 +593,12 @@ Error AudioDriverPulseAudio::capture_start() {
 		ERR_FAIL_V(ERR_CANT_OPEN);
 		ERR_FAIL_V(ERR_CANT_OPEN);
 	}
 	}
 
 
+	const char *dev = capture_device_name == "Default" ? NULL : capture_device_name.utf8().get_data();
 	pa_stream_flags flags = pa_stream_flags(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE);
 	pa_stream_flags flags = pa_stream_flags(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE);
-	int error_code = pa_stream_connect_record(pa_rec_str, NULL, &attr, flags);
+	int error_code = pa_stream_connect_record(pa_rec_str, dev, &attr, flags);
 	if (error_code < 0) {
 	if (error_code < 0) {
 		ERR_PRINTS("PulseAudio: pa_stream_connect_record error: " + String(pa_strerror(error_code)));
 		ERR_PRINTS("PulseAudio: pa_stream_connect_record error: " + String(pa_strerror(error_code)));
-		err = ERR_CANT_OPEN;
+		ERR_FAIL_V(ERR_CANT_OPEN);
 	}
 	}
 
 
 	audio_input_buffer.resize(input_buffer_frames * 8);
 	audio_input_buffer.resize(input_buffer_frames * 8);
@@ -581,21 +607,101 @@ Error AudioDriverPulseAudio::capture_start() {
 	}
 	}
 	audio_input_position = 0;
 	audio_input_position = 0;
 
 
-	unlock();
-
-	return err;
+	return OK;
 }
 }
 
 
-Error AudioDriverPulseAudio::capture_stop() {
+void AudioDriverPulseAudio::capture_finish_device() {
+
 	if (pa_rec_str) {
 	if (pa_rec_str) {
-		pa_stream_disconnect(pa_rec_str);
+		int ret = pa_stream_disconnect(pa_rec_str);
+		if (ret != 0) {
+			ERR_PRINTS("PulseAudio: pa_stream_disconnect error: " + String(pa_strerror(ret)));
+		}
 		pa_stream_unref(pa_rec_str);
 		pa_stream_unref(pa_rec_str);
 		pa_rec_str = NULL;
 		pa_rec_str = NULL;
 	}
 	}
+}
+
+Error AudioDriverPulseAudio::capture_start() {
+
+	lock();
+	Error err = capture_init_device();
+	unlock();
+
+	return err;
+}
+
+Error AudioDriverPulseAudio::capture_stop() {
+	lock();
+	capture_finish_device();
+	unlock();
 
 
 	return OK;
 	return OK;
 }
 }
 
 
+void AudioDriverPulseAudio::capture_set_device(const String &p_name) {
+
+	lock();
+	capture_new_device = p_name;
+	unlock();
+}
+
+void AudioDriverPulseAudio::pa_sourcelist_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;
+	}
+
+	if (l->monitor_of_sink == PA_INVALID_INDEX) {
+		ad->pa_rec_devices.push_back(l->name);
+	}
+
+	ad->pa_status++;
+}
+
+Array AudioDriverPulseAudio::capture_get_device_list() {
+
+	pa_rec_devices.clear();
+	pa_rec_devices.push_back("Default");
+
+	if (pa_ctx == NULL) {
+		return pa_rec_devices;
+	}
+
+	lock();
+
+	// Get the device list
+	pa_status = 0;
+	pa_operation *pa_op = pa_context_get_source_info_list(pa_ctx, pa_sourcelist_cb, (void *)this);
+	if (pa_op) {
+		while (pa_status == 0) {
+			int ret = pa_mainloop_iterate(pa_ml, 1, NULL);
+			if (ret < 0) {
+				ERR_PRINT("pa_mainloop_iterate error");
+			}
+		}
+
+		pa_operation_unref(pa_op);
+	} else {
+		ERR_PRINT("pa_context_get_server_info error");
+	}
+
+	unlock();
+
+	return pa_rec_devices;
+}
+
+String AudioDriverPulseAudio::capture_get_device() {
+
+	lock();
+	String name = capture_device_name;
+	unlock();
+
+	return name;
+}
+
 AudioDriverPulseAudio::AudioDriverPulseAudio() {
 AudioDriverPulseAudio::AudioDriverPulseAudio() {
 
 
 	pa_ml = NULL;
 	pa_ml = NULL;

+ 15 - 0
drivers/pulseaudio/audio_driver_pulseaudio.h

@@ -54,6 +54,10 @@ class AudioDriverPulseAudio : public AudioDriver {
 	String new_device;
 	String new_device;
 	String default_device;
 	String default_device;
 
 
+	String capture_device_name;
+	String capture_new_device;
+	String capture_default_device;
+
 	Vector<int32_t> samples_in;
 	Vector<int32_t> samples_in;
 	Vector<int16_t> samples_out;
 	Vector<int16_t> samples_out;
 
 
@@ -65,6 +69,7 @@ class AudioDriverPulseAudio : public AudioDriver {
 	int pa_ready;
 	int pa_ready;
 	int pa_status;
 	int pa_status;
 	Array pa_devices;
 	Array pa_devices;
+	Array pa_rec_devices;
 
 
 	bool active;
 	bool active;
 	bool thread_exited;
 	bool thread_exited;
@@ -76,10 +81,14 @@ class AudioDriverPulseAudio : public AudioDriver {
 	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_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);
 
 
 	Error init_device();
 	Error init_device();
 	void finish_device();
 	void finish_device();
 
 
+	Error capture_init_device();
+	void capture_finish_device();
+
 	void detect_channels();
 	void detect_channels();
 
 
 	static void thread_func(void *p_udata);
 	static void thread_func(void *p_udata);
@@ -93,9 +102,15 @@ public:
 	virtual void start();
 	virtual void start();
 	virtual int get_mix_rate() const;
 	virtual int get_mix_rate() const;
 	virtual SpeakerMode get_speaker_mode() const;
 	virtual SpeakerMode get_speaker_mode() const;
+
 	virtual Array get_device_list();
 	virtual Array get_device_list();
 	virtual String get_device();
 	virtual String get_device();
 	virtual void set_device(String device);
 	virtual void set_device(String device);
+
+	virtual Array capture_get_device_list();
+	virtual void capture_set_device(const String &p_name);
+	virtual String capture_get_device();
+
 	virtual void lock();
 	virtual void lock();
 	virtual void unlock();
 	virtual void unlock();
 	virtual void finish();
 	virtual void finish();