Kaynağa Gözat

feat: 优化

shuisheng 2 yıl önce
ebeveyn
işleme
228a8647db

+ 29 - 2
src/hooks/use-pull.ts

@@ -66,6 +66,31 @@ export function usePull(roomId: string) {
     remoteVideo.value = [];
   }
 
+  watch(
+    () => appStore.pkStream,
+    (newval) => {
+      console.log('pkStream变了', newval);
+      stopDrawingArr.value = [];
+      stopDrawingArr.value.forEach((cb) => cb());
+      console.log(
+        networkStore.getRtcMap(`${mySocketId.value}___${roomId}`)?.videoEl!
+      );
+      const { canvas, stopDrawing } = videoToCanvas({
+        videoEl: networkStore.getRtcMap(`${mySocketId.value}___${roomId}`)
+          ?.videoEl!,
+        resize: ({ w, h }) => {
+          videoHeight.value = `${w}x${h}`;
+        },
+      });
+      console.log(canvas);
+      document.body.appendChild(canvas);
+      stopDrawingArr.value.push(stopDrawing);
+      remoteVideo.value.push(canvas);
+      roomLiving.value = true;
+      videoLoading.value = false;
+    }
+  );
+
   watch(hlsVideoEl, () => {
     stopDrawingArr.value = [];
     stopDrawingArr.value.forEach((cb) => cb());
@@ -345,8 +370,10 @@ export function usePull(roomId: string) {
   }
 
   function closeWs() {
-    const instance = networkStore.wsMap.get(roomId);
-    instance?.close();
+    networkStore.wsMap.forEach((ws) => {
+      ws.close();
+      networkStore.removeWs(ws.roomId);
+    });
   }
 
   function closeRtc() {

+ 4 - 2
src/hooks/use-push.ts

@@ -60,8 +60,10 @@ export function usePush() {
   });
 
   function closeWs() {
-    const instance = networkStore.wsMap.get(roomId.value);
-    instance?.close();
+    networkStore.wsMap.forEach((ws) => {
+      ws.close();
+      networkStore.removeWs(ws.roomId);
+    });
   }
 
   function closeRtc() {

+ 90 - 27
src/hooks/use-websocket.ts

@@ -1,4 +1,5 @@
 import { getRandomString } from 'billd-utils';
+import { useDialog } from 'naive-ui';
 import { computed, onUnmounted, ref, watch } from 'vue';
 
 import { fetchRtcV1Publish } from '@/api/srs';
@@ -40,6 +41,8 @@ export const useWebsocket = () => {
   const appStore = useAppStore();
   const userStore = useUserStore();
   const networkStore = useNetworkStore();
+  const dialog = useDialog();
+
   const { maxBitrate, maxFramerate, resolutionRatio } = useRTCParams();
 
   const loopHeartbeatTimer = ref();
@@ -175,7 +178,7 @@ export const useWebsocket = () => {
         maxFramerate: currentMaxFramerate.value,
         resolutionRatio: currentResolutionRatio.value,
         isSRS: false,
-        roomId: `${roomId.value}`,
+        roomId: `${mySocketId.value}___${roomId.value}`,
         isAnchor,
         videoEl,
         sender,
@@ -226,6 +229,7 @@ export const useWebsocket = () => {
           requestId: getRandomString(8),
           msgType: WsMsgTypeEnum.nativeWebRtcOffer,
           data: {
+            live_room: appStore.liveRoomInfo!,
             live_room_id: Number(roomId.value),
             sender,
             receiver,
@@ -241,10 +245,12 @@ export const useWebsocket = () => {
      * 用户收到房主的offer,用户回复房主answer
      */
     sendAnswer: async ({
+      isPk,
       sdp,
       sender,
       receiver,
     }: {
+      isPk: boolean;
       sdp: RTCSessionDescriptionInit;
       sender: string;
       receiver: string;
@@ -259,17 +265,21 @@ export const useWebsocket = () => {
           receiver,
           videoEl: createVideo({ appendChild: true }),
         });
-        const stream = await handleUserMedia({ video: true, audio: true });
-        if (rtc?.peerConnection) {
-          rtc.peerConnection.onnegotiationneeded = (event) => {
-            console.log('onnegotiationneeded', event);
-          };
-          stream?.getTracks().forEach((track) => {
-            console.log(rtc, stream, track);
-            rtc.peerConnection?.addTrack(track, stream);
-          });
-        }
         await rtc.setRemoteDescription(sdp);
+        if (isPk) {
+          if (!isAnchor.value) {
+            const stream = await handleUserMedia({ video: true, audio: true });
+            if (rtc?.peerConnection) {
+              rtc.peerConnection.onnegotiationneeded = (event) => {
+                console.log('onnegotiationneeded', event);
+              };
+              stream?.getTracks().forEach((track) => {
+                console.log(rtc, stream, track);
+                rtc.peerConnection?.addTrack(track, stream);
+              });
+            }
+          }
+        }
         const answerSdp = await rtc.createAnswer();
         if (!answerSdp) {
           console.error('nativeWebRtc的answerSdp为空');
@@ -325,7 +335,11 @@ export const useWebsocket = () => {
         const ws = networkStore.wsMap.get(roomId.value);
         if (!ws) return;
         const rtc = srsWebRtc.newWebrtc({
-          roomId: `${isPk ? `pk-${roomId.value}` : `${roomId.value}`}`,
+          roomId: `${
+            isPk
+              ? `${mySocketId.value}___${roomId.value}___pk`
+              : `${mySocketId.value}___${roomId.value}`
+          }`,
           sender,
           videoEl: createVideo({ appendChild: true }),
         });
@@ -406,7 +420,7 @@ export const useWebsocket = () => {
             maxBitrate: currentMaxBitrate.value,
             maxFramerate: currentMaxFramerate.value,
             resolutionRatio: currentResolutionRatio.value,
-            roomId: `${roomId.value}`,
+            roomId: `${mySocketId.value}___${roomId.value}`,
             videoEl,
             isSRS: true,
             sender: data.sender,
@@ -441,7 +455,9 @@ export const useWebsocket = () => {
       console.log('收到srsAnswer', data);
       if (data.receiver === mySocketId.value) {
         console.warn('是发给我的srsAnswer');
-        const rtc = networkStore.getRtcMap(`${roomId.value}`)!;
+        const rtc = networkStore.getRtcMap(
+          `${mySocketId.value}___${roomId.value}`
+        )!;
         rtc.setRemoteDescription(data.sdp);
       } else {
         console.error('不是发给我的srsAnswer');
@@ -455,7 +471,9 @@ export const useWebsocket = () => {
         console.log('收到srsCandidate', data);
         if (data.receiver === mySocketId.value) {
           console.warn('是发给我的srsCandidate');
-          const rtc = networkStore.getRtcMap(`${roomId.value}`)!;
+          const rtc = networkStore.getRtcMap(
+            `${mySocketId.value}___${roomId.value}`
+          )!;
           rtc.addIceCandidate(data.candidate);
         } else {
           console.error('不是发给我的srsCandidate');
@@ -468,15 +486,55 @@ export const useWebsocket = () => {
       WsMsgTypeEnum.nativeWebRtcOffer,
       async (data: WsOfferType['data']) => {
         console.log('收到nativeWebRtcOffer', data);
-        if (data.receiver === mySocketId.value) {
-          console.warn('是发给我的nativeWebRtcOffer');
-          await nativeWebRtc.sendAnswer({
-            sender: data.sender,
-            receiver: data.receiver,
-            sdp: data.sdp,
-          });
+        console.log(data.live_room.type, LiveRoomTypeEnum.user_pk);
+        if (data.live_room.type === LiveRoomTypeEnum.user_pk) {
+          if (!isAnchor.value) {
+            dialog.warning({
+              title: '提示',
+              content: '是否加入PK',
+              positiveText: '确认',
+              onPositiveClick() {
+                return new Promise((resolve) => {
+                  resolve(1);
+                  if (data.receiver === mySocketId.value) {
+                    console.warn('是发给我的nativeWebRtcOffer');
+                    nativeWebRtc.sendAnswer({
+                      isPk: data.live_room.type === LiveRoomTypeEnum.user_pk,
+                      sender: data.sender,
+                      receiver: data.receiver,
+                      sdp: data.sdp,
+                    });
+                  } else {
+                    console.error('不是发给我的nativeWebRtcOffer');
+                  }
+                });
+              },
+            });
+          } else {
+            if (data.receiver === mySocketId.value) {
+              console.warn('是发给我的nativeWebRtcOffer');
+              nativeWebRtc.sendAnswer({
+                isPk: data.live_room.type === LiveRoomTypeEnum.user_pk,
+                sender: data.sender,
+                receiver: data.receiver,
+                sdp: data.sdp,
+              });
+            } else {
+              console.error('不是发给我的nativeWebRtcOffer');
+            }
+          }
         } else {
-          console.error('不是发给我的nativeWebRtcOffer');
+          if (data.receiver === mySocketId.value) {
+            console.warn('是发给我的nativeWebRtcOffer');
+            await nativeWebRtc.sendAnswer({
+              isPk: false,
+              sender: data.sender,
+              receiver: data.receiver,
+              sdp: data.sdp,
+            });
+          } else {
+            console.error('不是发给我的nativeWebRtcOffer');
+          }
         }
       }
     );
@@ -488,7 +546,9 @@ export const useWebsocket = () => {
         console.log('收到nativeWebRtcAnswer', data);
         if (data.receiver === mySocketId.value) {
           console.warn('是发给我的nativeWebRtcAnswer');
-          const rtc = networkStore.getRtcMap(`${roomId.value}`)!;
+          const rtc = networkStore.getRtcMap(
+            `${mySocketId.value}___${roomId.value}`
+          )!;
           await rtc.setRemoteDescription(data.sdp);
         } else {
           console.error('不是发给我的nativeWebRtcAnswer');
@@ -503,8 +563,10 @@ export const useWebsocket = () => {
         console.log('收到nativeWebRtcCandidate', data);
         if (data.receiver === mySocketId.value) {
           console.warn('是发给我的nativeWebRtcCandidate');
-          const rtc = networkStore.getRtcMap(`${roomId.value}`)!;
-          rtc.addIceCandidate(data.candidate);
+          const rtc = networkStore.getRtcMap(
+            `${mySocketId.value}___${roomId.value}`
+          )!;
+          rtc?.addIceCandidate(data.candidate);
         } else {
           console.error('不是发给我的nativeWebRtcCandidate');
         }
@@ -522,8 +584,9 @@ export const useWebsocket = () => {
         }
         isSRS.value = true;
         if (
+          data.live_room.type &&
           [LiveRoomTypeEnum.user_wertc, LiveRoomTypeEnum.user_pk].includes(
-            data.live_room.type!
+            data.live_room.type
           )
         ) {
           isSRS.value = false;

+ 1 - 0
src/interface-ws.ts

@@ -186,6 +186,7 @@ export type WsMsrBlobType = IWsFormat<{
 }>;
 
 export type WsOfferType = IWsFormat<{
+  live_room: ILiveRoom;
   sdp: any;
   sender: string;
   receiver: string;

+ 12 - 10
src/layout/pc/index.vue

@@ -1,14 +1,16 @@
 <template>
-  <div class="layout">
-    <div class="fixed-mask"></div>
-    <HeadCpt></HeadCpt>
-    <router-view v-slot="{ Component }">
-      <component :is="Component"></component>
-    </router-view>
-    <ModalCpt></ModalCpt>
-    <SidebarCpt v-if="MODULE_CONFIG_SWITCH.sidebar"></SidebarCpt>
-    <LoginModal v-if="appStore.showLoginModal"></LoginModal>
-  </div>
+  <n-dialog-provider>
+    <div class="layout">
+      <div class="fixed-mask"></div>
+      <HeadCpt></HeadCpt>
+      <router-view v-slot="{ Component }">
+        <component :is="Component"></component>
+      </router-view>
+      <ModalCpt></ModalCpt>
+      <SidebarCpt v-if="MODULE_CONFIG_SWITCH.sidebar"></SidebarCpt>
+      <LoginModal v-if="appStore.showLoginModal"></LoginModal>
+    </div>
+  </n-dialog-provider>
 </template>
 
 <script lang="ts" setup>

+ 1 - 1
src/network/webRTC.ts

@@ -402,7 +402,7 @@ export class WebRTCClass {
       if (event.candidate) {
         const networkStore = useNetworkStore();
         console.log('准备发送candidate', event.candidate.candidate);
-        const roomId = this.roomId;
+        const roomId = this.roomId.split('___')[1];
         console.log({
           roomId,
           sender: this.sender,

+ 3 - 0
src/store/network/index.ts

@@ -35,6 +35,9 @@ export const useNetworkStore = defineStore('network', {
     removeRtc(roomId: string) {
       this.rtcMap.delete(roomId);
     },
+    removeWs(roomId: string) {
+      this.wsMap.delete(roomId);
+    },
     getRtcMap(roomId: string) {
       return this.rtcMap.get(roomId);
     },

+ 45 - 3
src/views/pull/index.vue

@@ -57,7 +57,12 @@
             </div>
           </div>
         </div>
-        <div class="other">在线人数:{{ liveUserList.length }}</div>
+        <div
+          class="other"
+          @click="handlePk"
+        >
+          在线人数:{{ liveUserList.length }}
+        </div>
       </div>
       <div
         ref="containerRef"
@@ -346,7 +351,7 @@
 
 <script lang="ts" setup>
 import { getRandomString, openToTarget } from 'billd-utils';
-import { onMounted, onUnmounted, ref, watch } from 'vue';
+import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
 import { useRoute } from 'vue-router';
 
 import { fetchGoodsList } from '@/api/goods';
@@ -429,11 +434,48 @@ onUnmounted(() => {
   closeRtc();
 });
 
+async function handleUserMedia({ video, audio }) {
+  try {
+    const event = await navigator.mediaDevices.getUserMedia({
+      video,
+      audio,
+    });
+    return event;
+  } catch (error) {
+    console.log(error);
+  }
+}
+
+async function handlePk() {
+  const stream = await handleUserMedia({ video: true, audio: true });
+  const rtc = networkStore.getRtcMap(`${roomId.value}`)!;
+  if (rtc?.peerConnection) {
+    rtc.peerConnection.onnegotiationneeded = (event) => {
+      console.log('onnegotiationneeded', event);
+    };
+    stream?.getTracks().forEach((track) => {
+      console.log(rtc, stream, track);
+      rtc.peerConnection?.addTrack(track, stream);
+    });
+  }
+}
+
 watch(
   () => remoteVideo.value,
   (newVal) => {
     newVal.forEach((item) => {
-      remoteVideoRef.value?.appendChild(item);
+      console.log(
+        'kkkkk',
+        remoteVideoRef.value,
+        roomLiving.value,
+        videoLoading.value,
+        item
+      );
+      nextTick(() => {
+        setTimeout(() => {
+          remoteVideoRef.value?.appendChild(item);
+        }, 500);
+      });
     });
   },
   {

+ 26 - 17
src/views/push/index.vue

@@ -517,6 +517,7 @@ function handleScrollTop() {
 
 function handleSendBlob(event: BlobEvent) {
   bolbId.value += 1;
+  console.log(event.data);
   sendBlob({
     blob: event.data,
     blobId: `${bolbId.value}`,
@@ -2079,29 +2080,37 @@ function handleStartMedia(item: { type: MediaTypeEnum; txt: string }) {
       .title {
         text-align: initial;
       }
-      .item {
-        display: flex;
-        align-items: center;
-        justify-content: space-between;
-        margin: 5px 0;
-        font-size: 14px;
-        // &:hover {
-        //   .control {
-        //     display: flex;
-        //     align-items: center;
-        //   }
-        // }
-        .control {
+      .list {
+        overflow: scroll;
+        height: 218px;
+
+        @extend %customScrollbar;
+
+        .item {
           display: flex;
           align-items: center;
-          .control-item {
-            cursor: pointer;
-            &:not(:last-child) {
-              margin-right: 6px;
+          justify-content: space-between;
+          margin: 5px 0;
+          font-size: 14px;
+          // &:hover {
+          //   .control {
+          //     display: flex;
+          //     align-items: center;
+          //   }
+          // }
+          .control {
+            display: flex;
+            align-items: center;
+            .control-item {
+              cursor: pointer;
+              &:not(:last-child) {
+                margin-right: 6px;
+              }
             }
           }
         }
       }
+
       .bottom {
         position: absolute;
         bottom: 0;