dkulp
Full time elf
FPP 10.4
Release date: 10 November 2026FPP 10.4 is a point release on top of 10.3 — 259 commits from 9 contributors in the two and a half weeks since 10.3 shipped. The headliners are in File Manager: loudness (LUFS) Normalize replaces MP3Gain, and Listen/View now play right in the page. Beyond that, this release is mostly about steadier shows: MultiSync remotes that no longer stutter, seek or go dark, playlists started over MQTT or by command that the scheduler no longer cuts off, HDMI displays that say why they refused a video, and a long list of web UI fixes for names with special characters and pages that could save over a real config.
NOTE: The OS level moves from 2026-10b to 2026-11, but an "OS Level" upgrade is not required to run 10.4. The only changes at the OS level are kernel updates and security patches (the Pi images now start from the 2026-10-06 Raspberry Pi OS Trixie Lite release, kernel 6.18.50) — recommended, but entirely optional. A normal FPP update from 10.3 gets you every feature and fix listed below.
Enhancements
Audio & Video
- File Manager: MP3Gain is replaced by loudness (LUFS) Normalize (#3145). It measures each song's loudness and true peak and stores one gain per file, applied at playback — media files are never re-encoded, so sync and length are unchanged. It works on any audio format and on videos' soundtracks (a Normalize button on the Videos tab), defaults to -18 LUFS, and says when a song was held back to avoid clipping. "Remove Normalization" undoes it, and gains follow a file when it is renamed, copied or deleted. This also replaces the MP3Gain button that was broken on upgraded systems (#2873, #2986).
- File Manager: Listen (Music) and View (Videos) play in a dialog on the page instead of a new tab that never started in Chromium. Seeking works (including on Safari/iOS), closing the dialog stops playback, and a format the browser can't play offers a download link instead.
- A media file that won't play now says why in a banner: a damaged or non-media file, a format the device can't decode, an unreadable file, a failed HDMI/video output (with the driver's reason) or a stalled track. Before, the item sat at 00:00 with only a log line.
- When a projector or TV refuses a video, a new "Display Refused Video" warning explains it, and when the display's screen shape doesn't match its running mode the warning names the Force HDMI Resolution value to pick. This covers playlist video and camera/stream groups on HDMI (#3135).
- The HDMI display settings (Force HDMI Display, Enable HDMI Display on BeagleBone, Force HDMI Resolution) have their own "HDMI Display" group, shown in both Media Backend modes — Advanced (Full PipeWire) mode used to hide them (#3135).
- Troubleshooting → Video adds Display EDID, DRM State and Display Engine Load (Pi 0-3 HVS load and underruns). Diagnostic Reports include them with the display's serial numbers and manufacture date removed (#3135).
- AES67: output groups that contain only AES67 senders run the PipeWire graph at 48 kHz automatically, even on a cape with a fixed-clock sound card, saving about 16% of a core. A new "AES67GraphClockPriority" setting (off by default) does the same when the card shares a group with an AES67 sender.
- AES67 on a box with no hardware PTP clock (for example a USB Ethernet adapter) no longer lets ptp4l step the system clock to the grandmaster's time — some grandmasters use an epoch near 1970, which threw the clock back to January 1970 every few minutes. The stream is timed from NTP instead, the status shows "free running", and a warning explains it.
Backups & File Copy
- File Copy can restore Configuration one settings area at a time (for example just the schedule), the same way a JSON settings restore does, with the same "Keep this player's network settings" and "Keep player/remote settings" options (#3157).
Playlists & File Manager
- File Manager's Bulk Add (Add To Playlist) dialog has an optional "Don't automatch" checkbox, so a mixed selection can make a plain sequence-only, audio-only or video-only playlist.
- Playlist validation flags a media entry whose video output (a display or overlay model) no longer exists on the system.
Plugins
- FPP detects when a plugin's install, upgrade or uninstall script edits FPP's own files. The edits are named in the Plugin Manager log and saved as a patch, a warning is raised, and at the next FPP update they are set aside so the update goes through instead of aborting.
- A plugin's
fpp_uninstall.shcan tell when it is the uninstall half of a Reinstall (FPP_PLUGIN_REINSTALL=1), so it can keep its data. - C++ plugins can offer their own WebSocket endpoints (
/fppdws/plugin?name=...); a plugin built against them still loads on older FPP.
Capes & Hardware
- Cape Info's EEPROM Upgrade tab shows the installed cape's hardware and EEPROM versions, lists the images that match that hardware first, marks the one installed and pre-selects the newest match. Non-matching images are still listed, so a cape flashed with the wrong image can be recovered.
- The PocketBeagle 2's BOOT button (Industrial too) can be used as a GPIO trigger on the GPIO page.
- Raspberry Pi: the cape EEPROM write timeout is now 1000 ms, as on PocketBeagle 2, so writes to EEPROMs emulated in a microcontroller's flash no longer fail. Existing Pi's get it through the update; it applies after the next reboot.
Diagnostics
- Crash reports can tell a damaged or replaced library on disk from memory corruption: they record the code at the fault, check loaded libraries against their package checksums, and record CPU temperature and clock speed at the moment of the crash.
Bug Fixes (since 10.3)
Fixes already delivered in the 10.3 release (the PHP2Shell update) are included but not repeated here.
MultiSync
- A remote's audio no longer seeks on one late sync packet (common on 2.4 GHz Wi-Fi), which could cause 20+ audible dropouts in one song; a remote now acts only on an error that persists.
- A remote no longer keeps re-seeking its audio every couple of seconds, across songs, after a resync seek landed more than a second off. A remote playing a video with keyframes far apart no longer seeks every couple of seconds either; it stays in sync by adjusting playback speed.
- A remote playing the same sequence twice in a row no longer goes dark for the second play-through when a late sync packet from the first one arrives, and a sync packet in flight when the master stops or changes a sequence no longer makes the remote reopen what just stopped.
- Remotes playing media with more than two channels (5.1 and similar) keep up with the master instead of drifting over a second behind.
- The MultiSync page no longer leaks memory on every status poll, which eventually crashed the browser tab. Newly discovered systems appear without a page reload, and checked rows stay checked when you filter or show/hide columns.
- A remote listed at both a wired and a wireless address that answers on only one is no longer marked Unreachable; Restart FPPD on a remote does a quick restart instead of a full stop/start; and Copy Files to a remote that is down gives up after 15 s instead of hanging about two minutes per folder.
- A discovery range written from a host address (e.g.
x.x.x.5/29) scans the whole subnet; MultiSync ping bursts are no longer dropped where the larger receive buffer wasn't allowed; and after an fppd restart a leftover child process can no longer hold fppd's network ports and steal MultiSync traffic.
Scheduler & Playlists
- A playlist started over MQTT or with a Start Playlist command while a scheduled playlist runs is no longer cut off by the scheduler a moment later (#3140). An MQTT start also stops the running playlist first, so its stop preset no longer undoes the new playlist's lead-in.
- Repeating schedule entries end exactly when the next occurrence starts (#3141) — a one-second gap let a lower-priority entry start, and with Graceful stop every later repeat started late. An entry whose window is shorter than its repeat interval no longer runs past its End Time.
- A hard stop of an inserted playlist (for example at the end of a schedule window) no longer briefly restarts the playlist it was inserted into, Stop Now drops a pending inserted playlist, and the MQTT playlist name/status topics return to the show playlist after an Insert Playlist After Current finishes (#3142). Fixed a crash when two Start Playlist requests arrive together during an inserted playlist.
- Editing a playlist entry or command no longer saves "null" when a dropdown's saved value isn't currently in its list — Play Media entries quietly became audio-only when a display or overlay model was temporarily missing. Entries already saved that way are repaired on their next edit.
- The status page shows Playing, with working controls, for a sequence started on its own (File Manager Play, a StartSequence preset or the API).
- Random Media entries in the same playlist no longer all pick the same file, and the Prefix field shows in the editor. A note containing
<or'no longer breaks the playlist editor row. - Scheduler: a disabled playlist no longer hides an enabled one in the calendar; Save says "Schedule Not Reloaded" when fppd doesn't confirm; and a removed entry no longer briefly starts after a save.
- FSEQ effects run at their exact frame rate (a 17 ms effect ran 1.4% slow). The If command editor opens an If with a single bare condition, and Recurring Tasks saves when a task refers to a deleted preset, refuses intervals under 30 s, and no longer overwrites an unreadable file with an empty list.
Audio & Video
- Pi: fppd no longer crashes playing some H.265/HEVC videos, which hit MultiSync remotes joining mid-song over and over. It was a GStreamer bug in the hardware decoder; streams up to 1080p60 now decode in software.
- The PipeWire default sink chosen at boot now stays chosen (#3063). WirePlumber overwrote it within minutes, so with a USB card selected, plugin players (After Hours, EncoreRadio and others) played out of the onboard jack. Updated players get the fix on their next boot.
- A USB sound card with "HDMI" in its name (such as a USB3-to-HDMI adapter) is no longer mistaken for the board's HDMI port, which sent audio silently to the "no sound card" sink (#3159).
- The master volume now controls AES67 and Opus RTP network audio senders (#2860).
- Saved Input Mixing send levels and routing-path levels are restored after an Apply, an fppd restart or a reboot, instead of coming back at 100%.
- A 5.1 file on a stereo output (or stereo on mono) is folded down again instead of losing channels, and an Audio Output Group member with a delay no longer plays the last second of a stopped track.
- Video on a Pi 0-3: a Virtual Matrix on the same HDMI port steps aside while a video plays, so 1080p videos no longer fail to start or play in a small unscaled window. Force HDMI Resolution set on the kernel command line is honoured by Virtual Matrix outputs (#3082).
- A hung hardware video decoder now triggers fppd's restart and recovery, instead of a looping video playlist leaking threads until fppd crashed.
- A video playing to an overlay model lights the model again after an output reload.
- Media plugins (FM transmitter/RDS and similar) get the real media duration instead of 0, and a shorter clip after a longer one on the same slot reports its own length.
- The Hardware Decoding setting works — turning it off makes video use software decoders.
- AES67 drift correction follows a fixed-clock cape's real rate; false "source gap" reports and repeated gap log lines (which grew fppd.log to hundreds of MB) are gone; and turning on adaptiveResample with driftResample no longer breaks the send pipeline.
- PipeWire control API: slot 1 reports its file and times, and setting slot 1's volume works. WLED audio sync from an audio input no longer stalls while media plays.
Pixel Strings & Panels
- Pi 0-4: DPI pixel outputs and an HDMI virtual matrix running at the same time no longer hold each other up, which caused slow output frames from 10.3 on (#3171).
- ColorLight panels: while bridging E1.31/Art-Net/DDP input, the last row no longer flickers or lights part way (#3136). The "does not have link" warning clears when the link comes up just after boot (#3170), and ColorLight warnings clear after the config is fixed without restarting fppd.
- LED Panels page: Front/Back View toggling no longer swaps every L panel for R on save; ColorLight brightness is a percentage on every platform (off a Pi the brightest choice drove the receiver at 10%); the panels-wide/high selects fill when the matrix isn't first (Save wrote "nullxnull"); panel sizes with an addressing type keep it; and the Pi GPIO slowdown default follows the Pi model again.
- Pi PWM GPIO outputs drive their pin: on a Pi 5 P1-12 never changed, and on a Pi 4 GPIO18/19 were on the wrong function.
- BeagleBone shift-string capes with FalconV5 receivers query each receiver chain once per round, raising the achievable frame rate, and the frame-time estimate and pixel-budget warning are accurate for V4 and V5 receivers.
- The 50-pixel unlicensed limit on BBShiftString, BBB48String and DPIPixels no longer cuts the end off a string that uses null nodes, and DPI ports count start nulls in their pixel count and power estimate.
- An empty smart receiver between populated ones no longer gets an out-of-range auto overlay model that disabled the whole output. Clone String no longer fails with "Max rows to clone going down is 0".
- Test patterns started before outputs load cover every channel once they do, and a test or overlay range set while outputs are idle shows at once instead of up to 2.5 s later.
- FSEQ files with more than 255 sparse ranges are written correctly, and files written with the old truncated count are recovered on read.
Network & Wi-Fi
- A refused network interface save (for example a netmask typo) no longer wipes the interface's saved config, which left it unconfigured after a reboot.
- WiFi scans identify WPA3, WPA2/WPA3 transition, WEP, OWE and Enterprise networks — a WPA3-only network couldn't be joined from the Network page — and WiFi status gives the right reason while connecting.
- Generic UDP multicast goes out on the output's interface instead of the default route, and Generic UDP controllers are pinged so an offline one is flagged and skipped.
- Universe outputs reject a unicast address with leading zeros (
10.0.0.010), which was read as octal and sent elsewhere.
Web UI
- Pages no longer save over a real config while it is still loading: PWM, Other and Channel Inputs DMX outputs, Audio/Video Output Groups, Input Mixing and Video Inputs keep Save disabled until the saved config has loaded — the problem #3124 found on Pixel Strings.
- Names containing
#,?,%, quotes, apostrophes or HTML-like text work across the UI: File Manager (Info, Copy, Rename, Add To Playlist), playlists, the scheduler, command presets, recurring tasks, backup restore and cape firmware upload. The File Manager script editor saves a script exactly as written. - The volume slider stops where you let go instead of jumping back.
- An error popup over another dialog no longer blocks clicks on it; picking a file in the playlist File Chooser always closes it; and dialogs closed while fading in close.
- File Manager: a filtered table says "Filtered items" with the right count; Tail Follow no longer splits log lines; and buttons that need a selection start disabled.
- Fixed: settings saving "undefined", the playlist auto-scroll setting on the status page, the playlist row label at large text sizes (#3158), the SSH Shell link and remote content lists on a non-standard port, the SPI-WS2801 device list, the Virtual Display page's script errors, and the Get Help page scrolling sideways on a phone.
- Accessibility: the Start/Stop FPPD button, controls named by their tooltip and settings help icons have proper screen-reader names.
Backups & Settings
- API backups no longer delete every backup, including the one just made, once 60 backups exist.
- File Copy's Plugins item copies each plugin's settings, Configuration no longer copies crash reports and upload leftovers, and a restored schedule is used straight away (#3157). Backup/Restore to a remote copies the cape EEPROM.
- fppd picks up settings changes after the settings file is replaced (a restore or an editor), and changing log levels no longer gets reverted by a settings reload.
- A configuration backup that can't be built returns an error instead of a "successful" download containing the error text.
Privacy & Security
- Passwords and tokens (UI/OS password, GitHub token, MQTT, email and tether passwords) no longer appear in the Backup page's source or any page's script settings, and the initial setup page no longer receives the current UI password.
- API request paths are decoded only once, closing a cross-site request bypass through double encoding.
- The header bar escapes interface names and sensor labels, and Cape Info escapes the cape description, so a crafted cape EEPROM or sensors file can't inject markup.
- First-boot setup: a password typed before choosing "No Password" is no longer saved. Leftover temp files from network saves, which can hold the WiFi key, are kept out of backups.
- Quoted CSP override keywords in
csp_allowed_domains.jsonapply, and a manual update regenerates the CSP.
Capes & Hardware
- BeagleBone Black: fixed the SIGBUS crash when starting matrix or serial outputs seen since 10.2 on boards whose PRU was stopped.
- EEPROM upgrade selects the exact vendor match, so a vendor whose name is a prefix of another's can't take its cape. GPIO, USB DMX, Pixelnet, nRF24, serial and pixel-string config warnings come down once the config is fixed.
- The diagnostics throttling check reports the actual flag, and power-supply advice appears only for under-voltage (#3135).
- IIO ADCs that need a buffer trigger (such as the AD7998) read real values instead of 0. An original PocketBeagle no longer offers the eMMC activity LED trigger it doesn't have.
Crashes & Stability
- 32-bit players running many FSEQ effects at once no longer run out of address space and crash.
- fppd starts on a system without IPv6, survives a second SIGBUS on another thread, and fixed crashes and hangs at shutdown (a plugin's web request in flight, an HTTP request in flight, MQTT, DDP stats).
- fppd stops and restarts from the UI faster, and an output reload no longer hangs while every output cycle runs late.
Upgrade & Install
- Upgrading from FPP 9.x before 9.5 no longer stops at upgrade step 102, which skipped every later step, including the chrony time-sync migration.
- An FPP update whose rebase hits a conflict aborts it cleanly instead of leaving a checkout that blocked every later update.
- Background update checks no longer peg a single-core board: page-load git fetches run at most every 15 minutes at low priority, and a failed fetch retries instead of turning update checks off.
- A plugin reloaded at runtime (as a plugin upgrade does) sees its settings changes again, and plugin pages no longer print the plugin's config file path.
Deprecations
- The Advanced "Force Audio Card ID" setting is removed; it had done nothing since the SDL audio output was removed. Use the audio output selection.
- An API path that is deliberately encoded twice no longer resolves.
Continued next post...