后台直播:修复信令误断(onclose 提示与严格模式 onUnmounted)
Made-with: Cursor
This commit is contained in:
@@ -33,6 +33,8 @@ export function startPublishing(opts = {}) {
|
|||||||
const ws = new WebSocket(wsUrl)
|
const ws = new WebSocket(wsUrl)
|
||||||
const pc = new RTCPeerConnection({ iceServers: defaultIce })
|
const pc = new RTCPeerConnection({ iceServers: defaultIce })
|
||||||
let stream = null
|
let stream = null
|
||||||
|
/** 本地主动 stop / 摄像头失败关闭,避免 onclose 覆盖真实错误提示 */
|
||||||
|
let closedByLocal = false
|
||||||
|
|
||||||
const send = (o) => {
|
const send = (o) => {
|
||||||
if (ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify(o))
|
if (ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify(o))
|
||||||
@@ -56,7 +58,14 @@ export function startPublishing(opts = {}) {
|
|||||||
send({ type: 'offer', sdp: offer.sdp })
|
send({ type: 'offer', sdp: offer.sdp })
|
||||||
onStatus('已发起推流协商,等待服务端应答…')
|
onStatus('已发起推流协商,等待服务端应答…')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
onStatus(err.message || '无法打开摄像头')
|
const name = err && err.name
|
||||||
|
let tip = err.message || '无法打开摄像头'
|
||||||
|
if (name === 'NotAllowedError' || name === 'PermissionDeniedError') {
|
||||||
|
tip = '已拒绝摄像头权限:请在浏览器地址栏允许摄像头,并确认本页为 HTTPS。'
|
||||||
|
} else if (name === 'NotFoundError') {
|
||||||
|
tip = '未检测到摄像头设备。'
|
||||||
|
}
|
||||||
|
onStatus(tip)
|
||||||
stop()
|
stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,10 +95,18 @@ export function startPublishing(opts = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ws.onerror = () => onStatus('信令连接失败(请确认已登录且 Nginx 已配置 WebSocket)')
|
ws.onerror = () => {
|
||||||
ws.onclose = () => onStatus('信令已断开')
|
if (!closedByLocal) {
|
||||||
|
onStatus('信令连接失败(请确认已登录且 Nginx 已配置 WebSocket)')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ws.onclose = () => {
|
||||||
|
if (closedByLocal) return
|
||||||
|
onStatus('信令已断开:服务端关闭连接或网络中断。若刚能连上即断,请查服务端日志或配置 TURN(LIVE_ICE_SERVERS)。')
|
||||||
|
}
|
||||||
|
|
||||||
function stop() {
|
function stop() {
|
||||||
|
closedByLocal = true
|
||||||
try {
|
try {
|
||||||
ws.close()
|
ws.close()
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||||
|
import { onBeforeRouteLeave } from 'vue-router'
|
||||||
import { useAuthStore } from '../../stores/auth'
|
import { useAuthStore } from '../../stores/auth'
|
||||||
import { startPublishing } from '../../utils/liveWebRTC'
|
import { startPublishing } from '../../utils/liveWebRTC'
|
||||||
|
|
||||||
@@ -54,11 +55,21 @@ function stop() {
|
|||||||
status.value = '已停止'
|
status.value = '已停止'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onBeforeUnload() {
|
||||||
|
session.value?.stop()
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.title = '视频直播开播 - 管理后台'
|
document.title = '视频直播开播 - 管理后台'
|
||||||
|
window.addEventListener('beforeunload', onBeforeUnload)
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('beforeunload', onBeforeUnload)
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 离开本页时再结束推流;勿在 onUnmounted 里 stop,避免 Vue 开发严格模式双挂载误关 WebSocket */
|
||||||
|
onBeforeRouteLeave(() => {
|
||||||
stop()
|
stop()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user