interface PlayerProperties { isPlayback: boolean; isLiving: boolean; pullUrlInfo: { rtmpUrl: string; rtmpOriaacUrl: string; hlsOriaacUrl: string; hlsUrl: string; }; vodInfo: { state: number; pullUrl: string; }; } interface PlayerData { liveUrl: string; vodUrl: string; isPlaying: boolean; showVideo: boolean; fullScreen: boolean; height: number; retryCount: number; maxRetryCount: number; } interface PlayerComponent extends WechatMiniprogram.Component.TrivialInstance { data: PlayerData; properties: PlayerProperties; videoContext: WechatMiniprogram.VideoContext | null; } Component({ properties: { isPlayback: { type: Boolean, value: false, }, isLiving: { type: Boolean, value: false, }, pullUrlInfo: { type: Object, value: { rtmpUrl: "", rtmpOriaacUrl: "", hlsOriaacUrl: "", hlsUrl: "", }, }, vodInfo: { type: Object, value: { state: 0, pullUrl: "", }, }, }, data: { liveUrl: "", vodUrl: "", isPlaying: false, fullScreen: false, height: 0, showVideo: true, retryCount: 0, maxRetryCount: 3, }, lifetimes: { attached(this: PlayerComponent) { this.initPlayer(); }, detached(this: PlayerComponent) { this.cleanup(); }, }, observers: { "isLiving, pullUrlInfo": function ( this: PlayerComponent, isLiving: boolean, pullUrlInfo: PlayerProperties["pullUrlInfo"] ) { if (isLiving && pullUrlInfo.rtmpUrl) { this.setData({ liveUrl: pullUrlInfo.rtmpUrl }); } else { this.setData({ liveUrl: "" }); } }, vodInfo: function ( this: PlayerComponent, data: PlayerProperties["vodInfo"] ) { if (data && data.pullUrl) { this.setData({ vodUrl: data.pullUrl, isPlaying: true, showVideo: true, }); this.playVideo(); } }, }, methods: { playVideo(this: PlayerComponent) { if (!this.videoContext || !this.data.showVideo) return; setTimeout(() => { try { this.videoContext?.play(); } catch (error) { this.handlePlayError(); } }, 500); }, handlePlayError(this: PlayerComponent) { const { retryCount, maxRetryCount } = this.data; if (retryCount < maxRetryCount) { this.setData({ retryCount: retryCount + 1 }); setTimeout(() => { this.playVideo(); }, 2000); } else { this.setData({ showVideo: false, retryCount: 0, }); wx.showToast({ title: "播放失败,请检查网络连接", icon: "none", }); } }, initPlayer(this: PlayerComponent) { try { const sysInfo = wx.getSystemInfoSync(); this.setData({ height: sysInfo.screenHeight }); this.videoContext = wx.createVideoContext("vodVideo", this); } catch (err) { console.error("初始化播放器失败:", err); wx.showToast({ title: "播放器初始化失败", icon: "none" }); } }, onLiveStateChange( this: PlayerComponent, event: WechatMiniprogram.CustomEvent ) { const code = event.detail.code; const stateMap: Record = { 2001: "已连接", 2002: "已断开", 2003: "缓冲中", 2004: "播放开始", 2005: "播放结束", 2006: "加载中", }; console.log("直播状态:", stateMap[code] || `未知(${code})`); }, onLiveError(this: PlayerComponent, event: WechatMiniprogram.CustomEvent) { const errCode = event.detail.errCode; const errorMap: Record = { 10001: "系统错误", 10002: "网络错误", 10003: "解码错误", 10004: "直播流不存在", }; const msg = errorMap[errCode] || `直播错误: ${event.detail.errMsg}`; wx.showToast({ title: msg, icon: "none" }); }, onVideoPlay(this: PlayerComponent) { this.setData({ isPlaying: true, retryCount: 0, showVideo: true }); }, onVideoPause(this: PlayerComponent) { this.setData({ isPlaying: false }); }, onVideoEnded(this: PlayerComponent) { this.setData({ isPlaying: false }); }, onVideoError(this: PlayerComponent, err: WechatMiniprogram.CustomEvent) { if (err) { this.setData({ isPlaying: false, showVideo: false }); this.triggerEvent("controlstoggle", { state: 2 }); } }, cleanup(this: PlayerComponent) { this.videoContext = null; this.setData({ liveUrl: "", vodUrl: "", isPlaying: false, fullScreen: false, showVideo: true, retryCount: 0, }); }, }, });