Skip to content

[pull] master from jitsi:master - #838

Merged
pull[bot] merged 2 commits into
code:masterfrom
jitsi:master
Aug 19, 2026
Merged

[pull] master from jitsi:master#838
pull[bot] merged 2 commits into
code:masterfrom
jitsi:master

Conversation

@pull

@pull pull Bot commented Aug 19, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

hristoterezov and others added 2 commits August 19, 2026 10:07
* feat(documentPiP): auto open on tab switch and trigger button (#17450)

* feat(documentPiP): auto open on tab switch and trigger button

* suggestions

* lint:fix

* file and class name updates

* restore comment

* suggestions

* add: suggestions and webkit for safari auto open

* add: comment

* feat: document pip window content (#17576)

* feat(config): gate browser pip behind config flag

* fix(safari): PiP Video content

* lint:fix

* suggestions

* comment

* comment

* remove key state

* chore: add default fallback for browser pip config

* chore: dev styling gap for make

* hide

* lint

* fix: safari pip open with avatar show on video mute (#17721)

* fix(pip): deliver canvas avatar frames on WebKit

Safari never showed the PiP avatar (and refused to open PiP at all)
when the stage participant had video off from the start of the meeting,
because no frame was ever delivered to the hidden video element:

- CanvasCaptureMediaStreamTrack.requestFrame() in WebKit only arms a
  one-shot capture that fires on the next canvas paint. The render
  always painted first and requested after, so on a static avatar
  canvas the armed capture waited forever for a repaint. Later state
  churn accidentally satisfied the previous cycle's request, which is
  why the avatar appeared to work once PiP had been shown before.
- Frames published right after a srcObject assignment are silently
  dropped while Safari asynchronously wires the element to the stream.
  Streams never buffer for late sinks (W3C resolution in
  w3c/mediacapture-transform#114) and no readiness event exists, so a
  single publish at attach time cannot be reliable.

publishFrame() now nudges the canvas with an imperceptible 1px paint
after arming so an emission paint always follows (WebKit only), and
attaching the canvas stream republishes every 50ms until the element
reports data, bounded to 25 attempts (WebKit only). Chromium captures
synchronously and redelivers the current frame to late sinks, so it
needs neither.

* fix(pip): honor an explicit disableBrowserPiP in isPiPEnabled

External API consumers and the client answered "is PiP enabled"
differently: isPiPEnabled() ignored disableBrowserPiP entirely, so an
embedder passing disableBrowserPiP: true still got the iframe-visibility
observer installed while the client refused every show-PiP request. The
shared gate now honors an explicitly set flag.

The opt-in default (absent flag counts as disabled) intentionally stays
client-side in shouldShowPiP(): the external API evaluates isPiPEnabled()
against only the embedder-provided config and cannot see the deployment's
config.js, so defaulting to disabled there would silently break embedded
auto-PiP for deployments that opt in server-side. An over-approximating
embedder only costs a no-op show-PiP request that the client refuses.

* refactor(pip): unexport copyStylesheets

It is only called by initPiPWindow(); exporting it implied it is safe to
call independently, bypassing the PiP-window reference tracking that
initPiPWindow() enforces.

* fix(pip): notify on user-initiated MediaSession PiP open failure

Entering PiP through the browser's PiP icon (MediaSession 'useraction')
is just as user-initiated as the toolbar button, but its failures
produced no user-visible feedback because the handler never passed
notifyOnFailure. Such failures now surface exactly like toolbar-button
failures; automatic 'contentoccluded' entries stay silent (but still
logged) to avoid nagging the user on every tab switch. The handler
cannot leak rejections into the browser's fire-and-forget invocation
because openDocumentPiP() reports every failure internally.

* refactor(pip): drop no-op state rollback in openDocumentPiP error handler

isPiPActive can only become true via the success path
(handlePipEnterEvent), which the already-open and request-pending guards
make unreachable before a failure, so resetting it when requestWindow()
fails was dead code that read as a real rollback and obscured the actual
invariant.

* refactor(pip): move IOpenDocumentPiPOptions to types.ts

All other PiP interfaces live in types.ts; keeping this one inside
actions.ts made the feature's type surface inconsistent.

* refactor(pip): terminate the middleware switch case with break

The missing break only works while the switch has no default case;
adding one later would silently run exitPiP for every action. This also
matches the convention used by the other middlewares.

* refactor(pip): name PiPVideoElement timing values and the WebKit dismissal flag

The 25 x 50 ms canvas republish loop used magic numbers, and
webKitPiPDismissedRef did not encode that it is set only when PiP is
dismissed while the tab is still hidden - the invariant the automatic
re-entry suppression relies on. FOCUS_CHECK_DELAY_MS also moves
file-local since it is Electron-specific and used in one place.

* refactor(pip): compute Document PiP support once at module load

The result cannot change during the page lifetime, so a module-level
constant makes that explicit instead of re-evaluating it on every
render.

* refactor(pip): rename disableBrowserPiP to opt-in enableBrowserPiP

Enabling browser PiP required the double negative disableBrowserPiP:
false, and a disableX flag defaulting to true inverts the expectation
set by every other disableX config flag (they all default to false) -
review found it easy to misread and suggested the positive polarity.
The rename costs nothing now because the flag has not shipped on master
yet; after the branch merges it would be a breaking config change
forever.

Semantics are unchanged: an absent flag still means disabled in the
client and permissive on the external API side (which cannot see the
deployment's config), and an explicitly set value is honored by both.

* fix(pip): store the Document PiP window in Redux

React cannot observe the module-level window reference, so a rapid
close-and-reopen could leave DocumentPiPContent's memoized Emotion
cache bound to the previous, already-closed window whenever
isPiPActive did not observably change. Keeping the reference in the
pip state makes every mutation observable by construction - the
mutation is the dispatch - so the component re-renders and rebuilds
the cache exactly when the window changes, and the module-level
getStoredPiPWindow/clearPiPWindow/closeDocumentPiPWindow helpers
disappear along with the invariant that every mutation must remember
to pair itself with a dispatch.

The pip feature is excluded from the native TypeScript check, but
IPipState still reaches it through IReduxState while the native config
has no DOM lib defining Window - hence the ts-ignore on the field,
mirroring web-hid's HIDDevice. Types are erased at build time, so this
affects the type check only.

* fix(pip): reset PiP window body styles before stylesheets load

The copied stylesheets load asynchronously, so until they land the PiP
document keeps the UA default 8px body margin and overflow: auto. The
100vw/100vh container then overflows the body and scrollbars flash on
every open. Resetting margin and overflow synchronously removes the
flash, mirroring what multi-screen's buildWindow already does.

* refactor(pip): register the tab-visibility PiP listener once

Selecting pipWindow into the visibilitychange handler's closure put it
in the effect dependencies, tearing down and re-registering the
listener on every PiP open and close. Dispatching the existing hidePiP
thunk instead moves the active-PiP check into the thunk, where it reads
fresh state, so the handler needs no state in its closure and the
listener registers once for the lifetime of the mount.

---------

Co-authored-by: Bandhan Majumder <133476557+bandhan-majumder@users.noreply.github.com>
Co-authored-by: Bandhan Majumder <bandhanmajumder16@gmail.com>
…ording visibility

- Allow live streaming to start while transcription is active (#17732)
- Show local recording option in Record & Transcribe dialog even when
  transcription is running (#17731)

Transcription should be independent of live streaming; the Jibri-only
disable guard now checks cloud recording only. Local recording is
browser-side and has no dependency on whether JWT recording is enabled,
so it is now always rendered in _renderSessionToggles.
@pull pull Bot locked and limited conversation to collaborators Aug 19, 2026
@pull pull Bot added the ⤵️ pull label Aug 19, 2026
@pull
pull Bot merged commit ebdbd6b into code:master Aug 19, 2026
9 of 10 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants