Skip to content

2026.8.2-dev pre-release: WE HAVE A F...ING ESPHOME VIDEOPHONE!

Pre-release
Pre-release

Choose a tag to compare

@n-IA-hane n-IA-hane released this 12 Aug 14:23

2026.8.2-dev pre-release: WE HAVE A F...ING ESPHOME VIDEOPHONE!

2026.8.2-dev remains an active pre-release and work in progress. The tag and
HACS archive may be refreshed while field qualification continues. Use
2026.8.0 when you need the current stable release.

🔧 What 2026.8.2-dev adds

The original P4 videophone milestone is all still here. Since that first
development candidate, the project has also received a deep consolidation of
the PBX, SIP and media lifecycles:

  • one generation-owned call session now governs direct, trunk, forwarded,
    grouped, conference, browser and Assist calls;
  • answer, bridge activation, losing-leg settlement, projection, rollback and
    termination now use shared authoritative primitives instead of parallel call
    paths;
  • public idle is published only after call-scoped tasks, media owners, relays,
    sockets and RTP reservations have crossed the cleanup barrier;
  • SIP interoperability now includes reliable provisional responses and PRACK,
    initial and in-dialog delayed offers, RFC 4028 session refresh, remote forks
    and late 2xx settlement, REFER/NOTIFY, stronger Digest authentication,
    RFC 3263 discovery, TLS and IPv6;
  • registered clients, trunks and local endpoints share the same atomic
    audio/video renegotiation mechanics, including audio-first video add, remove
    and re-add without sacrificing the established audio call;
  • forwarding, ring groups, conference calls, DTMF routing and browser phones
    retain one call owner and release failed or losing destinations without
    disturbing the remaining members;
  • the P4 JPEG and H.264 paths gained bounded presentation work, bidirectional
    cadence stabilization, post-call LVGL recovery and one-shot framebuffer
    capture for direct physical-panel verification;
  • the ESP voice assistant is now documented as an independent optional device
    capability, separate from a SIP call to Home Assistant Assist;
  • the local qualification toolkit now covers real Home Assistant, Chromium,
    SIPp, baresip, registered clients, trunks, S3/P4 hardware, firmware metadata
    and post-call quiescence without running jobs automatically on GitHub pushes.

This is still a development release. The stable baseline remains 2026.8.0.

🏠 Home Assistant and VoIP Stack

  • The Home Assistant audio and video media paths now share one lifecycle for
    authenticated ownership, replacement barriers, live-session resolution,
    bridge leases, cleanup and final state publication.
  • Physical ESPHome phones and Home Assistant softphones now use the same
    device_id source selector. The service dispatches each phone through its
    native adapter, and an ESP service response is no longer resolved again as
    a browser phone.
  • The new packages/voip/ha_phone.yaml package provides the complete physical
    phone surface in one include: discovery entities, native call-control
    actions and the Home Assistant managed phonebook.
  • SIP routing identity and presentation identity remain separate. Stable URI
    users route calls, while standard quoted display names preserve spaces from
    ESP friendly names, local accounts and external callers. RFC 4916 connected
    identity lets the caller learn the resolved callee after answer.
  • SIP-to-SIP bridges negotiate each leg independently. Compatible codecs stay
    on direct RTP, while the optional bounded FFmpeg fallback converts an
    incompatible active direction to H.264, VP8 or RTP/JPEG as required by the
    receiving endpoint.
  • An established audio call can add, remove and add video again through
    standard in-dialog re-INVITE without restarting its audio relay. RTP profile,
    direction, payload type and codec changes commit as one media generation.
  • Transcoded SIP audio is paced by its negotiated packet time, and immediate
    redial waits for the previous bounded transcoder to release its slot.
  • Negotiated RFC 4733 DTMF payload types and media direction are retained
    through direct, bridged and trunk call paths.
  • Browser ownership follows the logical phone, committed SIP transaction,
    active call and media direction. Dashboard reloads and multiple cards can
    hand media over without creating a second call owner.
  • Mixed browser and SIP ring groups let the first valid answer win, cancel the
    losing INVITEs and settle every remaining leg.
  • Inbound routing, forwarding, conference ringing, SIP bridge handling and
    browser media claims now use focused lifecycle owners while CallRegistry
    remains the observable compatibility index.
  • In-dialog video activation now follows the bridge relay that is actually active, not merely the presence of a dormant recvonly SDP media line. Re-INVITEs preserve the negotiated RTP audio codec and payload instead of accidentally changing PCMA, PCMU, G.722 or Opus into L16.
  • Completed dialogs retain a bounded SIP transaction tombstone. A delayed retransmission of the original INVITE now receives 481 Call/Transaction Does Not Exist and cannot reclaim a softphone after BYE.
  • Unexpected teardown failures are surfaced instead of being silently hidden,
    and completed calls release their sessions, sockets, bridges and RTP ports.
  • FRITZ!Box REGISTER now uses the bare registrar URI, keeps the account AOR in
    To and From, refreshes CSeq and Via branch after authentication, follows SIP
    Timer F and runs without blocking Home Assistant setup.
  • FRITZ!Box interoperability has been improved for authenticated registration
    and internal service dial strings such as **621. Thanks to
    @ruedigerhanses-stack for the careful hardware testing and iterative
    validation in issue #95.
  • RTP audio with valid packet boundaries different from negotiated ptime is
    accumulated and reframed by the shared PCM converter. This fixes the
    reported FRITZ!Box PCMA/16000 320-byte input without forcing a codec change.
  • ESPHome phonebook delivery now tracks exact content per device. Reconnects
    restore only the restarted phone, while duplicate callbacks and unchanged
    setup retries no longer republish the roster to every ESP.
  • Home Assistant configuration, entities, issues, system health and service
    errors now include complete Brazilian Portuguese and German translations.
    The Lovelace card, editor and phonebook follow the active HA language too.
  • dnspython SRV and NAPTR record parsers are preloaded outside Home Assistant's
    event loop, removing the blocking-import warning during RFC 3263 trunk
    resolution without changing dial-plan or DNS behavior.
  • Renaming a logical phone and then changing one of its entity IDs no longer
    lets stale entity metadata restore the previous device name.

🎬 Browser video worker and card

  • JPEG encoding and decoding, plus H.264 and VP8 WebCodecs decoding when the
    browser supports it, can run in a dedicated worker instead of blocking the
    card UI.

  • Worker generations prevent stale frames from a replaced call from reaching
    the screen. VideoFrame and ImageBitmap objects are closed on success,
    replacement and error paths.

  • The card editor and view builder are now focused modules without changing
    the public card configuration.

  • The card remains the GUI and media surface of a logical softphone. The
    softphone itself continues to exist and ring independently of an open card.

  • Browser calls verify secure context, Web Audio support and microphone access
    before signaling. A web view without getUserMedia no longer accepts a call
    and immediately tears it down with BYE.

  • Thanks to @csfrussa, browser microphone downsampling now applies a
    fourth-order Butterworth anti-alias filter before decimation. In Chromium
    validation it reduced a 12 kHz tone folding into 4 kHz by 23.4 dB while the
    wanted 1 kHz signal remained unchanged.

  • A Microphone anti-alias filter switch in the card's idle Options panel
    lets each browser and logical phone compare the filtered and legacy paths.
    It is enabled by default, applies from the next call and adds no filtering
    cost when the browser and negotiated transmit rates already match.

  • Browser softphones can now enumerate and remember the preferred microphone,
    speaker and camera for each browser and logical phone. If no preference has
    been selected, the existing browser defaults remain unchanged.

  • Media devices can be changed while a call is ringing or established. Camera
    replacement preserves the active SIP session and disposes the superseded
    capture track instead of creating a parallel sender lifecycle.

  • The card keeps one responsive Options surface in idle, audio calls and
    video calls. During video it becomes a compact settings icon inside the call
    bar, while the opaque options view replaces the card content for clear and
    accessible device selection.

  • The existing hangup control now reacts subtly to received audio level without
    overriding its responsive dimensions or adding a second audio capture path.

A live P4 camera call in the Home Assistant softphone card

🎥 WE HAVE A F...ING ESPHOME VIDEOPHONE!

Everything started when @Psix-anp shared a working ESP32-P4 camera build based
on the ESPHome camera work by @youkorr. What can I say, half a second later I
was already experimenting with bidirectional SIP video on ESPHome.

And we made it. A P4 can now be a real audio and video SIP endpoint, including
bidirectional video on its own display. Better still, the JPEG path is light
enough to live inside the full P4 profile alongside Micro Wake Word, Voice
Assistant, AFE echo cancellation, LVGL, TTS and Sendspin.

This opens the door to custom ESPHome videophones and doorbells with echo
cancellation, full P4 voice-assistant tablets, and direct room-to-room audio
and video calls between P4 devices.

Two P4 videophone use cases, a door call and a room-to-room call

The implementation stays close to the accelerated Espressif media paths:

  • esp_video 2.3.0 owns the MIPI-CSI and V4L2 camera pipeline. JPEG SIP TX
    borrows the camera's already encoded access unit, so it does not capture or
    encode the same frame a second time.
  • The JPEG camera follows Espressif's V4L2 startup practice and discards the
    first two CSI buffers after STREAMON. Cross-codec calls therefore begin
    with a color-stable JPEG and VP8 keyframe instead of publishing a transient
    ISP startup frame.
  • The H.264 profile uses esp_h264 1.3.6 for the ESP32-P4 hardware encoder and
    software decoder, with esp_image_effects 1.1.0 for its optimized I420
    conversion.
  • ESP-IDF PPA handles scaling, rotation and color conversion. Hardware JPEG
    decode and direct MIPI DSI presentation keep the P4 display path lean.
  • JPEG and H.264 are gated at compile time. A JPEG firmware does not include
    the H.264 media path, and the H.264 firmware does not include JPEG SIP video.

The P4 profiles are now:

  • the canonical full AFE JPEG videophone,
    waveshare-p4-touch-full-afe-landscape-videophone-jpeg.yaml;
  • the lightweight bidirectional RTP/JPEG videophone,
    waveshare-p4-touch-videophone-jpeg.yaml;
  • the experimental bidirectional H.264 videophone,
    waveshare-p4-touch-videophone-h264.yaml.

H.264 remains experimental in this pre-release. JPEG is the current full P4
baseline.

⌨️ Smaller ESPHome improvements

The compact Spotpear profile now has a dedicated touch keypad that keeps
contact navigation and direct extension dialing on the device.

The Spotpear touch keypad

Existing ESP audio profiles keep their native PCM transport and audio-stack
behavior. This update does not replace the audio backend or reduce configured
sample rates. P4 codec selection remains compile-time gated and its media tasks
remain event driven.

⚠️ Breaking change

The former P4 full landscape profile was promoted to the canonical full JPEG
videophone and renamed:

yamls/full-experience/single-bus/waveshare-p4-touch-full-afe-landscape.yaml

is now:

yamls/full-experience/single-bus/waveshare-p4-touch-full-afe-landscape-videophone-jpeg.yaml

Review the complete
breaking changes
before updating an existing installation.

✅ Qualification

  • 1620 Python tests plus 140 subtests passed on the published candidate.
  • Ruff passed for the custom component, ESPHome components, tests and tools.
  • Every shipped JavaScript file passed syntax validation.
  • The canonical full JPEG profile completed repeated real HA-to-P4 calls with
    bidirectional audio and video, zero reported RTP loss or media drops, clean
    BYE handling and quiescent call-scoped resource cleanup.
  • A Zoiper-style PCMA and VP8 call completed audio-to-video re-INVITE through
    the HA B2BUA and its JPEG fallback. The first returned VP8 frame was a valid,
    color-stable keyframe; all four audio/video RTP flows reported zero packet
    loss and both JPEG depacketizers reported zero dropped access units.
  • The dedicated JPEG and experimental H.264 P4 profiles have both completed
    real bidirectional audio and video calls on hardware.
  • Real voip_stack.call service tests originated calls from P4 to WS3 and
    from WS3 to P4 using their Home Assistant Device IDs. Both directions
    reached in_call, returned the physical ESP source descriptor and cleaned
    both endpoints back to idle after hangup.
  • Ten consecutive real SIP cycles completed audio to video to audio renegotiation, bidirectional RTP, immediate redial and BYE / 200 OK. A real card-originated call succeeded immediately after the tenth cleanup.
  • The final hardware matrix completed 12 calls across P4, WS3 and a real
    trunk, including H.264 audio-video-audio-video renegotiation, SIP INFO and
    RFC 2833 DTMF, hangup from both directions, immediate redial and zero
    call-scoped resources after cleanup.

💖 Thanks for the donations

Special thanks to @jjhelin, @kuid87 and @jftkcs for supporting the project. If
VoIP Stack has been useful to you and you would like to support its continued
development, you can do so through
GitHub Sponsors.

📦 Installation and feedback

In HACS, enable pre-release versions for VoIP Stack. Open VoIP Stack, use the
three-dot menu, select Redownload and choose 2026.8.2-dev. Restart Home
Assistant, then clear the browser or Companion app cache so the updated card
multimedia engine is loaded.

When reporting a regression, include the exact test time, call direction,
endpoint models, selected codec and sanitized logs from INVITE through final
cleanup. The GitHub release contains the flat voip_stack.zip archive used by
HACS.

⚠️ Known issue: OnePlus high-refresh audio

On a OnePlus Nord 5, browser softphone receive audio can develop audible gaps
and increment the playback underrun counter at a high display refresh rate,
especially during touch interaction or orientation changes. The same call path
is stable on that phone at 60 Hz and has not reproduced on a Samsung S20 or
desktop browser.

The current workaround is to select the standard 60 Hz display mode, globally
or specifically for Chrome and the Home Assistant app. Initial evidence points
to device-side Chromium or OxygenOS scheduling under high-refresh rendering
load, but the exact cause is not yet proven. Deeper investigation is planned
after this release.

📞 Live SIP phonebook presence

  • Local SIP accounts now appear in the Home Assistant managed phonebook only while they have an active registrar binding.
  • REGISTER, explicit de-registration and natural Contact expiry rebuild and publish the same canonical roster to every connected ESPHome phone.
  • Static contacts and browser phones remain independent from SIP registration state, while offline ESPHome endpoints continue to follow their own availability.