| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879 |
- /**
- * 根据平台与房间状态挑选可播放地址(按协议偏好挑流,不依赖字段顺序)
- *
- * 服务端约定 `liveurl` 形如:
- * "rtmp://host/app/key,https://host/app/key.m3u8"
- * 也可能调换顺序、或者只返一条。本模块保证:
- * - APP-PLUS:优先 rtmp(live-player 低延迟),次选 flv / http-flv,最后 m3u8
- * - H5 :优先 m3u8(hls.js / 原生),次选 flv,最后退化 rtmp(无效)
- * - 小程序 :优先 m3u8,次选 flv(小程序基本不支持 rtmp)
- */
- function classifyStreamUrl(url) {
- const u = String(url || '').trim()
- if (!u) return ''
- const lower = u.toLowerCase().split('?')[0]
- if (lower.startsWith('rtmp://') || lower.startsWith('rtmps://')) return 'rtmp'
- if (lower.endsWith('.m3u8')) return 'm3u8'
- if (lower.endsWith('.flv')) return 'flv'
- if (lower.endsWith('.mp4')) return 'mp4'
- return 'http'
- }
- function splitCandidates(liveurl) {
- return String(liveurl || '')
- .split(',')
- .map((s) => s.trim())
- .filter(Boolean)
- }
- /** 按协议偏好顺序挑第一个匹配的;都没匹配返回 fallback(数组首项) */
- function pickByPreference(candidates, preference) {
- for (const proto of preference) {
- const hit = candidates.find((u) => classifyStreamUrl(u) === proto)
- if (hit) return hit
- }
- return candidates[0] || ''
- }
- export function resolvePlaybackUrl(roomPayload) {
- if (!roomPayload) return ''
- const phase = Number(roomPayload.state)
- if (phase === 0 || phase === 1) {
- const candidates = splitCandidates(roomPayload.liveurl)
- if (!candidates.length) return ''
- // #ifdef APP-PLUS
- // APP 上 <live-player> 原生支持 rtmp,延迟最低;m3u8 兜底。
- return pickByPreference(candidates, ['rtmp', 'flv', 'm3u8', 'http', 'mp4'])
- // #endif
- // #ifdef H5
- // H5 上 hls.js 播 m3u8,rtmp 无法在浏览器播放。
- return pickByPreference(candidates, ['m3u8', 'flv', 'http', 'mp4'])
- // #endif
- // #ifdef MP-WEIXIN || MP-ALIPAY || MP-BAIDU || MP-TOUTIAO || MP-QQ || MP-KUAISHOU || MP-LARK || MP-JD
- return pickByPreference(candidates, ['m3u8', 'flv', 'http', 'mp4'])
- // #endif
- return candidates[0]
- }
- if (phase === 2) {
- return roomPayload.recordurl || ''
- }
- return ''
- }
- export function describeRoomPhase(state) {
- const code = Number(state)
- if (code === 0) return 'preparing'
- if (code === 1) return 'onair'
- if (code === 2) return 'replay'
- return 'offline'
- }
- export { classifyStreamUrl, splitCandidates }
|