直播:status 返回观看人数,后台开播页轮询展示
Made-with: Cursor
This commit is contained in:
@@ -5,6 +5,9 @@
|
||||
<span>官网视频直播(WebRTC)</span>
|
||||
</template>
|
||||
<p class="status">{{ status }}</p>
|
||||
<p v-if="session" class="viewer-row">
|
||||
<el-tag type="info" effect="plain">当前观看人数:{{ viewerCount }}</el-tag>
|
||||
</p>
|
||||
<div class="form-block">
|
||||
<div class="field-row">
|
||||
<span class="field-label">画面来源</span>
|
||||
@@ -93,6 +96,11 @@ import { onBeforeRouteLeave } from 'vue-router'
|
||||
import { useAuthStore } from '../../stores/auth'
|
||||
import { startPublishing } from '../../utils/liveWebRTC'
|
||||
|
||||
function liveStatusUrl() {
|
||||
const base = (import.meta.env.VITE_API_BASE || '').replace(/\/$/, '')
|
||||
return base ? `${base}/api/web/live/status` : '/api/web/live/status'
|
||||
}
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const token = computed(() => authStore.getToken() || '')
|
||||
const previewWrapRef = ref(null)
|
||||
@@ -101,6 +109,8 @@ const previewScreenRef = ref(null)
|
||||
const previewCamRef = ref(null)
|
||||
const status = ref('就绪')
|
||||
const session = ref(null)
|
||||
const viewerCount = ref(0)
|
||||
let viewerPollTimer = null
|
||||
const captureMode = ref('camera')
|
||||
const selectedCameraId = ref('')
|
||||
const videoInputs = ref([])
|
||||
@@ -200,6 +210,37 @@ function clearPreview() {
|
||||
if (previewCamRef.value) previewCamRef.value.srcObject = null
|
||||
}
|
||||
|
||||
async function fetchViewerCount() {
|
||||
try {
|
||||
const r = await fetch(liveStatusUrl(), { cache: 'no-store' })
|
||||
if (!r.ok) return
|
||||
const j = await r.json()
|
||||
if (typeof j.viewers === 'number') viewerCount.value = j.viewers
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
function startViewerPoll() {
|
||||
stopViewerPoll()
|
||||
fetchViewerCount()
|
||||
viewerPollTimer = window.setInterval(fetchViewerCount, 2500)
|
||||
}
|
||||
|
||||
function stopViewerPoll() {
|
||||
if (viewerPollTimer != null) {
|
||||
clearInterval(viewerPollTimer)
|
||||
viewerPollTimer = null
|
||||
}
|
||||
}
|
||||
|
||||
watch(session, (s) => {
|
||||
if (s) {
|
||||
startViewerPoll()
|
||||
} else {
|
||||
stopViewerPoll()
|
||||
viewerCount.value = 0
|
||||
}
|
||||
})
|
||||
|
||||
async function applyCaptureSwitch() {
|
||||
if (!session.value?.switchMode) return
|
||||
switchingCapture.value = true
|
||||
@@ -250,6 +291,7 @@ onMounted(() => {
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
stopViewerPoll()
|
||||
window.removeEventListener('beforeunload', onBeforeUnload)
|
||||
window.removeEventListener('pointermove', onPipPointerMove)
|
||||
})
|
||||
@@ -268,6 +310,9 @@ onBeforeRouteLeave(() => {
|
||||
margin-bottom: 14px;
|
||||
min-height: 1.5em;
|
||||
}
|
||||
.viewer-row {
|
||||
margin: -6px 0 14px;
|
||||
}
|
||||
.form-block {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
@@ -45,8 +45,9 @@ func handleLiveStatus(c *gin.Context) {
|
||||
}
|
||||
h.mu.RLock()
|
||||
live := h.publishConn != nil && h.pubPC != nil && len(h.forwarders) > 0
|
||||
viewers := len(h.viewers)
|
||||
h.mu.RUnlock()
|
||||
c.JSON(http.StatusOK, gin.H{"live": live})
|
||||
c.JSON(http.StatusOK, gin.H{"live": live, "viewers": viewers})
|
||||
}
|
||||
|
||||
func handleLiveWS(c *gin.Context) {
|
||||
|
||||
Reference in New Issue
Block a user