From 8575471d2ada4e60c7e834798f58d870effe6748 Mon Sep 17 00:00:00 2001 From: jisu-kim Date: Wed, 4 Dec 2024 15:10:19 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=ED=94=8C=EB=A0=88=EC=9D=B4=EC=96=B4=20?= =?UTF-8?q?=EB=A6=AC=ED=8A=B8=EB=9D=BC=EC=9D=B4=20=EB=B0=8F=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/hooks/usePlayer.ts | 129 +++++++++++++++++--------------- 1 file changed, 68 insertions(+), 61 deletions(-) diff --git a/frontend/src/hooks/usePlayer.ts b/frontend/src/hooks/usePlayer.ts index a154fefc..d463e67c 100644 --- a/frontend/src/hooks/usePlayer.ts +++ b/frontend/src/hooks/usePlayer.ts @@ -1,81 +1,72 @@ -import Hls, { - Loader, - LoaderCallbacks, - LoaderConfiguration, - LoaderContext, - LoaderResponse, - LoaderStats, - HlsConfig -} from 'hls.js'; +import Hls, { Loader, LoaderCallbacks, LoaderConfiguration, LoaderContext, HlsConfig } from 'hls.js'; import { useEffect, useRef } from 'react'; class CustomLoader implements Loader { private loader: Loader; + private retryCount: number = 0; + private maxRetries: number = 6; + private retryDelay: number = 3000; + private DefaultLoader: new (config: HlsConfig) => Loader; constructor(config: HlsConfig) { - const DefaultLoader = Hls.DefaultConfig.loader as new (config: HlsConfig) => Loader; - this.loader = new DefaultLoader(config); + this.DefaultLoader = Hls.DefaultConfig.loader as new (config: HlsConfig) => Loader; + this.loader = new this.DefaultLoader(config); } - load(context: LoaderContext, config: LoaderConfiguration, callbacks: LoaderCallbacks) { - const { onSuccess, onError, onTimeout, onAbort, onProgress } = callbacks; + private createNewLoader(): Loader { + return new this.DefaultLoader({ + ...Hls.DefaultConfig, + enableWorker: true, + lowLatencyMode: true + }); + } - const newCallbacks: LoaderCallbacks = { - onSuccess: (response: LoaderResponse, stats: LoaderStats, context: LoaderContext, networkDetails: any = null) => { - onSuccess(response, stats, context, networkDetails); - }, - onError: ( - error: { code: number; text: string }, - context: LoaderContext, - networkDetails: any = null, - stats: LoaderStats - ) => { - if (error.code === 404) { - const emptyData = new ArrayBuffer(0); - onSuccess( - { - url: context.url, - data: emptyData - }, - { - trequest: performance.now(), - tfirst: performance.now(), - tload: performance.now(), - loaded: 0, - total: 0 - } as unknown as LoaderStats, - context, - networkDetails - ); - } else { - if (onError) { - onError(error, context, networkDetails, stats); + private retryLoad(context: LoaderContext, config: LoaderConfiguration, callbacks: LoaderCallbacks) { + this.loader = this.createNewLoader(); + + setTimeout(() => { + const retryCallbacks: LoaderCallbacks = { + ...callbacks, + onError: (error, context, networkDetails, stats) => { + if (error.code === 404 && this.retryCount < this.maxRetries) { + this.retryCount++; + this.retryLoad(context, config, callbacks); + } else { + this.retryCount = 0; + if (callbacks.onError) { + callbacks.onError(error, context, networkDetails, stats); + } } } - }, - onTimeout: (stats: LoaderStats, context: LoaderContext, networkDetails: any = null) => { - if (onTimeout) { - onTimeout(stats, context, networkDetails); - } - }, - onAbort: (stats: LoaderStats, context: LoaderContext, networkDetails: any = null) => { - if (onAbort) { - onAbort(stats, context, networkDetails); + }; + + this.loader.load(context, config, retryCallbacks); + }, this.retryDelay); + } + + load(context: LoaderContext, config: LoaderConfiguration, callbacks: LoaderCallbacks) { + const modifiedCallbacks: LoaderCallbacks = { + ...callbacks, + onSuccess: (response, stats, context, networkDetails) => { + this.retryCount = 0; + if (callbacks.onSuccess) { + callbacks.onSuccess(response, stats, context, networkDetails); } }, - onProgress: ( - stats: LoaderStats, - context: LoaderContext, - data: string | ArrayBuffer, - networkDetails: any = null - ) => { - if (onProgress) { - onProgress(stats, context, data, networkDetails); + onError: (error, context, networkDetails, stats) => { + if (error.code === 404 && this.retryCount < this.maxRetries) { + this.retryCount++; + this.retryLoad(context, config, callbacks); + } else { + this.retryCount = 0; + if (callbacks.onError) { + callbacks.onError(error, context, networkDetails, stats); + } } } }; - this.loader.load(context, config, newCallbacks); + this.loader.load(context, config, modifiedCallbacks); } abort() { @@ -124,6 +115,22 @@ export default function usePlayer(url: string) { videoElement.play(); }); + hls.on(Hls.Events.ERROR, (event, data) => { + if (data.fatal) { + switch (data.type) { + case Hls.ErrorTypes.NETWORK_ERROR: + hls.startLoad(); + break; + case Hls.ErrorTypes.MEDIA_ERROR: + hls.recoverMediaError(); + break; + default: + hls.destroy(); + break; + } + } + }); + return () => { hls.destroy(); };