FASTPATH: minimize UDP sound latency

The standard build is sending packets each 20ms, which means there are double packets (no new FFT results yet) and the max. delay between sampling and sending is up to 50ms.

* (FASTPATH only): FFT Task directly notifies UDP send when it has new data, reducing delays to the absolute minimum. this also optimizes UDP packets throughput, by avoiding duplicates.

* (FASTPATH only): receiver polling frequency is increased, to process new packets earlier (may increase CPU load)
This commit is contained in:
Frank
2023-11-29 13:08:14 +01:00
parent 38352c9d20
commit 7c68c14e63

View File

@@ -116,6 +116,8 @@ static float FFT_Magnitude = 0.0f; // FFT: volume (magnitude) of pe
static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay()
static bool udpSamplePeak = false; // Boolean flag for peak. Set at the same time as samplePeak, but reset by transmitAudioData
static unsigned long timeOfPeak = 0; // time of last sample peak detection.
volatile bool haveNewFFTResult = false; // flag to directly inform UDP sound sender when new FFT results are availeable (to reduce latency). Flag is reset at next UDP send
static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0}; // Our calculated freq. channel result table to be used by effects
static float fftCalc[NUM_GEQ_CHANNELS] = {0.0f}; // Try and normalize fftBin values to a max of 4096, so that 4096/16 = 256. (also used by dynamics limiter)
static float fftAvg[NUM_GEQ_CHANNELS] = {0.0f}; // Calculated frequency channel results, with smoothing (used if dynamics limiter is ON)
@@ -746,6 +748,9 @@ void FFTcode(void * parameter)
autoResetPeak();
detectSamplePeak();
// we have new results - notify UDP sound send
haveNewFFTResult = true;
#if !defined(I2S_GRAB_ADC1_COMPLETELY)
if ((audioSource == nullptr) || (audioSource->getType() != AudioSource::Type_I2SAdc)) // the "delay trick" does not help for analog ADC
#endif
@@ -1008,7 +1013,11 @@ class AudioReactive : public Usermod {
// variables for UDP sound sync
WiFiUDP fftUdp; // UDP object for sound sync (from WiFi UDP, not Async UDP!)
unsigned long lastTime = 0; // last time of running UDP Microphone Sync
#if defined(WLEDMM_FASTPATH)
const uint16_t delayMs = 5; // I don't want to sample too often and overload WLED
#else
const uint16_t delayMs = 10; // I don't want to sample too often and overload WLED
#endif
uint16_t audioSyncPort= 11988;// default port for UDP sound sync
bool updateIsRunning = false; // true during OTA.
@@ -2092,7 +2101,12 @@ class AudioReactive : public Usermod {
#ifdef ARDUINO_ARCH_ESP32
//UDP Microphone Sync - transmit mode
if ((audioSyncEnabled & 0x01) && (millis() - lastTime > 20)) {
#if defined(WLEDMM_FASTPATH)
if ((audioSyncEnabled & 0x01) && (haveNewFFTResult || (millis() - lastTime > 24))) { // fastpath: send data once results are ready, or each 25ms as fallback (max sampling time is 23ms)
#else
if ((audioSyncEnabled & 0x01) && (millis() - lastTime > 20)) { // standard: send data each 20ms
#endif
haveNewFFTResult = false; // reset notification
// Only run the transmit code IF we're in Transmit mode
transmitAudioData();
lastTime = millis();