Skip to content

Navigation Menu

Sign in
Sign up

Raise RTSP message limit so iOS mirror-stream SETUP isn't rejected - #11

Open
mhoogenbosch wants to merge 1 commit into
mazer666:main from
mhoogenbosch:fix/rtsp-body-limit-ios26
Open

Raise RTSP message limit so iOS mirror-stream SETUP isn't rejected #11
mhoogenbosch wants to merge 1 commit into
mazer666:main from
mhoogenbosch:fix/rtsp-body-limit-ios26

Conversation

@mhoogenbosch

@mhoogenbosch mhoogenbosch commented Jul 6, 2026

Copy link
Copy Markdown

Problem

When mirroring from an iPhone (observed: iPhone 17, iOS 26.5.2), the AirPlay session established fine (pair-verify, fp-setup, mirror keys, RECORD) and the audio stream even played briefly — but then the sender tore the whole session down and the screen stayed black.

The debug log showed the cause:

W/Logger: Request body too large (78575 bytes) — rejecting
I/Logger: Client disconnected

The iOS mirror-stream SETUP request carries a large binary plist (~77 KB in my capture). RtspRequestReader caps request bodies at MAX_MESSAGE_BYTES = 65536 (64 KB) and returns null for anything larger, so the video stream SETUP was dropped. The sender set up the audio stream (small SETUP), played ~1 s of audio, then gave up when its video SETUP got no response.

Fix

Raise MAX_MESSAGE_BYTES (in RtspHandler) from 64 KB to 1 MB. This clears the observed ~77 KB SETUP with ample headroom, and stays trivially safe on a LAN — the body is still read into a single bounded ByteArray(contentLength).

Testing

Built assembleGoogletvDebug, sideloaded on a Nokia Streaming Box 8010 (Google TV). Before: audio played ~1 s then instant Client disconnected. After: the session stays up and audio streaming is stable (continuous /feedback keep-alives for minutes, no teardown).

Note: full iOS 26 screen-mirror video still doesn't render on my end for other reasons (the sender doesn't emit a stream SETUP after RECORD on iOS 26, and the /play video-playback path hits an unhandled POST /fp-setup2) — I'll file those separately as an issue. This PR is scoped to the body-limit bug, which is a clear regression blocker on its own.

🤖 Generated with Claude Code

gemini-code-assist[bot] reacted with eyes emoji
An iOS/iPadOS mirroring SETUP request carries a large binary plist
(~77 KB observed from an iPhone 17 on iOS 26). RtspRequestReader capped
request bodies at MAX_MESSAGE_BYTES = 64 KB and rejected anything larger
("Request body too large — rejecting"), so the video-stream SETUP was
dropped. The sender set up the audio stream, briefly played audio, then
tore the whole session down when its video SETUP got no response —
screen stayed black.
Raise MAX_MESSAGE_BYTES to 1 MB. That clears the observed ~77 KB SETUP
with ample headroom for future senders, and is trivially safe on a LAN
(the body is still read into a single bounded ByteArray).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request increases the MAX_MESSAGE_BYTES constant in RtspHandler.kt from 64 KB to 1 MB to accommodate larger binary plist payloads from iOS/iPadOS mirror-stream SETUP requests, preventing video stream rejections. I have no feedback to provide as there are no review comments.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Copy link
Copy Markdown
Author

Issues are disabled on the repo, so posting the related iOS 26 findings here (separate from this PR's body-limit fix, which stands on its own). Tested with iPhone 17 / iOS 26.5.2 (sourceVersion=950.7.1) on a Nokia Streaming Box 8010, googletv debug build.

1. Screen mirroring — sender sends no stream SETUP after RECORD. With the body-limit fix in, the control session fully completes (pair-verify, fp-setup v=0x03, mirror keys, event channel, RECORD OK) and then only POST /feedback every 2 s, indefinitely and stably. There is never a mirror SETUP plist: streams=list[...] (no type 96 or 110), so nothing streams. Older senders emit the stream SETUP right after RECORD. Suspect GET /info (InfoResponder: model=AppleTV5,3, sourceVersion=220.68, features=0x1E5A7FFFF7) no longer matches what iOS 26 needs before opening the mirror video stream. fp-setup phase-1 mode varies across attempts (0/1/2).

2. /play video playback — unhandled POST /fp-setup2. Via an app's AirPlay button, iOS 26 reconnects, does GET /server-info, two fp-setup phases OK, then POST /fp-setup2 (120-byte body) → Unknown/unhandled RTSP: POST /fp-setup2, ~30 s stall, disconnect. iOS 26 seems to require this newer FairPlay step before it will proceed with /play.

3. mDNS (minor). (a) _airplay._tcp registration throws NameConflictException when the service name equals the system device name Google TV already advertises for Cast — leaves AirPlay "Disabled"; a distinct Device Name works around it (the code comment expects NsdManager auto-rename, but this Android build throws). (b) MdnsService.restart() on each teardown races the async unregister, so the name climbs ... (2), (3) and the device disappears/renames in the picker until a full restart.

Happy to capture full plists / the /fp-setup2 body hex / /info dumps if that helps chase the iOS 26 negotiation.

mhoogenbosch referenced this pull request in mhoogenbosch/PhairPlay Jul 19, 2026
...ected
iOS 26 senders emit a ~77 KB binary-plist SETUP for the mirror stream,
which exceeded the 64 KB cap — the reader rejected it and the sender tore
the session down right after audio started. Same fix as upstream PR #11.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Matej-Hajek pushed a commit to Matej-Hajek/PhairPlayPhone that referenced this pull request Jul 28, 2026
...ected
iOS 26 senders emit a ~77 KB binary-plist SETUP for the mirror stream,
which exceeded the 64 KB cap — the reader rejected it and the sender tore
the session down right after audio started. Same fix as upstream PR mazer666#11.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copy link
Copy Markdown

Hi @mazer666, sorry to comment here, but it seems the 'Issues' tab is disabled for this repository. I'm experiencing two critical bugs on Sony Android TV 12. Describe the bug
I am experiencing two specific issues with PhairPlay on my Sony TV:

 Screensaver interrupts casting: When casting for a long time (around 1 hour) or when the TV's power-saving/screensaver timer triggers, PhairPlay does not prevent the screen from sleeping. The TV automatically switches to the screensaver. Other casting apps usually prevent this.
 Discovery fails after deep sleep: If I turn off the TV via the remote (standby mode) and turn it back on after 3-4 hours, PhairPlay can no longer be discovered by any Apple device. This happens in both Sony's Normal mode and Pro mode.
To Reproduce
Issue 1: Start AirPlay mirroring. Wait for the TV's screensaver timeout. The cast is interrupted by the screensaver.
Issue 2: Put the TV to sleep via the remote. Wait 3-4 hours. Turn on the TV, launch PhairPlay, and try to search for the TV via AirPlay. It will not show up.
Expected behavior
 PhairPlay should keep the screen awake (FLAG_KEEP_SCREEN_ON or WakeLock) during an active casting session.
 PhairPlay should properly re-initialize the network broadcast service (mDNS) when the TV wakes up from standby.
Environment:
 TV Model: Sony X90J
 OS: Android TV 12
 Sender Devices: macOS 15.7.9, iPhone 13 / 16 Pro Max (iOS 18.7.2 / iOS 26.6)

mhoogenbosch commented Aug 26, 2026
edited
Loading

Copy link
Copy Markdown
Author

Hi @mazer666, sorry to comment here, but it seems the 'Issues' tab is disabled for this repository. I'm experiencing two critical bugs on Sony Android TV 12. Describe the bug I am experiencing two specific issues with PhairPlay on my Sony TV:

 Screensaver interrupts casting: When casting for a long time (around 1 hour) or when the TV's power-saving/screensaver timer triggers, PhairPlay does not prevent the screen from sleeping. The TV automatically switches to the screensaver. Other casting apps usually prevent this.
 Discovery fails after deep sleep: If I turn off the TV via the remote (standby mode) and turn it back on after 3-4 hours, PhairPlay can no longer be discovered by any Apple device. This happens in both Sony's Normal mode and Pro mode.
To Reproduce
Issue 1: Start AirPlay mirroring. Wait for the TV's screensaver timeout. The cast is interrupted by the screensaver.
Issue 2: Put the TV to sleep via the remote. Wait 3-4 hours. Turn on the TV, launch PhairPlay, and try to search for the TV via AirPlay. It will not show up.
Expected behavior
 PhairPlay should keep the screen awake (FLAG_KEEP_SCREEN_ON or WakeLock) during an active casting session.
 PhairPlay should properly re-initialize the network broadcast service (mDNS) when the TV wakes up from standby.
Environment:
 TV Model: Sony X90J
 OS: Android TV 12
 Sender Devices: macOS 15.7.9, iPhone 13 / 16 Pro Max (iOS 18.7.2 / iOS 26.6)

I created a fork for this APK, and fixed lot's of bugs.

https://github.com/mhoogenbosch/PhairPlay

Maybe it helps you, if not, feel free to raise an issue.

-- edit

You are right, there was no way of making sure the screensaver wouldn't pop on. I fixed this in my fork, en will create a PR for this upstream repo.

Copy link
Copy Markdown
Author

@sigurdshilfe both of your findings are fixed and sent upstream as #13.

You were right on both counts, and neither turned out to be Sony-specific — I could reproduce them on a Fire TV. There was no FLAG_KEEP_SCREEN_ON and no wake lock anywhere in the app, so nothing ever kept the screen up during a session. And an NsdManager registration does not survive the Wi-Fi interface going down in standby, with no code path to bring it back: on wake the receiver is still listening on port 7000 and still thinks it is running, while being invisible to every sender.

One extra thing came out of the second one: CHANGE_WIFI_MULTICAST_STATE has been in the manifest from the start but nothing ever used it, so Wi-Fi power-save was free to drop the multicast frames that carry every AirPlay query. That is now held by a MulticastLock while advertising, and may well be part of why discovery felt flaky beyond the standby case.

Verified on hardware by bouncing a TV's own Wi-Fi — the advertisement comes back within a second of the network returning, display name intact.

If you would rather not wait for #13 to be reviewed, the same fixes are in my fork's v1.1.0-mh.7 release with prebuilt APKs for Google TV and Fire TV: https://github.com/mhoogenbosch/PhairPlay/releases/tag/v1.1.0-mh.7adb install -r keeps your settings and display name. Do let me know if the standby case still bites you after that; I could only test it by forcing the interface down, not by leaving a TV off for four hours.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

1 more reviewer
@gemini-code-assist gemini-code-assist[bot] gemini-code-assist[bot] left review comments
Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

AltStyle によって変換されたページ (->オリジナル) /