Skip to content

FIXED: iOS 27 mirror window stays open (frozen last frame) after disconnect — typeless TEARDOWN doesn't reset the video renderer #540

Description

@LukeProducts

Environment

  • UxPlay 1.74 (built from current master)
  • GStreamer 1.28.4, Windows 11 / MSYS2 UCRT64 (bug is in shared, platform-independent code)
  • Client: iPhone 15 Pro, iOS 27 beta

Symptom
When the client stops mirroring, the video output window stays open showing a frozen last frame, instead of the renderer being reset/closed. On the next connection this also contributes to a stale display.

Root cause
raop_handler_teardown() in lib/raop_handlers.h handles three cases: teardown_96 (audio stream), teardown_110 (video stream, which calls video_reset(RESET_TYPE_RTP_SHUTDOWN)), and the "no type" case that destroys the sessions. On older iOS the client sent a type-110 stream teardown (triggering the video reset) before the final typeless TEARDOWN. iOS 26/27 sends the final TEARDOWN without a preceding type-110 (observed in the log: TEARDOWN request, 96=0, 110=0), so the video renderer's video_reset is never called and the window/last frame is left in place.

Fix
In the typeless teardown branch, when tearing down the mirror session, also call video_reset(RESET_TYPE_RTP_SHUTDOWN). It must be called after raop_rtp_mirror_destroy(): destroy joins the mirror receive thread, so no more buffers are pushed into the pipeline that the reset then tears down. (Calling the reset first races the still-running thread against pipeline teardown and can crash in libgstapp — observed as an access violation on reconnect.)

@@ raop_handler_teardown(raop_conn_t *conn, ...
         if (conn->raop_rtp_mirror) {
+            /* iOS 26+ may send the final TEARDOWN without a type-110 stream
+             * teardown first; without this reset the video window (and a
+             * frozen last frame) stays open after the client disconnects.
+             * The reset must come AFTER destroy: destroy joins the mirror
+             * thread, so no more buffers are pushed into the pipeline that
+             * the reset is about to tear down (race -> crash in libgstapp). */
             raop_rtp_mirror_destroy(conn->raop_rtp_mirror);
             conn->raop_rtp_mirror = NULL;
+            raop->callbacks.video_reset(raop->callbacks.cls, RESET_TYPE_RTP_SHUTDOWN);
         }

Activity

  1. fduncanh commented on Aug 29, 2026

    @fduncanh
    Collaborator

    we now have an iPad with iPadOS 27 Beta 5 to investigate any new iOS 27 issues

  2. fduncanh commented on Aug 29, 2026

    @fduncanh
    Collaborator

    @LukeProducts
    Yes we now can confirm this.

    Differences observed between UxPlay intercating with clients iPadOS 26.6 and iPadOS 27 beta 5 public (BuildVersion 24A5424a)

      1. ios27 does not set an initial GetInfo request for txtAirPlay
        this may affect BlueTooth LE discovery (to be checked)
    • 2 on Stop Mirroring, iOS 26 sends:
      TEARDOWN 96 (audio, if audio was initialized)
      TEARDOWN 110 (video)
      TEARDOWN

    ios27 beta omits the TEARDOWN 110, as reported here, so leaves the video window open.

    *NOTE iPadOS 26.6 does send that TEARDOWN 110 (contradicts @LukeProducts observation: there were some logger items between TEARDOWN110 and TEARDOWN, so maybe it was overlooked in iOS 26)

  3. fduncanh commented on Aug 29, 2026

    @fduncanh
    Collaborator

    @LukeProducts thanks for the fix!

    546820c

  4. changed the title [-]iOS 26/27 mirror window stays open (frozen last frame) after disconnect — typeless TEARDOWN doesn't reset the video renderer[/-] [+]FIXED: iOS 26/27 mirror window stays open (frozen last frame) after disconnect — typeless TEARDOWN doesn't reset the video renderer[/+] on Aug 29, 2026
  5. changed the title [-]FIXED: iOS 26/27 mirror window stays open (frozen last frame) after disconnect — typeless TEARDOWN doesn't reset the video renderer[/-] [+]FIXED: iOS 27 mirror window stays open (frozen last frame) after disconnect — typeless TEARDOWN doesn't reset the video renderer[/+] on Aug 29, 2026
  6. fduncanh commented on Aug 29, 2026

    @fduncanh
    Collaborator

    ios27 does not set an initial GetInfo request for txtAirPlay
    this may affect BlueTooth LE discovery (to be checked)

    iOS 27 still sends the GET /info txtAirPlay request when it detects the Bluetooth LE beacon, so nothing is broken there...

    httpd request received on socket 16, connection 0, method = GET, url = /info?txtAirPlay&txtRAOP, protocol = RTSP/1.0
    conn_request
    response to Bluetooth LE beacon advertisement received)
    New connection 0x7fbb540128b0 identified as Connection type RAOP
    
    GET /info?txtAirPlay&txtRAOP RTSP/1.0
    X-Apple-QR: BT
    
    <key>osVersion</key>
            <string>27.0</string>
            <key>ekey</key>
    
    
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions