diff --git a/audio_reactive.h b/audio_reactive.h
index 2bf3e6f..2ea616e 100644
--- a/audio_reactive.h
+++ b/audio_reactive.h
@@ -139,6 +139,7 @@ static volatile bool disableSoundProcessing = false; // if true, sound proc
static uint8_t audioSyncEnabled = AUDIOSYNC_NONE; // bit field: bit 0 - send, bit 1 - receive, bit 2 - use local if not receiving
static bool audioSyncSequence = true; // if true, the receiver will drop out-of-sequence packets
static uint8_t audioSyncPurge = 1; // 0: process each packet (don't purge); 1: auto-purge old packets; 2: only process latest received packet (always purge)
+static bool audioSyncSilenceStop = true; // if true, the sender will stop transmitting UDP packets after 30 seconds of continuous silence
static bool udpSyncConnected = false; // UDP connection status -> true if connected to multicast group
#define NUM_GEQ_CHANNELS 16 // number of frequency channels. Don't change !!
@@ -1237,6 +1238,7 @@ class AudioReactive : public Usermod {
// used to feed "Info" Page
unsigned long last_UDPTime = 0; // time of last valid UDP sound sync data packet
int receivedFormat = 0; // last received UDP sound sync format - 0=none, 1=v1 (0.13.x), 2=v2 (0.14.x)
+ unsigned long syncSilenceStart = 0; // millis() when continuous silence began for the sender; 0 = sound is (or was recently) present
float maxSample5sec = 0.0f; // max sample (after AGC) in last 5 seconds
unsigned long sampleMaxTimer = 0; // last time maxSample5sec was reset
#define CYCLE_SAMPLEMAX 3500 // time window for measuring
@@ -2433,6 +2435,11 @@ class AudioReactive : public Usermod {
#ifdef ARDUINO_ARCH_ESP32
//UDP Microphone Sync - transmit mode
+ // Track sender silence: reset timer when sound is present, start it when silence begins
+ if (audioSyncEnabled & AUDIOSYNC_SEND) {
+ if (volumeSmth >= 1.0f) syncSilenceStart = 0; // sound detected - clear silence timer
+ else if (syncSilenceStart == 0) syncSilenceStart = millis(); // just went silent - start timer
+ }
#if defined(WLEDMM_FASTPATH)
if ((audioSyncEnabled & AUDIOSYNC_SEND) && (haveNewFFTResult || (millis() - lastTime > 24))) { // fastpath: send data once results are ready, or each 25ms as fallback (max sampling time is 23ms)
#else
@@ -2440,7 +2447,10 @@ class AudioReactive : public Usermod {
#endif
haveNewFFTResult = false; // reset notification
// Only run the transmit code IF we're in Transmit mode
- transmitAudioData();
+ // Sender silence gate: skip transmission when silence has persisted for more than 30 seconds
+ if (!audioSyncSilenceStop || (syncSilenceStart == 0) || (millis() - syncSilenceStart < 30000UL)) {
+ transmitAudioData();
+ }
lastTime = millis();
}
#endif
@@ -2882,6 +2892,7 @@ class AudioReactive : public Usermod {
sync[F("mode")] = audioSyncEnabled;
sync[F("skip_old_data")] = audioSyncPurge;
sync[F("check_sequence")] = audioSyncSequence;
+ sync[F("silence_stop")] = audioSyncSilenceStop;
}
@@ -2966,6 +2977,7 @@ class AudioReactive : public Usermod {
configComplete &= getJsonValue(top["sync"][F("mode")], audioSyncEnabled);
configComplete &= getJsonValue(top["sync"][F("skip_old_data")], audioSyncPurge);
configComplete &= getJsonValue(top["sync"][F("check_sequence")], audioSyncSequence);
+ configComplete &= getJsonValue(top["sync"][F("silence_stop")], audioSyncSilenceStop);
// WLEDMM notify user when a reboot is necessary
#ifdef ARDUINO_ARCH_ESP32
@@ -3203,6 +3215,11 @@ class AudioReactive : public Usermod {
oappend(SET_F("addOption(dd,'On',1);"));
oappend(SET_F("addInfo(ux+':sync:check_sequence',1,'when receiving ☾
Sync audio data with other WLEDs');")); // must append this to the last field of 'sync'
+ // silence_stop: Sender stops transmitting UDP packets after 30s of continuous silence
+ oappend(SET_F("dd=addDropdown(ux,'sync:silence_stop');"));
+ oappend(SET_F("addOption(dd,'Off',0);"));
+ oappend(SET_F("addOption(dd,'On',1);"));
+ oappend(SET_F("addInfo(ux+':sync:silence_stop',1,'stop sending after 30s silence ☾
Sync audio data with other WLEDs');")); // must append this to the last field of 'sync'
oappend(SET_F("addInfo(ux+':digitalmic:type',1,'requires reboot!');")); // 0 is field type, 1 is actual field
#ifdef ARDUINO_ARCH_ESP32