MCPcopy Create free account
hub / github.com/aethersdr/AetherSDR / feedDaxAudio

Method feedDaxAudio

src/core/VirtualAudioBridge.cpp:267–347  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

265}
266
267void VirtualAudioBridge::feedDaxAudio(int channel, const QByteArray& pcm)
268{
269 // This slot may run on PanadapterStream's network thread via
270 // Qt::DirectConnection — keep it lock-free and free of Qt-thread-affine
271 // calls. The silence-timer stop and ring-buffer readPos snap that used
272 // to live here have moved to feedSilenceToAllChannels (GUI-thread tick),
273 // which observes m_lastAudioMs to decide when to self-stop.
274 if (channel < 1 || channel > NUM_CHANNELS) return;
275
276 auto* block = m_blocks[channel - 1];
277 if (!block) return;
278
279 // Note "real audio just arrived" so the GUI-thread silence timer can
280 // stop itself on its next tick. No locks, no Qt API touched here.
281 m_lastAudioMs.store(QDateTime::currentMSecsSinceEpoch(),
282 std::memory_order_relaxed);
283
284 // Input: float32 stereo PCM @ 24 kHz from the radio (native DAX rate).
285 // After the float32 migration (502b934, b0c49d7), both PCC_IF_NARROW
286 // and PCC_IF_NARROW_REDUCED emit float32 stereo from PanadapterStream.
287 // Output: float32 stereo @ 24 kHz into the ring buffer — direct 1:1 copy.
288 // HAL plugin also runs at 24 kHz, so no resampling needed.
289 const auto* samples = reinterpret_cast<const float*>(pcm.constData());
290 const int numSamples = pcm.size() / static_cast<int>(sizeof(float)); // total float count (L,R,L,R,...)
291
292 const float chGain = m_channelGain[channel - 1].load(std::memory_order_relaxed);
293 auto& stats = m_rxTiming[channel - 1];
294 if (!stats.windowElapsed.isValid())
295 stats.windowElapsed.start();
296
297 uint32_t wp = block->writePos.load(std::memory_order_relaxed);
298
299 for (int i = 0; i < numSamples; ++i) {
300 block->ringBuffer[wp % DaxShmBlock::RING_SIZE] = samples[i] * chGain;
301 ++wp;
302 }
303
304 block->writePos.store(wp, std::memory_order_release);
305 stats.writtenSamples += static_cast<uint64_t>(numSamples);
306
307 uint32_t currentRp = block->readPos.load(std::memory_order_acquire);
308 uint32_t backlogSamples = wp - currentRp;
309 stats.peakBacklogSamples = std::max(stats.peakBacklogSamples, backlogSamples);
310
311 if (backlogSamples > DaxShmBlock::RING_SIZE)
312 ++stats.overrunEvents;
313
314 if (backlogSamples > kRxMaxBacklogSamples) {
315 const uint32_t newRp = wp - kRxTargetBacklogSamples;
316 if (newRp > currentRp) {
317 const uint32_t trimmedSamples = newRp - currentRp;
318 block->readPos.store(newRp, std::memory_order_release);
319 currentRp = newRp;
320 backlogSamples = wp - currentRp;
321
322 stats.trimmedSamples += trimmedSamples;
323 ++stats.trimEvents;
324

Callers

nothing calls this directly

Calls 5

samplesToMsFunction · 0.85
sizeMethod · 0.45
loadMethod · 0.45
isValidMethod · 0.45
startMethod · 0.45

Tested by

no test coverage detected