From 6ac89685830caac6beb8d4863a8c570a7a62d377 Mon Sep 17 00:00:00 2001 From: ExtremesecrecyOne <131911364+ExtremesecrecyOne@users.noreply.github.com> Date: Wed, 23 Jul 2025 12:18:19 -0700 Subject: [PATCH] Devices with only I or O Fix Added new fields to track ALSA device capabilities, letting the application know whether a device supports capture or playback Updated serialization to include the new flags in the JSON data exchanged with the UI Modified the dummy driver so test devices always indicate capture and playback support Adjusted the TypeScript model and dialog to filter device choices based on the new flags, ensuring only valid options appear in selectors --- src/DummyAudioDriver.cpp | 2 + src/PiPedalAlsa.cpp | 40 +++++++++++-------- src/PiPedalAlsa.hpp | 2 + vite/src/pipedal/AlsaDeviceInfo.tsx | 6 ++- vite/src/pipedal/JackServerSettingsDialog.tsx | 35 ++++++++++------ 5 files changed, 55 insertions(+), 30 deletions(-) diff --git a/src/DummyAudioDriver.cpp b/src/DummyAudioDriver.cpp index a03e034..de8a9dd 100644 --- a/src/DummyAudioDriver.cpp +++ b/src/DummyAudioDriver.cpp @@ -517,6 +517,8 @@ namespace pipedal result.sampleRates_.push_back(48000); result.minBufferSize_ = 16; result.maxBufferSize_ = 1024; + result.supportsCapture_ = true; + result.supportsPlayback_ = true; return result; } diff --git a/src/PiPedalAlsa.cpp b/src/PiPedalAlsa.cpp index af1be7e..b2f7f1a 100644 --- a/src/PiPedalAlsa.cpp +++ b/src/PiPedalAlsa.cpp @@ -97,20 +97,16 @@ std::vector PiPedalAlsaDevices::GetAlsaDevices() info.name_ = snd_ctl_card_info_get_name(alsaInfo); info.longName_ = snd_ctl_card_info_get_longname(alsaInfo); - snd_pcm_t *hDevice = nullptr; + snd_pcm_t *captureDevice = nullptr; + snd_pcm_t *playbackDevice = nullptr; + bool captureOk = snd_pcm_open(&captureDevice, cardId.c_str(), SND_PCM_STREAM_CAPTURE, 0) == 0; + bool playbackOk = snd_pcm_open(&playbackDevice, cardId.c_str(), SND_PCM_STREAM_PLAYBACK, 0) == 0; + info.supportsCapture_ = captureOk; + info.supportsPlayback_ = playbackOk; - // must support capture AND playback - err = snd_pcm_open(&hDevice, cardId.c_str(), SND_PCM_STREAM_CAPTURE, 0); - if (err == 0) - { - snd_pcm_close(hDevice); - } - if (err == 0) - { - err = snd_pcm_open(&hDevice, cardId.c_str(), SND_PCM_STREAM_PLAYBACK, 0); - } - if (err == 0) + if (captureOk || playbackOk) { + snd_pcm_t *hDevice = captureOk ? captureDevice : playbackDevice; snd_pcm_hw_params_t *params = nullptr; err = snd_pcm_hw_params_malloc(¶ms); if (err == 0) @@ -151,15 +147,25 @@ std::vector PiPedalAlsaDevices::GetAlsaDevices() info.minBufferSize_ = (uint32_t)minBufferSize; info.maxBufferSize_ = (uint32_t)maxBufferSize; - cacheDevice(info.name_, info); - result.push_back(info); } } } if (params != nullptr) snd_pcm_hw_params_free(params); - snd_pcm_close(hDevice); - } + if (captureOk) + snd_pcm_close(captureDevice); + if (playbackOk && playbackDevice != captureDevice) + snd_pcm_close(playbackDevice); + if (err == 0) + { + cacheDevice(info.name_, info); + result.push_back(info); + } + else if (getCachedDevice(info.name_, &info)) + { + result.push_back(info); + } + } else { if (getCachedDevice(info.name_, &info)) @@ -480,6 +486,8 @@ JSON_MAP_REFERENCE(AlsaDeviceInfo, longName) JSON_MAP_REFERENCE(AlsaDeviceInfo, sampleRates) JSON_MAP_REFERENCE(AlsaDeviceInfo, minBufferSize) JSON_MAP_REFERENCE(AlsaDeviceInfo, maxBufferSize) +JSON_MAP_REFERENCE(AlsaDeviceInfo, supportsCapture) +JSON_MAP_REFERENCE(AlsaDeviceInfo, supportsPlayback) JSON_MAP_END() JSON_MAP_BEGIN(AlsaMidiDeviceInfo) diff --git a/src/PiPedalAlsa.hpp b/src/PiPedalAlsa.hpp index cf602b2..5259837 100644 --- a/src/PiPedalAlsa.hpp +++ b/src/PiPedalAlsa.hpp @@ -31,6 +31,8 @@ namespace pipedal { std::string longName_; std::vector sampleRates_; uint32_t minBufferSize_ = 0,maxBufferSize_ = 0; + bool supportsCapture_ = false; + bool supportsPlayback_ = false; bool isDummyDevice() const { return id_.starts_with("dummy:"); diff --git a/vite/src/pipedal/AlsaDeviceInfo.tsx b/vite/src/pipedal/AlsaDeviceInfo.tsx index 0cd10ff..d1f97e0 100644 --- a/vite/src/pipedal/AlsaDeviceInfo.tsx +++ b/vite/src/pipedal/AlsaDeviceInfo.tsx @@ -9,6 +9,8 @@ export default class AlsaDeviceInfo { this.sampleRates = input.sampleRates as number[]; this.minBufferSize = input.minBufferSize; this.maxBufferSize = input.maxBufferSize; + this.supportsCapture = input.supportsCapture ? true : false; + this.supportsPlayback = input.supportsPlayback ? true : false; return this; } static deserialize_array(input: any): AlsaDeviceInfo[] @@ -62,5 +64,7 @@ export default class AlsaDeviceInfo { longName: string = ""; sampleRates: number[] = []; minBufferSize: number = 0; - maxBufferSize: number = 0; + maxBufferSize: number = 0; + supportsCapture: boolean = false; + supportsPlayback: boolean = false; }; \ No newline at end of file diff --git a/vite/src/pipedal/JackServerSettingsDialog.tsx b/vite/src/pipedal/JackServerSettingsDialog.tsx index c35a442..a295bb5 100644 --- a/vite/src/pipedal/JackServerSettingsDialog.tsx +++ b/vite/src/pipedal/JackServerSettingsDialog.tsx @@ -220,8 +220,8 @@ function isOkEnabled(jackServerSettings: JackServerSettings, alsaDevices?: AlsaD { if (!jackServerSettings.valid) return false; if (!alsaDevices) return false; - const inDevice = alsaDevices.find(d => d.id === jackServerSettings.alsaInputDevice); - const outDevice = alsaDevices.find(d => d.id === jackServerSettings.alsaOutputDevice); + const inDevice = alsaDevices.find(d => d.id === jackServerSettings.alsaInputDevice && d.supportsCapture); + const outDevice = alsaDevices.find(d => d.id === jackServerSettings.alsaOutputDevice && d.supportsPlayback); if (!inDevice || !outDevice) return false; const deviceBufferSize = jackServerSettings.bufferSize * jackServerSettings.numberOfBuffers; @@ -289,15 +289,24 @@ const JackServerSettingsDialog = withStyles( return result; } - let inDevice = alsaDevices.find(d => d.id === result.alsaInputDevice); - let outDevice = alsaDevices.find(d => d.id === result.alsaOutputDevice); + let inDevice = alsaDevices.find(d => d.id === result.alsaInputDevice && d.supportsCapture); + let outDevice = alsaDevices.find(d => d.id === result.alsaOutputDevice && d.supportsPlayback); if (!inDevice) { - inDevice = alsaDevices[0]; - result.alsaInputDevice = inDevice.id; + inDevice = alsaDevices.find(d => d.supportsCapture); + if (inDevice) { + result.alsaInputDevice = inDevice.id; + } } if (!outDevice) { - outDevice = alsaDevices[0]; - result.alsaOutputDevice = outDevice.id; + outDevice = alsaDevices.find(d => d.supportsPlayback); + if (outDevice) { + result.alsaOutputDevice = outDevice.id; + } + } + + if (!inDevice || !outDevice) { + result.valid = false; + return result; } if (result.sampleRate === 0) result.sampleRate = 48000; @@ -467,9 +476,9 @@ const JackServerSettingsDialog = withStyles( disabled={!this.state.alsaDevices || this.state.alsaDevices.length === 0} style={{ width: 220 }} > - {this.state.alsaDevices?.map(d => ( - {d.name} - )) || Loading...} + {this.state.alsaDevices?.filter(d => d.supportsCapture).map(d => ( + {d.name} + )) || Loading...} @@ -483,8 +492,8 @@ const JackServerSettingsDialog = withStyles( disabled={!this.state.alsaDevices || this.state.alsaDevices.length === 0} style={{ width: 220 }} > - {this.state.alsaDevices?.map(d => ( - {d.name} + {this.state.alsaDevices?.filter(d => d.supportsPlayback).map(d => ( + {d.name} )) || Loading...}