@@ -341,6 +341,14 @@ App::App(const Options& opts) : options_(opts), sim_ui_visible_(opts.enable_sim)
341341 if (waterfall_) {
342342 waterfall_->addSamples (samples.data (), samples.size ());
343343 }
344+ if (!audio_.hasOutputDevice ()) {
345+ std::string output_dev = getOutputDeviceName ();
346+ if (!audio_.openOutput (output_dev)) {
347+ guiLog (" TX audio: openOutput failed for '%s'" ,
348+ output_dev.empty () ? " Default" : output_dev.c_str ());
349+ return ;
350+ }
351+ }
344352 audio_.startPlayback ();
345353 audio_.queueTxSamples (samples);
346354 }
@@ -369,6 +377,14 @@ App::App(const Options& opts) : options_(opts), sim_ui_visible_(opts.enable_sim)
369377 if (waterfall_) {
370378 waterfall_->addSamples (samples.data (), samples.size ());
371379 }
380+ if (!audio_.hasOutputDevice ()) {
381+ std::string output_dev = getOutputDeviceName ();
382+ if (!audio_.openOutput (output_dev)) {
383+ guiLog (" TX burst audio: openOutput failed for '%s'" ,
384+ output_dev.empty () ? " Default" : output_dev.c_str ());
385+ return ;
386+ }
387+ }
372388 audio_.startPlayback ();
373389 audio_.queueTxSamples (samples);
374390 }
@@ -458,6 +474,14 @@ App::App(const Options& opts) : options_(opts), sim_ui_visible_(opts.enable_sim)
458474 if (waterfall_) {
459475 waterfall_->addSamples (samples.data (), samples.size ());
460476 }
477+ if (!audio_.hasOutputDevice ()) {
478+ std::string output_dev = getOutputDeviceName ();
479+ if (!audio_.openOutput (output_dev)) {
480+ guiLog (" PING audio: openOutput failed for '%s'" ,
481+ output_dev.empty () ? " Default" : output_dev.c_str ());
482+ return ;
483+ }
484+ }
461485 audio_.startPlayback ();
462486 audio_.queueTxSamples (samples);
463487 }
@@ -486,6 +510,14 @@ App::App(const Options& opts) : options_(opts), sim_ui_visible_(opts.enable_sim)
486510 if (waterfall_) {
487511 waterfall_->addSamples (samples.data (), samples.size ());
488512 }
513+ if (!audio_.hasOutputDevice ()) {
514+ std::string output_dev = getOutputDeviceName ();
515+ if (!audio_.openOutput (output_dev)) {
516+ guiLog (" PONG audio: openOutput failed for '%s'" ,
517+ output_dev.empty () ? " Default" : output_dev.c_str ());
518+ return ;
519+ }
520+ }
489521 audio_.startPlayback ();
490522 audio_.queueTxSamples (samples);
491523 }
@@ -731,8 +763,6 @@ App::App(const Options& opts) : options_(opts), sim_ui_visible_(opts.enable_sim)
731763 initAudio ();
732764 if (audio_initialized_) {
733765 audio_.setOutputGain (settings_.tx_drive );
734- std::string output_dev = getOutputDeviceName ();
735- audio_.openOutput (output_dev);
736766 startRadioRx ();
737767 }
738768 });
@@ -750,8 +780,6 @@ App::App(const Options& opts) : options_(opts), sim_ui_visible_(opts.enable_sim)
750780
751781 if (audio_initialized_) {
752782 audio_.setOutputGain (settings_.tx_drive );
753- std::string output_dev = getOutputDeviceName ();
754- audio_.openOutput (output_dev);
755783 startRadioRx ();
756784 }
757785 });
@@ -812,17 +840,12 @@ App::App(const Options& opts) : options_(opts), sim_ui_visible_(opts.enable_sim)
812840 ultra::gui::startupTrace (" App" , " init-audio-enter" );
813841 initAudio ();
814842 if (audio_initialized_) {
815- std::string output_dev = getOutputDeviceName ();
816- if (audio_.openOutput (output_dev)) {
817- deferred_radio_rx_start_pending_ = true ;
818- uint32_t now_ms = SDL_GetTicks ();
819- deferred_radio_rx_start_deadline_ms_ = now_ms;
820- deferred_radio_rx_start_timeout_ms_ = now_ms + 3000 ;
821- deferred_radio_rx_start_attempts_ = 0 ;
822- guiLog (" Startup audio stage 1/2 complete: output ready, starting RX capture ASAP (timeout=3000ms)" );
823- } else {
824- guiLog (" Startup audio stage: openOutput failed" );
825- }
843+ deferred_radio_rx_start_pending_ = true ;
844+ uint32_t now_ms = SDL_GetTicks ();
845+ deferred_radio_rx_start_deadline_ms_ = now_ms;
846+ deferred_radio_rx_start_timeout_ms_ = now_ms + 3000 ;
847+ deferred_radio_rx_start_attempts_ = 0 ;
848+ guiLog (" Startup audio stage 1/2 complete: core ready, starting RX capture ASAP (timeout=3000ms)" );
826849 }
827850 ultra::gui::startupTrace (" App" , " init-audio-exit" );
828851 } else {
@@ -1548,20 +1571,13 @@ void App::render() {
15481571 initAudio ();
15491572 if (audio_initialized_) {
15501573 ultra::gui::startupTrace (" App" , " deferred-audio-open-output-enter" );
1551- std::string output_dev = getOutputDeviceName ();
1552- if (audio_.openOutput (output_dev)) {
1553- deferred_radio_rx_start_pending_ = true ;
1554- deferred_radio_rx_start_deadline_ms_ = now_ms;
1555- deferred_radio_rx_start_timeout_ms_ = now_ms + 3000 ;
1556- deferred_radio_rx_start_attempts_ = 0 ;
1557- guiLog (" Deferred audio stage 1/2 complete: output ready, starting RX capture ASAP (timeout=3000ms)" );
1558- ultra::gui::startupTrace (" App" , " deferred-audio-open-output-exit" );
1559- deferred_audio_auto_init_pending_ = false ;
1560- } else {
1561- guiLog (" Deferred audio auto-init: openOutput failed" );
1562- ultra::gui::startupTrace (" App" , " deferred-audio-open-output-fail" );
1563- deferred_audio_auto_init_pending_ = false ;
1564- }
1574+ deferred_radio_rx_start_pending_ = true ;
1575+ deferred_radio_rx_start_deadline_ms_ = now_ms;
1576+ deferred_radio_rx_start_timeout_ms_ = now_ms + 3000 ;
1577+ deferred_radio_rx_start_attempts_ = 0 ;
1578+ guiLog (" Deferred audio stage 1/2 complete: core ready, starting RX capture ASAP (timeout=3000ms)" );
1579+ ultra::gui::startupTrace (" App" , " deferred-audio-open-output-exit" );
1580+ deferred_audio_auto_init_pending_ = false ;
15651581 } else {
15661582 deferred_audio_auto_init_attempts_++;
15671583 ultra::gui::startupTrace (" App" , " deferred-audio-init-fail" );
@@ -1611,18 +1627,39 @@ void App::render() {
16111627 // === DEBUG: Test signal keys (F1-F7) ===
16121628 if (ImGui::IsKeyPressed (ImGuiKey_F1)) {
16131629 auto tone = modem_.generateTestTone (1 .0f );
1630+ if (!audio_.hasOutputDevice ()) {
1631+ std::string output_dev = getOutputDeviceName ();
1632+ if (!audio_.openOutput (output_dev)) {
1633+ appendRxLogLine (" [TEST] Failed to open output device for tone" );
1634+ return ;
1635+ }
1636+ }
16141637 audio_.startPlayback ();
16151638 audio_.queueTxSamples (tone);
16161639 appendRxLogLine (" [TEST] Sent 1500 Hz tone" );
16171640 }
16181641 if (ImGui::IsKeyPressed (ImGuiKey_F2)) {
16191642 auto samples = modem_.transmitTestPattern (0 );
1643+ if (!audio_.hasOutputDevice ()) {
1644+ std::string output_dev = getOutputDeviceName ();
1645+ if (!audio_.openOutput (output_dev)) {
1646+ appendRxLogLine (" [TEST] Failed to open output device for pattern" );
1647+ return ;
1648+ }
1649+ }
16201650 audio_.startPlayback ();
16211651 audio_.queueTxSamples (samples);
16221652 appendRxLogLine (" [TEST] Sent pattern: ALL ZEROS (LDPC encoded)" );
16231653 }
16241654 if (ImGui::IsKeyPressed (ImGuiKey_F3)) {
16251655 auto samples = modem_.transmitTestPattern (1 );
1656+ if (!audio_.hasOutputDevice ()) {
1657+ std::string output_dev = getOutputDeviceName ();
1658+ if (!audio_.openOutput (output_dev)) {
1659+ appendRxLogLine (" [TEST] Failed to open output device for pattern" );
1660+ return ;
1661+ }
1662+ }
16261663 audio_.startPlayback ();
16271664 audio_.queueTxSamples (samples);
16281665 appendRxLogLine (" [TEST] Sent pattern: DEADBEEF (LDPC encoded)" );
@@ -1801,10 +1838,6 @@ bool App::startRadioRx() {
18011838 guiLog (" startRadioRx guard: simulation enabled" );
18021839 return false ;
18031840 }
1804- if (!audio_.hasOutputDevice ()) {
1805- guiLog (" startRadioRx guard: output device not open" );
1806- return false ;
1807- }
18081841 if (radio_rx_enabled_) {
18091842 return true ;
18101843 }
@@ -2140,7 +2173,6 @@ void App::renderOperateTab() {
21402173 }
21412174 modem_.reset ();
21422175 if (audio_initialized_) {
2143- audio_.openOutput (getOutputDeviceName ());
21442176 startRadioRx ();
21452177 }
21462178 }
@@ -2191,7 +2223,6 @@ void App::renderOperateTab() {
21912223 ImGui::SameLine ();
21922224 if (ImGui::SmallButton (" Start RX" )) {
21932225 if (!audio_initialized_) initAudio ();
2194- audio_.openOutput (getOutputDeviceName ());
21952226 startRadioRx ();
21962227 }
21972228 } else {
@@ -2241,7 +2272,6 @@ void App::renderOperateTab() {
22412272 guiLog (" Connect clicked: simulation=%d, remote='%s'" , simulation_enabled_, remote_callsign_);
22422273 if (!simulation_enabled_ && !radio_rx_enabled_) {
22432274 if (!audio_initialized_) initAudio ();
2244- audio_.openOutput (getOutputDeviceName ());
22452275 startRadioRx ();
22462276 }
22472277 std::string remote_call (remote_callsign_, boundedCStringLen (remote_callsign_));
0 commit comments