From d969266662da0157e03e2bb1551aa4f2628e0c71 Mon Sep 17 00:00:00 2001 From: Vanilagy <1696106+Vanilagy@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:30:26 +0100 Subject: [PATCH] Simplify isWebKit, get rid of isSafari --- src/media-sink.ts | 8 ++++---- src/misc.ts | 41 +++++++---------------------------------- src/source.ts | 1 + 3 files changed, 12 insertions(+), 38 deletions(-) diff --git a/src/media-sink.ts b/src/media-sink.ts index 1d0665a..195ff2a 100644 --- a/src/media-sink.ts +++ b/src/media-sink.ts @@ -26,7 +26,7 @@ import { insertSorted, isFirefox, isNumber, - isSafari, + isWebKit, last, mapAsyncGenerator, promiseWithResolvers, @@ -918,7 +918,7 @@ class VideoDecoderWrapper extends DecoderWrapper { } else { assert(this.decoder); - if (!isSafari()) { + if (!isWebKit()) { insertSorted(this.inputTimestamps, packet.timestamp, x => x); } @@ -1049,7 +1049,7 @@ class VideoDecoderWrapper extends DecoderWrapper { /** Handler for the WebCodecs VideoDecoder for ironing out browser differences. */ sampleHandler(sample: VideoSample) { - if (isSafari()) { + if (isWebKit()) { // For correct B-frame handling, we don't just hand over the frames directly but instead add them to // a queue, because we want to ensure frames are emitted in presentation order. We flush the queue // each time we receive a frame with a timestamp larger than the highest we've seen so far, as we @@ -1137,7 +1137,7 @@ class VideoDecoderWrapper extends DecoderWrapper { this.alphaRaslSkipped = false; } - if (isSafari()) { + if (isWebKit()) { for (const sample of this.sampleQueue) { this.finalizeAndEmitSample(sample); } diff --git a/src/misc.ts b/src/misc.ts index 0ec4458..c6f5119 100644 --- a/src/misc.ts +++ b/src/misc.ts @@ -658,44 +658,17 @@ export class CallSerializer { } } -let isSafariCache: boolean | null = null; -export const isSafari = () => { - if (isSafariCache !== null) { - return isSafariCache; - } - - const result = !!( - typeof navigator !== 'undefined' - && navigator.vendor?.match(/apple/i) - && !navigator.userAgent?.match(/crios/i) - && !navigator.userAgent?.match(/fxios/i) - && !navigator.userAgent?.match(/Opera|OPT\//) - ); - - isSafariCache = result; - return result; -}; - let isWebKitCache: boolean | null = null; export const isWebKit = () => { - if (isWebKitCache !== null) return isWebKitCache; - if (typeof navigator === 'undefined') return (isWebKitCache = false); + if (isWebKitCache !== null) { + return isWebKitCache; + } - const ua = navigator.userAgent || ''; - const maxTouchPoints = navigator.maxTouchPoints || 0; + // This even returns true for WebKit-wrapping browsers such as Chrome on iOS + const result = !!(typeof navigator !== 'undefined' && navigator.vendor?.match(/apple/i)); - // iOS/iPadOS detection: - // - All iOS/iPadOS browsers use WebKit (WKWebView) - // - iPadOS 13+ can report "Macintosh" in UA; detect via touch points - const isIOSLike - = /iPhone|iPad|iPod/i.test(ua) || (/Macintosh/i.test(ua) && maxTouchPoints > 1); - - // On iOS/iPadOS: always WebKit (even if UA says CriOS/Edg/OPR/etc.) - if (isIOSLike) return (isWebKitCache = true); - - // Off iOS: only Safari is WebKit on mainstream desktops - const result = isSafari(); - return (isWebKitCache = result); + isWebKitCache = result; + return result; }; let isFirefoxCache: boolean | null = null; diff --git a/src/source.ts b/src/source.ts index 91fe2b2..68ebac1 100644 --- a/src/source.ts +++ b/src/source.ts @@ -210,6 +210,7 @@ export class BlobSource extends Source { private async _runWorker(worker: ReadWorker) { let reader = this._readers.get(worker); if (reader === undefined) { + // https://github.com/Vanilagy/mediabunny/issues/184 // WebKit has critical bugs with blob.stream(): // - WebKitBlobResource error 1 when streaming large files // - Memory buildup and reload loops on iOS (network process crashes)