106 lines
3.2 KiB
TypeScript
106 lines
3.2 KiB
TypeScript
import Hls from 'hls.js';
|
||
import { log } from 'node:console';
|
||
let hlsInstance: Hls | null = null;
|
||
// let hlsRetryCount = 0;
|
||
|
||
export const initHls = (monitorVideoUrl, monitorVideoRef, isDialogVisible?: () => boolean) => {
|
||
console.log('isDialogVisible', isDialogVisible);
|
||
const url = monitorVideoUrl.value;
|
||
const video = monitorVideoRef.value;
|
||
if (!url || !video) return;
|
||
|
||
// 销毁已有实例
|
||
if (hlsInstance) {
|
||
try {
|
||
hlsInstance.destroy();
|
||
} catch (e) {
|
||
// ignore
|
||
}
|
||
hlsInstance = null;
|
||
}
|
||
|
||
if (Hls.isSupported()) {
|
||
const hls = new Hls({
|
||
// ★ ZLM 注册流需要时间,配置自动重试
|
||
manifestLoadingMaxRetry: 5, // m3u8 加载最多重试20次
|
||
manifestLoadingRetryDelay: 500, // 每次重试间隔500ms
|
||
manifestLoadingTimeOut: 5000, // m3u8 请求超时5秒
|
||
levelLoadingMaxRetry: 2, // ts 分片加载最多重试20次
|
||
levelLoadingRetryDelay: 500,
|
||
lowLatencyMode: false, // 关掉低延迟模式,更稳定
|
||
startLevel: -1 // 自动选择码率
|
||
});
|
||
hls.loadSource(url);
|
||
hls.attachMedia(video);
|
||
hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
||
// 自动播放(若浏览器允许)
|
||
try {
|
||
video.play().catch(() => {});
|
||
} catch (e) {}
|
||
// 加载成功,重置重试计数
|
||
// hlsRetryCount = 0;
|
||
});
|
||
// ★ 错误自动恢复:hls.js 拿到空 m3u8 或 ts 加载失败时自动重试
|
||
hls.on(Hls.Events.ERROR, (event, data) => {
|
||
if (data.fatal && (!isDialogVisible || isDialogVisible())) {
|
||
switch (data.type) {
|
||
case Hls.ErrorTypes.NETWORK_ERROR:
|
||
hls.startLoad();
|
||
hls.once(Hls.Events.FRAG_LOADED, () => {
|
||
//分片加载成功后播放
|
||
try {
|
||
video.play().catch(() => {});
|
||
} catch (e) {}
|
||
});
|
||
ElMessage.error('网络错误, 请检查网络或重试');
|
||
break;
|
||
case Hls.ErrorTypes.MEDIA_ERROR:
|
||
// 媒体解码错误 → 尝试恢复
|
||
hls.recoverMediaError();
|
||
break;
|
||
default:
|
||
// 其他致命错误 → 销毁,让下一次 initHls 重建
|
||
hls.destroy();
|
||
hlsInstance = null;
|
||
break;
|
||
}
|
||
}
|
||
});
|
||
hlsInstance = hls;
|
||
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
||
// Safari/原生支持 HLS
|
||
video.src = url;
|
||
video.addEventListener('loadedmetadata', () => {
|
||
try {
|
||
video.play().catch(() => {});
|
||
} catch (e) {}
|
||
});
|
||
} else {
|
||
//proxy?.$modal.msgWarning('当前浏览器不支持 HLS 播放');
|
||
ElMessage.error('当前浏览器不支持 HLS 播放');
|
||
}
|
||
};
|
||
|
||
export const destroyHls = (monitorVideoRef) => {
|
||
try {
|
||
if (hlsInstance) {
|
||
hlsInstance.destroy();
|
||
hlsInstance = null;
|
||
}
|
||
} catch (e) {}
|
||
const video = monitorVideoRef.value;
|
||
if (video) {
|
||
// 清理原生 src,避免残留
|
||
try {
|
||
video.pause();
|
||
video.removeAttribute('src');
|
||
// 对某些浏览器,需要调用 load() 来重置 media element
|
||
if (typeof video.load === 'function') video.load();
|
||
} catch (e) {
|
||
console.log('Error in destroyHls:', e);
|
||
}
|
||
}
|
||
};
|
||
|
||
export default { initHls, destroyHls };
|