Skip to content
This repository was archived by the owner on May 16, 2024. It is now read-only.

upstream merge#12

Open
hannojg wants to merge 1446 commits into
cuvent:masterfrom
TheWidlarzGroup:master
Open

upstream merge#12
hannojg wants to merge 1446 commits into
cuvent:masterfrom
TheWidlarzGroup:master

Conversation

@hannojg

@hannojg hannojg commented May 24, 2021

Copy link
Copy Markdown

No description provided.

moskalakamil and others added 30 commits January 22, 2026 00:20
* fix: external subtitle asset composition

* fix: filter for supported subtitles before adding them
* fix(ios): prevent KVO crash in HybridVideoPlayer.release()

Fix a crash that occurs when rapidly creating/destroying video players
(e.g., fast swiping through a FlatList of videos). The crash message is:
"Cannot remove an observer for the key path 'currentItem.status'"

Root cause:
When release() was called, it would set playerItem = nil and then
playerObserver = nil, which triggered the observer's deinit. However,
the KVO observers were still registered on the playerItem, causing
a crash when the system tried to remove them.

Solution:
1. Explicitly invalidate all KVO observers BEFORE changing any state
2. Change invalidatePlayerItemObservers() from private to internal
   so it can be called from HybridVideoPlayer.release()
3. Skip self.player.replaceCurrentItem(with: nil) which was also
   triggering the crash by changing currentItem while observers
   were still active

This ensures clean KVO removal before any state changes that could
interfere with the observer lifecycle.

* refactor: address review feedback - clean up comments and reorganize release()

- Remove verbose KVO CRASH FIX comments
- Move observer invalidation calls to "Clear player observer" section
- Restore replaceCurrentItem(with: nil) after observer cleanup

* refactor: reorder cleaners

---------

Co-authored-by: Eran Kaufman <eran@sefirot.io>
Co-authored-by: Kamil Moskała <91079590+moskalakamil@users.noreply.github.com>
* docs: refactor tabs

* docs: update video-view docs

* docs: lowercase tabs

* feat(docs): add downloading section

* chore: add chapters example video

* docs: update sidebar type

* docs: update tab heading

* docs: add title to fundaments

* docs: lowercase plugin

* docs(sidebar): remove link to offline sdk

* docs: add `ads` tab

* chore: add `build` to eslint ignore

* docs: remove theme mermaid

* refactor: update deploy values

* chore: upper case tabs

* refactor: update configuration tabs name

* feat: add `ask for plugin` tab

* refactor: update analytics tab

* docs: update player class tip

* docs: make chapters paid

* docs: update utm's

* docs(downloading): update intro

* chore: bump `docusaurus-ui` package to 0.1.2

* fix: update paths

* docs: update dashes

* docs: update downloading events example imports

* docs: update readme

* docs: update case

* refactor: update intro & offer
* fix: update observer thread

* fix(ios): fix showNotificationControls not working when set during initialization

* fix(ios): set custom metadata on AVPlayerItem for now playing info

* refactor: warn when wront artwork url

* docs: update file header

* chore: warn when failed to load artwork image
…4852)

* fix(ios): restore inline UI after PIP stop to prevent black screen

* fix: restore pip when view is attached
* fix: fixed audio focus change on ios

* Fix formatting for audio session category options

---------

Co-authored-by: Kamil Moskała <91079590+moskalakamil@users.noreply.github.com>
* fix(ios): load artwork asynchronously to unblock notification controls

* fix(ios): remove playback observer on player removal and guard artwork callback

* fix: cleaning up player

* refactor: `if` syntax

* fix: add missing cleaner

* fix: remove `rounded` from current time

* chore: update pod versions

* refactor(ios): use targeted update functions at each call site

* refactor(ios): use async/await to load artwork metadata

* fix(ios): update static now playing info after setting external metadata

* fix: find new player before updating playback state

* fix(ios): take over notification controls when registering an already-playing player

* fix(ios): clear stale artwork and guard against item change in async artwork load

* fix: guard notification controls updates against stale player item

* fix: update playback duration periodically to handle streams with initially unknown duration
* fix(ios): stabilize NowPlaying controls

* fix(ios): dispatch NowPlaying update to main thread (#4862)

* docs: remove comment (#4863)

* rename player with `_`
* fix: video in fullscreen freezing after swiping

* fix(ios): use optional chainin
* chore: Upgrade to Nitro 0.35.0

* Replace `bigint` with `UInt64`

* chore: Regenerate specs now for Nitro 0.35.0

* fix: Use Int64 as it can be -1

* Remove unnecessary patches

* fix: change duration type to number

* fix: avoid mutating VideoInformation fields after init

* chore: regenerate specs with new duration type

* fix: use Double for duration in VideoInformation

* docs: react-native-nitro-modules version

* chore: update react-native-nitro-modules version (rnv & drm)

---------

Co-authored-by: fnwk <filip.wnek200@gmail.com>
* chore(nitro): update generated files

* feat: implement disableAudioSessionManagement for IOS
* docs(seo): add meta titles, descriptions and keywords to all pages

* docs(seo): configure sitemap, metadata, JSON-LD and enable llms.txt

* docs(seo): improve homepage title and description

* docs(seo): add robots.txt with AI crawler rules

* docs(geo): add curated llms.txt for AI discoverability

* docs: fix typo baners → banners

* docs(geo): generate llms.txt via plugin instead of static file
* docs(seo): add meta titles, descriptions and keywords to all pages

* docs(seo): configure sitemap, metadata, JSON-LD and enable llms.txt

* docs(seo): improve homepage title and description

* docs(seo): add robots.txt with AI crawler rules

* docs(geo): add curated llms.txt for AI discoverability

* docs: fix typo baners → banners

* docs(geo): generate llms.txt via plugin instead of static file

* docs(seo): refine meta titles, sidebar labels and descriptions
* Add shaka as an optional dependency and fix their type

* Scaffold web

* Implement VideoView for web

* Implement html video properties using headless video

* Implement event handlers for web

* Map source

* Fix package lock

* Some cleanup

* Fix typescript issues

* Fix event listeners `this`

* Rework everything to use videojs instead of shaka

* Handle media sessions

* Add optional `mimeType` string in source object

* Add error handling for the web

* Fix media session for web

* Add audio track support

* Add video track handling on web

* Add quality selector

* Handle text track change event

* Add text track handling

* Fix typescript

* Fix native compilation due to double/long mismatch

* fix(web): fix naming and typos

Rename WebEventEmiter→WebEventEmitter, ViewViewProps→VideoViewProps.
Fix field/comment typos and update all imports.

* fix(web): critical runtime fixes

Fix BigInt(NaN), player.src(undefined), codeMap fallback, videoWidth,
quality guard, listener leaks, vid.style, window.videojs, MediaSession SSR.

* fix(web): bridge onError to consumers and fix __destroy cleanup

* refactor(web): extract WebTrackHandler and shared video.js types

* feat(web): add supportedFeatures and __DEV__ warnings for unsupported methods

* chore: split tsconfig into web & default

* refactor(web): split events by platform and isolate DOM types

* chore: remove audio/video track and quality APIs from both platforms

* feat(web): migrate from video.js v8 to v10 (@videojs/react)

* fix(web): proper store attach order and video element fallback

* fix(web): fix container warning and store lifecycle

* feat(example): web

* refactor(web): move events to folder, fix error codes

* refactor: remove dead code

* fix(web): resize mode

* refactor(web): add preload type

* refactor(web): extract VideoStore type, simplify player with media getter

* chore: remove .editorconfig and shell.nix

* style: normalize quotes to single in non-web files

* fix(web): use WeakRef for store to prevent DESTROYED errors on re-render

* fix(web): fullscreen targets container, guard double enable, remove unused mimeType

* feat(web): add experimental audio/video track APIs with WebVideoPlayer type

* docs: add web support page

* fix(web): types

* fix(web): overlay radius

* fix: lint errors, add missing VideoPlayerBase members, fix eslint for web files

* docs: update web docs

* docs: fix broken links in web support page

* fix(web): add WebError type with proper HTML5 MediaError code mapping

* refactor: extract WebMediaProxy for unified store/video access

* lint: code

* docs(web): update event note

* fix(web): bufferAhead

* refactor: events logic

* feat: implement missins no-op fn on web

* fix(web): types

* fix(android): duration in seconds

* fix(web): notification controls race condition

* docs(web-support): update seo

---------

Co-authored-by: Kamil Moskała <moskalakamil07@gmail.com>
Co-authored-by: Kamil Moskała <91079590+moskalakamil@users.noreply.github.com>
…-Picture transitions (#4921)

* fix(ios): resume playback when returning to foreground after a background pause

With `playInBackground`, VideoManager leaves the player running on background and
does not set `wasAutoPaused`. If the system then pauses it (background playback
not possible, e.g. automatic PiP did not engage), it stayed stuck paused on
return because the foreground handlers only resumed `wasAutoPaused` players.

Track whether the player was playing when backgrounded and resume it on
`applicationWillEnterForeground`; an explicit `pause()` clears the intent.

* fix(ios): re-activate the audio session when returning to the foreground

`activateAudioSession()` early-returns while the cached `isAudioSessionActive` is
true. The system can deactivate the session out-of-band (an interruption, or
while backgrounded), leaving the cache stale, so it is never re-activated and a
resumed player plays silently.

Invalidate the cache on interruption `.began` and on foreground so the session is
genuinely re-activated.

* fix(ios): only auto-resume after a background system pause, not other pauses

The foreground recovery must resume only when the system paused background
playback — not for stops that should stay paused. Clear the resume intent on:
a user pause via the lock screen / Control Center / a headset (remote command
center bypasses `HybridVideoPlayer.pause()`); an interruption (`.began`);
headphones unplugged (`.oldDeviceUnavailable`); and the item ending.

* fix(android): reset wasAutoPaused after foreground resume

onAppEnterForeground resumed auto-paused players but never cleared
wasAutoPaused, so the flag stayed true after the first background cycle (it is
only ever set, never reset). A player the user later paused by hand would then
be wrongly auto-resumed on the next foreground. Clear it after resuming,
mirroring the iOS handler.

* fix(android): keep playback state when entering PiP

* fix(android): pause playback when the PiP window is closed

* fix(android): auto-enter PiP only while the last-played video is playing (match iOS)

* fix(ios): re-activate the audio session idempotently on foreground

There is no public AVAudioSession `isActive` getter, so the cached flag goes
stale once the system deactivates the session out-of-band (e.g. while
suspended). Drop the early return in activateAudioSession() — setActive(true)
is idempotent when already active — so returning to the foreground reliably
re-asserts the session without poking the cached flag.

* fix(android): clear auto-enter PiP when the last-played view shouldn't drive it

refreshPictureInPictureParams() returned early when the last-played view had
PiP disabled or auto-enter off. Because setPictureInPictureParams merges, an
auto-enter flag enabled by an earlier view would linger, so the activity could
still auto-enter PiP for a view that shouldn't drive it. Always set params
explicitly, disabling auto-enter when the last-played view doesn't want it.

* fix(android): disable auto-enter PiP when there is no last-played video

refreshPictureInPictureParams() returned early when no video had played or the
last-played view was gone, so a previously-enabled auto-enter flag could linger
on the activity (setPictureInPictureParams merges). Sync the params in that case
too by disabling auto-enter. Drop the now-unused VideoView arg from
createDisabledPictureInPictureParams().

* fix(android): pause on PiP close regardless of exact stopped lifecycle state

Closing the PiP window finishes the activity (CREATED → DESTROYED), so checking
the exact CREATED state could miss the pause depending on timing and leave audio
playing after dismissal. Pause whenever the fragment is no longer started.

* perf(ios): skip setCategory when the audio session config is unchanged

configureAudioSession() runs on every audio-session refresh and called
setCategory unconditionally. On a real device setCategory is a non-trivial IPC
(milliseconds, occasionally hundreds when it actually reconfigures the route).
The category, mode and options are readable (unlike the active state), so skip
the call when they already match — no behaviour change, just fewer redundant IPCs.

* fix(ios): refresh the audio session on play/pause so the mix mode follows playback

The mix mode (mix-with-others vs interrupt) and activation were only recomputed
on prop/lifecycle changes, never on play/pause. So a video started while another
app played audio kept mixing instead of interrupting until an unrelated refresh.
Call requestAudioSessionUpdate() on timeControlStatus changes so the session
tracks the actual playback state.

* fix(ios): don't auto-resume a video paused inside Picture-in-Picture

The foreground background-resume only checked wasPlayingInBackground && !isPlaying,
so a video paused via the PiP window (which sets rate to 0 without going through
our pause path) was wrongly resumed on return. Observe rateDidChangeNotification and
cancel the resume intent on a .setRateCalled pause (deliberate — PiP/app/lock screen),
while keeping it for .appBackgrounded (system) pauses. Available since iOS 15.

* refactor(ios): move PiP-pause resume logic out of the player observer

VideoPlayerObserver no longer reaches into VideoManager. It observes rate via
rateDidChangeNotification (replacing the KVO of \.rate; same trigger plus the
reason) and forwards onRateChanged(rate:reason:). HybridVideoPlayer — the owner
of wasPlayingInBackground — clears the background-resume intent on a .setRateCalled
pause, next to the other places that clear it. No behaviour change.

* fix(ios): deliver the rate-change observer synchronously

Reading player.rate from a queue:.main block reads it at async delivery time, not
post time, so a rapid pause->play coalesces into one stale read and the .setRateCalled
pause that clears the background-resume flag can be missed.

queue: nil delivers synchronously on the posting thread, matching the other observers
here and the threading of the KVO it replaced.

* fix(android): keep auto-pausing non-PiP players when backgrounding into PiP

onAppEnterBackground returned early for every player while the activity was in PiP, so
a second non-background player kept emitting audio in the background.

Skip only the player that drives PiP and auto-pause the rest. If the PiP video is not
yet designated (auto-enter can race the designation), pause nothing rather than risk
pausing the PiP video.

* fix(android): refresh PiP params and cancel auto-pause on playWhenReady changes

playWhenReady can change without isPlaying (e.g. pausing while buffering), so the PiP
auto-enter flag, which is gated on playWhenReady, went stale when refreshed only from
onIsPlayingChanged.

A player resuming in the background (media notification) must also cancel a pending
auto-pause, otherwise the next foreground force-resumes a video the user left paused.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.