diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx index b586cf4b..fe07a672 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx @@ -2005,11 +2005,11 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props }, tracks: [{ kind: 'subtitles', src: currentSubtitleBlob, default: true }], hlsOptions: { - // 버퍼 길이 축소로 메모리 사용 완화 - maxBufferLength: 10, - maxMaxBufferLength: 30, - liveSyncDuration: 5, - liveMaxLatencyDuration: 10, + // 버퍼 길이를 약간 늘려 재버퍼링 감소 + maxBufferLength: 30, + maxMaxBufferLength: 90, + liveSyncDuration: 8, + liveMaxLatencyDuration: 16, }, }, youtube: YOUTUBECONFIG, @@ -2019,10 +2019,10 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props youtube: YOUTUBECONFIG, file: { hlsOptions: { - maxBufferLength: 10, - maxMaxBufferLength: 30, - liveSyncDuration: 5, - liveMaxLatencyDuration: 10, + maxBufferLength: 30, + maxMaxBufferLength: 90, + liveSyncDuration: 8, + liveMaxLatencyDuration: 16, }, }, }; @@ -2222,11 +2222,15 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props useEffect(() => { return () => { + console.log('[PlayerPanel] unmount cleanup start'); + cleanupPlayerOnUnmount(); + stopExternalPlayer(); dispatch(clearShopNowInfo()); dispatch(CLEAR_PLAYER_INFO()); setShopNowInfo([]); + console.log('[PlayerPanel] unmount cleanup done'); }; - }, []); + }, [cleanupPlayerOnUnmount, stopExternalPlayer, dispatch]); const focusBackToPanel = useCallback(() => { // 포커스를 PlayerPanel 쪽으로 강제 이동해 YouTube iframe이 포커스를 가져가는 것을 차단 @@ -2265,6 +2269,40 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props } }, []); + // PlayerPanel 언마운트 시 비디오 자원 강제 해제 (popPanel 시점) + const cleanupPlayerOnUnmount = useCallback(() => { + const playerInstance = videoPlayer.current; + const media = playerInstance?.video; + + try { + playerInstance?.pause?.(); + playerInstance?.stopVideo?.(); + } catch (err) { + // ignore + } + + if (media) { + try { + media.pause?.(); + media.stopVideo?.(); + media.seekTo?.(0); + if ('currentTime' in media) { + media.currentTime = 0; + } + if ('src' in media) { + media.src = ''; + media.removeAttribute?.('src'); + } + if ('srcObject' in media) { + media.srcObject = null; + } + media.load?.(); + } catch (err) { + // ignore + } + } + }, []); + const onEnded = useCallback( (e) => { if (panelInfoRef.current.shptmBanrTpNm === 'MEDIA') {