123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915 |
- import { ElMessage, ElMessageBox } from "element-plus";
- import { reactive, ref, Ref } from "vue";
- import * as RongIMLib from "@rongcloud/imlib-next";
- import * as RTC from "@rongcloud/plugin-rtc";
- import { debounce } from "throttle-debounce";
- import request from "/src/helpers/request";
- import { state } from "/src/state";
- import mitt from "mitt";
- import event, { LIVE_EVENT_MESSAGE } from "./event";
- import dayjs from "dayjs";
- import { removeToken } from "/src/utils/auth";
- import qs from "query-string";
- // import { SeatsCtrl } from './message-type'
- type imConnectStatus = "connecting" | "connected" | "disconnect";
- type VideoStatus =
- | "init"
- | "stream"
- | "liveing"
- | "stopped"
- | "error"
- | "loading";
- export type TrackType = "microphone" | "microphone2" | "camera" | "screen";
- let publishError = false;
- type ActiveTracks = {
- [key in TrackType]: RTC.RCLocalTrack | null;
- };
- type DeviceStatus = {
- [key in TrackType]: "init" | "granted" | "denied" | "closed" | "none";
- };
- export const START_LIVE_TIME = "start-live-time";
- export const START_LIVE_STATUS = "start-live-status";
- export const VIDEO_DEVICE_ID = "video-deviceId";
- export const AUDIO_DEVICE_ID = "audio-deviceId";
- export const AUDIO_DEVICE_ID2 = "audio-deviceId2";
- export const AUDIO_DEVICE_VOLUME = "audio-device-volume";
- const runtime = reactive({
- /** 房间id */
- roomUid: sessionStorage.getItem("roomUid") || "",
- /** IM连接状态 */
- imConnectStatus: "connecting" as imConnectStatus,
- // 屏幕分享状态
- screenShareStatus: false,
- // 视频节点
- videoRef: ref<HTMLVideoElement | null>(null),
- // RTC实例
- rtcClient: null as RTC.RCRTCClient | null,
- /** 加入房间实例 */
- joinedRoom: null as RTC.RCLivingRoom | null,
- // Tracks
- mediaStreamTrack: [] as MediaStreamTrack[],
- // 媒体流
- mediaStreams: null as MediaStream | null,
- // 视频状态
- videoStatus: "init" as VideoStatus,
- // 麦克风设备列表
- microphones: [] as MediaDeviceInfo[],
- // 摄像头设备列表
- cameras: [] as MediaDeviceInfo[],
- // 摄像头设备
- selectedCamera: null as MediaDeviceInfo | null,
- // 麦克风设备
- selectedMicrophone: null as MediaDeviceInfo | null,
- // 系统音频设备
- selectedMicrophone2: null as MediaDeviceInfo | null,
- // 点赞数量
- likeCount: 0,
- // 观看人数
- lookCount: 0,
- // 上一次点赞数量
- lastLikeCount: 0,
- /** 当前活跃的数据流 */
- activeTracks: {} as ActiveTracks,
- /** 是否关闭连麦 */
- allowSeatsCtrl: true,
- /** 是否关闭发言 */
- allowChatCtrl: true,
- /** 当前设备获取状态 */
- deviceStatus: {
- microphone: "init",
- camera: "init",
- screen: "init",
- } as DeviceStatus,
- syncLikeTimer: null as any,
- });
- export default runtime;
- // c9kqb3rdc451j 测试环境
- const RONG_IM_TOKEN = "c9kqb3rdc451j";
- // const RONG_IM_TOKEN = "6tnym1br6pv07";
- RongIMLib.init({
- appkey: RONG_IM_TOKEN,
- });
- // 注册自定义消息类型
- // 控制是否允许连麦
- const MessageSeatsCtrl = RongIMLib.registerMessageType(
- "RC:Chatroom:SeatsCtrl",
- true,
- true
- );
- // 控制是否允许发言
- const MessageChatBan = RongIMLib.registerMessageType(
- "RC:Chatroom:ChatBan",
- true,
- true
- );
- // 连麦消息
- const MessageSeatApply = RongIMLib.registerMessageType(
- "RC:Chatroom:SeatApply",
- true,
- true
- );
- // 响应连麦消息
- const MessageSeatResponse = RongIMLib.registerMessageType(
- "RC:Chatroom:SeatResponse",
- true,
- true
- );
- // 同步房间观众数量
- const MessageMemberCount = RongIMLib.registerMessageType(
- "RC:Chatroom:MemberCount",
- true,
- true
- );
- // 当前连麦人员同步
- const MessageSeatMember = RongIMLib.registerMessageType(
- "RC:Chatroom:SeatMember",
- true,
- true
- );
- // 当前点赞数量同步
- const MessageLikeCount = RongIMLib.registerMessageType(
- "RC:Chatroom:LikeCount",
- true,
- true
- );
- // 老师进入房间,刷新页面也会发送
- const MessageWelcome = RongIMLib.registerMessageType(
- "RC:Chatroom:Welcome",
- true,
- true
- );
- // 暂停直播消息
- const MessagePauseLive = RongIMLib.registerMessageType(
- "RC:Chatroom:PauseLive",
- true,
- true
- );
- type MessageProps = {
- messageType:
- | "RC:Chatroom:Welcome"
- | "RC:TxtMsg"
- | "RC:Chatroom:Barrage"
- | "RC:Chatroom:Like"
- | "RC:Chatroom:SeatsCtrl"
- | "RC:Chatroom:ChatBan"
- | "RC:Chatroom:SeatApply";
- content: any;
- senderUserId: any;
- };
- type MessageEvent = {
- messages: MessageProps[];
- };
- export const runtimeEvent = mitt();
- const Events = RongIMLib.Events;
- /**
- * 监听消息通知
- */
- const { MESSAGES, ...RestMessage } = Events;
- RongIMLib.addEventListener(Events.MESSAGES, (evt: MessageEvent) => {
- console.log(evt, "收到消息");
- const { messages } = evt;
- for (const message of messages) {
- // console.log(LIVE_EVENT_MESSAGE[message.messageType], message)
- const isSelf =
- message.senderUserId &&
- Number(message.senderUserId) === state.user?.speakerId;
- if (!isSelf && LIVE_EVENT_MESSAGE[message.messageType]) {
- event.emit(LIVE_EVENT_MESSAGE[message.messageType], {
- ...message.content,
- $EventMessage: message,
- });
- }
- }
- });
- for (const Message of Object.values(RestMessage)) {
- RongIMLib.addEventListener(Message, (evt: any) => {
- console.log(Message, evt);
- // chatroomDestroyed
- event.emit(Message, { $EventMessage: null });
- });
- }
- /**
- * 监听 IM 连接状态变化
- */
- RongIMLib.addEventListener(Events.CONNECTING, () => {
- console.log("connecting");
- runtime.imConnectStatus = "connecting";
- });
- RongIMLib.addEventListener(Events.CONNECTED, () => {
- console.log("connected");
- runtime.imConnectStatus = "connected";
- });
- RongIMLib.addEventListener(Events.DISCONNECT, () => {
- console.log("disconnect");
- runtime.imConnectStatus = "disconnect";
- closeLive(true, "IM");
- const search = qs.parse(window.location.search);
- console.log(search, "disconnect");
- window.location.href =
- window.location.origin +
- "/live?" +
- qs.stringify({ ...search, time: new Date().getTime() });
- // event.emit(LIVE_EVENT_MESSAGE["RC:ForcedOffline"])
- // if (runtime.joinedRoom && runtime.videoStatus === 'liveing') {
- // closeLive(true, 'IM')
- // }
- });
- export const connectIM = async (imToken: string) => {
- try {
- const user = await RongIMLib.connect(imToken);
- runtime.rtcClient = RongIMLib.installPlugin(RTC.installer, {});
- console.log("connect success", user.data?.userId);
- return user;
- } catch (error) {
- throw error;
- }
- };
- /**
- * 设置声音
- * @param video
- * @param Value 声音大小
- */
- export const setVolume = (value: number) => {
- localStorage.setItem(AUDIO_DEVICE_VOLUME, value.toString());
- if (runtime.videoRef) {
- runtime.videoRef.volume = value / 100;
- }
- const tempM = runtime.activeTracks.microphone;
- // runtime.activeTracks.microphone && runtime.activeTracks.microphone._element;
- // @ts-ignore
- const tempE = tempM._element;
- if (tempE) {
- // @ts-ignore
- runtime.activeTracks.microphone._element.volume = value / 100;
- }
- };
- /**
- * 设置video视频流
- */
- export const setVideoSrcObject = (
- video: HTMLVideoElement | null,
- mediaStreams: MediaStream | null
- ) => {
- if (video && mediaStreams) {
- video.srcObject = mediaStreams;
- video.onloadedmetadata = () => {
- video.play();
- };
- }
- };
- /**
- * 发起屏幕共享
- */
- export const shareScreenVideo = async () => {
- if (runtime.screenShareStatus) {
- ElMessage.error("正在屏幕共享中,请先关闭屏幕共享");
- return;
- }
- if (
- runtime.rtcClient &&
- !runtime.screenShareStatus &&
- runtime.videoStatus === "liveing"
- ) {
- let screenTrack: RTC.RCLocalTrack | undefined;
- try {
- screenTrack = await getTrack("screen");
- } catch (error) {
- ElMessage.error("屏幕分享失败,请检查是否授权");
- }
- if (!screenTrack) {
- return;
- }
- const oldTrack = runtime.activeTracks.camera as RTC.RCLocalTrack;
- // removeTrack([oldTrack], 'camera')
- if (oldTrack) {
- await runtime.joinedRoom?.unpublish([oldTrack]);
- }
- setTrack([screenTrack as RTC.RCLocalTrack], "screen");
- if (runtime.videoRef) {
- screenTrack?.play(runtime.videoRef);
- runtime.screenShareStatus = true;
- }
- screenTrack?.on(
- RTC.RCLocalTrack.EVENT_LOCAL_TRACK_END,
- (track: RTC.RCLocalTrack) => {
- runtime.screenShareStatus = false;
- track.destroy();
- // removeTrack([track], 'screen')
- if (oldTrack) {
- setTrack([oldTrack as RTC.RCLocalTrack], "camera");
- if (runtime.videoRef) {
- oldTrack.play(runtime.videoRef);
- }
- }
- // setVideoSrcObject(runtime.videoRef, this.mediaStreams)
- }
- );
- }
- };
- /**
- * 取消屏幕共享流的访问,会导致取消屏幕共享
- */
- export const closeShareScreenVideo = () => {
- document.exitPictureInPicture();
- const screenTrack = runtime.activeTracks.screen as RTC.RCLocalTrack;
- if (screenTrack) {
- screenTrack.destroy();
- runtime.screenShareStatus = false;
- }
- const oldTrack = runtime.activeTracks.camera as RTC.RCLocalTrack;
- if (oldTrack) {
- setTrack([oldTrack as RTC.RCLocalTrack], "camera");
- if (runtime.videoRef) {
- oldTrack.play(runtime.videoRef);
- }
- }
- };
- export const createVideoPictureInPicture = (ms: MediaStream) => {
- const video = document.createElement("video");
- video.style.display = "none";
- document.body.append(video);
- video.srcObject = ms;
- video.play();
- setTimeout(() => {
- video.requestPictureInPicture();
- }, 1000);
- };
- /**
- * 开启或关闭屏幕共享
- */
- export const toggleShareScreenVideo = async () => {
- if (runtime.screenShareStatus) {
- try {
- await ElMessageBox.confirm("是否确认取消屏幕共享?");
- closeShareScreenVideo();
- } catch (error) {}
- } else {
- shareScreenVideo();
- // @ts-ignore
- createVideoPictureInPicture(runtime.activeTracks.camera._msStream);
- console.log(runtime.activeTracks.camera);
- // runtime.videoRef?.requestPictureInPicture()
- }
- };
- /**
- *
- * 获取所有音频输入设备
- * @returns {Promise<void>}
- */
- export const getMicrophones = async () => {
- const microphones = await RTC.device.getMicrophones();
- runtime.microphones = microphones;
- return microphones;
- };
- /**
- *
- * 获取所有视频输入设备
- * @returns {Promise<void>}
- */
- export const getCameras = async () => {
- const cameras = await RTC.device.getCameras();
- runtime.cameras = cameras;
- return cameras;
- };
- /**
- *
- * 设置当前视频设备
- * @param camera MediaDeviceInfo
- */
- export const setSelectCamera = async (camera: MediaDeviceInfo) => {
- runtime.selectedCamera = camera;
- localStorage.setItem(VIDEO_DEVICE_ID, camera.deviceId);
- const oldTrack = runtime.activeTracks.camera as RTC.RCLocalTrack;
- if (oldTrack) {
- await removeTrack([oldTrack], "camera", oldTrack.isPublished());
- }
- const track = await getTrack("camera");
- setTrack([track], "camera", runtime.videoStatus === "liveing");
- };
- /**
- *
- * 设置当前麦克风设备
- * @param microphone MediaDeviceInfo
- */
- export const setSelectMicrophone = async (microphone: MediaDeviceInfo) => {
- runtime.selectedMicrophone = microphone;
- localStorage.setItem(AUDIO_DEVICE_ID, microphone.deviceId);
- const oldTrack = runtime.activeTracks.microphone as RTC.RCLocalTrack;
- if (oldTrack) {
- await removeTrack([oldTrack], "microphone", oldTrack.isPublished());
- }
- const track = await getTrack("microphone");
- setTrack([track], "microphone", runtime.videoStatus === "liveing");
- runtimeEvent.emit("microphoneChange", microphone);
- };
- /**
- *
- * 设置当前麦克风设备
- * @param microphone MediaDeviceInfo
- */
- export const setSelectMicrophone2 = async (microphone: MediaDeviceInfo) => {
- runtime.selectedMicrophone2 = microphone;
- localStorage.setItem(AUDIO_DEVICE_ID2, microphone.deviceId);
- const oldTrack = runtime.activeTracks.microphone2 as RTC.RCLocalTrack;
- if (oldTrack) {
- await removeTrack([oldTrack], "microphone2", oldTrack.isPublished());
- }
- const track = await getTrack("microphone2");
- setTrack([track], "microphone2", runtime.videoStatus === "liveing");
- runtimeEvent.emit("microphone2Change", microphone);
- };
- type TrackResult = {
- code: RTC.RCRTCCode;
- track:
- | RTC.RCMicphoneAudioTrack
- | RTC.RCCameraVideoTrack
- | RTC.RCScreenVideoTrack
- | undefined;
- };
- export const getTrack = async (
- trackType: TrackType
- ): Promise<RTC.RCLocalTrack> => {
- let res: TrackResult | undefined;
- let Track: RTC.RCLocalTrack | null = null;
- if (trackType === "microphone") {
- res = (await runtime.rtcClient?.createMicrophoneAudioTrack("RongCloudRTC", {
- micphoneId: runtime.selectedMicrophone?.deviceId,
- sampleRate:
- Number(localStorage.getItem("sampleRate") || "44100") || 44100,
- })) as TrackResult;
- } else if (trackType === "microphone2") {
- res = (await runtime.rtcClient?.createMicrophoneAudioTrack("RongCloudRTC", {
- micphoneId: runtime.selectedMicrophone2?.deviceId,
- })) as TrackResult;
- } else if (trackType === "camera") {
- // const sm = await requireMedia({
- // audio: true,
- // video: true,
- // })
- // console.log(sm.getTracks())
- res = (await runtime.rtcClient?.createCameraVideoTrack("RongCloudRTC", {
- cameraId: runtime.selectedCamera?.deviceId,
- faceMode: "user",
- frameRate: RTC.RCFrameRate.FPS_30,
- resolution: RTC.RCResolution.W1920_H1080,
- })) as TrackResult;
- } else {
- res = (await runtime?.rtcClient?.createScreenVideoTrack("screenshare", {
- frameRate: RTC.RCFrameRate.FPS_30,
- resolution: RTC.RCResolution.W1920_H1080,
- })) as TrackResult;
- }
- Track = res?.track as RTC.RCLocalTrack;
- if (trackType === "camera" && !runtime.cameras.length) {
- runtime.deviceStatus[trackType] = "none";
- } else if (
- (trackType === "microphone" || trackType === "microphone2") &&
- !runtime.microphones.length
- ) {
- runtime.deviceStatus[trackType] = "none";
- } else if (trackType === "screen" && !runtime.screenShareStatus) {
- runtime.deviceStatus[trackType] = "none";
- }
- if (res.code === RTC.RCRTCCode.PERMISSION_DENIED) {
- runtime.deviceStatus[trackType] = "denied";
- } else {
- runtime.deviceStatus[trackType] = "granted";
- }
- // if (res.code !== RTC.RCRTCCode.SUCCESS || !Track) {
- // throw new Error('获取数据流失败')
- // }
- if (res.code === RTC.RCRTCCode.GET_DISPLAY_MEDIA_FAILED) {
- throw new Error("获取屏幕共享失败");
- }
- return Track;
- };
- export type OnAudioProcess = (num: number, deviceId: string) => void;
- export const listenAudioChecker = (
- stream: MediaStream,
- onaudioprocess: OnAudioProcess
- ) => {
- const audioContext = window.AudioContext;
- const ac = new audioContext();
- const liveSource = ac.createMediaStreamSource(stream);
- const analyser = ac.createAnalyser();
- liveSource.connect(analyser);
- analyser.fftSize = 2048;
- analyser.minDecibels = -90;
- analyser.maxDecibels = -10;
- analyser.smoothingTimeConstant = 0.85;
- // setInterval(() => {
- // getVoiceSize(analyser)
- // }, 50)
- // return analyser
- const levelChecker = ac.createScriptProcessor(4096, 1, 1);
- levelChecker.connect(ac.destination);
- liveSource.connect(levelChecker);
- levelChecker.onaudioprocess = (e) =>
- debounce(200, () => {
- const buffer = e.inputBuffer.getChannelData(0);
- var maxVal = 0;
- for (var i = 0; i < buffer.length; i++) {
- if (maxVal < buffer[i]) {
- maxVal = buffer[i];
- }
- }
- // console.log(stream.getAudioTracks()[0])
- onaudioprocess(maxVal * 100, stream.getAudioTracks()[0]?.label);
- // console.log(maxVal * 100, stream.getAudioTracks()[0]?.label)
- // console.log(e.inputBuffer.getChannelData(0))
- })();
- return levelChecker;
- };
- const getVoiceSize = (analyser: AnalyserNode) => {
- const dataArray = new Uint8Array(analyser.frequencyBinCount);
- analyser.getByteFrequencyData(dataArray);
- const data = dataArray.slice(100, 1000);
- const sum = data.reduce((a, b) => a + b);
- // for(var i = 0; i < analyser.frequencyBinCount; i++) {
- // var v = dataArray[i] / 128.0
- // console.log(v)
- // }
- console.log(sum, 128 * analyser.frequencyBinCount);
- };
- /**
- * 添加视频流,会同步修改当先视频与推送的流
- * @param track
- */
- export const setTrack = async (
- tracks: RTC.RCLocalTrack[],
- trackType: TrackType,
- needPublish = true
- ) => {
- const filterTracks = tracks.filter((track) => !!track);
- for (const track of filterTracks) {
- // @ts-ignore
- // await runtime.mediaStreams?.addTrack(track._msTrack)
- if (trackType === "microphone") {
- // track?.play()
- }
- runtime.activeTracks[trackType] = track;
- }
- if (trackType === "camera" && runtime.videoRef) {
- runtime.activeTracks[trackType]?.play(runtime.videoRef);
- }
- if (needPublish) {
- // console.log('publish', runtime.joinedRoom)
- try {
- const res = await runtime.joinedRoom?.publish(
- tracks.filter((track) => !!track)
- );
- console.log(res, "pub");
- if (res?.code !== RTC.RCRTCCode.SUCCESS && !publishError) {
- publishError = true;
- window.onbeforeunload = null;
- ElMessageBox.alert("视频推流失败,请刷新页面重新开启?", "提示", {
- confirmButtonText: "确定",
- callback: () => {
- publishError = false;
- window.location.reload();
- },
- });
- }
- } catch (err: any) {
- console.log(err, "err");
- }
- }
- };
- /**
- * 删除视频流,会同步修改当先视频与推送的流
- * @param track
- */
- export const removeTrack = async (
- tracks: RTC.RCLocalTrack[],
- trackType: TrackType,
- needPublish = true
- ) => {
- const filterTracks = tracks.filter((track) => !!track);
- if (needPublish) {
- await runtime.joinedRoom?.unpublish(filterTracks);
- }
- for (const track of filterTracks) {
- // @ts-ignore
- // await runtime.mediaStreams?.removeTrack(track._msTrack)
- // runtime.activeTracks[trackType].destroy()
- // console.log(runtime.activeTracks[trackType])
- track?.destroy();
- runtime.activeTracks[trackType] = null;
- }
- };
- export const joinIMRoom = async (
- roomId: string,
- type: RTC.RCLivingType,
- listenEvents: RTC.IRoomEventListener | null
- ) => {
- await RongIMLib.joinChatRoom(roomId, { count: -1 });
- const join = await runtime.rtcClient?.joinLivingRoom(roomId, type);
- if (join?.code != RTC.RCRTCCode.SUCCESS) throw Error("加入房间失败");
- join.room?.registerRoomEventListener(listenEvents);
- return join;
- };
- export const joinRoom = async (
- roomId: string,
- type: RTC.RCLivingType,
- listenEvents: RTC.IRoomEventListener | null
- ) => {
- // try {
- // await request.get('/api-web/imLiveBroadcastRoom/joinRoom', {
- // params: {
- // roomUid: runtime.roomUid,
- // userId: state.user?.speakerId,
- // }
- // })
- // } catch (error) {}
- return await joinIMRoom(roomId, type, listenEvents);
- };
- /**
- * 开始直播
- */
- export const startLive = async (resetTime = true) => {
- if (runtime.videoStatus !== "stream") {
- const errorMessage = "请确定摄像头已经开启";
- ElMessage.error(errorMessage);
- throw Error(errorMessage);
- }
- const room = runtime.joinedRoom;
- if (room) {
- // const microphoneAudioTrack = await getTrack('microphone')
- // const cameraVideoTrack = await getTrack('camera')
- await setTrack(
- [runtime.activeTracks.camera as RTC.RCLocalVideoTrack],
- "camera"
- );
- await setTrack(
- [runtime.activeTracks.microphone as RTC.RCLocalAudioTrack],
- "microphone"
- );
- // const builder = await runtime.joinedRoom?.getMCUConfigBuilder()
- // // @ts-ignore
- // await builder.setOutputVideoRenderMode?.(RTC.MixVideoRenderMode.WHOLE)
- // // @ts-ignore
- // await builder.flush()
- // console.log(runtime.activeTracks)
- await request.get("/api-web/imLiveBroadcastRoom/opsLiveVideo", {
- params: {
- type: "1",
- roomUid: runtime.roomUid,
- userId: state.user?.speakerId,
- },
- });
- runtime.videoStatus = "liveing";
- }
- if (resetTime) {
- sessionStorage.setItem(START_LIVE_TIME, dayjs().valueOf().toString());
- }
- sessionStorage.setItem(START_LIVE_STATUS, "liveing");
- };
- /**
- * 关闭直播
- */
- export const closeLive = async (
- remove = false,
- source: "IM" | "Logout" = "Logout"
- ) => {
- // removeMedia(runtime.mediaStreams, runtime.mediaStreamTrack)
- try {
- if (source === "Logout") {
- await request.get("/api-web/imLiveBroadcastRoom/opsLiveVideo", {
- params: {
- type: "2",
- roomUid: runtime.roomUid,
- userId: state.user?.speakerId,
- },
- });
- }
- } catch {}
- sessionStorage.removeItem(START_LIVE_TIME);
- sessionStorage.removeItem(START_LIVE_STATUS);
- // 关闭房间仅移除推流即可
- for (const key in runtime.activeTracks) {
- if (Object.prototype.hasOwnProperty.call(runtime.activeTracks, key)) {
- const track = runtime.activeTracks[key as TrackType] as RTC.RCLocalTrack;
- if (track) {
- await runtime.joinedRoom?.unpublish([track]);
- if (remove) {
- await removeTrack([track], key as TrackType);
- }
- }
- }
- }
- runtime.videoStatus = "stream";
- };
- /**
- * 同步点赞数量
- */
- export const loopSyncLike = async () => {
- // (runtime.likeCount !== runtime.lastLikeCount || runtime.likeCount === 0) &&
- if (state.user && runtime.joinedRoom) {
- try {
- await request.get("/api-web/imLiveBroadcastRoom/syncLike", {
- hideLoading: true,
- hideMessage: true,
- params: {
- likeNum: runtime.likeCount,
- roomUid: runtime.roomUid,
- },
- });
- runtime.lastLikeCount = runtime.likeCount;
- sendMessage({ count: runtime.likeCount }, "LikeCount");
- } catch (error) {}
- }
- runtime.syncLikeTimer = setTimeout(() => {
- loopSyncLike();
- }, 1000 * 10);
- };
- type SendMessageType =
- | "text"
- | "image"
- | "audio"
- | "video"
- | "file"
- | "SeatsCtrl"
- | "ChatBan"
- | "SeatApply"
- | "SeatResponse"
- | "MemberCount"
- | "SeatMember"
- | "LikeCount"
- | "Welcome"
- | "PauseLive";
- export const getSendMessageUser = () => {
- return {
- id: String(state.user?.speakerId),
- name: state.user?.speakerName,
- userId: String(state.user?.speakerId),
- userName: state.user?.speakerName,
- };
- };
- /**
- *
- * @param msg 消息内容
- * @param type 消息类型
- * @returns null 或者 发送消息的结果
- */
- export const sendMessage = async (msg: any, type: SendMessageType = "text") => {
- let message: RongIMLib.BaseMessage<unknown> | null = null;
- if (!msg) return;
- const conversation = {
- conversationType: RongIMLib.ConversationType.CHATROOM,
- targetId: runtime.joinedRoom?.getRoomId() as string,
- };
- if (type === "text") {
- message = new RongIMLib.TextMessage({
- user: getSendMessageUser(),
- content: msg,
- });
- } else if (type === "SeatsCtrl") {
- message = new MessageSeatsCtrl(msg);
- } else if (type === "ChatBan") {
- message = new MessageChatBan(msg);
- } else if (type === "SeatApply") {
- message = new MessageSeatApply(msg);
- } else if (type === "SeatResponse") {
- message = new MessageSeatResponse(msg);
- } else if (type === "MemberCount") {
- message = new MessageMemberCount(msg);
- } else if (type === "SeatMember") {
- message = new MessageSeatMember(msg);
- } else if (type === "LikeCount") {
- message = new MessageLikeCount(msg);
- } else if (type === "Welcome") {
- message = new MessageWelcome(msg);
- } else if (type === "PauseLive") {
- message = new MessagePauseLive(msg);
- }
- if (!message) return;
- console.log(message);
- return await RongIMLib.sendMessage(conversation, message);
- };
- export const openDevice = async (trackType: TrackType, needPublish = true) => {
- if (
- (trackType === "microphone" || trackType === "microphone2") &&
- runtime.activeTracks[trackType]
- ) {
- runtime.activeTracks[trackType]?.unmute();
- } else {
- const track = await getTrack(trackType);
- await setTrack([track], trackType, needPublish);
- if (runtime.videoRef) {
- track?.play(runtime.videoRef);
- }
- }
- };
- export const closeDevice = async (trackType: TrackType, needPublish = true) => {
- const track = runtime.activeTracks[trackType];
- if (trackType !== "microphone" && trackType !== "microphone2") {
- // console.log('closeDevice', track)
- // track?.destroy()
- await removeTrack([track] as RTC.RCLocalTrack[], trackType, needPublish);
- } else {
- track?.mute();
- }
- };
- export const toggleDevice = async (trackType: TrackType) => {
- if (runtime.screenShareStatus) {
- await toggleShareScreenVideo();
- return;
- }
- const track = runtime.activeTracks[trackType];
- const needPublish = runtime.videoStatus === "liveing";
- if (track) {
- if (trackType === "camera") {
- runtime.deviceStatus.camera = "closed";
- }
- closeDevice(trackType, needPublish);
- } else {
- if (trackType === "camera") {
- runtime.deviceStatus.camera = "granted";
- }
- openDevice(trackType, needPublish);
- }
- };
- export const leaveIMRoom = async (source: "IM" | "Logout" = "Logout") => {
- await closeLive(true, source);
- if (runtime.joinedRoom) {
- // @ts-ignore
- await runtime.rtcClient?.leaveRoom(runtime.joinedRoom);
- runtime.joinedRoom = null;
- await RongIMLib.disconnect();
- runtime.imConnectStatus = "disconnect";
- }
- };
|