Skip to content

feat: add picture-in-picture pop-out for the live screen share - #1164

Draft
ankushdharkar wants to merge 1 commit into
developfrom
feat/live-picture-in-picture
Draft

ankushdharkar wants to merge 1 commit into
developfrom
feat/live-picture-in-picture

Conversation

@ankushdharkar

Copy link
Copy Markdown
Contributor

Date: 23-08-26

Developer Name: @ankushdharkar


Issue Ticket Number:-

Description:

Attendees listen to the event audio in a separate app (Twitter Spaces and similar), and the /live page carries only the host's screen share, so the video needs to float on top of whatever they switch to. This PR adds a Picture-in-Picture "Pop out" button to the live panel for every role and fixes the attribute typo that blocked inline playback on iOS Safari.

  • app/components/live-panel.hbs: new Pop out / Pop in icon button (@id="picture-in-picture"), rendered only when @isPictureInPictureSupported is true. The icon and title flip with @isPictureInPicture.
  • app/constants/live.js: new BUTTONS_TYPE.PICTURE_IN_PICTURE and a PICTURE_IN_PICTURE_MODE constant (picture-in-picture / inline) for the webkit presentation mode strings.
  • app/controllers/live.js: new togglePictureInPicture action, wired into buttonClickHandler for the new button type.
  • app/services/live.js: isPictureInPictureSupported getter (standard API plus document.pictureInPictureEnabled, or the webkit webkitSupportsPresentationMode API); togglePictureInPicture action that exits an active PiP element, otherwise calls requestPictureInPicture on the standard path, falls back to webkitSetPresentationMode for iOS Safari, and shows an info toast when neither API exists or the video element is not ready; an isPictureInPicture tracked flag kept in sync by enterpictureinpicture, leavepictureinpicture and webkitpresentationmodechanged listeners registered through registerPictureInPictureListeners / removePictureInPictureListeners. The toggle is called synchronously from the click handler because browsers only allow PiP inside a user gesture.
  • app/modifiers/picture-in-picture-events.js: new ember-modifier that runs a setup callback on insert and a teardown callback on destroy, so the listeners follow the video element's lifecycle.
  • app/components/video-screen.hbs / video-screen.js: fixes the misspelled playsinlne attribute to playsinline (iOS Safari forced fullscreen playback without it, so PiP never started) and attaches the new modifier.
  • app/templates/live.hbs: passes isPictureInPicture and isPictureInPictureSupported from the live service into LivePanel.
  • Tests: 3 new integration tests in tests/integration/components/live-panel-test.js, 2 new unit tests in a new tests/unit/controllers/live-test.js, and 8 new unit tests in tests/unit/services/live-test.js covering the standard path, the exit path, both webkit paths, the no-API toast, the not-ready toast, event tracking and platform support detection.

No microphone or camera permission is involved; the video element stays muted.

Is Under Feature Flag

  • Yes (live route is behind the dev query flag)
  • No

Database changes

  • Yes
  • No

Breaking changes (If your feature is breaking/missing something please mention pending tickets)

  • Yes
  • No

Is Development Tested?

  • Yes
  • No

Tested in staging?

  • Yes
  • No

Add relevant Screenshot below ( e.g test coverage etc. )

Test run

Automated checks only (no images to attach). Logs from the implementing session under /tmp/test-results/www-emberjs/.

pnpm ember test (log 20260823-013836-ember.log, exit 0):

1..401
# tests 401
# pass  395
# skip  6
# todo  0
# fail  0

# ok

All 13 new tests reported ok in that run:

ok 119 Chrome 151.0 - Integration | Component | live-panel: it renders the pop out button for guest and host when picture in picture is supported
ok 120 Chrome 151.0 - Integration | Component | live-panel: it hides the pop out button when picture in picture is not supported
ok 121 Chrome 151.0 - Integration | Component | live-panel: it should call the button click handler with picture-in-picture on pop out click
ok 297 Chrome 151.0 - Unit | Controller | live: it toggles picture in picture from the pop out button
ok 298 Chrome 151.0 - Unit | Controller | live: it shares the screen from the screen share button
ok 376 Chrome 151.0 - Unit | Service | live > picture in picture: it requests picture in picture when the standard API is available
ok 377 Chrome 151.0 - Unit | Service | live > picture in picture: it exits picture in picture when a picture in picture element is active
ok 378 Chrome 151.0 - Unit | Service | live > picture in picture: it uses the webkit presentation mode when only the webkit API exists
ok 379 Chrome 151.0 - Unit | Service | live > picture in picture: it leaves the webkit presentation mode when already popped out
ok 380 Chrome 151.0 - Unit | Service | live > picture in picture: it informs the user when the browser has no picture in picture API
ok 381 Chrome 151.0 - Unit | Service | live > picture in picture: it informs the user when the video element is not ready
ok 382 Chrome 151.0 - Unit | Service | live > picture in picture: it tracks picture in picture state from the video element events
ok 383 Chrome 151.0 - Unit | Service | live > picture in picture: it reports picture in picture support from the platform APIs

pnpm lint (log 20260823-013543-lint.log): lint clean, lint:js, lint:hbs, lint:format and lint:css all exited 0 (429 files linted by template-lint).

No coverage numbers were collected.

Additional Notes

  • Manual device checks are still outstanding: iOS Safari and Android Chrome have not been exercised by a human. In particular it is not yet confirmed whether a MediaStream-sourced video element enters Picture-in-Picture on iOS via the webkit presentation mode path; the isPictureInPictureSupported getter hides the button when neither API exists, and the toast covers a refused request, but the iOS behaviour itself is unverified.
  • A separate screen-only PR on this repo also fixes the playsinlne typo in app/components/video-screen.hbs. Whichever of the two lands second needs a trivial rebase on that line.
  • Behavioural note for reviewers: the button is visible for every role, not only the host, because attendees are the ones who need the video floating over their audio app.
  • Environment caveat from the implementing session: package.json declares node >= 25 while the local run used Node v22.22.0 with pnpm 11.22.0, which only produced an engine warning; the test and lint runs above completed under that setup.
  • Suggested review order: app/services/live.js (the toggle and support detection), then app/components/video-screen.hbs and the modifier, then the panel template and tests.

Attendees listen to the event audio in a separate app, so the screen
share needs to float on top of whatever they switch to. The panel now
carries a Pop out button for every role that toggles picture in picture
on the screen share video element.

* fix the playsinlne typo on the video element, iOS Safari needs
  playsinline or it forces fullscreen playback and picture in picture
  never starts
* support the standard picture in picture API and the webkit
  presentation mode used by iOS Safari, with an info toast when the
  browser has neither
* track the enter and leave events so the button can say Pop in while
  the video is floating
* hide the button when the platform has no picture in picture API

No microphone or camera permission is involved, the video element stays
muted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@ankushdharkar, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 59 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 78d2b288-2b67-4aee-96f0-d4afd7a0efee

📥 Commits

Reviewing files that changed from the base of the PR and between 6e19f3b and ba17baf.

📒 Files selected for processing (11)
  • app/components/live-panel.hbs
  • app/components/video-screen.hbs
  • app/components/video-screen.js
  • app/constants/live.js
  • app/controllers/live.js
  • app/modifiers/picture-in-picture-events.js
  • app/services/live.js
  • app/templates/live.hbs
  • tests/integration/components/live-panel-test.js
  • tests/unit/controllers/live-test.js
  • tests/unit/services/live-test.js

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying www-rds with  Cloudflare Pages  Cloudflare Pages

Latest commit: ba17baf
Status: ✅  Deploy successful!
Preview URL: https://d8de4649.www-rds.pages.dev
Branch Preview URL: https://feat-live-picture-in-picture.www-rds.pages.dev

View logs

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a Picture-in-Picture pop-out for the live screen share

1 participant