sokol: sokol_audio ALSA: buffer size initialization problem on some Linux configs

In function _saudio_backend_init(), snd_pcm_hw_params_set_rate_near() return negative result.

Reproduced on two different computers. Both run Arch current (x86_64):

  • Card: HDA Intel, Chip: Analog Devices AD1989B
  • Card: HDA Intel PCH, Chip: Conexant CX20751/2

The following patch fixes sound (saudio-app and modplay-app work), but I’m not sure that it doesn’t hammer something else.

diff --git a/modules/sokol/sokol_audio.h b/modules/sokol/sokol_audio.h
index bf7e4a7..ebafca2 100644
--- a/modules/sokol/sokol_audio.h
+++ b/modules/sokol/sokol_audio.h
@@ -1044,7 +1044,6 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
     snd_pcm_hw_params_any(_saudio.backend.device, params);
     snd_pcm_hw_params_set_access(_saudio.backend.device, params, SND_PCM_ACCESS_RW_INTERLEAVED);
     snd_pcm_hw_params_set_channels(_saudio.backend.device, params, _saudio.num_channels);
-    snd_pcm_hw_params_set_buffer_size(_saudio.backend.device, params, _saudio.buffer_frames);
     if (0 > snd_pcm_hw_params_test_format(_saudio.backend.device, params, SND_PCM_FORMAT_FLOAT_LE)) {
         goto error;
     }
@@ -1056,6 +1055,12 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
     if (0 > snd_pcm_hw_params_set_rate_near(_saudio.backend.device, params, &val, &dir)) {
         goto error;
     }
+    snd_pcm_uframes_t periodsize = _saudio.buffer_frames * 2;
+    rc = snd_pcm_hw_params_set_buffer_size_near(_saudio.backend.device, params, &periodsize);
+    if(rc < 0) {
+        goto error;
+    }
+
     if (0 > snd_pcm_hw_params(_saudio.backend.device, params)) {
         goto error;
     }

I.e. we set rate first, then try to set buffer size. The code was copied from alsa samples. I’m not sure, if we must change anything else (period_size).

P.S. It would be nice, if samples report sound initializion failure somehow. With red screen for example.

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Comments: 19 (13 by maintainers)

Most upvoted comments

…another more robust solution is to rewrite the ring buffer code so that the audio streaming buffer size doesn’t need to be a multiple of the ring-buffer packet size… I just remembered that I did something similar in the plmpeg.h sokol-sample… This would allow sokol_audio.h to work with odd buffer sizes (like 1881 frames we’ve seen here).

I need to think this through a bit, and it will be a little while until I can take care of this.

Yes, to this. The AAudio backend could benefit from being able to take a lower latency path where the callback can be called with different values (even within one audio session) depending on the characteristics of the underlying audio device.

Alsamixer.

Screenshot 2020-10-13 at 16 07 17

Conexant is on Lenovo IdeaPad 100. “Analog Devices AD1989B” on desktop with some ASUS motherboard.

I’ve looked at openal-soft ALSA initialization code and borrowed one function call, that you are not using. With this patch, everything works. But I don’t understand why…

diff --git a/sokol_audio.h b/sokol_audio.h
index 8df5813..897526a 100644
--- a/sokol_audio.h
+++ b/sokol_audio.h
@@ -1083,6 +1083,11 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
         SOKOL_LOG("sokol_audio.h: requested channel count not supported");
         goto error;
     }
+    /* disable resampler */
+    if(snd_pcm_hw_params_set_rate_resample(_saudio.backend.device, params, 0) < 0) {
+        SOKOL_LOG("set_rate_resample failed");
+        goto error;
+    }
     /* let ALSA pick a nearby sampling rate */
     rate = _saudio.sample_rate;
     dir = 0;