What happened?
On macOS using the precompiled AetherSDR v0.8.8 binary, the application crashes immediately when the user changes the Audio Input device in Radio Setup → Audio tab. The application operates normally with the macOS system default audio input device. As soon as the user selects any alternative input device from the dropdown, the app crashes with no recovery — macOS generates a crash report. A crash report has been emailed to support@aethersdr.com with the bug number in the subject line.
This appears to be a hot-swap/re-initialization crash: the QAudioSource (TX mic capture) is likely torn down and re-created mid-stream while the audio pipeline is active, resulting in a use-after-free, a null pointer dereference, or an invalid Qt audio state transition.
What did you expect?
Selecting a different Audio Input device in the Audio tab should gracefully stop the current QAudioSource capture session, release the existing audio device, initialize a new QAudioSource with the selected device, and resume mic/TX audio capture — without crashing and without requiring a reconnect or application restart. The newly selected device should be persisted via AppSettings and restored on the next launch (consistent with the existing "Audio device persistence" feature noted in the changelog).
Steps to reproduce
Launch AetherSDR v0.8.8 (macOS precompiled build).
Connect to a FLEX-6600 (firmware 4.1.5.39794).
Confirm audio is working with the macOS default input device.
Open Radio Setup (gear icon or menu).
Navigate to the Audio tab.
In the Audio Input (microphone / TX source) dropdown, select any device other than the current macOS system default.
Result: Application crashes immediately. macOS generates a crash report.
Radio model & firmware
Radio: FLEX-6600
Firmware: 4.1.5.39794
OS & version
OS: macOS (version 26.4)
AetherSDR: 0.8.8 (precompiled binary)
Qt: 6.11.0
Developer Notes
Most likely files involved:
File | Relevance -- | -- src/core/AudioEngine.h / AudioEngine.cpp | Owns QAudioSource (TX mic capture) and QAudioSink (RX playback). The hot-swap of the input device almost certainly happens — or fails — here. src/gui/RadioSetupDialog.cpp | Audio tab UI. The combo box currentIndexChanged signal triggers the device-switch code path. Look for the slot connected to the input device selector. src/core/AppSettings.h / AppSettings.cpp | Device selection is persisted here; confirm the new device key is written before the crash, not after. src/core/VirtualAudioBridge.cpp(macOS DAX) | On macOS the VirtualAudioBridge (CoreAudio HAL plugin / shared memory bridge) may be involved if DAX is enabled. Tearing it down mid-stream could be a second crash vector.
Probable root causes (in order of likelihood):
Use-after-free / dangling QAudioSource pointer. If RadioSetupDialog calls something like delete m_audioSource; m_audioSource = new QAudioSource(newDevice, ...) while the audio thread is still calling m_audioSource->read() or reading from its QIODevice, this is an immediate crash on macOS (which has stricter memory protections than Linux).
QAudioSource::stop() not called before destruction. Qt6's QAudioSource must be explicitly stopped before being destroyed or re-initialized. Skipping stop() leaves the CoreAudio session open and the subsequent new QAudioSourcemay fail to acquire the device or collide with the still-running session, producing a null/invalid object that is then dereferenced.
macOS CoreAudio session conflict. macOS requires exclusive or at minimum coordinated access to audio devices. Switching devices without properly closing the previous CoreAudio session can trigger a HAL exception that is not caught at the Qt level, presenting as a crash rather than an error signal.
VirtualAudioBridge shared-memory handle invalidated. If DAX is active, the VirtualAudioBridge holds a CoreAudio HAL reference tied to the original input device. Re-initializing QAudioSource without notifying VirtualAudioBridge first could invalidate its shared memory bridge handle.
AppSettings key written with new device name before old QAudioSource is cleanly stopped, causing a reload of the wrong/uninitialized device on the next audio callback.
Suggested logging to enable before reproducing (Help → Support):
Enable all of the following categories before reproducing the crash:
Audio — will capture QAudioSource state transitions, device init, and any Qt audio errors
Core / Engine — general AudioEngine lifecycle events
DAX — if VirtualAudioBridge is involved on the macOS DAX path
Retrieve the log bundle immediately after the crash (or from the macOS crash report) and attach it to this issue. The last few lines before the crash should identify whether the fault occurs during stop(), ~QAudioSource(), the new QAudioSourceconstructor, or the first read() on the new source.
Suggested fix direction:
In AudioEngine (or wherever the input device swap is initiated), ensure the following sequence is strictly ordered on the audio thread (or with the audio thread paused):
// 1. Stop and destroy old source cleanly
if (m_txAudioSource) {
m_txAudioSource->stop();
delete m_txAudioSource;
m_txAudioSource = nullptr;
}
// 2. (macOS) Notify VirtualAudioBridge if active
// 3. Construct new source
QAudioFormat fmt;
// ... configure format ...
m_txAudioSource = new QAudioSource(newDeviceInfo, fmt, this);
// 4. Persist selection
AppSettings::instance().setValue("AudioInputDevice", newDeviceInfo.description());
// 5. Restart capture if TX is active
If device switching is currently triggered directly from a GUI signal without marshalling onto the audio thread, that race condition should be addressed as part of this fix.
support-bundle-20260410-111729.tar.gz
support-bundle-20260410-115423.tar.gz
What happened?
On macOS using the precompiled AetherSDR v0.8.8 binary, the application crashes immediately when the user changes the Audio Input device in Radio Setup → Audio tab. The application operates normally with the macOS system default audio input device. As soon as the user selects any alternative input device from the dropdown, the app crashes with no recovery — macOS generates a crash report. A crash report has been emailed to support@aethersdr.com with the bug number in the subject line.
This appears to be a hot-swap/re-initialization crash: the QAudioSource (TX mic capture) is likely torn down and re-created mid-stream while the audio pipeline is active, resulting in a use-after-free, a null pointer dereference, or an invalid Qt audio state transition.
What did you expect?
Selecting a different Audio Input device in the Audio tab should gracefully stop the current QAudioSource capture session, release the existing audio device, initialize a new QAudioSource with the selected device, and resume mic/TX audio capture — without crashing and without requiring a reconnect or application restart. The newly selected device should be persisted via AppSettings and restored on the next launch (consistent with the existing "Audio device persistence" feature noted in the changelog).
Steps to reproduce
Launch AetherSDR v0.8.8 (macOS precompiled build).
Connect to a FLEX-6600 (firmware 4.1.5.39794).
Confirm audio is working with the macOS default input device.
Open Radio Setup (gear icon or menu).
Navigate to the Audio tab.
In the Audio Input (microphone / TX source) dropdown, select any device other than the current macOS system default.
Result: Application crashes immediately. macOS generates a crash report.
Radio model & firmware
Radio: FLEX-6600
Firmware: 4.1.5.39794
OS & version
OS: macOS (version 26.4)
AetherSDR: 0.8.8 (precompiled binary)
Qt: 6.11.0
Developer Notes
Most likely files involved:
File | Relevance -- | -- src/core/AudioEngine.h / AudioEngine.cpp | Owns QAudioSource (TX mic capture) and QAudioSink (RX playback). The hot-swap of the input device almost certainly happens — or fails — here. src/gui/RadioSetupDialog.cpp | Audio tab UI. The combo box currentIndexChanged signal triggers the device-switch code path. Look for the slot connected to the input device selector. src/core/AppSettings.h / AppSettings.cpp | Device selection is persisted here; confirm the new device key is written before the crash, not after. src/core/VirtualAudioBridge.cpp(macOS DAX) | On macOS the VirtualAudioBridge (CoreAudio HAL plugin / shared memory bridge) may be involved if DAX is enabled. Tearing it down mid-stream could be a second crash vector.
Probable root causes (in order of likelihood):
Use-after-free / dangling QAudioSource pointer. If RadioSetupDialog calls something like delete m_audioSource; m_audioSource = new QAudioSource(newDevice, ...) while the audio thread is still calling m_audioSource->read() or reading from its QIODevice, this is an immediate crash on macOS (which has stricter memory protections than Linux).
QAudioSource::stop() not called before destruction. Qt6's QAudioSource must be explicitly stopped before being destroyed or re-initialized. Skipping stop() leaves the CoreAudio session open and the subsequent new QAudioSourcemay fail to acquire the device or collide with the still-running session, producing a null/invalid object that is then dereferenced.
macOS CoreAudio session conflict. macOS requires exclusive or at minimum coordinated access to audio devices. Switching devices without properly closing the previous CoreAudio session can trigger a HAL exception that is not caught at the Qt level, presenting as a crash rather than an error signal.
VirtualAudioBridge shared-memory handle invalidated. If DAX is active, the VirtualAudioBridge holds a CoreAudio HAL reference tied to the original input device. Re-initializing QAudioSource without notifying VirtualAudioBridge first could invalidate its shared memory bridge handle.
AppSettings key written with new device name before old QAudioSource is cleanly stopped, causing a reload of the wrong/uninitialized device on the next audio callback.
Suggested logging to enable before reproducing (Help → Support):
Enable all of the following categories before reproducing the crash:
Audio — will capture QAudioSource state transitions, device init, and any Qt audio errors
Core / Engine — general AudioEngine lifecycle events
DAX — if VirtualAudioBridge is involved on the macOS DAX path
Retrieve the log bundle immediately after the crash (or from the macOS crash report) and attach it to this issue. The last few lines before the crash should identify whether the fault occurs during stop(), ~QAudioSource(), the new QAudioSourceconstructor, or the first read() on the new source.
Suggested fix direction:
In AudioEngine (or wherever the input device swap is initiated), ensure the following sequence is strictly ordered on the audio thread (or with the audio thread paused):
// 1. Stop and destroy old source cleanly
if (m_txAudioSource) {
m_txAudioSource->stop();
delete m_txAudioSource;
m_txAudioSource = nullptr;
}
// 2. (macOS) Notify VirtualAudioBridge if active
// 3. Construct new source
QAudioFormat fmt;
// ... configure format ...
m_txAudioSource = new QAudioSource(newDeviceInfo, fmt, this);
// 4. Persist selection
AppSettings::instance().setValue("AudioInputDevice", newDeviceInfo.description());
// 5. Restart capture if TX is active
If device switching is currently triggered directly from a GUI signal without marshalling onto the audio thread, that race condition should be addressed as part of this fix.
support-bundle-20260410-111729.tar.gz
support-bundle-20260410-115423.tar.gz