| 2143 | // ─── RX stream ─────────────────────────────────────────────────────────────── |
| 2144 | |
| 2145 | bool AudioEngine::startRxStream() |
| 2146 | { |
| 2147 | if (m_audioSink) return true; // already running |
| 2148 | |
| 2149 | m_rxBuffer.clear(); |
| 2150 | m_rxPackets.clear(); |
| 2151 | m_kiwiSdrRxBuffer.clear(); |
| 2152 | m_kiwiSdrRxPackets.clear(); |
| 2153 | m_rxOutputBuffer.clear(); |
| 2154 | m_kiwiSdrOutputBuffer.clear(); |
| 2155 | m_radeRxBuffer.clear(); |
| 2156 | for (const auto& source : m_externalKiwiSources) { |
| 2157 | if (!source) { |
| 2158 | continue; |
| 2159 | } |
| 2160 | source->rxBuffer.clear(); |
| 2161 | source->rxPackets.clear(); |
| 2162 | source->outputBuffer.clear(); |
| 2163 | source->nr2Output.clear(); |
| 2164 | source->rxResampler.reset(); |
| 2165 | source->rxResamplerR.reset(); |
| 2166 | source->prebuffering = source->enabled; |
| 2167 | } |
| 2168 | m_rxBufferBytes.store(0); |
| 2169 | m_rxBufferPeakBytes.store(0); |
| 2170 | m_rxBufferUnderrunCount.store(0); |
| 2171 | m_rxBufferSampleRate.store(DEFAULT_SAMPLE_RATE); |
| 2172 | m_rxZombieTickCount = 0; |
| 2173 | m_rxStaleTickCount = 0; |
| 2174 | m_lastProcessedUSecs = 0; |
| 2175 | m_lastAudioFeedTime.start(); // initialize liveness watchdog (#1411) |
| 2176 | |
| 2177 | QAudioDevice dev = QMediaDevices::defaultAudioOutput(); |
| 2178 | bool rxFallbackOccurred = false; |
| 2179 | QStringList rxFallbackReasons; |
| 2180 | QStringList rxFormatAttempts; |
| 2181 | const auto noteRxFallback = [&rxFallbackOccurred, &rxFallbackReasons](const QString& reason) { |
| 2182 | rxFallbackOccurred = true; |
| 2183 | if (!reason.isEmpty() && !rxFallbackReasons.contains(reason)) { |
| 2184 | rxFallbackReasons << reason; |
| 2185 | } |
| 2186 | }; |
| 2187 | const auto noteRxAttempt = [&rxFormatAttempts](const QAudioFormat& format) { |
| 2188 | const QString attempt = formatAudioAttempt(format.sampleRate(), |
| 2189 | format.channelCount(), |
| 2190 | format.sampleFormat()); |
| 2191 | if (!rxFormatAttempts.contains(attempt)) { |
| 2192 | rxFormatAttempts << attempt; |
| 2193 | } |
| 2194 | }; |
| 2195 | if (!m_outputDevice.isNull()) { |
| 2196 | const auto outputs = QMediaDevices::audioOutputs(); |
| 2197 | if (devicePresent(outputs, m_outputDevice)) { |
| 2198 | dev = m_outputDevice; |
| 2199 | } else { |
| 2200 | qCWarning(lcAudio) << "AudioEngine: saved output device is unavailable, using the system default output instead"; |
| 2201 | noteRxFallback(QStringLiteral("saved output unavailable -> system default")); |
| 2202 | m_outputDevice = QAudioDevice{}; |
no test coverage detected