Revert the PiP content-source switch, and add pause from anywhere - #129
Merged
Merged
Conversation
Two halves of one feature. **Pause, from any surface.** New CONTROL commands pause_stream and resume_stream hold a running stream instead of ending it: the app keeps the connection, the camera and the encoder, and simply stops sending video. Resuming asks for a keyframe, so OBS has something self-contained to restart on — no reconnect, no re-negotiation. Audio is deliberately untouched: a phone doubling as the wireless mic should not go silent because the picture is held. The buttons are on the Live screen (next to Stop), in the source properties, and in the web panel, all reading the same STATE so whichever one you press, the others follow. These need no remote-start permission — they can only hold a stream the user already started, never turn a camera on. **A paused stream looks paused.** An async source keeps its last frame, so a pause was indistinguishable from a stall: same frozen picture, no explanation. The decoder now keeps a 64x36 luma thumbnail of the last frame — sampled sparsely, so the cost is the same at 4K as at 720p and never touches chroma — and pausing blows it back up to frame size. The upscale is the blur: no kernel, no per-frame work, and grey with a pause glyph over it so it reads across a room as deliberate rather than broken. One frame, pushed once. The GPU pipeline keeps its frames in textures with no thumbnail to sample, so there the picture stays as it was. iOS reports the involuntary case through the same path: when a hidden PiP window loses the camera, STATE says paused with reason "camera" while the status keeps the sentence explaining what to do about it. The Live screen hides its resume button in that case — a button that cannot resume anything is a lie — and the stream comes back on its own when capture does. Docs: PROTOCOL gains the commands and the STATE fields, UI_DESIGN gains the Paused status word and why it borrows Standby's amber, and the Documentation screen, settings, web-panel and troubleshooting pages all describe the button and the still. Release-Bump: minor Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C83kP6jfQWe7dwrjB4KMPB
v1.11.3 swapped the video-call content source for the sample-buffer one to get the close and restore buttons back. On a device the window then never opened at all, so background streaming was gone outright — a worse failure than the missing buttons it was meant to fix, and the one PiP failure with no symptom of its own: the stream simply ends as the app leaves the screen, exactly as it did before the feature existed. So this restores AVPictureInPictureVideoCallViewController, and with it the orientation handling that had been removed as redundant: the window is shaped and rotated to how the phone is being held, read while the app is still on screen. Two things kept from the attempt. The failure to start is now logged with iOS's own reason rather than silently swallowed, which is what would have explained this in seconds. And the file records why this flavour is the one that works, so the swap isn't attempted blind again: Apple documents camera-in-PiP alongside this controller, and the device agrees. The window therefore has no buttons of its own. Stopping or pausing from outside the app goes through OBS, the web panel or Siri — the app's Documentation screen and the troubleshooting page now say that instead of describing buttons that aren't there. Release-Bump: patch Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C83kP6jfQWe7dwrjB4KMPB
Deploying lenslink with
|
| Latest commit: |
7aec646
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://4f11e2e4.lenslink.pages.dev |
| Branch Preview URL: | https://claude-battery-icon-visibili.lenslink.pages.dev |
The revert brought back the v1.11.2 troubleshooting text, which describes close and restore buttons on the PiP window. Those never existed on this content source — that was the whole reason for the switch that had to be reverted — so the page now says the window has none, and points at the controls that do work: OBS, the web panel, Siri, or tapping the window to come back. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C83kP6jfQWe7dwrjB4KMPB
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
1. Revert: background streaming is broken on v1.11.3 (the urgent half)
v1.11.3 swapped the video-call content source for the sample-buffer one to get the close and restore buttons back. On a device the window then never opened at all, so background streaming was gone outright — a worse failure than the missing buttons it was meant to fix, and the one PiP failure with no symptom of its own: the stream simply ends as the app leaves the screen, exactly as it did before the feature existed.
This restores
AVPictureInPictureVideoCallViewController, and with it the orientation handling that had been removed as redundant — the window is shaped and rotated to how the phone is being held, read while the app is still on screen (that fix shipped in the same release that broke the window, so it has never actually been seen working).Two things kept from the attempt:
failedToStartPictureInPictureWithErrornow logs iOS's own reason instead of silently swallowing it. That is what would have explained this in seconds rather than a release cycle.BackgroundPiP.swiftrecords why this flavour is the one that works, so the swap isn't attempted blind again.The window therefore has no buttons of its own. Stopping or pausing from outside the app goes through OBS, the web panel or Siri; the Documentation screen and troubleshooting page now say that rather than describing buttons that aren't there.
2. Pause, from any surface — and a paused stream that looks paused
New CONTROL commands
pause_stream/resume_streamhold a running stream instead of ending it: the app keeps the connection, the camera and the encoder, and stops sending video. Resuming asks for a keyframe, so OBS has something self-contained to restart on. Audio is deliberately untouched — a phone doubling as the wireless mic shouldn't go silent because the picture is held. Buttons are on the Live screen (next to Stop), in the source properties, and in the web panel, all reading the same STATE so pressing one updates the others. They need no remote-start permission, since they can only hold a stream the user already started.An async source keeps its last frame, so a pause was indistinguishable from a stall. The decoder now keeps a 64×36 luma thumbnail of the last frame — sampled sparsely, so it costs the same at 4K as at 720p and never touches chroma — and pausing blows it back up to frame size. The upscale is the blur: no kernel, no per-frame work, grey with a pause glyph over it. One frame, pushed once. The GPU pipeline keeps frames in textures with no thumbnail to sample, so there the picture stays as it was.
That also covers the PiP case: when a parked window loses the camera, STATE says
pausedwith reasoncamera, so OBS shows the still instead of a frozen frame, while the app's status keeps the sentence explaining what to do. The Live screen hides its resume button there, since nothing it could press would resume anything.Docs: PROTOCOL gains the commands and STATE fields, UI_DESIGN gains the Paused status word, and the Documentation screen plus the settings, web-panel and troubleshooting pages describe the buttons and the still.
How it was tested
ios-app/syntax-check.sh— parses clean;site/build.py+check-links.py— 16 pages, 0 broken links.paused-still.cand the decoder thumbnail (no libobs in the dev container).Release-Bump: minor
🤖 Generated with Claude Code
https://claude.ai/code/session_01C83kP6jfQWe7dwrjB4KMPB