Browse Source

增加视频流

gemercheung 2 years ago
parent
commit
2ac0e648c6

+ 2 - 2
index.html

@@ -25,8 +25,8 @@
   <body>
     <div id="app"></div>
     <script type="module" src="/src/main.ts"></script>
-    <script src="<{VITE_APP_SDK_DIR}>/kankan-sdk-deps.js?v=4.4.2-alpha.5"></script>
-    <script src="<{VITE_APP_SDK_DIR}>/kankan-sdk.js?v=4.4.2-alpha.5"></script>
+    <script src="<{VITE_APP_SDK_DIR}>/kankan-sdk-deps.js?v=4.4.3-alpha.4"></script>
+    <script src="<{VITE_APP_SDK_DIR}>/kankan-sdk.js?v=4.4.3-alpha.4"></script>
     <script src="<{BASE_URL}><{VITE_APP_STATIC_DIR}>/static/lib/flv.min.js"></script>
     <script src="<{BASE_URL}><{VITE_APP_STATIC_DIR}>/static/lib/vconsole.js"></script>
     <script src="<{BASE_URL}><{VITE_APP_STATIC_DIR}>/static/lib/swiper/swiper-bundle.min.js"></script>

+ 21 - 1
src/components/chatRoom/camera.vue

@@ -1,5 +1,5 @@
 <template>
-  <teleport to=".local" v-if="isPublished && isLeader">
+  <teleport to=".local" v-if="(isRTCJoined || isPublished) && isLeader">
     <div class="micBox">
       <i class="speak_mic" v-if="!roomLeader?.IsMuted"></i>
       <i class="speak_mic_off" v-else></i>
@@ -14,7 +14,9 @@
 </template>
 <script lang="ts" setup>
   //   import { ref } from 'vue';
+
   import { computed, onMounted } from 'vue';
+  // import { useRtcSdk } from '/@/hooks/useTRTC';
   // import { useSocket } from '/@/hooks/userSocket';
 
   //   import { useRtcSdk } from '/@/hooks/useTRTC';
@@ -23,13 +25,28 @@
   const rtcStore = useRtcStore();
   // const destination = computed(() => (rtcStore.isLeader ? '.local' : '.remote'));
   const isPublished = computed(() => rtcStore.isPublished);
+  const isRTCJoined = computed(() => rtcStore.isRTCJoined);
   const isLeader = computed(() => rtcStore.isLeader);
   const remoteStreams = computed(() => rtcStore.remoteStreams);
   const roomLeader = computed(() => rtcStore.getRoomLeader());
+  // const { muteVideoLeader } = useRtcSdk();
   // const hasVideo = computed(() => rtcStore.videoDeviceId.length > 0);
   onMounted(() => {});
 </script>
 <style lang="scss">
+  #PageRtcLive {
+    &.customer + div.local {
+      display: none;
+    }
+  }
+  #PageRtcLive {
+    &.hideCam + div.local {
+      display: none;
+      + div.remote {
+        display: none;
+      }
+    }
+  }
   .local,
   .remote {
     width: 1.94rem;
@@ -40,6 +57,9 @@
     overflow: hidden;
     z-index: 10000;
     border-radius: 50%;
+    video {
+      background: transparent;
+    }
     .micBox {
       width: 100%;
       height: 0.44rem;

+ 10 - 10
src/components/chatRoom/controls/join.ts

@@ -1,5 +1,5 @@
 import consolaGlobalInstance from 'consola';
-import sortBy from 'lodash-es/sortBy';
+// import sortBy from 'lodash-es/sortBy';
 import { unref } from 'vue';
 import { useI18n } from '/@/hooks/useI18n';
 // import { unref } from 'vue';
@@ -87,12 +87,12 @@ export function handleJoin(data: any) {
   }, 1500);
 }
 
-const banLaterEnterer = (members: UserInfoType[], user: UserInfoType) => {
-  if (members && user) {
-    console.log('banLaterEnterer', members);
-    const sameIDsArray = members.some((item) => item.UserId === user.UserId);
-    const sortList = sortBy(sameIDsArray, ['InTime'], ['asc']);
-    console.log('banLaterEnterer', sortList);
-    // const beforeUSer =
-  }
-};
+// const banLaterEnterer = (members: UserInfoType[], user: UserInfoType) => {
+//   if (members && user) {
+//     console.log('banLaterEnterer', members);
+//     const sameIDsArray = members.some((item) => item.UserId === user.UserId);
+//     const sortList = sortBy(sameIDsArray, ['InTime'], ['asc']);
+//     console.log('banLaterEnterer', sortList);
+//     // const beforeUSer =
+//   }
+// };

+ 58 - 11
src/components/chatRoom/index.vue

@@ -1,6 +1,9 @@
 <template>
   <!-- 主区域 start  -->
-  <div id="PageRtcLive">
+  <div
+    id="PageRtcLive"
+    :class="{ [role]: true, showCam: !muteVideoLeader, hideCam: muteVideoLeader }"
+  >
     <chat v-show="chatShow && isPanoramaMode" :chatList="chatList" :currentUser="currentUser" />
     <!-- 当前人数 start -->
     <div class="member_number" v-if="isPanoramaMode">
@@ -62,6 +65,14 @@
         <div style="font-size: 0.65rem" v-if="isNativeLeader && sceneList.length > 1">
           <ImageIcon type="scene" @click="showScenes = !showScenes" />
         </div>
+
+        <div style="font-size: 0.65rem" v-if="isNativeLeader">
+          <template v-if="hosterhasVideo">
+            <ImageIcon type="video_on" v-if="!muteVideoLeader" @click="handleHideCamera" />
+            <ImageIcon type="video_off" v-if="muteVideoLeader" @click="handleShowCamera" />
+          </template>
+          <ImageIcon type="video_disable" v-else />
+        </div>
         <div class="exit" @click="showCloseDialog = true"></div>
       </div>
     </div>
@@ -200,6 +211,8 @@
   const selfRoomStatus = computed(() => rtcStore.getSelfRoomStatus());
   const audioMuted = computed(() => unref(selfRoomStatus)?.IsMuted);
 
+  const hosterhasVideo = computed(() => rtcStore.videoDeviceId?.length > 0);
+  const { muteVideoLeader } = useRtcSdk();
   let roomCounter = ref(-1);
   let roomCount: NodeJS.Timeout;
   const { t } = useI18n();
@@ -291,17 +304,25 @@
     watch(
       () => [isJoined, isNativeLeader],
       async (val) => {
-        console.log('初始化同屏', unref(val[0]), unref(val[1]));
-        if (unref(val[0])) {
-          const app = await useApp();
-          if (unref(isNativeLeader)) {
-            app.Connect.follow.start({ follow: false });
-          } else {
-            console.log('customer-follow');
-            app.Connect.follow.start({ follow: true });
+        try {
+          console.log('初始化同屏', unref(val[0]), unref(val[1]));
+          if (unref(val[0])) {
+            const app = await useApp();
+            if (unref(isNativeLeader)) {
+              setTimeout(() => {
+                app.Connect.follow.start({ follow: false });
+              }, 1000);
+            } else {
+              console.log('customer-follow');
+              setTimeout(() => {
+                app.Connect.follow.start({ follow: true });
+              }, 1000);
+            }
+            app.Connect.follow.on('data', leaderSync);
+            app.Connect.paint.on('data', leaderPaint);
           }
-          app.Connect.follow.on('data', leaderSync);
-          app.Connect.paint.on('data', leaderPaint);
+        } catch (error) {
+          console.log('error', error);
         }
       },
       {
@@ -474,6 +495,32 @@
     });
     changeScene(unref(scene));
   };
+  const handleHideCamera = () => {
+    const { localStream, muteVideoLeader } = useRtcSdk();
+    const { socket } = useSocket();
+    muteVideoLeader.value = true;
+    socket.emit('action', {
+      type: 'sync-camera',
+      data: {
+        show: false,
+        userId: rtcStore.userId,
+      },
+    });
+    localStream.muteVideo();
+  };
+  const handleShowCamera = () => {
+    const { localStream, muteVideoLeader } = useRtcSdk();
+    const { socket } = useSocket();
+    socket.emit('action', {
+      type: 'sync-camera',
+      data: {
+        show: true,
+        userId: rtcStore.userId,
+      },
+    });
+    muteVideoLeader.value = false;
+    localStream.unmuteVideo();
+  };
 </script>
 
 <style scoped lang="scss">

+ 108 - 39
src/hooks/useTRTC.ts

@@ -21,18 +21,20 @@ export const checkDevice = async () => {
       item['value'] = item.deviceId;
     });
     if (microphoneItems?.length) {
-      rtcStore.setAudioDeviceId(microphoneItems[0].deviceId);
+      rtcStore.setAudioDeviceId(
+        microphoneItems[0].deviceId || microphoneItems[0].groupId || 'default',
+      );
     } else {
       rtcStore.setAudioDeviceId('');
     }
 
     const camerasItems = await TRTC.getCameras();
-
+    console.log('camerasItems', camerasItems);
     camerasItems.forEach((item) => {
       item['value'] = item.deviceId;
     });
     if (camerasItems?.length) {
-      rtcStore.setVideoDeviceId(camerasItems[0].deviceId || camerasItems[0].groupId);
+      rtcStore.setVideoDeviceId(camerasItems[0].deviceId || camerasItems[0].groupId || 'default');
     } else {
       rtcStore.setVideoDeviceId('');
     }
@@ -46,9 +48,6 @@ const checkSystemRequirements = async () => {
   console.log('result', result);
   const isSmallStreamSupported = await TRTC.isSmallStreamSupported();
   console.log('isSmallStreamSupported', isSmallStreamSupported);
-  // if (!isSmallStreamSupported) {
-  //   alert('You browser does not support opening small streams.');
-  // }
 };
 
 // interface UseRtcSdkType {
@@ -58,29 +57,39 @@ const checkSystemRequirements = async () => {
 async function createLocalStream() {
   try {
     const rtcStore = useRtcStore();
-    const enableVideo = rtcStore.isLeader && rtcStore.videoDeviceId.length > 0;
+    const enableVideo = rtcStore.isLeader && rtcStore.videoDeviceId?.length > 0;
+    console.warn('enableVideo', enableVideo);
     localStream = TRTC.createStream({
       userId: rtcStore.userId,
       audio: true,
       video: enableVideo,
+      cameraId: rtcStore.videoDeviceId,
       microphoneId: rtcStore.audioDeviceId,
     });
     //开大小流
-    await localClient.enableSmallStream();
-    localClient.setSmallStreamProfile({
-      width: 160,
-      height: 90,
-      bitrate: 100,
-      frameRate: 15,
-    });
+    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);
   }
 }
 
@@ -119,18 +128,32 @@ async function handleJoin() {
 
   await createLocalStream();
   await handlePublish();
-  await localStream
-    .play('local')
-    .then(() => {
-      consola.info({
-        message: '音采源',
-        tag: 'rtc:audio',
+  //
+  // setTimeout(() => {
+  const playLocal = () => {
+    localStream
+      .play('local')
+      .then(() => {
+        consola.info({
+          message: '本地采集成功!',
+          tag: 'rtc:audio',
+        });
+        rtcStore.setIsRTCJoined(true);
+      })
+      .catch((error) => {
+        consola.info({
+          message: '本地采集失败!' + error,
+          tag: 'rtc:audio',
+        });
+        setTimeout(() => {
+          console.log('再次播放');
+          playLocal();
+        }, 500);
       });
-    })
-    .catch((error) => {
-      console.log('play-local-error', error);
-    });
-  rtcStore.setIsRTCJoined(true);
+  };
+
+  playLocal();
+  // }, 1000);
 
   localStream.on('error', (error) => {
     if (error.getCode() === 0x4043) {
@@ -278,7 +301,9 @@ function uninstallEventHandlers() {
 
 function handleMuteVideo(event) {
   console.log(`[${event.userId}] mute video`);
-  if (event.userId.indexOf('leader') > -1) {
+  const rtcStore = useRtcStore();
+  const roomLeader = rtcStore.getRoomLeader();
+  if (event.userId === roomLeader?.UserId) {
     muteVideoLeader.value = true;
   }
 }
@@ -292,7 +317,9 @@ function handleMuteAudio(event) {
 
 function handleUnmuteVideo(event) {
   console.log(`[${event.userId}] unmute video`);
-  if (event.userId.indexOf('leader') > -1) {
+  const rtcStore = useRtcStore();
+  const roomLeader = rtcStore.getRoomLeader();
+  if (event.userId === roomLeader?.UserId) {
     muteVideoLeader.value = false;
   }
 }
@@ -367,19 +394,60 @@ async function handleStreamSubscribed(event) {
     // debugger
   }
   await nextTick();
-  setTimeout(async () => {
-    try {
-      consola.info({
-        message: '客音源-->' + remoteId,
-        tag: 'rtc:audio',
-      });
-      consola.info({
-        message: rtcStore.remoteStreams,
-        tag: 'rtc:audio',
+  const playRemote = () => {
+    remoteStream
+      .play(remoteId)
+      .then(() => {
+        consola.info({
+          message: '远端采集成功!' + remoteId,
+          tag: 'rtc:audio',
+        });
+      })
+      .catch((error) => {
+        consola.info({
+          message: '远端采集失败!' + error,
+          tag: 'rtc:audio',
+        });
+        setTimeout(() => {
+          console.log('远端再次播放' + remoteId);
+          playRemote();
+        }, 500);
       });
-      await remoteStream.play(remoteId);
-    } catch (error) { }
-  }, 200);
+  };
+  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'),
+        },
+        () => {
+          remoteStream.resume();
+        },
+      );
+    }
+  });
+
+  // setTimeout(async () => {
+  //   try {
+  //     consola.info({
+  //       message: '客音源-->' + remoteId,
+  //       tag: 'rtc:audio',
+  //     });
+  //     consola.info({
+  //       message: rtcStore.remoteStreams,
+  //       tag: 'rtc:audio',
+  //     });
+  //     await remoteStream.play(remoteId);
+  //   } catch (error) {}
+  // }, 200);
 }
 
 function handleStreamRemoved(event) {
@@ -425,6 +493,7 @@ export function useRtcSdk() {
     handleJoin,
     handleLeave,
     localStream,
+    muteVideoLeader,
     invitedRemoteStreams,
     client: localClient,
   };