Handle having no sinks in the PulseAudio driver.

Also make PulseAudio errors more verbose.

(cherry picked from commit 65a10f4db5)
This commit is contained in:
R. Alex Hofer 2021-05-13 18:28:22 -04:00 committed by Rémi Verschelde
parent 2a18909210
commit 5eff9569c6
No known key found for this signature in database
GPG key ID: C3336907360768E1
2 changed files with 41 additions and 9 deletions

View file

@ -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(); init_device();
if (err == OK) { thread.start(AudioDriverPulseAudio::thread_func, this);
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) {

View file

@ -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);