gemercheung 2 years ago
parent
commit
65a65935d0
6 changed files with 655 additions and 28 deletions
  1. 1 1
      src/App.vue
  2. 26 4
      src/components/chatRoom/camera.vue
  3. 64 13
      src/hooks/useAgora.ts
  4. 2 0
      src/hooks/useRoom.ts
  5. 59 10
      src/hooks/useTRTC.ts
  6. 503 0
      src/hooks/useTencent.ts

+ 1 - 1
src/App.vue

@@ -356,7 +356,7 @@
       {{ maxNumber }}
       {{ maxNumber }}
     </span> -->
     </span> -->
     <span>
     <span>
-      {{ t('base.debuginfo') }}:公告,测试1.2.0-0711-01,角色:{{ rtcStore.role }} rId:{{
+      {{ t('base.debuginfo') }}:公告,测试1.2.0-0807-01,角色:{{ rtcStore.role }} rId:{{
         rtcStore.roomId || browser.getURLParam('roomId')
         rtcStore.roomId || browser.getURLParam('roomId')
       }}
       }}
       sceneIndex:{{ currentSceneIndex }} uid::
       sceneIndex:{{ currentSceneIndex }} uid::

+ 26 - 4
src/components/chatRoom/camera.vue

@@ -1,7 +1,8 @@
 <template>
 <template>
   <div
   <div
     :id="cameraBoxId"
     :id="cameraBoxId"
-    class="camera_box"
+    class="camera_box flip camera_box_host"
+    @click.stop="handleSwitchCam"
     v-show="
     v-show="
       isLeader &&
       isLeader &&
       isRTCJoined &&
       isRTCJoined &&
@@ -17,8 +18,7 @@
       <i class="speak_mic_off" v-else></i>
       <i class="speak_mic_off" v-else></i>
     </span>
     </span>
   </div>
   </div>
-  <!-- :id="cameraRemoteBoxId" -->
-  <!-- muteVideoLeader:{{ muteVideoLeader }} -->
+
   <div
   <div
     id="cameraRemoteBox"
     id="cameraRemoteBox"
     class="camera_box"
     class="camera_box"
@@ -52,8 +52,30 @@
   const cameraBoxId = computed(() => 'camera_box_' + rtcStore.userId);
   const cameraBoxId = computed(() => 'camera_box_' + rtcStore.userId);
   // const cameraRemoteBoxId = computed(() => 'camera_remote_box_' + rtcStore.userId);
   // const cameraRemoteBoxId = computed(() => 'camera_remote_box_' + rtcStore.userId);
   const isPanoramaMode = computed(() => appStore.mode === 'panorama');
   const isPanoramaMode = computed(() => appStore.mode === 'panorama');
-  const { muteVideoLeader, globalVideoEnable } = useRtcSdk();
+  const {
+    muteVideoLeader: muteVideoLeaderSDK,
+    globalVideoEnable,
+    useCameraFront,
+    switchToBackCam,
+    switchToFrontCam,
+  } = useRtcSdk();
+  const muteVideoLeader = computed(() => muteVideoLeaderSDK.value);
   const hosterhasVideo = computed(() => rtcStore.isHasCamera);
   const hosterhasVideo = computed(() => rtcStore.isHasCamera);
+  const handleSwitchCam = () => {
+    if (hosterhasVideo.value) {
+      const host = document.querySelector('.camera_box_host');
+      if (host) {
+        host.classList.remove('animated');
+        host.classList.add('animated');
+        setTimeout(() => host.classList.remove('animated'), 1000);
+      }
+      if (useCameraFront.value) {
+        switchToBackCam();
+      } else {
+        switchToFrontCam();
+      }
+    }
+  };
 
 
   // const remoteStreams = computed(() => rtcStore.remoteStreams);
   // const remoteStreams = computed(() => rtcStore.remoteStreams);
   // console.log('hosterhasVideo', unref(hosterhasVideo));
   // console.log('hosterhasVideo', unref(hosterhasVideo));

+ 64 - 13
src/hooks/useAgora.ts

@@ -4,9 +4,16 @@ import { useRtcStore } from '/@/store/modules/rtc';
 export type AgoraClient = IAgoraRTCClient;
 export type AgoraClient = IAgoraRTCClient;
 export { ILocalAudioTrack, ILocalVideoTrack } from 'agora-rtc-sdk-ng';
 export { ILocalAudioTrack, ILocalVideoTrack } from 'agora-rtc-sdk-ng';
 import { useRtcSdk } from './useTRTC';
 import { useRtcSdk } from './useTRTC';
+import { ref } from 'vue';
 
 
 export let localAudioTrack: ILocalAudioTrack;
 export let localAudioTrack: ILocalAudioTrack;
 export let localVideoTrack: ILocalVideoTrack;
 export let localVideoTrack: ILocalVideoTrack;
+export let localClient: IAgoraRTCClient;
+
+const isHasCamera = ref(false);
+const isHasMicrophone = ref(false);
+const userID = ref('');
+
 export const createAgoraClient = async (
 export const createAgoraClient = async (
   sdkAppId: string,
   sdkAppId: string,
   roomId: string,
   roomId: string,
@@ -15,8 +22,15 @@ export const createAgoraClient = async (
 ): Promise<IAgoraRTCClient> => {
 ): Promise<IAgoraRTCClient> => {
   const rtcStore = useRtcStore();
   const rtcStore = useRtcStore();
   const { muteVideoLeader } = useRtcSdk();
   const { muteVideoLeader } = useRtcSdk();
+
+  const isOK = AgoraRTC.checkSystemRequirements();
+  if (!isOK) {
+    console.log('当前不支持');
+  }
   const client: IAgoraRTCClient = AgoraRTC.createClient({ mode: 'rtc', codec: 'vp9' });
   const client: IAgoraRTCClient = AgoraRTC.createClient({ mode: 'rtc', codec: 'vp9' });
+  localClient = client;
   const uid = await client.join(String(sdkAppId), roomId, sign, userId);
   const uid = await client.join(String(sdkAppId), roomId, sign, userId);
+  userID.value = userId;
   console.log('client', uid, client);
   console.log('client', uid, client);
 
 
   client.on('volume-indicator', function (result) {
   client.on('volume-indicator', function (result) {
@@ -59,28 +73,33 @@ export const createAgoraClient = async (
       user.audioTrack?.play();
       user.audioTrack?.play();
     }
     }
   });
   });
+  try {
+    isHasCamera.value = (await AgoraRTC.getCameras()).length > 0;
+    isHasMicrophone.value = (await AgoraRTC.getMicrophones()).length > 0;
+
+    isHasCamera.value && (localVideoTrack = await AgoraRTC.createCameraVideoTrack());
+    isHasMicrophone.value && (localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack());
+  } catch (error) {}
 
 
-  const isHasCamera = (await AgoraRTC.getCameras()).length > 0;
-  localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
-  localVideoTrack = await AgoraRTC.createCameraVideoTrack();
   const localVideoEl = document.getElementById(`camera_box_${userId}`);
   const localVideoEl = document.getElementById(`camera_box_${userId}`);
-  //
+  console.warn('isHasCamera', isHasCamera.value);
+  console.warn('isHasMicrophone', isHasMicrophone.value);
   if (rtcStore.role === 'leader') {
   if (rtcStore.role === 'leader') {
-    console.warn('isHasCamera', isHasCamera);
-
-    if (isHasCamera) {
+    if (isHasCamera.value) {
       rtcStore.setHasCamera();
       rtcStore.setHasCamera();
       if (localVideoEl) {
       if (localVideoEl) {
         localVideoTrack.play(localVideoEl);
         localVideoTrack.play(localVideoEl);
       }
       }
-      await client.publish([localAudioTrack, localVideoTrack]);
+
+      isHasCamera.value && (await client.publish(localVideoTrack));
+      isHasMicrophone.value && (await client.publish(localAudioTrack));
     } else {
     } else {
-      await client.publish([localAudioTrack]);
+      isHasMicrophone.value && (await client.publish([localAudioTrack]));
     }
     }
   } else {
   } else {
-    await client.publish([localAudioTrack]);
+    isHasMicrophone.value && (await client.publish([localAudioTrack]));
   }
   }
-  localAudioTrack.setMuted(true);
+  isHasMicrophone.value && localAudioTrack.setMuted(true);
   rtcStore.setIsRTCJoined(true);
   rtcStore.setIsRTCJoined(true);
   return client;
   return client;
 };
 };
@@ -95,10 +114,42 @@ export const unMuteVideo = () => {
 export const mutedAudio = () => {
 export const mutedAudio = () => {
   //通用禁音方法
   //通用禁音方法
   console.error('mutedAudio');
   console.error('mutedAudio');
-  localAudioTrack.setMuted(true);
+  if (isHasMicrophone.value) {
+    localAudioTrack.setMuted(true);
+    // localAudioTrack.stop();
+  }
 };
 };
 export const unMutedAudio = () => {
 export const unMutedAudio = () => {
   //通用开音方法
   //通用开音方法
   console.error('unMutedAudio');
   console.error('unMutedAudio');
-  localAudioTrack.setMuted(false);
+  if (isHasMicrophone.value) {
+    localAudioTrack.setMuted(false);
+    // localAudioTrack.play();
+  }
+};
+
+export const switchToFrontCam = async () => {
+  localVideoTrack.close();
+  localClient.unpublish(localVideoTrack);
+  localVideoTrack = await AgoraRTC.createCameraVideoTrack({
+    facingMode: 'user',
+  });
+  const localVideoEl = document.getElementById(`camera_box_${userID.value}`);
+  if (localVideoEl) {
+    localVideoTrack.play(localVideoEl);
+  }
+  await localClient.publish(localVideoTrack);
+};
+
+export const switchToBackCam = async () => {
+  // localStream.switchDevice('video', 'environment');
+  localClient.unpublish(localVideoTrack);
+  localVideoTrack = await AgoraRTC.createCameraVideoTrack({
+    facingMode: 'environment',
+  });
+  const localVideoEl = document.getElementById(`camera_box_${userID.value}`);
+  if (localVideoEl) {
+    localVideoTrack.play(localVideoEl);
+  }
+  await localClient.publish(localVideoTrack);
 };
 };

+ 2 - 0
src/hooks/useRoom.ts

@@ -176,6 +176,7 @@ export const getSign = async (
   userId: string,
   userId: string,
   channelName: string,
   channelName: string,
   roleId: string,
   roleId: string,
+  platform?: string,
 ): Promise<getSignType> => {
 ): Promise<getSignType> => {
   let role = 2;
   let role = 2;
   if (roleId === 'leader') {
   if (roleId === 'leader') {
@@ -186,6 +187,7 @@ export const getSign = async (
       userId,
       userId,
       roleId: role,
       roleId: role,
       channelName,
       channelName,
+      platform,
     },
     },
   });
   });
   return res.data.data;
   return res.data.data;

+ 59 - 10
src/hooks/useTRTC.ts

@@ -12,8 +12,18 @@ import {
   mutedAudio as argoraMutedAudio,
   mutedAudio as argoraMutedAudio,
   unMuteVideo as argoraUnMuteVideo,
   unMuteVideo as argoraUnMuteVideo,
   muteVideo as argoraMuteVideo,
   muteVideo as argoraMuteVideo,
+  switchToFrontCam as argoraSwitchToFrontCam,
+  switchToBackCam as argoraSwitchToBackCam,
 } from './useAgora';
 } from './useAgora';
-// import { useI18n } from './useI18n';
+import {
+  createRTCSocket as createTXRTCSocket,
+  unMutedAudio as txUnMutedAudio,
+  mutedAudio as txMutedAudio,
+  unMuteVideo as txUnMuteVideo,
+  muteVideo as txMuteVideo,
+  switchToFrontCam as txSwitchToFrontCam,
+  switchToBackCam as txSwitchToBackCam,
+} from './useTencent';
 import { useMiniApp } from './useMiniApp';
 import { useMiniApp } from './useMiniApp';
 import { useRoom } from './useRoom';
 import { useRoom } from './useRoom';
 
 
@@ -22,8 +32,11 @@ let localClient: Client | AgoraClient;
 const sdkType = ref(0);
 const sdkType = ref(0);
 
 
 // const muteAudioLeader = ref(false);
 // const muteAudioLeader = ref(false);
-const muteVideoLeader = ref(false);
+export const muteVideoLeader = ref(false);
+export const useCameraFront = ref(true);
+
 const { isUsingMiniApp } = useMiniApp();
 const { isUsingMiniApp } = useMiniApp();
+
 const globalVideoEnable = computed(
 const globalVideoEnable = computed(
   () => Number(import.meta.env.VITE_ENABLE_VIDEO) === 1 && !unref(isUsingMiniApp),
   () => Number(import.meta.env.VITE_ENABLE_VIDEO) === 1 && !unref(isUsingMiniApp),
 );
 );
@@ -33,13 +46,7 @@ const globalVideoEnable = computed(
 // const isInitRTC = computed(() => useRtcStore().isInitRTC);
 // const isInitRTC = computed(() => useRtcStore().isInitRTC);
 
 
 async function initRtcSDK(): Promise<void> {
 async function initRtcSDK(): Promise<void> {
-  // debugger;
   createRTCSocket();
   createRTCSocket();
-  // watchEffect(() => {
-  //   if (isInitRTC.value) {
-  //
-  //   }
-  // });
 }
 }
 
 
 async function createRTCSocket(): Promise<void> {
 async function createRTCSocket(): Promise<void> {
@@ -47,8 +54,7 @@ async function createRTCSocket(): Promise<void> {
     if (!unref(isUsingMiniApp)) {
     if (!unref(isUsingMiniApp)) {
       const { getSign } = useRoom();
       const { getSign } = useRoom();
       const rtcStore = useRtcStore();
       const rtcStore = useRtcStore();
-      // const res = await getSign(rtcStore.userId);
-      const res = await getSign(rtcStore.userId, rtcStore.roomId, rtcStore.role);
+      const res = await getSign(rtcStore.userId, rtcStore.roomId, rtcStore.role, 'fire');
       console.warn('web rtc入口', res);
       console.warn('web rtc入口', res);
       const { sign, operatorType, sdkAppId } = res;
       const { sign, operatorType, sdkAppId } = res;
       sdkType.value = Number(operatorType);
       sdkType.value = Number(operatorType);
@@ -60,6 +66,12 @@ async function createRTCSocket(): Promise<void> {
           rtcStore.userId,
           rtcStore.userId,
         );
         );
       } else if (operatorType === 0) {
       } else if (operatorType === 0) {
+        localClient = await createTXRTCSocket(
+          String(sdkAppId),
+          rtcStore.roomId,
+          sign,
+          rtcStore.userId,
+        );
         //腾讯云
         //腾讯云
       }
       }
     } else {
     } else {
@@ -75,12 +87,16 @@ async function createRTCSocket(): Promise<void> {
 const handleLeave = () => {
 const handleLeave = () => {
   //通用离开方法
   //通用离开方法
   localClient.leave();
   localClient.leave();
+  console.error('rtc-leave');
 };
 };
 const mutedAudio = () => {
 const mutedAudio = () => {
   //通用禁音方法
   //通用禁音方法
   if (sdkType.value === 1) {
   if (sdkType.value === 1) {
     argoraMutedAudio();
     argoraMutedAudio();
   }
   }
+  if (sdkType.value === 0) {
+    txMutedAudio();
+  }
   //通用离开方法
   //通用离开方法
 };
 };
 const unMutedAudio = () => {
 const unMutedAudio = () => {
@@ -88,12 +104,18 @@ const unMutedAudio = () => {
   if (sdkType.value === 1) {
   if (sdkType.value === 1) {
     argoraUnMutedAudio();
     argoraUnMutedAudio();
   }
   }
+  if (sdkType.value === 0) {
+    txUnMutedAudio();
+  }
 };
 };
 const muteVideo = () => {
 const muteVideo = () => {
   //通用开音方法
   //通用开音方法
   if (sdkType.value === 1) {
   if (sdkType.value === 1) {
     argoraMuteVideo();
     argoraMuteVideo();
   }
   }
+  if (sdkType.value === 0) {
+    txMuteVideo();
+  }
   muteVideoLeader.value = true;
   muteVideoLeader.value = true;
 };
 };
 const unMuteVideo = () => {
 const unMuteVideo = () => {
@@ -101,9 +123,33 @@ const unMuteVideo = () => {
   if (sdkType.value === 1) {
   if (sdkType.value === 1) {
     argoraUnMuteVideo();
     argoraUnMuteVideo();
   }
   }
+  if (sdkType.value === 0) {
+    txUnMuteVideo();
+  }
   muteVideoLeader.value = false;
   muteVideoLeader.value = false;
 };
 };
 
 
+const switchToFrontCam = () => {
+  //通用前置摄像方法
+  if (sdkType.value === 1) {
+    argoraSwitchToFrontCam();
+  }
+  if (sdkType.value === 0) {
+    txSwitchToFrontCam();
+  }
+  useCameraFront.value = true;
+};
+const switchToBackCam = () => {
+  //通用后置摄像方法
+  if (sdkType.value === 1) {
+    argoraSwitchToBackCam();
+  }
+  if (sdkType.value === 0) {
+    txSwitchToBackCam();
+  }
+  useCameraFront.value = false;
+};
+
 export function useRtcSdk() {
 export function useRtcSdk() {
   return {
   return {
     initRtcSDK,
     initRtcSDK,
@@ -113,6 +159,9 @@ export function useRtcSdk() {
     muteVideo,
     muteVideo,
     unMuteVideo,
     unMuteVideo,
     muteVideoLeader,
     muteVideoLeader,
+    switchToFrontCam,
+    switchToBackCam,
+    useCameraFront,
     client: localClient,
     client: localClient,
     globalVideoEnable,
     globalVideoEnable,
   };
   };

+ 503 - 0
src/hooks/useTencent.ts

@@ -0,0 +1,503 @@
+import consola from 'consola';
+import { computed, nextTick, ref, unref } from 'vue';
+import TRTC from 'trtc-js-sdk';
+
+import type { LocalStream, Client } from 'trtc-js-sdk';
+import { useMiniApp } from './useMiniApp';
+import { useRtcStore } from '/@/store/modules/rtc';
+// import Dialog from '/@/components/basic/dialog';
+import { useI18n } from './useI18n';
+import { muteVideoLeader } from './useTRTC';
+// import { useRoom } from './useRoom';
+
+let localClient: Client;
+let localStream: LocalStream;
+const isHasMicrophone = ref(false);
+const audioDeviceId = ref('');
+const videoDeviceId = ref('');
+
+// const invitedRemoteStreams = ref<RemoteStream[]>([]);
+const { isUsingMiniApp } = useMiniApp();
+const globalVideoEnable = computed(
+  () => Number(import.meta.env.VITE_ENABLE_VIDEO) === 1 && !unref(isUsingMiniApp),
+);
+export const checkDevice = async () => {
+  try {
+    const rtcStore = useRtcStore();
+    const microphoneItems = await TRTC.getMicrophones();
+    console.log('microphoneItems', microphoneItems);
+    if (microphoneItems.length > 0) {
+    }
+    microphoneItems.forEach((item) => {
+      item['value'] = item.deviceId;
+    });
+    if (microphoneItems?.length) {
+      isHasMicrophone.value = true;
+      audioDeviceId.value = microphoneItems[0].deviceId || microphoneItems[0].groupId || 'default';
+    }
+
+    const camerasItems = await TRTC.getCameras();
+    console.warn('camerasItems', camerasItems);
+    camerasItems.forEach((item) => {
+      item['value'] = item.deviceId;
+    });
+    if (camerasItems?.length) {
+      rtcStore.setHasCamera();
+      videoDeviceId.value = camerasItems[0].deviceId || camerasItems[0].groupId || 'default';
+    }
+  } catch (error) {
+    console.log('error', error);
+  }
+};
+
+const checkSystemRequirements = async () => {
+  const result = await TRTC.checkSystemRequirements();
+  console.log('result', result);
+  const isSmallStreamSupported = await TRTC.isSmallStreamSupported();
+  console.log('isSmallStreamSupported', isSmallStreamSupported);
+};
+
+// interface UseRtcSdkType {
+//     createRTCSocket: () => Promise<void>
+// }
+
+async function createLocalStream() {
+  try {
+    const rtcStore = useRtcStore();
+
+    const enableVideo = rtcStore.isLeader && rtcStore.isHasCamera && unref(globalVideoEnable);
+
+    console.warn('enableVideo', enableVideo, rtcStore.isHasCamera, unref(globalVideoEnable));
+    localStream = TRTC.createStream({
+      userId: rtcStore.userId,
+      audio: true,
+      video: enableVideo,
+      // cameraId: unref(videoDeviceId),
+      facingMode: 'user',
+      microphoneId: unref(audioDeviceId),
+    });
+    //开大小流
+    const isSmallStreamSupported = TRTC.isSmallStreamSupported();
+    if (isSmallStreamSupported) {
+      await localClient.enableSmallStream();
+      localClient.setSmallStreamProfile({
+        width: 160,
+        height: 90,
+        bitrate: 100,
+        frameRate: 15,
+      });
+    } else {
+      localStream.setVideoProfile('360p');
+    }
+    await localStream.initialize();
+    return Promise.resolve();
+
+    // if (rtcStore.audioMuted) {
+    //   localStream.muteAudio();
+    // }
+  } catch (error) {
+    console.log(error, 'createStream');
+    return Promise.reject(error);
+  }
+}
+
+export async function createRTCSocket(
+  sdkAppId: string,
+  roomId: string,
+  sign: string,
+  userId: string,
+): Promise<Client> {
+  try {
+    if (!unref(isUsingMiniApp)) {
+      console.warn('web rtc入口');
+      await checkSystemRequirements();
+      await checkDevice();
+      await handleJoin(Number(sdkAppId), roomId, sign, userId);
+      return Promise.resolve(localClient);
+    } else {
+      console.log('小程序关闭rtc入口');
+      return Promise.resolve(localClient);
+    }
+  } catch (error) {
+    consola.error({
+      tag: 'createRTCSocket',
+      message: error,
+    });
+    return Promise.resolve(localClient);
+  }
+}
+async function handleJoin(sdkAppId: number, roomId: string, sign: string, userId: string) {
+  const rtcStore = useRtcStore();
+  try {
+    localClient = TRTC.createClient({
+      mode: 'rtc',
+      sdkAppId: sdkAppId || parseInt(rtcStore.sdkAppId, 10),
+      userId: userId,
+      userSig: sign || rtcStore.genUserSig,
+      useStringRoomId: true,
+      enableAutoPlayDialog: false,
+    });
+    installEventHandlers();
+    await localClient.join({ roomId: roomId });
+    rtcStore.setIsRTCJoined(true);
+  } catch (error) {
+    console.error(error, 'error-----------');
+  }
+
+  await createLocalStream();
+  await handlePublish();
+  await nextTick();
+  //
+  // setTimeout(() => {
+  const playLocal = () => {
+    const playId = 'camera_box_' + rtcStore.userId;
+    localStream
+      .play(playId)
+      .then(() => {
+        consola.info({
+          message: '本地采集成功!',
+          tag: 'rtc:audio',
+        });
+      })
+      .catch((error) => {
+        consola.info({
+          message: '本地采集失败!' + error,
+          tag: 'rtc:audio',
+        });
+        setTimeout(() => {
+          console.log('再次播放');
+          playLocal();
+        }, 500);
+      });
+  };
+
+  playLocal();
+  // }, 1000);
+
+  // if (!rtcStore.isLeader) {
+  localStream.muteAudio();
+  console.log('参加者默认-muteAudio');
+  // }
+
+  localStream.on('error', (error) => {
+    if (error.getCode() === 0x4043) {
+      // 自动播放受限导致播放失败,此时引导用户点击页面。
+      // 在点击事件的回调函数中,执行 stream.resume();
+      const rtcStore = useRtcStore();
+      const { t } = useI18n();
+      rtcStore.showBaseDialog(
+        {
+          title: t('base.tips'),
+          desc: t('base.audioPermission'),
+          okTxt: t('base.confirm'),
+          closeTxt: t('base.cancel'),
+        },
+        () => {
+          localStream.resume();
+        },
+      );
+    }
+  });
+}
+
+async function handlePublish() {
+  const rtcStore = useRtcStore();
+  if (!rtcStore.isJoined) {
+    return;
+  }
+  if (rtcStore.isPublished) {
+    return;
+  }
+  // if (!rtcStore.isLeader) {
+  //   return;
+  // }
+  try {
+    await localClient.unpublish(localStream);
+    await localClient.publish(localStream);
+    rtcStore.setIsPublished(true);
+  } catch (error) {
+    console.error(error, '---------------handlePublish--------------------');
+  }
+}
+
+async function handleUnpublish() {
+  const rtcStore = useRtcStore();
+  if (!rtcStore.isJoined) {
+    return;
+  }
+  if (!rtcStore.isPublished) {
+    return;
+  }
+  try {
+    await localClient.unpublish(localStream);
+    // store.commit("rtc/setIsPublished", false);
+    rtcStore.setIsPublished(false);
+  } catch (error) {
+    console.error(error, '-----------handleUnpublish--------------');
+  }
+}
+
+export async function handleLeave() {
+  const rtcStore = useRtcStore();
+  if (rtcStore.isPublished) {
+    await handleUnpublish();
+  }
+  try {
+    uninstallEventHandlers();
+    localClient && (await localClient.leave());
+    localClient && localClient.destroy();
+    // invitedRemoteStreams.value.forEach((item) => {
+    //   item.stop();
+    // });
+    // invitedRemoteStreams.value = [];
+    // rtcStore.setVideoDeviceId('');
+    // rtcStore.setAudioDeviceId('');
+    // store.commit("rtc/setVideoDeviceId", "");
+    // store.commit("rtc/setAudioDeviceId", "");
+
+    if (localStream) {
+      localStream.stop();
+      localStream.close();
+      // localStream = null;
+      console.log('有执行到这里-------------');
+    }
+  } catch (error) {
+    console.error(error, '-----------handleLeave--------------');
+  }
+}
+
+function installEventHandlers() {
+  if (!localClient) {
+    return;
+  }
+  localClient.on('error', handleError);
+  localClient.on('client-banned', handleBanned);
+  localClient.on('peer-join', handlePeerJoin);
+  localClient.on('peer-leave', handlePeerLeave);
+  localClient.on('stream-added', handleStreamAdded);
+  localClient.on('stream-subscribed', handleStreamSubscribed);
+  localClient.on('stream-removed', handleStreamRemoved);
+  localClient.on('stream-updated', handleStreamUpdated);
+  localClient.on('mute-video', handleMuteVideo);
+  localClient.on('mute-audio', handleMuteAudio);
+  localClient.on('unmute-video', handleUnmuteVideo);
+  localClient.on('unmute-audio', handleUnmuteAudio);
+}
+
+function uninstallEventHandlers() {
+  if (!localClient) {
+    return;
+  }
+  localClient.off('error', handleError);
+  localClient.off('client-banned', handleBanned);
+  localClient.off('peer-join', handlePeerJoin);
+  localClient.off('peer-leave', handlePeerLeave);
+  localClient.off('stream-added', handleStreamAdded);
+  localClient.off('stream-subscribed', handleStreamSubscribed);
+  localClient.off('stream-removed', handleStreamRemoved);
+  localClient.off('stream-updated', handleStreamUpdated);
+  localClient.off('mute-video', handleMuteVideo);
+  localClient.off('mute-audio', handleMuteAudio);
+  localClient.off('unmute-video', handleUnmuteVideo);
+  localClient.off('unmute-audio', handleUnmuteAudio);
+}
+
+function handleMuteVideo(event) {
+  console.log(`[${event.userId}] mute video`);
+  const rtcStore = useRtcStore();
+  const roomLeader = rtcStore.getRoomLeader();
+  if (event.userId === roomLeader?.UserId) {
+    muteVideoLeader.value = true;
+  }
+}
+
+function handleMuteAudio(event) {
+  // if (event.userId.indexOf('leader') > -1) {
+  //   muteAudioLeader.value = true;
+  // }
+  console.log(event, `[] mute audio`);
+}
+
+function handleUnmuteVideo(event) {
+  console.log(`[${event.userId}] unmute video`);
+  const rtcStore = useRtcStore();
+  const roomLeader = rtcStore.getRoomLeader();
+  if (event.userId === roomLeader?.UserId) {
+    muteVideoLeader.value = false;
+  }
+}
+
+function handleUnmuteAudio(event) {
+  console.log(`[${event.userId}] unmute audio`);
+  // if (event.userId.indexOf('leader') > -1) {
+  //   muteAudioLeader.value = false;
+  // }
+}
+
+function handleError(error) {
+  console.log(`LocalClient error: ${error.message_}`);
+}
+
+function handleBanned(error) {
+  console.log(`Client has been banned for ${error.message_}`);
+}
+
+function handlePeerJoin(event) {
+  const { userId } = event;
+  if (userId !== 'local-screen') {
+    console.log(`Peer Client [${userId}] joined`);
+  }
+}
+
+function handlePeerLeave(event) {
+  const { userId } = event;
+  if (userId !== 'local-screen') {
+    console.log(`[${userId}] leave`);
+  }
+}
+
+function handleStreamAdded(event) {
+  const remoteStream = event.stream;
+  const id = remoteStream.getId();
+  const userId = remoteStream.getUserId();
+  const rtcStore = useRtcStore();
+
+  console.log(remoteStream, '-------------remoteStream');
+
+  if (remoteStream.getUserId() === rtcStore.userId) {
+    // don't need to screen shared by us
+    localClient.unsubscribe(remoteStream).catch((error) => {
+      console.info(`unsubscribe failed: ${error.message_}`);
+    });
+  } else {
+    console.log(`remote stream added: [${userId}] ID: ${id} type: ${remoteStream.getType()}`);
+    localClient.subscribe(remoteStream).catch((error) => {
+      console.info(`subscribe failed: ${error.message_}`);
+    });
+  }
+}
+
+async function handleStreamSubscribed(event) {
+  const remoteStream = event.stream;
+  const rtcStore = useRtcStore();
+  // const { t } = useI18n();
+  // debugger;
+  const remoteUserId = remoteStream.getUserId();
+  const remoteId = remoteStream.getId();
+  if (remoteUserId == rtcStore.userId) {
+    return;
+  }
+
+  if (!rtcStore.isIdInRemoteStream(remoteId)) {
+    consola.info({
+      message: remoteId,
+      tag: 'rtc:audio',
+    });
+    rtcStore.pushRemoteStreams(remoteStream);
+    // debugger
+  }
+  await nextTick();
+  const playRemote = () => {
+    // const playId = 'camera_remote_box_' + rtcStore.userId;
+    const playId = 'cameraRemoteBox';
+    remoteStream
+      .play(playId)
+      .then(() => {
+        consola.info({
+          message: '远端采集成功 !playId: ' + playId + ' remoteId:' + remoteId,
+          tag: 'rtc:audio',
+        });
+      })
+      .catch((error) => {
+        consola.info({
+          message: '远端采集失败!' + error,
+          tag: 'rtc:audio',
+        });
+        setTimeout(() => {
+          console.log('远端再次播放' + remoteId);
+          playRemote();
+        }, 500);
+      });
+  };
+  playRemote();
+  remoteStream.on('error', (error) => {
+    if (error.getCode() === 0x4043) {
+      // 自动播放受限导致播放失败,此时引导用户点击页面。
+      // 在点击事件的回调函数中,执行 stream.resume();
+      const rtcStore = useRtcStore();
+      const { t } = useI18n();
+      rtcStore.showBaseDialog(
+        {
+          title: t('base.tips'),
+          desc: t('base.audioPermission'),
+          okTxt: t('base.confirm'),
+          closeTxt: t('base.cancel'),
+        },
+        () => {
+          console.log('手机端', rtcStore.remoteStreams);
+          rtcStore.remoteStreams.forEach((item) => {
+            item.resume();
+          });
+          remoteStream.resume();
+        },
+      );
+    }
+  });
+}
+
+function handleStreamRemoved(event) {
+  const remoteStream = event.stream;
+  const userId = remoteStream.getUserId();
+  const remoteStreamId = remoteStream.getId();
+  consola.info({
+    message: `远端流删除: [${userId},${remoteStreamId}]`,
+    tag: 'rtc:audio',
+  });
+  const rtcStore = useRtcStore();
+  rtcStore.removeRemoteStreams(remoteStreamId);
+  const node = document.getElementById(`player_` + remoteStreamId);
+  consola.info({
+    message: `远端流删除:` + node,
+    tag: 'rtc:audio',
+  });
+  if (node) {
+    console.log('node', node);
+  }
+}
+
+function handleStreamUpdated(event) {
+  const remoteStream = event.stream;
+  const userId = remoteStream.getUserId();
+  console.log(
+    `RemoteStream updated: [${userId}] audio:${remoteStream.hasAudio()} video:${remoteStream.hasVideo()}`,
+  );
+}
+export const mutedAudio = () => {
+  //通用禁音方法
+  console.error('mutedAudio');
+  if (isHasMicrophone.value) {
+    localStream.muteAudio();
+  }
+};
+export const unMutedAudio = () => {
+  //通用开音方法
+  console.error('unMutedAudio');
+  if (isHasMicrophone.value) {
+    localStream.unmuteAudio();
+  }
+};
+export const muteVideo = () => {
+  //通用开音方法
+  localStream.muteVideo();
+};
+export const unMuteVideo = () => {
+  localStream.unmuteVideo();
+};
+
+export const switchToFrontCam = () => {
+  localStream.switchDevice('video', 'user');
+};
+
+export const switchToBackCam = () => {
+  localStream.switchDevice('video', 'environment');
+};