Wenn der ESPuino gerade musik abspielt und man den Befehl „schlafe sofort“ sendet. Dann bekomme ich einen roten Ring und die Box startet neu. Wenn keine Musik abgespielt wird, dann funktioniert das „schlafe sofort“ ohne Probleme. Irgendwie wird vermutlich der Watchdog ausgelöst.
Hab’s eben getestet - allerdings auf dem ganz neuen dev, auf dem jetzt auch Mediahub drin ist. Hatte einen aktiven Abspielvorgang und habe aus dem Webinterface heraus „schlafe sofort“ initiiert. Hat keine Probleme gemacht, habe den Test 2x ausgeführt.
Keine Logs, keine Versionsnummer, generell keine Details. So wird das nix
.
Bei mir ist das auch an zwei der Boxen (tatsächlich auch nur an denen mit einem Lautsprecher.
Hier mal ein Dump dazu, falls das was hilft:
Dump.txt (17,0 KB)
Nee, der MAX hat ja so einen Modus, wo er l+r quasi in einen Ausgang mergt. Den muss man über externe Spannungsteiler-Beschaltung entsprechend anfordern (was die Complete macht und auch die mini4L). Nur wenn man das nicht tut, dann könnte das Sinn machen. Hab mich schon öfter gefragt, ob das eigentlich weg könnte die Option.
Laut ChatGpt liegt es an der audio.cpp
Der Heap wird in ESP32-audioI2S::stereo2mono() überschrieben. Die Schleife verarbeitet den Puffer fälschlich doppelt.
wir sollen aus
void Audio::stereo2mono(int32_t* buff, size_t len) {
for (uint16_t i = 0; i < len * 2; i += 2) {
int64_t l = buff[i];
int64_t r = buff[i + 1];
int32_t m = (int32_t)((l + r) >> 1);
buff[i] = m;
buff[i + 1] = m;
}
}
das machen
void Audio::stereo2mono(int32_t* buff, size_t len) {
for (size_t i = 0; i + 1 < len; i += 2) {
int64_t l = buff[i];
int64_t r = buff[i + 1];
int32_t m = static_cast<int32_t>((l + r) >> 1);
buff[i] = m;
buff[i + 1] = m;
}
}
entscheidend ist das fehlende *2 in der Schleife
- for (uint16_t i = 0; i < len * 2; i += 2) {
+ for (size_t i = 0; i + 1 < len; i += 2) {
Ich teste das mal heute Abend
Ich hab’s mal durch Claude gejagt.
Der ist der Meinung, dass
delete audio;
audio = nullptr;
in der Funktion void AudioPlayer_Exit(void) ersetzt werden sollte durch:
if (audio) {
audio->stopSong();
}
Und zwar, weil das nur beim Shutdown aufgerufen wird und der Heap eh gelöscht wird. Vermutung ist, dass es eine Race Condition auslöst.
// Do NOT `delete audio` here: AudioPlayer_Exit() runs only from
// System_PreparePowerDown(), i.e. right before esp_deep_sleep_start() or
// ESP.restart() - the heap is wiped either way, so freeing is pointless.
// Worse, delete → ~Audio() → stopAudioTask() force-vTaskDelete()s the
// decode task on an unchecked 0.3s mutex timeout; with playback active it can
// hit the task mid-decode and corrupt the heap (crash on shutdown while
// playing). stopSong() is the synchronized, proven-safe stop used on every
// track change - it mutes, ends decoding and closes the file cleanly.
Gut, wenn man das eine Ebene tiefer direkt in der Lib beheben kann - umso besser.
Also die Lösung in der Lib funktioniert.
Ich habe jetzt ein PR bei @Wolle aufgemacht Fix out-of-bounds access in stereo2mono() by joker-mik · Pull Request #1391 · schreibfaul1/ESP32-audioI2S · GitHub
… Wolle ist fix und hat es gemerged ![]()

