| 2.0.4.4 | — | archived | Factory firmware. Full flash dump backed up at C:\Users\dansc\xiaozhi_backup_full.bin. |
| 2.2.5 | 2026-04-05 | superseded | First custom build — board zhengchen-1.54tft-wifi-bitcraft, OTA URL set to this server, Chinese UI. OTA-flashed from 2.0.4.4. |
| 2.2.5 † | 2026-04-05 | running on device | English UI rebuild (Windows) — CONFIG_LANGUAGE_EN_US=y, fixed hardcoded Chinese high-temp label. |
| 2.2.6 | 2026-04-07 | crashes | First Linux build. Hangs after AudioCodec init — never reaches WiFi. Root cause: circular GetInstance() deadlock fixed in 2.2.8. |
| 2.2.7 | 2026-04-07 | crashes | Added http->SetTimeout(300000). Same deadlock crash as 2.2.6. |
| 2.2.8 | 2026-04-08 | superseded | Fixed GetInstance() deadlock: moved MediaPlayer::RegisterMcpTools() from constructor to AddCommonTools(). First working Linux build. |
| 2.2.9 | 2026-04-08 | superseded | Fixed media playback silent failure: stream_url_ cleared by StopPlayback() before StreamTask ran. |
| 2.2.10 | 2026-04-08 | superseded | Fixed ReadAll() deadlock for files >8 KB. Rewrote StreamTask to stream via Read() chunks into OggDemuxer. |
| 2.2.11 | 2026-04-08 | superseded | Fixed stack overflow: OggDemuxer moved to heap; task stack increased to 16 384 bytes. Audio confirmed working. |
| 2.2.12 | 2026-04-08 | superseded | Added MediaPlayer::Stop(). BOOT button stops media on tap. Used unsafe vTaskDelete — replaced in 2.2.13. |
| 2.2.13 | 2026-04-08 | regression | Atomic stop_requested_ flag. Added wait-for-idle loop — broke audio (output path torn down at idle). Rolled back in 2.2.14. |
| 2.2.14 | 2026-04-08 | superseded | Reverted wait-for-idle; audio works. Atomic stop flag retained. |
| 2.2.15 | 2026-04-08 | superseded | Added Flappy Bird game. Button not responding — BUTTON_SINGLE_CLICK debounce too slow. Fixed in 2.2.17. |
| 2.2.16 | 2026-04-08 | superseded | Attempted to suppress AI TTS via empty MCP return — insufficient (AI speaks regardless). Superseded by 2.2.18. |
| 2.2.17 | 2026-04-08 | superseded | Fixed Flappy Bird button: moved to BUTTON_PRESS_DOWN (fires immediately). AI speech suppressed after game/media launch. |
| 2.2.18 | 2026-04-08 | superseded | Fixed AI speech overlap: AbortSpeaking(kAbortReasonNone) cuts TTS at protocol level. BOOT button stop with press_consumed_ flag. Graceful game exit via lv_scr_load_anim. |
| 2.2.19 | 2026-04-08 | superseded | Flappy Bird: persistent "GAME OVER" overlay; long-press BOOT exits. Long-press WiFi config blocked during game. |
| 2.2.20 | 2026-04-08 | superseded | Added VideoPlayer module: .axv container (MJPEG + Opus), 4 MCP tools. Double-buffered JPEG decode to PSRAM. Test video (SMPTE bars) added. |
| 2.2.21–2.2.23 | 2026-04-09 | superseded | Details not documented. |
| 2.2.24 | 2026-04-09 | superseded | Baseline for this session — VideoPlayer functional. |
| 2.2.25 | 2026-04-10 | superseded | Fixed video running ~1.5× too fast: wake word acoustic feedback (speaker → mic) was triggering ResetDecoder() during playback, breaking audio backpressure. Fixed by disabling wake word detection during video and guarding ResetDecoder() calls in state machine. |
| 2.2.26 | 2026-04-10 | superseded | Added FlappyBird sound effects (flap/score/death via OGG assets). Added self.device.about MCP tool — fetches description from /esp32/xiaozhi/about and returns it to AI. Added public /esp32/xiaozhi/about.html page. |
| 2.2.27 | 2026-04-10 | superseded | Fixed generic media playback path so video items resolved by self.media.search are delegated to VideoPlayer instead of the audio-only OGG demuxer. |
| 2.2.28 | 2026-04-10 | superseded | Split video playback into separate reader and renderer tasks, added audio prebuffering, and started dropping stale video frames based on container timestamps instead of blocking audio. |
| 2.2.29 | 2026-04-10 | superseded | Ends active voice sessions when video starts and ignores late conversational events while media is active, preventing the AI from interrupting playback with retry speech. |
| 2.2.30 | 2026-04-10 | superseded | Removes per-frame JPEG output allocation/copy churn by decoding directly into reusable PSRAM framebuffers. Audio stayed solid; video remained decode-bound. |
| 2.2.31 | 2026-04-11 | superseded | Added playback-end diagnostics: HTTP read stalls, audio queue block time, late-frame stats, deeper audio buffering, and higher stream-reader priority. |
| 2.2.32 | 2026-04-11 | superseded | Streams playback telemetry live every 5 seconds during active video and surfaces the detailed diagnostics on this dashboard. Designed to distinguish stream transport stalls from local decode/render limits while playback is still running. |
| 2.2.33 | 2026-04-11 | regression | Introduced ranged video fetching and timeline resync, but startup failed before the first packet was delivered. Video items resolved correctly from the library, but playback exited after about 1.4 seconds with zero rendered frames. |
| 2.2.34 | 2026-04-11 | regression | Attempted a startup fallback to the legacy stream when the first Range request was ignored, but telemetry showed the same early-exit failure pattern as 2.2.33. The ranged transport remained broken on-device. |
| 2.2.35 | 2026-04-12 | superseded | Removed the ranged transport path and restored the known-good continuous HTTP streaming reader from 2.2.32 while keeping the live playback telemetry. This recovery build made video work again after the 2.2.33/2.2.34 transport regression. |
| 2.2.36 | 2026-04-12 | superseded | Expanded video telemetry into a full pipeline profile: startup latency, HTTP read timing, packet copy cost, queue overflow vs backlog drops, JPEG decode timing, frame-present timing, frame-age metrics, and explicit playback end reason. That data showed the renderer was oversleeping on far-future frames. |
| 2.2.37 | 2026-04-12 | superseded | Reworked video frame selection and pacing. The renderer now trims stale frames, selects the newest frame that is actually due, preserves future frames in the queue, and rechecks pacing in short intervals instead of sleeping on far-future frames. |
| 2.2.38 | 2026-04-12 | superseded | Added resumable video transport and new resume counters. Playback did attempt a resume after an early stream close, but the device’s range request was malformed and the server returned HTTP 416. |
| 2.2.39 | 2026-04-12 | superseded | Fixes the resume request formatting. The firmware now builds the Range header using a plain decimal string instead of printf-style formatting, which avoids malformed resume requests on the embedded libc build. |
| 2.2.40–2.2.74 | 2026-04–06 | superseded | Extensive video-pipeline iteration: ranged HTTP, sync_v1 batched transport, then full WebSocket streaming (media/ws/<id>) for video. Server-side pacing (_WS_LEAD_MS = 10000) keeps the device ~10 s ahead of audio_clock for jitter absorption. NVS-deferred end-of-playback summaries to avoid HttpClient lifecycle bugs. |
| 2.2.75–2.2.82 | 2026-06-03/04 | superseded | Patched managed-component tcp_receive and ssl_receive task priorities from 1 → 6 to stop them being starved by the video tasks. Coredump partition added to capture panics. Persistent telemetry WebSocket so per-event POSTs no longer instantiate HttpClient and trip the lifetime races. End-of-playback summary now sent via WS immediately (NVS only as fallback when WS isn't up). |
| 2.2.83–2.2.85 | 2026-06-04 | superseded | Restructured WS receive: dispatch happens inline on the receive task, eliminating the intermediate raw_queue whose auto-drop policy was silently discarding the OLDEST frames (the ones the renderer needed). Pinned video_stream/video_render to core 0/1 respectively. Pinned audio: opus_codec+audio_output+audio_input+audio_detection+audio_communication and both AFE-internal tasks to core 0. Dynamic ws_base_url via OTA response so server IP changes propagate without re-flash. Auto-OTA poll every 60 s when idle. |
| 2.2.86–2.2.87 | 2026-06-04 | superseded | Added per-core CPU stats to the playback summary (cpu_core0_busy_pct, cpu_core1_busy_pct, cpu_top_task_name, cpu_top_task_pct, cpu_top_task_core). Enabled CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y. Initial implementation reported since-boot stats; corrected to per-playback-window delta. Build-deploy verification: the script now hashes the version string out of the binary and aborts if it doesn't match CMakeLists.txt, after a 2.2.86 ship of the wrong binary caused a download-reboot loop. |
| 2.2.88 | 2026-06-04 | superseded | Big fix. The render task was spin-looping at 34 591 wakeups/sec when frames were not yet due. The "future_wait_us" branch did continue before reaching the vTaskDelay further down the loop body — sleep code unreachable. Result: core 1 sat at 100% even on 8 fps content, and LVGL got starved of CPU which is why visual playback didn't match the rendered-frame counter. Moved the delay inside the same branch as the continue. Core 1 dropped from 100% → 33% at 8 fps. |
| 2.2.89 | 2026-06-05 | current | Bumped kMaxQueuedVideoFrames 120 → 320 to cover the server's 10 s lead at 24 fps source rate. Verified 24 fps playback: R = 23.40 fps rendered (97.6% of 23.976 source), only 55 backlog drops over 137 s, 0 queue overflow, 0 audio underruns, core 1 at 81 %, core 0 at 27 %. Sustained ~245 KB/s network throughput. Top task taskLVGL at 43 % on core 1. |