Fix PulseAudio problems with 8 channels devices

(cherry picked from commit 34395c6a38)
This commit is contained in:
Marcelo Fernandez 2018-04-12 12:01:23 -03:00 committed by Hein-Pieter van Braam
parent 4b5472b100
commit a7ea441504
2 changed files with 26 additions and 27 deletions

View File

@ -60,7 +60,7 @@ void AudioDriverPulseAudio::pa_sink_info_cb(pa_context *c, const pa_sink_info *l
return; return;
} }
ad->pa_channels = l->channel_map.channels; ad->pa_map = l->channel_map;
ad->pa_status++; ad->pa_status++;
} }
@ -73,7 +73,7 @@ void AudioDriverPulseAudio::pa_server_info_cb(pa_context *c, const pa_server_inf
void AudioDriverPulseAudio::detect_channels() { void AudioDriverPulseAudio::detect_channels() {
pa_channels = 2; pa_channel_map_init_stereo(&pa_map);
if (device_name == "Default") { if (device_name == "Default") {
// Get the default output device name // Get the default output device name
@ -129,46 +129,52 @@ Error AudioDriverPulseAudio::init_device() {
} }
// Detect the amount of channels PulseAudio is using // Detect the amount of channels PulseAudio is using
// Note: If using an even amount of channels (2, 4, etc) channels and pa_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_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_channels + 1) // will have the amount of channels Godot is using (in this case it's pa_map.channels + 1)
detect_channels(); detect_channels();
switch (pa_channels) { switch (pa_map.channels) {
case 1: // Mono case 1: // Mono
case 3: // Surround 2.1 case 3: // Surround 2.1
case 5: // Surround 5.0 case 5: // Surround 5.0
case 7: // Surround 7.0 case 7: // Surround 7.0
channels = pa_channels + 1; channels = pa_map.channels + 1;
break; break;
case 2: // Stereo case 2: // Stereo
case 4: // Surround 4.0 case 4: // Surround 4.0
case 6: // Surround 5.1 case 6: // Surround 5.1
case 8: // Surround 7.1 case 8: // Surround 7.1
channels = pa_channels; channels = pa_map.channels;
break; break;
default: default:
WARN_PRINTS("PulseAudio: Unsupported number of channels: " + itos(pa_channels)); WARN_PRINTS("PulseAudio: Unsupported number of channels: " + itos(pa_map.channels));
pa_channels = 2; pa_channel_map_init_stereo(&pa_map);
channels = 2; channels = 2;
break; break;
} }
pa_sample_spec spec;
spec.format = PA_SAMPLE_S16LE;
spec.channels = pa_channels;
spec.rate = mix_rate;
int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY); int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
buffer_frames = closest_power_of_2(latency * mix_rate / 1000); buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
pa_buffer_size = buffer_frames * pa_channels; pa_buffer_size = buffer_frames * pa_map.channels;
if (OS::get_singleton()->is_stdout_verbose()) { if (OS::get_singleton()->is_stdout_verbose()) {
print_line("PulseAudio: detected " + itos(pa_channels) + " channels"); print_line("PulseAudio: detected " + itos(pa_map.channels) + " channels");
print_line("PulseAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms"); print_line("PulseAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
} }
pa_sample_spec spec;
spec.format = PA_SAMPLE_S16LE;
spec.channels = pa_map.channels;
spec.rate = mix_rate;
pa_str = pa_stream_new(pa_ctx, "Sound", &spec, &pa_map);
if (pa_str == NULL) {
ERR_PRINTS("PulseAudio: pa_stream_new error: " + String(pa_strerror(pa_context_errno(pa_ctx))));
ERR_FAIL_V(ERR_CANT_OPEN);
}
pa_buffer_attr attr; pa_buffer_attr attr;
// set to appropriate buffer length (in bytes) from global settings // set to appropriate buffer length (in bytes) from global settings
attr.tlength = pa_buffer_size * sizeof(int16_t); attr.tlength = pa_buffer_size * sizeof(int16_t);
@ -177,12 +183,6 @@ Error AudioDriverPulseAudio::init_device() {
attr.maxlength = (uint32_t)-1; attr.maxlength = (uint32_t)-1;
attr.minreq = (uint32_t)-1; attr.minreq = (uint32_t)-1;
pa_str = pa_stream_new(pa_ctx, "Sound", &spec, NULL);
if (pa_str == NULL) {
ERR_PRINTS("PulseAudio: pa_stream_new error: " + String(pa_strerror(pa_context_errno(pa_ctx))));
ERR_FAIL_V(ERR_CANT_OPEN);
}
const char *dev = device_name == "Default" ? NULL : device_name.utf8().get_data(); const char *dev = device_name == "Default" ? NULL : 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_playback(pa_str, dev, &attr, flags, NULL, NULL); int error_code = pa_stream_connect_playback(pa_str, dev, &attr, flags, NULL, NULL);
@ -297,7 +297,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
ad->unlock(); ad->unlock();
if (ad->channels == ad->pa_channels) { if (ad->channels == ad->pa_map.channels) {
for (unsigned int i = 0; i < ad->pa_buffer_size; i++) { for (unsigned int i = 0; i < ad->pa_buffer_size; i++) {
ad->samples_out[i] = ad->samples_in[i] >> 16; ad->samples_out[i] = ad->samples_in[i] >> 16;
} }
@ -307,7 +307,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
unsigned int out_idx = 0; unsigned int out_idx = 0;
for (unsigned int i = 0; i < ad->buffer_frames; i++) { for (unsigned int i = 0; i < ad->buffer_frames; i++) {
for (unsigned int j = 0; j < ad->pa_channels - 1; j++) { for (unsigned int j = 0; j < ad->pa_map.channels - 1; j++) {
ad->samples_out[out_idx++] = ad->samples_in[in_idx++] >> 16; ad->samples_out[out_idx++] = ad->samples_in[in_idx++] >> 16;
} }
uint32_t l = ad->samples_in[in_idx++]; uint32_t l = ad->samples_in[in_idx++];
@ -516,7 +516,6 @@ AudioDriverPulseAudio::AudioDriverPulseAudio() {
buffer_frames = 0; buffer_frames = 0;
pa_buffer_size = 0; pa_buffer_size = 0;
channels = 0; channels = 0;
pa_channels = 0;
pa_ready = 0; pa_ready = 0;
pa_status = 0; pa_status = 0;

View File

@ -47,6 +47,7 @@ class AudioDriverPulseAudio : public AudioDriver {
pa_mainloop *pa_ml; pa_mainloop *pa_ml;
pa_context *pa_ctx; pa_context *pa_ctx;
pa_stream *pa_str; pa_stream *pa_str;
pa_channel_map pa_map;
String device_name; String device_name;
String new_device; String new_device;
@ -59,7 +60,6 @@ class AudioDriverPulseAudio : public AudioDriver {
unsigned int buffer_frames; unsigned int buffer_frames;
unsigned int pa_buffer_size; unsigned int pa_buffer_size;
int channels; int channels;
int pa_channels;
int pa_ready; int pa_ready;
int pa_status; int pa_status;
Array pa_devices; Array pa_devices;