Browse Source

Handle having no sinks in the PulseAudio driver.

Also make PulseAudio errors more verbose.
R. Alex Hofer 4 years ago
parent
commit
65a10f4db5

+ 40 - 8
drivers/pulseaudio/audio_driver_pulseaudio.cpp

@@ -40,13 +40,19 @@ void AudioDriverPulseAudio::pa_state_cb(pa_context *c, void *userdata) {
 
 
 	switch (pa_context_get_state(c)) {
 	switch (pa_context_get_state(c)) {
 		case PA_CONTEXT_TERMINATED:
 		case PA_CONTEXT_TERMINATED:
+			print_verbose("PulseAudio: context terminated");
+			ad->pa_ready = -1;
+			break;
 		case PA_CONTEXT_FAILED:
 		case PA_CONTEXT_FAILED:
+			print_verbose("PulseAudio: context failed");
 			ad->pa_ready = -1;
 			ad->pa_ready = -1;
 			break;
 			break;
 		case PA_CONTEXT_READY:
 		case PA_CONTEXT_READY:
+			print_verbose("PulseAudio: context ready");
 			ad->pa_ready = 1;
 			ad->pa_ready = 1;
 			break;
 			break;
 		default:
 		default:
+			print_verbose("PulseAudio: context other");
 			// TODO: Check if we want to handle some of the other
 			// TODO: Check if we want to handle some of the other
 			// PA context states like PA_CONTEXT_UNCONNECTED.
 			// PA context states like PA_CONTEXT_UNCONNECTED.
 			break;
 			break;
@@ -61,6 +67,13 @@ void AudioDriverPulseAudio::pa_sink_info_cb(pa_context *c, const pa_sink_info *l
 		return;
 		return;
 	}
 	}
 
 
+	// If eol is set to a negative number there's an error.
+	if (eol < 0) {
+		ERR_PRINT("PulseAudio: sink info error: " + String(pa_strerror(pa_context_errno(c))));
+		ad->pa_status--;
+		return;
+	}
+
 	ad->pa_map = l->channel_map;
 	ad->pa_map = l->channel_map;
 	ad->pa_status++;
 	ad->pa_status++;
 }
 }
@@ -73,6 +86,13 @@ void AudioDriverPulseAudio::pa_source_info_cb(pa_context *c, const pa_source_inf
 		return;
 		return;
 	}
 	}
 
 
+	// If eol is set to a negative number there's an error.
+	if (eol < 0) {
+		ERR_PRINT("PulseAudio: sink info error: " + String(pa_strerror(pa_context_errno(c))));
+		ad->pa_status--;
+		return;
+	}
+
 	ad->pa_rec_map = l->channel_map;
 	ad->pa_rec_map = l->channel_map;
 	ad->pa_status++;
 	ad->pa_status++;
 }
 }
@@ -86,7 +106,7 @@ void AudioDriverPulseAudio::pa_server_info_cb(pa_context *c, const pa_server_inf
 	ad->pa_status++;
 	ad->pa_status++;
 }
 }
 
 
-void AudioDriverPulseAudio::detect_channels(bool capture) {
+Error AudioDriverPulseAudio::detect_channels(bool capture) {
 	pa_channel_map_init_stereo(capture ? &pa_rec_map : &pa_map);
 	pa_channel_map_init_stereo(capture ? &pa_rec_map : &pa_map);
 
 
 	String device = capture ? capture_device_name : device_name;
 	String device = capture ? capture_device_name : device_name;
@@ -104,7 +124,8 @@ void AudioDriverPulseAudio::detect_channels(bool capture) {
 
 
 			pa_operation_unref(pa_op);
 			pa_operation_unref(pa_op);
 		} else {
 		} else {
-			ERR_PRINT("pa_context_get_server_info error");
+			ERR_PRINT("pa_context_get_server_info error: " + String(pa_strerror(pa_context_errno(pa_ctx))));
+			return FAILED;
 		}
 		}
 	}
 	}
 
 
@@ -114,6 +135,7 @@ void AudioDriverPulseAudio::detect_channels(bool capture) {
 	} else {
 	} else {
 		strcpy(dev, device.utf8().get_data());
 		strcpy(dev, device.utf8().get_data());
 	}
 	}
+	print_verbose("PulseAudio: Detecting channels for device: " + String(dev));
 
 
 	// 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;
@@ -133,6 +155,10 @@ void AudioDriverPulseAudio::detect_channels(bool capture) {
 		}
 		}
 
 
 		pa_operation_unref(pa_op);
 		pa_operation_unref(pa_op);
+
+		if (pa_status == -1) {
+			return FAILED;
+		}
 	} else {
 	} else {
 		if (capture) {
 		if (capture) {
 			ERR_PRINT("pa_context_get_source_info_by_name error");
 			ERR_PRINT("pa_context_get_source_info_by_name error");
@@ -140,6 +166,8 @@ void AudioDriverPulseAudio::detect_channels(bool capture) {
 			ERR_PRINT("pa_context_get_sink_info_by_name error");
 			ERR_PRINT("pa_context_get_sink_info_by_name error");
 		}
 		}
 	}
 	}
+
+	return OK;
 }
 }
 
 
 Error AudioDriverPulseAudio::init_device() {
 Error AudioDriverPulseAudio::init_device() {
@@ -156,7 +184,13 @@ Error AudioDriverPulseAudio::init_device() {
 	// Note: If using an even amount of channels (2, 4, etc) channels and pa_map.channels will be equal,
 	// Note: If using an even amount of channels (2, 4, etc) channels and pa_map.channels will be equal,
 	// if not then pa_map.channels will have the real amount of channels PulseAudio is using and channels
 	// if not then pa_map.channels will have the real amount of channels PulseAudio is using and channels
 	// will have the amount of channels Godot is using (in this case it's pa_map.channels + 1)
 	// will have the amount of channels Godot is using (in this case it's pa_map.channels + 1)
-	detect_channels();
+	Error err = detect_channels();
+	if (err != OK) {
+		// This most likely means there are no sinks.
+		ERR_PRINT("PulseAudio: init device failed to detect number of channels");
+		return err;
+	}
+
 	switch (pa_map.channels) {
 	switch (pa_map.channels) {
 		case 1: // Mono
 		case 1: // Mono
 		case 3: // Surround 2.1
 		case 3: // Surround 2.1
@@ -294,10 +328,8 @@ Error AudioDriverPulseAudio::init() {
 		return ERR_CANT_OPEN;
 		return ERR_CANT_OPEN;
 	}
 	}
 
 
-	Error err = init_device();
-	if (err == OK) {
-		thread.start(AudioDriverPulseAudio::thread_func, this);
-	}
+	init_device();
+	thread.start(AudioDriverPulseAudio::thread_func, this);
 
 
 	return OK;
 	return OK;
 }
 }
@@ -441,7 +473,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
 
 
 					pa_operation_unref(pa_op);
 					pa_operation_unref(pa_op);
 				} else {
 				} else {
-					ERR_PRINT("pa_context_get_server_info error");
+					ERR_PRINT("pa_context_get_server_info error: " + String(pa_strerror(pa_context_errno(ad->pa_ctx))));
 				}
 				}
 
 
 				if (old_default_device != ad->default_device) {
 				if (old_default_device != ad->default_device) {

+ 1 - 1
drivers/pulseaudio/audio_driver_pulseaudio.h

@@ -89,7 +89,7 @@ class AudioDriverPulseAudio : public AudioDriver {
 	Error capture_init_device();
 	Error capture_init_device();
 	void capture_finish_device();
 	void capture_finish_device();
 
 
-	void detect_channels(bool capture = false);
+	Error detect_channels(bool capture = false);
 
 
 	static void thread_func(void *p_udata);
 	static void thread_func(void *p_udata);