Browse Source

fix: video优化

shuisheng 1 năm trước cách đây
mục cha
commit
642ba4d133

+ 2 - 2
deploy/static-build.sh

@@ -6,7 +6,7 @@
 # Email: 2274751790@qq.com
 # FilePath: /billd-live/deploy/static-build.sh
 # Github: https://github.com/galaxy-s10
-# LastEditTime: 2024-02-20 11:51:28
+# LastEditTime: 2024-03-14 14:15:20
 # LastEditors: shuisheng
 ###
 
@@ -54,7 +54,7 @@ pnpm -v
 
 echo 设置pnpm淘宝镜像:
 pnpm config set registry https://registry.npmmirror.com/
-pnpm config set @billd:registry http://registry.hsslive.cn/
+pnpm config set @billd:registry https://registry.hsslive.cn/
 
 echo 查看当前pnpm镜像:
 pnpm config get registry

+ 28 - 0
src/components/SystemModal/index.vue

@@ -0,0 +1,28 @@
+<template>
+  <div>
+    <n-modal v-model:show="showModal">
+      <n-card
+        style="width: 500px"
+        title="提示"
+        role="dialog"
+        closable
+      >
+        <div>
+          欢迎进入直播间,遇到问题请提<a
+            href="https://github.com/galaxy-s10/billd-live/issues/new"
+            target="_blank"
+            >issue</a
+          >
+        </div>
+      </n-card>
+    </n-modal>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+const showModal = ref(true);
+</script>
+
+<style lang="scss" scoped></style>

+ 1 - 6
src/constant.ts

@@ -22,14 +22,9 @@ export const appBuildInfo =
 
 export const WEBSOCKET_URL =
   process.env.NODE_ENV === 'development'
-    ? `ws://192.168.1.102:4300` // `ws://localhost:4300`
+    ? `ws://localhost:4300` // `ws://localhost:4300`
     : `wss://srs-pull.${prodDomain}`;
 
-// export const WEBSOCKET_URL =
-//   process.env.NODE_ENV === 'development'
-//     ? `ws://localhost:4300` // `ws://localhost:4300`
-//     : `wss://srs-pull.${prodDomain}`;
-
 export const AXIOS_BASEURL =
   process.env.NODE_ENV === 'development'
     ? `/api`

+ 6 - 16
src/hooks/use-push.ts

@@ -12,6 +12,7 @@ import { useNetworkStore } from '@/store/network';
 import { useUserStore } from '@/store/user';
 import { ILiveRoom } from '@/types/ILiveRoom';
 import {
+  WsConnectStatusEnum,
   WsMessageType,
   WsMsgTypeEnum,
   WsMsrBlobType,
@@ -44,6 +45,7 @@ export function usePush() {
     initWs,
     handleStartLive,
     handleSendGetLiveUser,
+    connectStatus,
     mySocketId,
     canvasVideoStream,
     lastCoverImg,
@@ -75,22 +77,6 @@ export function usePush() {
     });
   }
 
-  watch(
-    () => appStore.allTrack,
-    (newTrack) => {
-      console.log('appStore.allTrack变了');
-      const mixedStream = new MediaStream();
-      newTrack.forEach((item) => {
-        if (item.track) {
-          mixedStream.addTrack(item.track);
-        }
-      });
-      console.log('新的allTrack音频轨', mixedStream.getAudioTracks());
-      console.log('新的allTrack视频轨', mixedStream.getVideoTracks());
-    },
-    { deep: true }
-  );
-
   watch(
     () => currentResolutionRatio.value,
     (newVal) => {
@@ -212,6 +198,10 @@ export function usePush() {
     if (!roomNameIsOk()) {
       return;
     }
+    if (connectStatus.value !== WsConnectStatusEnum.connect) {
+      window.$message.warning('websocket未连接');
+      return;
+    }
 
     roomLiving.value = true;
     const el = appStore.allTrack.find((item) => {

+ 2 - 1
src/hooks/use-websocket.ts

@@ -70,7 +70,7 @@ export const useWebsocket = () => {
   const { updateWebRtcMeetingOneConfig, webRtcMeetingOne } =
     useWebRtcMeetingOne();
 
-  const connectStatus = ref();
+  const connectStatus = ref<WsConnectStatusEnum>();
   const loopHeartbeatTimer = ref();
   const loopGetLiveUserTimer = ref();
   const liveUserList = ref<ILiveUser[]>([]);
@@ -825,6 +825,7 @@ export const useWebsocket = () => {
     initWs,
     handleStartLive,
     handleSendGetLiveUser,
+    connectStatus,
     mySocketId,
     canvasVideoStream,
     lastCoverImg,

+ 1 - 1
src/hooks/webrtc/srs.ts

@@ -37,7 +37,7 @@ export const useWebRtcSrs = () => {
         maxBitrate: currentMaxBitrate.value,
         maxFramerate: currentMaxFramerate.value,
         resolutionRatio: currentResolutionRatio.value,
-        isSRS: false,
+        isSRS: true,
         roomId: roomId.value,
         videoEl: data.videoEl,
         sender: data.sender,

+ 9 - 0
src/utils/index.ts

@@ -454,6 +454,15 @@ export const createVideo = ({
   videoEl.oncontextmenu = (e) => {
     e.preventDefault();
   };
+  setTimeout(() => {
+    if (autoplay) {
+      try {
+        videoEl.play();
+      } catch (error) {
+        console.log('play失败', error);
+      }
+    }
+  }, 0);
   if (appendChild) {
     if (!show) {
       videoEl.style.width = `1px`;

+ 30 - 26
src/utils/network/webRTC.ts

@@ -571,38 +571,42 @@ export class WebRTCClass {
       this.peerConnection = new RTCPeerConnection({
         iceServers,
       });
-      this.peerConnection.ondatachannel = (event) => {
-        this.cbDataChannel = event.channel;
-        this.update();
-      };
-      this.dataChannel = this.peerConnection.createDataChannel(
-        'MessageChannel',
-        {
-          // maxRetransmits,用户代理应尝试重新传输在不可靠模式下第一次失败的消息的最大次数。虽然该值是 16 位无符号数,但每个用户代理都可以将其限制为它认为合适的任何最大值。
-          maxRetransmits: 3,
-          // ordered,表示通过 RTCDataChannel 的信息的到达顺序需要和发送顺序一致 (true), 或者到达顺序不需要和发送顺序一致 (false). 默认:true
-          ordered: false,
-          protocol: 'udp',
-        }
-      );
-      this.dataChannel.onopen = () => {
-        this.prettierLog({
-          msg: 'dataChannel连接成功!',
-          type: 'success',
-        });
-      };
-      this.dataChannel.onerror = () => {
-        this.prettierLog({
-          msg: 'dataChannel连接失败!',
-          type: 'error',
-        });
-      };
+      if (!this.isSRS) {
+        this.handleDataChannel();
+      }
       this.handleStreamEvent();
       this.handleConnectionEvent();
       this.update();
     }
   };
 
+  handleDataChannel = () => {
+    if (!this.peerConnection) return;
+    this.peerConnection.ondatachannel = (event) => {
+      this.cbDataChannel = event.channel;
+      this.update();
+    };
+    this.dataChannel = this.peerConnection.createDataChannel('MessageChannel', {
+      // maxRetransmits,用户代理应尝试重新传输在不可靠模式下第一次失败的消息的最大次数。虽然该值是 16 位无符号数,但每个用户代理都可以将其限制为它认为合适的任何最大值。
+      maxRetransmits: 3,
+      // ordered,表示通过 RTCDataChannel 的信息的到达顺序需要和发送顺序一致 (true), 或者到达顺序不需要和发送顺序一致 (false). 默认:true
+      ordered: false,
+      protocol: 'udp',
+    });
+    this.dataChannel.onopen = () => {
+      this.prettierLog({
+        msg: 'dataChannel连接成功!',
+        type: 'success',
+      });
+    };
+    this.dataChannel.onerror = () => {
+      this.prettierLog({
+        msg: 'dataChannel连接失败!',
+        type: 'error',
+      });
+    };
+  };
+
   /** 手动关闭webrtc连接 */
   close = () => {
     try {

+ 1 - 0
src/views/home/index.vue

@@ -1,5 +1,6 @@
 <template>
   <div class="home-wrap">
+    <SystemModal></SystemModal>
     <div class="play-container">
       <div
         v-if="configBg && configBg !== ''"

+ 14 - 63
src/views/push/index.vue

@@ -545,6 +545,8 @@ watch(
     if (!newval) {
       handleEndLive();
       showNoLiveTipModalCpt.value = true;
+    } else {
+      uploadLivePreview();
     }
   }
 );
@@ -1074,7 +1076,6 @@ function handleStartLive() {
     window.$message.warning('至少选择一个素材');
     return;
   }
-  uploadLivePreview();
   initAudio();
   startLive({
     type: liveType,
@@ -1177,15 +1178,6 @@ function autoCreateVideo(data: {
             }
           }
         });
-        console.log(
-          '初始化',
-          ratio,
-          canvasDom.width,
-          canvasDom.height,
-          width * ratio,
-          height * ratio,
-          canvasDom
-        );
         handleMoving({ canvasDom, id });
         handleScaling({ canvasDom, id });
         canvasDom.scale(ratio / window.devicePixelRatio);
@@ -1380,13 +1372,6 @@ function handleMoving({
   id: string;
 }) {
   canvasDom.on('moving', () => {
-    console.log(
-      'moving',
-      canvasDom.width,
-      canvasDom.height,
-      canvasDom.scaleX,
-      canvasDom.scaleY
-    );
     appStore.allTrack.forEach((item) => {
       if (id === item.id) {
         item.rect = {
@@ -1435,50 +1420,20 @@ async function handleCache() {
     async function handleMediaVideo() {
       const { code, file } = await readFile(item.id);
       if (code === 1 && file) {
-        const { videoEl, stream } = await autoCreateVideo({
+        const { videoEl, stream, canvasDom } = await autoCreateVideo({
           file,
           id: obj.id,
-          muted: true,
+          muted: item.muted,
+          rect: item.rect,
         });
         if (obj.volume !== undefined) {
           videoEl.volume = obj.volume / 100;
         }
-        console.log('kkkkk', videoEl);
-        document.body.appendChild(videoEl);
-        // await new Promise((resolve) => {
-        //   videoEl.onloadedmetadata = () => {
-        //     const stream = videoEl
-        //       // @ts-ignore
-        //       .captureStream();
-        //     const width = stream.getVideoTracks()[0].getSettings().width!;
-        //     const height = stream.getVideoTracks()[0].getSettings().height!;
-        //     videoEl.width = width;
-        //     videoEl.height = height;
-
-        //     const canvasDom = markRaw(
-        //       new fabric.Image(videoEl, {
-        //         top: (item.rect?.top || 0) / window.devicePixelRatio,
-        //         left: (item.rect?.left || 0) / window.devicePixelRatio,
-        //         width,
-        //         height,
-        //       })
-        //     );
-        //     handleMoving({ canvasDom, id: item.id });
-        //     handleScaling({ canvasDom, id: item.id });
-        //     canvasDom.scale(
-        //       item.scaleInfo[window.devicePixelRatio].scaleX || 1
-        //     );
-        //     canvasDom.opacity = item.openEye ? 1 : 0;
-        //     fabricCanvas.value!.add(canvasDom);
-        //     obj.videoEl = videoEl;
-        //     obj.canvasDom = canvasDom;
-        //     resolve({ videoEl, canvasDom });
-        //   };
-        // });
-        // const stream = videoEl
-        //   // @ts-ignore
-        //   .captureStream() as MediaStream;
+        handleMoving({ canvasDom, id: obj.id });
+        handleScaling({ canvasDom, id: obj.id });
+        canvasDom.scale(item.scaleInfo[window.devicePixelRatio].scaleX);
         obj.videoEl = videoEl;
+        obj.canvasDom = canvasDom;
         obj.stream = stream;
         obj.streamid = stream.id;
         obj.track = stream.getVideoTracks()[0];
@@ -1635,6 +1590,7 @@ async function handleCache() {
         };
       });
     }
+
     if ([MediaTypeEnum.metting, MediaTypeEnum.pk].includes(obj.type)) {
       err.push(obj.id);
     }
@@ -1782,7 +1738,6 @@ async function addMediaOk(val: AppRootState['allTrack'][0]) {
     });
     setScaleInfo({ canvasDom, track: videoTrack, scale });
     videoTrack.videoEl = videoEl;
-    // @ts-ignore
     videoTrack.canvasDom = canvasDom;
 
     const audio = event.getAudioTracks();
@@ -1845,7 +1800,6 @@ async function addMediaOk(val: AppRootState['allTrack'][0]) {
     });
     setScaleInfo({ canvasDom, track: videoTrack, scale });
     videoTrack.videoEl = videoEl;
-    // @ts-ignore
     videoTrack.canvasDom = canvasDom;
 
     const res = [...appStore.allTrack, videoTrack];
@@ -1877,7 +1831,6 @@ async function addMediaOk(val: AppRootState['allTrack'][0]) {
     });
     setScaleInfo({ canvasDom, track: videoTrack, scale });
     videoTrack.videoEl = videoEl;
-    // @ts-ignore
     videoTrack.canvasDom = canvasDom;
 
     const res = [...appStore.allTrack, videoTrack];
@@ -1894,7 +1847,6 @@ async function addMediaOk(val: AppRootState['allTrack'][0]) {
     });
     setScaleInfo({ canvasDom, track: videoTrack, scale });
     videoTrack.videoEl = videoEl;
-    // @ts-ignore
     videoTrack.canvasDom = canvasDom;
 
     const res = [...appStore.allTrack, videoTrack];
@@ -2143,19 +2095,19 @@ async function addMediaOk(val: AppRootState['allTrack'][0]) {
       const file = val.mediaInfo[0].file!;
       const { code } = await saveFile({ file, fileName: mediaVideoTrack.id });
       if (code !== 1) return;
-      // const videoEl = createVideo({ muted: false, appendChild: false });
       const { videoEl, canvasDom, scale, stream } = await autoCreateVideo({
         file,
         id: mediaVideoTrack.id,
-        muted: false,
+        muted: mediaVideoTrack.muted,
       });
       setScaleInfo({ canvasDom, track: mediaVideoTrack, scale });
+      mediaVideoTrack.videoEl = videoEl;
+      mediaVideoTrack.canvasDom = canvasDom;
       mediaVideoTrack.stream = stream;
       mediaVideoTrack.streamid = stream.id;
       mediaVideoTrack.track = stream.getVideoTracks()[0];
       mediaVideoTrack.trackid = stream.getVideoTracks()[0].id;
-      mediaVideoTrack.videoEl = videoEl;
-      mediaVideoTrack.canvasDom = canvasDom;
+
       if (stream.getAudioTracks()[0]) {
         console.log('视频有音频', stream.getAudioTracks()[0]);
         mediaVideoTrack.audio = 1;
@@ -2302,7 +2254,6 @@ function handleActiveObject(item: AppRootState['allTrack'][0]) {
 }
 
 function handleDel(item: AppRootState['allTrack'][0]) {
-  console.log('iii', item);
   if (item.canvasDom !== undefined) {
     fabricCanvas.value?.remove(item.canvasDom);
   }