From e23869d99ba77b0600706b25649229aad3dc3098 Mon Sep 17 00:00:00 2001 From: eleir9268 Date: Sun, 13 Sep 2026 12:10:10 -0400 Subject: [PATCH] QNX: ALSA audio support. (#16304) --- docs/README-qnx.md | 6 ++++ src/audio/SDL_sysaudio.h | 4 +++ src/audio/alsa/SDL_alsa_audio.c | 58 +++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/docs/README-qnx.md b/docs/README-qnx.md index bf08e2a784..d79d52a3c2 100644 --- a/docs/README-qnx.md +++ b/docs/README-qnx.md @@ -42,3 +42,9 @@ You can find the cross-compiled build tools at https://github.com/qnx-ports/buil - Currently, only software and OpenGLES2 rendering is supported. - Unless your application is managed by a window manager capable of closing the application, you will need to quit it yourself. - Restraining the mouse to a window or warping the mouse cursor will not work. + +## Notes - alsa +- For sound to work on the rpi, you may need to run, + ```bash + export SDL_AUDIO_DEVICE_SAMPLE_FRAMES=6912 # Or any other value retrieved from speaker-test + ``` diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index 858354a9aa..df22b84cbc 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -40,7 +40,11 @@ // these are used when no better specifics are known. We default to CD audio quality. #define DEFAULT_AUDIO_PLAYBACK_FORMAT SDL_AUDIO_S16 #define DEFAULT_AUDIO_PLAYBACK_CHANNELS 2 +#ifdef SDL_PLATFORM_QNXNTO +#define DEFAULT_AUDIO_PLAYBACK_FREQUENCY 48000 +#else #define DEFAULT_AUDIO_PLAYBACK_FREQUENCY 44100 +#endif #define DEFAULT_AUDIO_RECORDING_FORMAT SDL_AUDIO_S16 #define DEFAULT_AUDIO_RECORDING_CHANNELS 1 diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c index aa89b1ad9f..976bfbd6d0 100644 --- a/src/audio/alsa/SDL_alsa_audio.c +++ b/src/audio/alsa/SDL_alsa_audio.c @@ -86,7 +86,11 @@ static snd_pcm_state_t (*ALSA_snd_pcm_state)(snd_pcm_t *); static int (*ALSA_snd_device_name_hint)(int, const char *, void ***); static char *(*ALSA_snd_device_name_get_hint)(const void *, const char *); static int (*ALSA_snd_device_name_free_hint)(void **); +#ifdef SDL_PLATFORM_QNXNTO +static int (*ALSA_snd_pcm_avail_delay)(snd_pcm_t *, snd_pcm_sframes_t *, snd_pcm_sframes_t *); +#else static snd_pcm_sframes_t (*ALSA_snd_pcm_avail)(snd_pcm_t *); +#endif static size_t (*ALSA_snd_ctl_card_info_sizeof)(void); static size_t (*ALSA_snd_pcm_info_sizeof)(void); static int (*ALSA_snd_card_next)(int *); @@ -176,7 +180,11 @@ static bool load_alsa_syms(void) SDL_ALSA_SYM(snd_device_name_hint); SDL_ALSA_SYM(snd_device_name_get_hint); SDL_ALSA_SYM(snd_device_name_free_hint); +#ifdef SDL_PLATFORM_QNXNTO + SDL_ALSA_SYM(snd_pcm_avail_delay); +#else SDL_ALSA_SYM(snd_pcm_avail); +#endif SDL_ALSA_SYM(snd_ctl_card_info_sizeof); SDL_ALSA_SYM(snd_pcm_info_sizeof); SDL_ALSA_SYM(snd_card_next); @@ -379,7 +387,13 @@ static bool ALSA_WaitDevice(SDL_AudioDevice *device) const int delay = SDL_clamp(fulldelay, 1, 5); while (!SDL_GetAtomicInt(&device->shutdown)) { +#ifdef SDL_PLATFORM_QNXNTO + snd_pcm_sframes_t avail_frames; + snd_pcm_sframes_t delay_frames; + const int rc = ALSA_snd_pcm_avail_delay(device->hidden->pcm, &avail_frames, &delay_frames); +#else const int rc = ALSA_snd_pcm_avail(device->hidden->pcm); +#endif if (rc < 0) { const int status = RecoverALSADevice(device->hidden->pcm, rc); if (status < 0) { @@ -388,9 +402,15 @@ static bool ALSA_WaitDevice(SDL_AudioDevice *device) return false; } } +#ifdef SDL_PLATFORM_QNXNTO + if (avail_frames >= sample_frames) { + break; + } +#else if (rc >= sample_frames) { break; } +#endif SDL_Delay(delay); } return true; @@ -427,6 +447,29 @@ static bool ALSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int bu static Uint8 *ALSA_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size) { +#ifdef SDL_PLATFORM_QNXNTO + snd_pcm_sframes_t avail_frames; + snd_pcm_sframes_t delay_frames; + int rc = ALSA_snd_pcm_avail_delay(device->hidden->pcm, &avail_frames, &delay_frames); + if ((rc < 0) || (avail_frames == 0)) { + // Wait a bit and try again, maybe the hardware isn't quite ready yet? + SDL_Delay(1); + + rc = ALSA_snd_pcm_avail_delay(device->hidden->pcm, &avail_frames, &delay_frames); + if ((rc < 0) || (avail_frames == 0)) { + // We'll catch it next time + *buffer_size = 0; + return NULL; + } + } + + const int requested_frames = SDL_min(device->sample_frames, avail_frames); + const int requested_bytes = requested_frames * SDL_AUDIO_FRAMESIZE(device->spec); + SDL_assert(requested_bytes <= *buffer_size); + //SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "ALSA GETDEVICEBUF: NEED %d BYTES", requested_bytes); + *buffer_size = requested_bytes; + return device->hidden->mixbuf; +#else snd_pcm_sframes_t rc = ALSA_snd_pcm_avail(device->hidden->pcm); if (rc <= 0) { // Wait a bit and try again, maybe the hardware isn't quite ready yet? @@ -446,6 +489,7 @@ static Uint8 *ALSA_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size) //SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "ALSA GETDEVICEBUF: NEED %d BYTES", requested_bytes); *buffer_size = requested_bytes; return device->hidden->mixbuf; +#endif } static int ALSA_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen) @@ -453,10 +497,20 @@ static int ALSA_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen) const int frame_size = SDL_AUDIO_FRAMESIZE(device->spec); SDL_assert((buflen % frame_size) == 0); +#ifdef SDL_PLATFORM_QNXNTO + snd_pcm_sframes_t total_available; + snd_pcm_sframes_t total_delay; + + (void)ALSA_snd_pcm_avail_delay(device->hidden->pcm, &total_available, &total_delay); + if (total_available == 0) { + return 0; // go back to WaitDevice and try again. + } +#else const snd_pcm_sframes_t total_available = ALSA_snd_pcm_avail(device->hidden->pcm); if (total_available == 0) { return 0; // go back to WaitDevice and try again. } +#endif const int total_frames = SDL_min(buflen / frame_size, total_available); const int rc = ALSA_snd_pcm_readi(device->hidden->pcm, buffer, total_frames); @@ -1047,12 +1101,16 @@ static int ALSA_pcm_cfg_hw_chans_n_scan(struct ALSA_pcm_cfg_ctx *ctx, unsigned i //========================================================================================== // Here the alsa pcm is in SND_PCM_STATE_PREPARED state, let's figure out a good fit for // SDL channel map, it may request to change the target number of channels though. +#ifdef SDL_PLATFORM_QNXNTO + return CHANS_N_CONFIGURED; +#else status = alsa_chmap_cfg(ctx); if (status < 0) { return status; // we forward the SDL error } else if (status == CHMAP_INSTALLED) { return CHANS_N_CONFIGURED; // we are finished here } +#endif // status == CHANS_N_NEXT ALSA_snd_pcm_free_chmaps(ctx->chmap_queries);