diff --git a/components/ItemContent.tsx b/components/ItemContent.tsx index 8f61b855..5f70083c 100644 --- a/components/ItemContent.tsx +++ b/components/ItemContent.tsx @@ -73,12 +73,6 @@ export const ItemContent: React.FC = React.memo( defaultSubtitleIndex, } = useDefaultPlaySettings(item, settings); - console.log("defaultMediaSource", { - defaultAudioIndex, - defaultBitrate, - defaultSubtitleIndex, - }); - const logoUrl = useMemo( () => (item ? getLogoImageUrlById({ api, item }) : null), [api, item], diff --git a/components/MediaSourceButton.tsx b/components/MediaSourceButton.tsx index 10cabf77..05847f35 100644 --- a/components/MediaSourceButton.tsx +++ b/components/MediaSourceButton.tsx @@ -104,11 +104,6 @@ export const MediaSourceButton: React.FC = ({ // Audio track group if (audioStreams.length > 0) { - console.log("Audio comparison:", { - selectedAudioIndex: selectedOptions.audioIndex, - streamIndices: audioStreams.map((s) => s.Index), - }); - groups.push({ title: t("item_card.audio"), options: audioStreams.map((stream) => ({ diff --git a/components/PlayButton.tsx b/components/PlayButton.tsx index a873698c..a162525f 100644 --- a/components/PlayButton.tsx +++ b/components/PlayButton.tsx @@ -280,7 +280,6 @@ export const PlayButton: React.FC = ({ ]); const onPress = useCallback(async () => { - console.log("onPress"); if (!item) return; lightHapticFeedback(); diff --git a/components/PlayButton.tv.tsx b/components/PlayButton.tv.tsx index b201b106..b66cce35 100644 --- a/components/PlayButton.tv.tsx +++ b/components/PlayButton.tv.tsx @@ -59,7 +59,6 @@ export const PlayButton: React.FC = ({ ); const onPress = () => { - console.log("onpress"); if (!item) return; lightHapticFeedback(); diff --git a/hooks/useDefaultPlaySettings.ts b/hooks/useDefaultPlaySettings.ts index dd0f5326..51b0e9ee 100644 --- a/hooks/useDefaultPlaySettings.ts +++ b/hooks/useDefaultPlaySettings.ts @@ -12,12 +12,6 @@ const useDefaultPlaySettings = (item: BaseItemDto, settings: Settings | null) => const { mediaSource, audioIndex, subtitleIndex, bitrate } = getDefaultPlaySettings(item, settings); - console.log("defaultPlaySettings", { - audioIndex, - subtitleIndex, - bitrate, - }); - return { defaultMediaSource: mediaSource, defaultAudioIndex: audioIndex, diff --git a/hooks/useWebsockets.ts b/hooks/useWebsockets.ts index 32b110a4..87dd9162 100644 --- a/hooks/useWebsockets.ts +++ b/hooks/useWebsockets.ts @@ -96,8 +96,6 @@ export const useWebSocket = ({ | Record | undefined; // Arguments are Dictionary - console.log("[WS] ~ ", lastMessage); - if (command === "PlayPause") { console.log("Command ~ PlayPause"); togglePlay(); diff --git a/modules/mpv-player/ios/IOSurfaceBufferPool.swift b/modules/mpv-player/ios/IOSurfaceBufferPool.swift index 7e8f18e6..28c542c7 100644 --- a/modules/mpv-player/ios/IOSurfaceBufferPool.swift +++ b/modules/mpv-player/ios/IOSurfaceBufferPool.swift @@ -94,7 +94,6 @@ final class IOSurfaceBufferPool { } } - Logger.shared.log("IOSurfaceBufferPool configured: \(width)x\(height), \(buffers.count) buffers", type: "Info") return true } @@ -122,7 +121,6 @@ final class IOSurfaceBufferPool { lock.lock() defer { lock.unlock() } - // Only return to available pool if it's one of our managed buffers if buffers.contains(where: { $0.pixelBuffer == buffer.pixelBuffer }) { availableBuffers.append(buffer) } diff --git a/modules/mpv-player/ios/MPVMetalRenderer.swift b/modules/mpv-player/ios/MPVMetalRenderer.swift index d637fa95..b25fee1b 100644 --- a/modules/mpv-player/ios/MPVMetalRenderer.swift +++ b/modules/mpv-player/ios/MPVMetalRenderer.swift @@ -108,7 +108,7 @@ final class MPVMetalRenderer { self.device = device self.commandQueue = device.makeCommandQueue() self.displayLayer = displayLayer - self.bufferPool = IOSurfaceBufferPool(device: device, maxBufferCount: 3) + self.bufferPool = IOSurfaceBufferPool(device: device, maxBufferCount: 6) guard let screen = UIApplication.shared.connectedScenes .compactMap({ ($0 as? UIWindowScene)?.screen }) @@ -147,10 +147,18 @@ final class MPVMetalRenderer { // Performance options setOption(name: "demuxer-thread", value: "yes") setOption(name: "profile", value: "fast") - setOption(name: "vd-lavc-threads", value: "0") // Auto-detect + setOption(name: "vd-lavc-threads", value: "0") setOption(name: "cache", value: "yes") - setOption(name: "demuxer-max-bytes", value: "150M") - setOption(name: "demuxer-readahead-secs", value: "20") + setOption(name: "demuxer-max-bytes", value: "50M") + setOption(name: "demuxer-readahead-secs", value: "10") + + // A/V sync options - prioritize audio sync and allow frame drops + setOption(name: "video-sync", value: "audio") + setOption(name: "framedrop", value: "vo") + setOption(name: "video-latency-hacks", value: "yes") + + // Audio buffer to prevent underruns during heavy video load + setOption(name: "audio-buffer", value: "0.2") // Subtitle options - burn into video frames setOption(name: "vf", value: "sub") @@ -218,6 +226,7 @@ final class MPVMetalRenderer { } else { self.displayLayer.flushAndRemoveImage() } + self.displayLayer.controlTimebase = nil } isStopping = false @@ -622,9 +631,8 @@ final class MPVMetalRenderer { self.displayLayer.enqueue(sampleBuffer) } - // Return buffer to pool after a short delay to ensure it's been displayed - DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) { [weak self] in - self?.bufferPool?.enqueueBuffer(buffer) + DispatchQueue.main.asyncAfter(deadline: .now() + 0.032) { [weak self, weak bufferPool] in + bufferPool?.enqueueBuffer(buffer) } } } diff --git a/modules/mpv-player/ios/MpvPlayerView.swift b/modules/mpv-player/ios/MpvPlayerView.swift index 0814bafe..ad7d4699 100644 --- a/modules/mpv-player/ios/MpvPlayerView.swift +++ b/modules/mpv-player/ios/MpvPlayerView.swift @@ -269,6 +269,7 @@ class MpvPlayerView: ExpoView { deinit { pipController?.stopPictureInPicture() renderer?.stop() + displayLayer.controlTimebase = nil displayLayer.removeFromSuperlayer() } } diff --git a/providers/WebSocketProvider.tsx b/providers/WebSocketProvider.tsx index 028a71e8..6553e7ab 100644 --- a/providers/WebSocketProvider.tsx +++ b/providers/WebSocketProvider.tsx @@ -96,7 +96,6 @@ export const WebSocketProvider = ({ children }: WebSocketProviderProps) => { newWebSocket.onmessage = (e) => { try { const message = JSON.parse(e.data); - console.log("[WS] Received message:", message); setLastMessage(message); // Store the last message in context } catch (error) { console.error("Error parsing WebSocket message:", error); @@ -124,12 +123,10 @@ export const WebSocketProvider = ({ children }: WebSocketProviderProps) => { const handlePlayCommand = useCallback( (data: any) => { if (!data || !data.ItemIds || !data.ItemIds.length) { - console.warn("[WS] Received Play command with no items"); return; } const itemId = data.ItemIds[0]; - console.log(`[WS] Handling Play command for item: ${itemId}`); router.push({ pathname: "/(auth)/player/direct-player",