feat: playroom sync finished
This commit is contained in:
@@ -11,6 +11,8 @@ const videoRef = ref(null);
|
|||||||
const player = ref(null);
|
const player = ref(null);
|
||||||
const hlsInstance = ref(null);
|
const hlsInstance = ref(null);
|
||||||
|
|
||||||
|
const emit = defineEmits(['canplay', 'play', 'pause', 'remote-play-failed']);
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
autoplay: { type: Boolean, default: false },
|
autoplay: { type: Boolean, default: false },
|
||||||
videoUrl: { type: String, required: true },
|
videoUrl: { type: String, required: true },
|
||||||
@@ -121,10 +123,12 @@ onMounted(() => {
|
|||||||
|
|
||||||
player.value.on('play', () => {
|
player.value.on('play', () => {
|
||||||
console.log('播放:', props.videoUrl);
|
console.log('播放:', props.videoUrl);
|
||||||
|
emit('play', { time: getCurrentTime() });
|
||||||
});
|
});
|
||||||
|
|
||||||
player.value.on('pause', () => {
|
player.value.on('pause', () => {
|
||||||
console.log('暂停');
|
console.log('暂停');
|
||||||
|
emit('pause', { time: getCurrentTime() });
|
||||||
});
|
});
|
||||||
|
|
||||||
player.value.on('ended', () => {
|
player.value.on('ended', () => {
|
||||||
@@ -140,13 +144,82 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
player.value.on('canplay', () => {
|
player.value.on('canplay', () => {
|
||||||
console.log('视频可以播放');
|
// 缓冲、seek 后常会多次触发;不在此刷屏打印,由父组件用 pending* 决定是否执行同步
|
||||||
|
emit('canplay');
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('初始化播放器失败:', error);
|
console.error('初始化播放器失败:', error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getCurrentTime = () => {
|
||||||
|
const video = player.value?.video;
|
||||||
|
if (!video || typeof video.currentTime !== 'number' || Number.isNaN(video.currentTime)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return video.currentTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
const seekTo = (timeSec) => {
|
||||||
|
const t = Number(timeSec);
|
||||||
|
if (!Number.isFinite(t) || t < 0) return;
|
||||||
|
if (player.value?.seek) {
|
||||||
|
try {
|
||||||
|
player.value.seek(t);
|
||||||
|
return;
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
const video = player.value?.video;
|
||||||
|
if (video && typeof video.currentTime === 'number') {
|
||||||
|
try {
|
||||||
|
video.currentTime = t;
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{ remote?: boolean }} options
|
||||||
|
* remote=true:来自 WebSocket 同步,无用户手势;需静音才能通过多数浏览器的自动播放策略
|
||||||
|
*/
|
||||||
|
const play = async (options = {}) => {
|
||||||
|
const remote = options?.remote === true;
|
||||||
|
const video = player.value?.video;
|
||||||
|
if (!video?.play) return false;
|
||||||
|
if (remote) {
|
||||||
|
try {
|
||||||
|
video.muted = true;
|
||||||
|
video.setAttribute?.('playsinline', 'true');
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await video.play();
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('[videoPlayer] play() 被拒绝(多为自动播放策略):', e?.name, e?.message);
|
||||||
|
if (remote) {
|
||||||
|
emit('remote-play-failed', { error: e });
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const pause = () => {
|
||||||
|
if (player.value?.pause) {
|
||||||
|
try {
|
||||||
|
player.value.pause();
|
||||||
|
return;
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
const video = player.value?.video;
|
||||||
|
if (video?.pause) {
|
||||||
|
try {
|
||||||
|
video.pause();
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ getCurrentTime, seekTo, play, pause });
|
||||||
|
|
||||||
watch(() => props.videoUrl, (newUrl) => {
|
watch(() => props.videoUrl, (newUrl) => {
|
||||||
if (player.value && newUrl) {
|
if (player.value && newUrl) {
|
||||||
console.log('切换视频到:', newUrl);
|
console.log('切换视频到:', newUrl);
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ export const PlayroomStore = defineStore("PlayroomStore",
|
|||||||
return {
|
return {
|
||||||
currentPlayroom,
|
currentPlayroom,
|
||||||
currentUrl,
|
currentUrl,
|
||||||
|
getCurrentId,
|
||||||
setCurrentPlayroom,
|
setCurrentPlayroom,
|
||||||
clearPlayroom,
|
clearPlayroom,
|
||||||
addmember,
|
addmember,
|
||||||
|
|||||||
@@ -37,7 +37,15 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="20">
|
<el-col :span="20">
|
||||||
<video-player :autoplay="false" :videoUrl="currentURL" />
|
<video-player
|
||||||
|
ref="videoPlayerRef"
|
||||||
|
:autoplay="false"
|
||||||
|
:videoUrl="currentURL"
|
||||||
|
@canplay="handlePlayerCanplay"
|
||||||
|
@play="handleLocalPlay"
|
||||||
|
@pause="handleLocalPause"
|
||||||
|
@remote-play-failed="handleRemotePlayFailed"
|
||||||
|
/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
@@ -120,19 +128,56 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref, watchEffect } from 'vue';
|
import { nextTick, onBeforeUnmount, onMounted, ref, watchEffect } from 'vue';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { userInfoStore } from '@/store/user';
|
import { userInfoStore } from '@/store/user';
|
||||||
import videoPlayer from '@/components/videoPlayer.vue';
|
import videoPlayer from '@/components/videoPlayer.vue';
|
||||||
import { PlayroomStore } from '@/store/playroom';
|
import { PlayroomStore } from '@/store/playroom';
|
||||||
import { getPlayroomDetails } from '@/api/playroom';
|
import { getPlayroomDetails } from '@/api/playroom';
|
||||||
import { connectWebSocket } from '@/websocket/roomSocket';
|
import { getUserInfo } from '@/api/user';
|
||||||
|
import {
|
||||||
|
connectWebSocket,
|
||||||
|
ROOM_SOCKET_VIDEO_PAUSE_EVENT,
|
||||||
|
ROOM_SOCKET_VIDEO_PLAY_EVENT,
|
||||||
|
ROOM_SOCKET_VIDEO_SYNC_EVENT,
|
||||||
|
sendMessage
|
||||||
|
} from '@/websocket/roomSocket';
|
||||||
|
|
||||||
//import audioPlayer from '@/components/audioPlayer.vue'; // 假设你有一个音频播放组件
|
//import audioPlayer from '@/components/audioPlayer.vue'; // 假设你有一个音频播放组件
|
||||||
|
|
||||||
const curruentRoomInfo = PlayroomStore();
|
const curruentRoomInfo = PlayroomStore();
|
||||||
const userinfo = userInfoStore();
|
const userinfo = userInfoStore();
|
||||||
|
|
||||||
|
const videoPlayerRef = ref(null);
|
||||||
|
const pendingSyncSeekSec = ref(null);
|
||||||
|
const pendingSyncUrl = ref(null);
|
||||||
|
const isApplyingRemoteControl = ref(false);
|
||||||
|
const pendingRemoteAction = ref(null); // 'play' | 'pause' | null
|
||||||
|
|
||||||
|
const getSelfFrom = () => {
|
||||||
|
// u_id 在 JSON 里经常是 number,若只判断 typeof === 'string' 会漏掉,最后错误落到 id===0 → from 变成 0
|
||||||
|
const rawId = userinfo.user?.id;
|
||||||
|
if (typeof rawId === 'number' && rawId > 0) return rawId;
|
||||||
|
if (typeof rawId === 'string' && rawId.trim() !== '') {
|
||||||
|
const n = Number(rawId);
|
||||||
|
if (Number.isFinite(n) && n > 0) return n;
|
||||||
|
}
|
||||||
|
const rawUid = userinfo.user?.u_id;
|
||||||
|
if (typeof rawUid === 'number' && Number.isFinite(rawUid) && rawUid !== 0) return rawUid;
|
||||||
|
if (typeof rawUid === 'string' && rawUid.trim() !== '') return rawUid.trim();
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isSelfMessage = (from) => {
|
||||||
|
// 后端可能用数字 id,也可能用 u_id;任一对上即视为自己,避免只比 getSelfFrom() 一种形态
|
||||||
|
const f = String(from);
|
||||||
|
const id = userinfo.user?.id;
|
||||||
|
const uid = userinfo.user?.u_id;
|
||||||
|
if (id != null && String(id) === f) return true;
|
||||||
|
if (uid != null && String(uid) === f) return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
const dialogVisibleCode = ref(false)
|
const dialogVisibleCode = ref(false)
|
||||||
const dialogVisibleVideo = ref(false)
|
const dialogVisibleVideo = ref(false)
|
||||||
|
|
||||||
@@ -283,10 +328,150 @@ const getInvitingCode = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const replaceURL = () => {
|
const replaceURL = () => {
|
||||||
|
const playbackTimeSec = videoPlayerRef.value?.getCurrentTime?.() ?? 0;
|
||||||
currentURL.value = changingVideoUrl.value;
|
currentURL.value = changingVideoUrl.value;
|
||||||
dialogVisibleVideo.value = false;
|
|
||||||
|
|
||||||
}
|
const msg = {
|
||||||
|
cmd: "VIDEO_SYNC",
|
||||||
|
from: getSelfFrom(),
|
||||||
|
url: changingVideoUrl.value,
|
||||||
|
timestamp: Number(playbackTimeSec.toFixed(3)),
|
||||||
|
playroom: curruentRoomInfo.getCurrentId()
|
||||||
|
}
|
||||||
|
console.log(msg);
|
||||||
|
sendMessage(msg);
|
||||||
|
dialogVisibleVideo.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePlayerCanplay = () => {
|
||||||
|
const hasWork =
|
||||||
|
pendingSyncSeekSec.value != null ||
|
||||||
|
pendingRemoteAction.value != null ||
|
||||||
|
pendingSyncUrl.value != null;
|
||||||
|
if (!hasWork) return;
|
||||||
|
|
||||||
|
if (pendingSyncSeekSec.value != null) {
|
||||||
|
const t = Number(pendingSyncSeekSec.value);
|
||||||
|
if (Number.isFinite(t) && t >= 0) {
|
||||||
|
videoPlayerRef.value?.seekTo?.(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pendingRemoteAction.value === 'play') {
|
||||||
|
void videoPlayerRef.value?.play?.({ remote: true });
|
||||||
|
} else if (pendingRemoteAction.value === 'pause') {
|
||||||
|
videoPlayerRef.value?.pause?.();
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingSyncSeekSec.value = null;
|
||||||
|
pendingSyncUrl.value = null;
|
||||||
|
pendingRemoteAction.value = null;
|
||||||
|
|
||||||
|
if (isApplyingRemoteControl.value) {
|
||||||
|
setTimeout(() => {
|
||||||
|
isApplyingRemoteControl.value = false;
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemotePlayFailed = () => {
|
||||||
|
ElMessage.info('同步播放被浏览器拦截:请在本页点击一次播放器上的播放(需用户手势后才能出声)');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleVideoSync = (payload) => {
|
||||||
|
if (!payload) return;
|
||||||
|
|
||||||
|
const from = payload.from;
|
||||||
|
// 如果同步消息来自自己,直接跳过
|
||||||
|
if (isSelfMessage(from)) return;
|
||||||
|
|
||||||
|
const url = payload.url;
|
||||||
|
if (typeof url !== 'string' || url.trim() === '') return;
|
||||||
|
|
||||||
|
const ts = Number(payload.timestamp ?? 0);
|
||||||
|
pendingSyncSeekSec.value = Number.isFinite(ts) && ts >= 0 ? ts : 0;
|
||||||
|
pendingSyncUrl.value = url;
|
||||||
|
|
||||||
|
// 先切 URL,等 canplay 后再 seek
|
||||||
|
currentURL.value = url;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLocalPlay = () => {
|
||||||
|
if (isApplyingRemoteControl.value) return;
|
||||||
|
const t = videoPlayerRef.value?.getCurrentTime?.() ?? 0;
|
||||||
|
const msg = {
|
||||||
|
cmd: "VIDEO_PLAY",
|
||||||
|
from: getSelfFrom(),
|
||||||
|
playroom: curruentRoomInfo.getCurrentId(),
|
||||||
|
timestamp: Number(Number(t).toFixed(3)),
|
||||||
|
url: currentURL.value,
|
||||||
|
};
|
||||||
|
console.log("[ws send]", msg);
|
||||||
|
sendMessage(msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLocalPause = () => {
|
||||||
|
if (isApplyingRemoteControl.value) return;
|
||||||
|
const t = videoPlayerRef.value?.getCurrentTime?.() ?? 0;
|
||||||
|
const msg = {
|
||||||
|
cmd: "VIDEO_PAUSE",
|
||||||
|
from: getSelfFrom(),
|
||||||
|
playroom: curruentRoomInfo.getCurrentId(),
|
||||||
|
timestamp: Number(Number(t).toFixed(3)),
|
||||||
|
url: currentURL.value,
|
||||||
|
};
|
||||||
|
console.log("[ws send]", msg);
|
||||||
|
sendMessage(msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
const applyRemotePlayPause = async (payload, action) => {
|
||||||
|
if (!payload) return;
|
||||||
|
|
||||||
|
const from = payload.from;
|
||||||
|
if (isSelfMessage(from)) return;
|
||||||
|
|
||||||
|
console.log("[ws recv]", action, payload);
|
||||||
|
|
||||||
|
const url = payload.url;
|
||||||
|
if (typeof url === 'string' && url.trim() !== '' && url !== currentURL.value) {
|
||||||
|
// 远端可能切了新 URL,但你本地还没收到/处理到 LINK/VIDEO_SYNC,先对齐
|
||||||
|
pendingSyncUrl.value = url;
|
||||||
|
currentURL.value = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ts = Number(payload.timestamp ?? 0);
|
||||||
|
pendingSyncSeekSec.value = Number.isFinite(ts) && ts >= 0 ? ts : 0;
|
||||||
|
|
||||||
|
isApplyingRemoteControl.value = true;
|
||||||
|
pendingRemoteAction.value = action;
|
||||||
|
|
||||||
|
// 尽量立刻执行一次(同 URL 时不用等 canplay)
|
||||||
|
// 用 nextTick + setTimeout(0) 确保 URL/DOM 更新完成再触发 play/pause
|
||||||
|
await nextTick();
|
||||||
|
setTimeout(async () => {
|
||||||
|
const seekSec = pendingSyncSeekSec.value;
|
||||||
|
try {
|
||||||
|
videoPlayerRef.value?.seekTo?.(seekSec);
|
||||||
|
// 先清 pending,避免 await play() 期间多次 canplay 又走一遍 handlePlayerCanplay
|
||||||
|
pendingSyncSeekSec.value = null;
|
||||||
|
pendingSyncUrl.value = null;
|
||||||
|
pendingRemoteAction.value = null;
|
||||||
|
if (action === 'play') {
|
||||||
|
console.log("[apply]", "play", seekSec);
|
||||||
|
await videoPlayerRef.value?.play?.({ remote: true });
|
||||||
|
} else {
|
||||||
|
console.log("[apply]", "pause", seekSec);
|
||||||
|
videoPlayerRef.value?.pause?.();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("[apply failed]", e);
|
||||||
|
} finally {
|
||||||
|
setTimeout(() => {
|
||||||
|
isApplyingRemoteControl.value = false;
|
||||||
|
}, 250);
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
};
|
||||||
|
|
||||||
const joinVoiceRoom = () => {
|
const joinVoiceRoom = () => {
|
||||||
membersInVoice.value.push({
|
membersInVoice.value.push({
|
||||||
@@ -309,14 +494,44 @@ const goback = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const syncListener = (e) => handleVideoSync(e?.detail);
|
||||||
|
const playListener = (e) => applyRemotePlayPause(e?.detail, 'play');
|
||||||
|
const pauseListener = (e) => applyRemotePlayPause(e?.detail, 'pause');
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const r_id = window.location.search.split('=')[1];
|
const r_id = window.location.search.split('=')[1];
|
||||||
|
// 新窗口只进房间时不会经过 home,getUserInfo 可能从未执行,导致 id/u_id 仍是默认值
|
||||||
|
if (
|
||||||
|
userinfo.token &&
|
||||||
|
(!String(userinfo.user?.u_id || '').trim() || userinfo.user?.id === 0)
|
||||||
|
) {
|
||||||
|
const ok = await getUserInfo();
|
||||||
|
if (!ok && getSelfFrom() === 0) {
|
||||||
|
ElMessage.warning('用户信息未就绪,播放同步里的 from 可能为 0,请重新登录或从首页进入房间');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log("[playroom-debug][room onMounted 即将连 WS]", {
|
||||||
|
"user.id": userinfo.user?.id,
|
||||||
|
"id 非 0": typeof userinfo.user?.id === "number" && userinfo.user.id > 0,
|
||||||
|
"user.u_id": userinfo.user?.u_id,
|
||||||
|
getSelfFrom: getSelfFrom(),
|
||||||
|
hasToken: Boolean(userinfo.token),
|
||||||
|
note: "房间 WebSocket 仅用 r_id + token 子协议,不校验 id;from 为 0 是发消息时 store 里 id/u_id 仍为空",
|
||||||
|
});
|
||||||
await getRoomInfo(r_id)
|
await getRoomInfo(r_id)
|
||||||
connectWebSocket(r_id)
|
connectWebSocket(r_id)
|
||||||
|
|
||||||
|
window.addEventListener(ROOM_SOCKET_VIDEO_SYNC_EVENT, syncListener);
|
||||||
|
window.addEventListener(ROOM_SOCKET_VIDEO_PLAY_EVENT, playListener);
|
||||||
|
window.addEventListener(ROOM_SOCKET_VIDEO_PAUSE_EVENT, pauseListener);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
window.removeEventListener(ROOM_SOCKET_VIDEO_SYNC_EVENT, syncListener);
|
||||||
|
window.removeEventListener(ROOM_SOCKET_VIDEO_PLAY_EVENT, playListener);
|
||||||
|
window.removeEventListener(ROOM_SOCKET_VIDEO_PAUSE_EVENT, pauseListener);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { userInfoStore } from "@/store/user";
|
import { userInfoStore } from "@/store/user";
|
||||||
|
|
||||||
|
export const ROOM_SOCKET_VIDEO_SYNC_EVENT = "room:video_sync";
|
||||||
|
export const ROOM_SOCKET_VIDEO_PLAY_EVENT = "room:video_play";
|
||||||
|
export const ROOM_SOCKET_VIDEO_PAUSE_EVENT = "room:video_pause";
|
||||||
|
|
||||||
// userinfo 实例
|
// userinfo 实例
|
||||||
const userinfo = userInfoStore();
|
const userinfo = userInfoStore();
|
||||||
@@ -62,9 +65,19 @@ export const connectWebSocket = (r_id: number) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log(retrytime);
|
console.log(retrytime);
|
||||||
|
// 调试:房间 WS 不依赖 user.id(URL 只有 r_id,鉴权在子协议 token);id 只影响你主动发的消息里的 from
|
||||||
|
console.log("[playroom-debug][connectWebSocket]", {
|
||||||
|
r_id,
|
||||||
|
"user.id": userinfo.user?.id,
|
||||||
|
"user.id > 0": typeof userinfo.user?.id === "number" && userinfo.user.id > 0,
|
||||||
|
"user.u_id": userinfo.user?.u_id,
|
||||||
|
hasToken: Boolean(userinfo.token),
|
||||||
|
socketUrl,
|
||||||
|
});
|
||||||
socket.value = new WebSocket(socketUrl, "token-"+ userinfo.token);
|
socket.value = new WebSocket(socketUrl, "token-"+ userinfo.token);
|
||||||
|
|
||||||
socket.value.onopen = (event: any) => {
|
socket.value.onopen = (event: any) => {
|
||||||
|
console.log("[playroom-debug][ws open] 连接已建立,此时 user.id =", userinfo.user?.id, "u_id =", userinfo.user?.u_id);
|
||||||
console.log("WebSocket for video 连接已建立", event);
|
console.log("WebSocket for video 连接已建立", event);
|
||||||
setReconnectScheduled(false);
|
setReconnectScheduled(false);
|
||||||
setIsManualClose(false);
|
setIsManualClose(false);
|
||||||
@@ -89,7 +102,23 @@ export const connectWebSocket = (r_id: number) => {
|
|||||||
sendMessage(msg);
|
sendMessage(msg);
|
||||||
break;
|
break;
|
||||||
case "VIDEO_SYNC":
|
case "VIDEO_SYNC":
|
||||||
// console.log("视频同步消息", MessageData);
|
console.log("视频同步消息", MessageData);
|
||||||
|
// 通过事件分发给页面(避免 websocket 层直接依赖具体视图)
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent(ROOM_SOCKET_VIDEO_SYNC_EVENT, { detail: MessageData })
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "VIDEO_PLAY":
|
||||||
|
console.log("视频播放");
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent(ROOM_SOCKET_VIDEO_PLAY_EVENT, { detail: MessageData })
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "VIDEO_PAUSE":
|
||||||
|
console.log("视频暂停");
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent(ROOM_SOCKET_VIDEO_PAUSE_EVENT, { detail: MessageData })
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}catch(error){
|
}catch(error){
|
||||||
|
|||||||
Reference in New Issue
Block a user