瀏覽代碼

feat: 优化

shuisheng 2 年之前
父節點
當前提交
020a820b9e

+ 1 - 19
src/components/QrPay/index.vue

@@ -52,6 +52,7 @@ import { onMounted, onUnmounted, ref } from 'vue';
 
 import { fetchAliPay, fetchAliPayStatus } from '@/api/order';
 import { PayStatusEnum } from '@/interface';
+import { formatDownTime } from '@/utils';
 
 const payOk = ref(false);
 const aliPayBase64 = ref('');
@@ -80,25 +81,6 @@ onMounted(() => {
   });
 });
 
-function formatDownTime(endTime: number, startTime: number) {
-  const times = (endTime - startTime) / 1000;
-  // js获取剩余天数
-  const d = parseInt(String(times / 60 / 60 / 24));
-  // js获取剩余小时
-  const h = parseInt(String((times / 60 / 60) % 24));
-  // js获取剩余分钟
-  const m = parseInt(String((times / 60) % 60));
-  // js获取剩余秒
-  const s = parseInt(String(times % 60));
-  if (d > 0) {
-    return `${d}天${h}时`;
-  } else if (h > 0) {
-    return `${h}时${m}分`;
-  } else {
-    return `${m}分${s}秒`;
-  }
-}
-
 async function generateQR(text) {
   let base64 = '';
   try {

+ 28 - 18
src/hooks/use-pull.ts

@@ -1,5 +1,5 @@
 import mpegts from 'mpegts.js';
-import { Ref, nextTick, onUnmounted, ref, watch } from 'vue';
+import { Ref, onUnmounted, ref, watch } from 'vue';
 import { useRoute } from 'vue-router';
 
 import { useFlvPlay, useHlsPlay } from '@/hooks/use-play';
@@ -12,12 +12,10 @@ import { useUserStore } from '@/store/user';
 import { createVideo, videoToCanvas } from '@/utils';
 
 export function usePull({
-  localVideoRef,
-  isSRS,
+  remoteVideoRef,
   liveType,
 }: {
-  localVideoRef: Ref<HTMLVideoElement[]>;
-  isSRS: boolean;
+  remoteVideoRef: Ref<HTMLDivElement>;
   liveType: liveTypeEnum;
 }) {
   const route = useRoute();
@@ -26,6 +24,7 @@ export function usePull({
   const appStore = useAppStore();
   const roomId = ref(route.params.roomId as string);
   const roomLiveType = ref<liveTypeEnum>(liveType);
+  const localStream = ref<MediaStream>();
   const danmuStr = ref('');
   const autoplayVal = ref(false);
   const videoLoading = ref(false);
@@ -39,16 +38,17 @@ export function usePull({
   const videoElArr = ref<HTMLVideoElement[]>([]);
   const remoteVideo = ref<HTMLElement[]>([]);
   const {
+    isPull,
     mySocketId,
     initSrsWs,
+    handleStartLive,
     roomLiving,
     liveRoomInfo,
     anchorInfo,
-    localStream,
     liveUserList,
     damuList,
   } = useSrsWs();
-
+  isPull.value = true;
   const { flvPlayer, flvVideoEl, startFlvPlay } = useFlvPlay();
   const { hlsVideoEl, startHlsPlay } = useHlsPlay();
   const stopDrawingArr = ref<any[]>([]);
@@ -100,6 +100,7 @@ export function usePull({
   }
 
   async function handlePlay() {
+    console.warn('handlePlay');
     if (roomLiveType.value === liveTypeEnum.srsFlvPull) {
       if (!autoplayVal.value) return;
       await handleFlvPlay();
@@ -123,9 +124,18 @@ export function usePull({
     () => roomLiving.value,
     (val) => {
       if (val) {
-        flvurl.value = liveRoomInfo.value?.flv_url!;
-        hlsurl.value = liveRoomInfo.value?.hls_url!;
-        handlePlay();
+        console.log(roomLiveType.value, '32323312');
+        if (roomLiveType.value === liveTypeEnum.webrtcPull) {
+          // handleStartLive({
+          //   type: LiveRoomTypeEnum.user_wertc,
+          //   receiver: '',
+          //   videoEl: document.createElement('video'),
+          // });
+        } else {
+          flvurl.value = liveRoomInfo.value?.flv_url!;
+          hlsurl.value = liveRoomInfo.value?.hls_url!;
+          handlePlay();
+        }
       }
     }
   );
@@ -236,14 +246,14 @@ export function usePull({
 
   function addVideo() {
     sidebarList.value.push({ socketId: mySocketId.value });
-    nextTick(() => {
-      liveUserList.value.forEach((item) => {
-        const socketId = item.id;
-        if (socketId === mySocketId.value) {
-          localVideoRef.value[mySocketId.value].srcObject = localStream.value;
-        }
-      });
-    });
+    // nextTick(() => {
+    //   liveUserList.value.forEach((item) => {
+    //     const socketId = item.id;
+    //     if (socketId === mySocketId.value) {
+    //       remoteVideoRef.value[mySocketId.value].srcObject = localStream.value;
+    //     }
+    //   });
+    // });
   }
 
   function keydownDanmu(event: KeyboardEvent) {

+ 155 - 7
src/hooks/use-push.ts

@@ -8,7 +8,7 @@ import {
 } from '@/api/userLiveRoom';
 import { DanmuMsgTypeEnum, ILiveRoom, IMessage } from '@/interface';
 import { WsMsgTypeEnum } from '@/network/webSocket';
-import { useAppStore } from '@/store/app';
+import { AppRootState, useAppStore } from '@/store/app';
 import { useNetworkStore } from '@/store/network';
 import { useUserStore } from '@/store/user';
 import { createVideo, generateBase64 } from '@/utils';
@@ -29,23 +29,117 @@ export function usePush() {
   const danmuStr = ref('');
   const isLiving = ref(false);
   const liveRoomInfo = ref<ILiveRoom>();
+  const localStream = ref<MediaStream>();
   const videoElArr = ref<HTMLVideoElement[]>([]);
 
   const {
+    isPull,
     initSrsWs,
-    addTrack,
-    delTrack,
     handleStartLive,
     mySocketId,
     canvasVideoStream,
     lastCoverImg,
-    localStream,
     liveUserList,
     damuList,
     currentMaxFramerate,
     currentMaxBitrate,
     currentResolutionRatio,
   } = useSrsWs();
+  isPull.value = false;
+
+  watch(
+    () => appStore.allTrack,
+    (newTrack, oldTrack) => {
+      console.log('appStore.allTrack变了', newTrack, oldTrack);
+      const mixedStream = new MediaStream();
+      newTrack.forEach((item) => {
+        if (item.track) {
+          mixedStream.addTrack(item.track);
+        }
+      });
+      console.log('新的allTrack音频轨', mixedStream.getAudioTracks());
+      console.log('新的allTrack视频轨', mixedStream.getVideoTracks());
+      console.log('旧的allTrack音频轨', localStream.value?.getAudioTracks());
+      console.log('旧的allTrack视频轨', localStream.value?.getVideoTracks());
+      localStream.value = mixedStream;
+    },
+    { deep: true }
+  );
+
+  watch(
+    () => currentResolutionRatio.value,
+    (newVal) => {
+      if (canvasVideoStream.value) {
+        canvasVideoStream.value.getVideoTracks().forEach((track) => {
+          track.applyConstraints({
+            frameRate: { max: currentMaxFramerate.value },
+            height: newVal,
+          });
+        });
+      } else {
+        appStore.allTrack.forEach((info) => {
+          info.track?.applyConstraints({
+            frameRate: { max: currentMaxFramerate.value },
+            height: newVal,
+          });
+        });
+      }
+
+      networkStore.rtcMap.forEach(async (rtc) => {
+        const res = await rtc.setResolutionRatio(newVal);
+        if (res === 1) {
+          window.$message.success('切换分辨率成功!');
+        } else {
+          window.$message.success('切换分辨率失败!');
+        }
+      });
+    }
+  );
+
+  watch(
+    () => currentMaxFramerate.value,
+    (newVal) => {
+      console.log(currentMaxFramerate.value, 'currentMaxFramerate.value');
+      if (canvasVideoStream.value) {
+        canvasVideoStream.value.getVideoTracks().forEach((track) => {
+          track.applyConstraints({
+            frameRate: { max: newVal },
+            height: currentResolutionRatio.value,
+          });
+        });
+      } else {
+        appStore.allTrack.forEach((info) => {
+          info.track?.applyConstraints({
+            frameRate: { max: newVal },
+            height: currentResolutionRatio.value,
+          });
+        });
+      }
+
+      networkStore.rtcMap.forEach(async (rtc) => {
+        const res = await rtc.setMaxFramerate(newVal);
+        if (res === 1) {
+          window.$message.success('切换帧率成功!');
+        } else {
+          window.$message.success('切换帧率失败!');
+        }
+      });
+    }
+  );
+
+  watch(
+    () => currentMaxBitrate.value,
+    (newVal) => {
+      networkStore.rtcMap.forEach(async (rtc) => {
+        const res = await rtc.setMaxBitrate(newVal);
+        if (res === 1) {
+          window.$message.success('切换码率成功!');
+        } else {
+          window.$message.success('切换码率失败!');
+        }
+      });
+    }
+  );
 
   watch(
     () => localStream.value,
@@ -101,6 +195,53 @@ export function usePush() {
     closeWs();
     closeRtc();
   });
+  function addTrack(addTrackInfo: { track; stream }) {
+    networkStore.rtcMap.forEach((rtc) => {
+      const sender = rtc.peerConnection
+        ?.getSenders()
+        .find((sender) => sender.track?.id === addTrackInfo.track?.id);
+      if (!sender) {
+        console.log(
+          'pc添加track-开播后中途添加,替换它',
+          addTrackInfo.track?.id
+        );
+        rtc.peerConnection
+          ?.getSenders()
+          ?.find((sender) => sender.track?.kind === 'audio')
+          ?.replaceTrack(canvasVideoStream.value!.getAudioTracks()[0]);
+      }
+    });
+    const mixedStream = new MediaStream();
+    appStore.allTrack.forEach((item) => {
+      if (item.track) {
+        mixedStream.addTrack(item.track);
+      }
+    });
+    console.log('addTrack后结果的音频轨', mixedStream.getAudioTracks());
+    console.log('addTrack后结果的视频轨', mixedStream.getVideoTracks());
+    localStream.value = mixedStream;
+  }
+
+  function delTrack(delTrackInfo: AppRootState['allTrack'][0]) {
+    networkStore.rtcMap.forEach((rtc) => {
+      const sender = rtc.peerConnection
+        ?.getSenders()
+        .find((sender) => sender.track?.id === delTrackInfo.track?.id);
+      if (sender) {
+        console.log('删除track', delTrackInfo, sender);
+        rtc.peerConnection?.removeTrack(sender);
+      }
+    });
+    const mixedStream = new MediaStream();
+    appStore.allTrack.forEach((item) => {
+      if (item.track) {
+        mixedStream.addTrack(item.track);
+      }
+    });
+    console.log('delTrack后结果的音频轨', mixedStream.getAudioTracks());
+    console.log('delTrack后结果的视频轨', mixedStream.getVideoTracks());
+    localStream.value = mixedStream;
+  }
 
   function closeWs() {
     const instance = networkStore.wsMap.get(roomId.value);
@@ -147,7 +288,7 @@ export function usePush() {
     });
   }
 
-  async function startLive() {
+  async function startLive({ type, receiver }) {
     if (!loginTip()) return;
     const flag = await userHasLiveRoom();
     if (!flag) {
@@ -155,7 +296,9 @@ export function usePush() {
       await handleCreateUserLiveRoom();
       return;
     }
-    if (!roomNameIsOk()) return;
+    if (!roomNameIsOk()) {
+      return;
+    }
 
     isLiving.value = true;
     const el = appStore.allTrack.find((item) => {
@@ -174,7 +317,12 @@ export function usePush() {
         }
       }
     }
-    handleStartLive({ coverImg: lastCoverImg.value, name: roomName.value });
+    handleStartLive({
+      coverImg: lastCoverImg.value,
+      name: roomName.value,
+      type,
+      receiver,
+    });
   }
 
   /** 结束直播 */

+ 171 - 172
src/hooks/use-srs-ws.ts

@@ -13,11 +13,14 @@ import {
 } from '@/interface';
 import {
   WSGetRoomAllUserType,
+  WsAnswerType,
+  WsCandidateType,
   WsGetLiveUserType,
   WsHeartbeatType,
   WsJoinType,
   WsLeavedType,
   WsMessageType,
+  WsOfferType,
   WsOtherJoinType,
   WsRoomLivingType,
   WsStartLiveType,
@@ -30,14 +33,12 @@ import {
   WsMsgTypeEnum,
   prettierReceiveWsMsg,
 } from '@/network/webSocket';
-import { AppRootState, useAppStore } from '@/store/app';
 import { useNetworkStore } from '@/store/network';
 import { useUserStore } from '@/store/user';
 
 import { useRTCParams } from './use-rtc-params';
 
 export const useSrsWs = () => {
-  const appStore = useAppStore();
   const userStore = useUserStore();
   const networkStore = useNetworkStore();
   const { maxBitrate, maxFramerate, resolutionRatio } = useRTCParams();
@@ -45,11 +46,11 @@ export const useSrsWs = () => {
   const loopHeartbeatTimer = ref();
   const liveUserList = ref<ILiveUser[]>([]);
   const roomId = ref('');
+  const isPull = ref(false);
   const roomLiving = ref(false);
   const isAnchor = ref(false);
   const liveRoomInfo = ref<ILiveRoom>();
   const anchorInfo = ref<IUser>();
-  const localStream = ref<MediaStream>();
   const canvasVideoStream = ref<MediaStream>();
   const lastCoverImg = ref('');
   const currentMaxBitrate = ref(maxBitrate.value[2].value);
@@ -58,156 +59,10 @@ export const useSrsWs = () => {
 
   const damuList = ref<IDanmu[]>([]);
 
-  watch(
-    () => appStore.allTrack,
-    (newTrack, oldTrack) => {
-      console.log('appStore.allTrack变了', newTrack, oldTrack);
-      const mixedStream = new MediaStream();
-      newTrack.forEach((item) => {
-        if (item.track) {
-          mixedStream.addTrack(item.track);
-        }
-      });
-      console.log('新的allTrack音频轨', mixedStream.getAudioTracks());
-      console.log('新的allTrack视频轨', mixedStream.getVideoTracks());
-      console.log('旧的allTrack音频轨', localStream.value?.getAudioTracks());
-      console.log('旧的allTrack视频轨', localStream.value?.getVideoTracks());
-      localStream.value = mixedStream;
-    },
-    { deep: true }
-  );
-
   onUnmounted(() => {
     clearInterval(loopHeartbeatTimer.value);
   });
 
-  watch(
-    () => currentResolutionRatio.value,
-    (newVal) => {
-      if (canvasVideoStream.value) {
-        canvasVideoStream.value.getVideoTracks().forEach((track) => {
-          track.applyConstraints({
-            frameRate: { max: currentMaxFramerate.value },
-            height: newVal,
-          });
-        });
-      } else {
-        appStore.allTrack.forEach((info) => {
-          info.track?.applyConstraints({
-            frameRate: { max: currentMaxFramerate.value },
-            height: newVal,
-          });
-        });
-      }
-
-      networkStore.rtcMap.forEach(async (rtc) => {
-        const res = await rtc.setResolutionRatio(newVal);
-        if (res === 1) {
-          window.$message.success('切换分辨率成功!');
-        } else {
-          window.$message.success('切换分辨率失败!');
-        }
-      });
-    }
-  );
-
-  watch(
-    () => currentMaxFramerate.value,
-    (newVal) => {
-      console.log(currentMaxFramerate.value, 'currentMaxFramerate.value');
-      if (canvasVideoStream.value) {
-        canvasVideoStream.value.getVideoTracks().forEach((track) => {
-          track.applyConstraints({
-            frameRate: { max: newVal },
-            height: currentResolutionRatio.value,
-          });
-        });
-      } else {
-        appStore.allTrack.forEach((info) => {
-          info.track?.applyConstraints({
-            frameRate: { max: newVal },
-            height: currentResolutionRatio.value,
-          });
-        });
-      }
-
-      networkStore.rtcMap.forEach(async (rtc) => {
-        const res = await rtc.setMaxFramerate(newVal);
-        if (res === 1) {
-          window.$message.success('切换帧率成功!');
-        } else {
-          window.$message.success('切换帧率失败!');
-        }
-      });
-    }
-  );
-
-  watch(
-    () => currentMaxBitrate.value,
-    (newVal) => {
-      networkStore.rtcMap.forEach(async (rtc) => {
-        const res = await rtc.setMaxBitrate(newVal);
-        if (res === 1) {
-          window.$message.success('切换码率成功!');
-        } else {
-          window.$message.success('切换码率失败!');
-        }
-      });
-    }
-  );
-
-  function addTrack(addTrackInfo: { track; stream }) {
-    if (isAnchor.value) {
-      networkStore.rtcMap.forEach((rtc) => {
-        const sender = rtc.peerConnection
-          ?.getSenders()
-          .find((sender) => sender.track?.id === addTrackInfo.track?.id);
-        if (!sender) {
-          console.log(
-            'pc添加track-开播后中途添加,替换它',
-            addTrackInfo.track?.id
-          );
-          rtc.peerConnection
-            ?.getSenders()
-            ?.find((sender) => sender.track?.kind === 'audio')
-            ?.replaceTrack(canvasVideoStream.value!.getAudioTracks()[0]);
-        }
-      });
-    }
-    const mixedStream = new MediaStream();
-    appStore.allTrack.forEach((item) => {
-      if (item.track) {
-        mixedStream.addTrack(item.track);
-      }
-    });
-    console.log('addTrack后结果的音频轨', mixedStream.getAudioTracks());
-    console.log('addTrack后结果的视频轨', mixedStream.getVideoTracks());
-    localStream.value = mixedStream;
-  }
-
-  function delTrack(delTrackInfo: AppRootState['allTrack'][0]) {
-    if (isAnchor.value) {
-      networkStore.rtcMap.forEach((rtc) => {
-        const sender = rtc.peerConnection
-          ?.getSenders()
-          .find((sender) => sender.track?.id === delTrackInfo.track?.id);
-        if (sender) {
-          console.log('删除track', delTrackInfo, sender);
-          rtc.peerConnection?.removeTrack(sender);
-        }
-      });
-    }
-    const mixedStream = new MediaStream();
-    appStore.allTrack.forEach((item) => {
-      if (item.track) {
-        mixedStream.addTrack(item.track);
-      }
-    });
-    console.log('delTrack后结果的音频轨', mixedStream.getAudioTracks());
-    console.log('delTrack后结果的视频轨', mixedStream.getVideoTracks());
-    localStream.value = mixedStream;
-  }
-
   const mySocketId = computed(() => {
     return networkStore.wsMap.get(roomId.value)?.socketIo?.id || '-1';
   });
@@ -225,15 +80,20 @@ export const useSrsWs = () => {
     }, 1000 * 5);
   }
 
-  async function sendOffer({ receiver }: { receiver: string }) {
-    console.log('开始sendOffer');
+  async function handleSendOffer({
+    receiver,
+    type,
+  }: {
+    receiver: string;
+    type: LiveRoomTypeEnum;
+  }) {
+    console.log('开始handleSendOffer');
     const ws = networkStore.wsMap.get(roomId.value);
     if (!ws) return;
     const rtc = networkStore.getRtcMap(`${roomId.value}___${receiver}`);
     if (!rtc) return;
     const sdp = await rtc.createOffer();
     await rtc.setLocalDescription(sdp!);
-
     const myLiveRoom = userStore.userInfo!.live_rooms![0];
     const res = await fetchRtcV1Publish({
       api: `/rtc/v1/publish/`,
@@ -264,18 +124,66 @@ export const useSrsWs = () => {
     );
   }
 
-  function handleStartLive({ coverImg, name }) {
+  watch(liveUserList, () => {
+    // if (!isPull.value) return;
+    // console.log('>>>>>');
+    // liveUserList.value.forEach(async (item) => {
+    //   console.log(item);
+    //   const receiver = item.id;
+    //   if (receiver === mySocketId.value) return;
+    //   console.log(receiver, 'ppdpsd');
+    //   const rtc = new WebRTCClass({
+    //     maxBitrate: currentMaxBitrate.value,
+    //     maxFramerate: currentMaxFramerate.value,
+    //     resolutionRatio: currentResolutionRatio.value,
+    //     roomId: `${roomId.value}___${receiver!}`,
+    //     videoEl: document.createElement('video'),
+    //     isSRS: false,
+    //     receiver,
+    //   });
+    //   const ws = networkStore.wsMap.get(roomId.value)!;
+    //   const offer = await rtc.createOffer();
+    //   await rtc.setLocalDescription(offer!);
+    //   ws.send<WsOfferType['data']>({
+    //     msgType: WsMsgTypeEnum.offer,
+    //     data: {
+    //       sdp: offer,
+    //       live_room_id: Number(roomId.value),
+    //       sender: mySocketId.value,
+    //       receiver,
+    //     },
+    //   });
+    // });
+  });
+
+  function handleStartLive({
+    coverImg,
+    name,
+    type,
+    receiver,
+  }: {
+    coverImg?: string;
+    name?: string;
+    type: LiveRoomTypeEnum;
+    receiver: string;
+    videoEl?: HTMLVideoElement;
+  }) {
     networkStore.wsMap.get(roomId.value)?.send<WsStartLiveType['data']>({
       msgType: WsMsgTypeEnum.startLive,
       data: {
-        cover_img: coverImg,
-        name,
-        type: LiveRoomTypeEnum.user_srs,
+        cover_img: coverImg!,
+        name: name!,
+        type,
       },
     });
-    startNewSrsWebRtc({
+    if (type === LiveRoomTypeEnum.user_wertc) {
+      console.log(liveUserList.value.length, 'kkk1123');
+      return;
+    }
+    startNewWebRtc({
       videoEl: document.createElement('video'),
-      receiver: 'srs',
+      receiver,
+      type,
     });
   }
 
@@ -295,15 +203,17 @@ export const useSrsWs = () => {
   }
 
   /** 原生的webrtc时,receiver必传 */
-  function startNewSrsWebRtc({
+  function startNewWebRtc({
     receiver,
     videoEl,
+    type,
   }: {
     receiver: string;
     videoEl: HTMLVideoElement;
+    type: LiveRoomTypeEnum;
   }) {
-    console.warn('SRS开始new WebRTCClass', `${roomId.value}___${receiver!}`);
-    const rtc = new WebRTCClass({
+    console.warn('开始new WebRTCClass', `${roomId.value}___${receiver!}`);
+    new WebRTCClass({
       maxBitrate: currentMaxBitrate.value,
       maxFramerate: currentMaxFramerate.value,
       resolutionRatio: currentResolutionRatio.value,
@@ -312,16 +222,10 @@ export const useSrsWs = () => {
       isSRS: true,
       receiver,
     });
-    if (canvasVideoStream.value) {
-      localStream.value = canvasVideoStream.value;
-      canvasVideoStream.value.getTracks().forEach((track) => {
-        console.log('pc添加track-srs', track.kind, track.id);
-        rtc.peerConnection?.addTrack(track, localStream.value!);
-      });
-    }
 
-    sendOffer({
+    handleSendOffer({
       receiver,
+      type,
     });
   }
 
@@ -345,6 +249,68 @@ export const useSrsWs = () => {
       ws.status = WsConnectStatusEnum.disconnect;
       ws.update();
     });
+    ws.socketIo.on(WsMsgTypeEnum.offer, async (data: WsOfferType['data']) => {
+      console.log('收到offer', data);
+      if (data.receiver === mySocketId.value) {
+        console.warn('是发给我的offer');
+        const rtc = new WebRTCClass({
+          maxBitrate: currentMaxBitrate.value,
+          maxFramerate: currentMaxFramerate.value,
+          resolutionRatio: currentResolutionRatio.value,
+          roomId: `${roomId.value}___${data.receiver!}`,
+          videoEl: document.createElement('video'),
+          isSRS: true,
+          receiver: data.receiver,
+        });
+        canvasVideoStream.value?.getTracks().forEach((track) => {
+          if (rtc && canvasVideoStream.value) {
+            console.log('插入track', track);
+            rtc.peerConnection?.addTrack(track, canvasVideoStream.value);
+          }
+        });
+        await rtc.setRemoteDescription(data.sdp);
+        const answer = await rtc.createAnswer();
+        if (answer) {
+          await rtc.setLocalDescription(answer);
+          ws.send<WsAnswerType['data']>({
+            msgType: WsMsgTypeEnum.answer,
+            data: {
+              live_room_id: Number(roomId.value),
+              sdp: answer,
+              receiver: data.sender,
+              sender: mySocketId.value,
+            },
+          });
+        } else {
+          console.error('没有answer');
+        }
+      } else {
+        console.error('不是发给我的offer');
+      }
+    });
+    ws.socketIo.on(WsMsgTypeEnum.answer, (data: WsAnswerType['data']) => {
+      console.log('收到answer', data);
+      if (data.receiver === mySocketId.value) {
+        console.warn('是发给我的answer', `${roomId.value}___${data.receiver}`);
+        const rtc = networkStore.getRtcMap(`${roomId.value}___${data.sender}`)!;
+        console.log(rtc, 'll');
+        rtc.setRemoteDescription(data.sdp);
+      } else {
+        console.error('不是发给我的answer');
+      }
+    });
+    ws.socketIo.on(WsMsgTypeEnum.candidate, (data: WsCandidateType['data']) => {
+      console.log('收到candidate', data);
+      if (data.receiver === mySocketId.value) {
+        console.warn('是发给我的candidate');
+        const rtc = networkStore.getRtcMap(
+          `${roomId.value}___${data.receiver}`
+        )!;
+        rtc.addIceCandidate(data.candidate);
+      } else {
+        console.error('不是发给我的candidate');
+      }
+    });
 
     // 主播正在直播
     ws.socketIo.on(WsMsgTypeEnum.roomLiving, (data: WsRoomLivingType) => {
@@ -421,6 +387,41 @@ export const useSrsWs = () => {
           live_room_id: data.live_room.id!,
         },
       });
+      if (!isPull.value) {
+        console.log('>>>>>');
+        liveUserList.value.forEach(async (item) => {
+          console.log(item);
+          const receiver = item.id;
+          if (
+            receiver === mySocketId.value ||
+            networkStore.getRtcMap(`${roomId.value}___${receiver!}`)
+          )
+            return;
+          console.log(receiver, 'ppdpsd');
+          const rtc = new WebRTCClass({
+            maxBitrate: currentMaxBitrate.value,
+            maxFramerate: currentMaxFramerate.value,
+            resolutionRatio: currentResolutionRatio.value,
+            roomId: `${roomId.value}___${receiver!}`,
+            videoEl: document.createElement('video'),
+            isSRS: false,
+            receiver,
+          });
+          networkStore.updateRtcMap(`${roomId.value}___${receiver!}`, rtc);
+          const ws = networkStore.wsMap.get(roomId.value)!;
+          const offer = await rtc.createOffer();
+          await rtc.setLocalDescription(offer!);
+          ws.send<WsOfferType['data']>({
+            msgType: WsMsgTypeEnum.offer,
+            data: {
+              sdp: offer,
+              live_room_id: Number(roomId.value),
+              sender: mySocketId.value,
+              receiver,
+            },
+          });
+        });
+      }
     });
 
     // 用户离开房间
@@ -475,9 +476,8 @@ export const useSrsWs = () => {
   }
 
   return {
+    isPull,
     initSrsWs,
-    addTrack,
-    delTrack,
     handleStartLive,
     mySocketId,
     canvasVideoStream,
@@ -485,7 +485,6 @@ export const useSrsWs = () => {
     roomLiving,
     liveRoomInfo,
     anchorInfo,
-    localStream,
     liveUserList,
     damuList,
     currentMaxFramerate,

+ 1 - 1
src/layout/pc/head/index.vue

@@ -289,7 +289,7 @@ const about = ref([
   },
   {
     label: 'b站视频',
-    url: 'https://space.bilibili.com/381307133/channel/seriesdetail?sid=3285689',
+    url: 'https://space.bilibili.com/381307133/channel/collectiondetail?sid=1458070&ctype=0',
   },
 ]);
 const resource = ref([

+ 10 - 0
src/network/webRTC.ts

@@ -286,6 +286,16 @@ export class WebRTCClass {
     }
   };
 
+  addIceCandidate = async (candidate: RTCIceCandidateInit) => {
+    try {
+      await this.peerConnection?.addIceCandidate(candidate);
+      console.log('addIceCandidate成功');
+    } catch (error) {
+      console.error('addIceCandidate错误');
+      console.log(error);
+    }
+  };
+
   // 创建answer
   createAnswer = async () => {
     if (!this.peerConnection) return;

+ 47 - 0
src/utils/index.ts

@@ -2,6 +2,53 @@
 
 import { getRangeRandom } from 'billd-utils';
 
+/**
+ * 格式化倒计时
+ * @param endTime
+ * @param startTime
+ */
+export function formatDownTime(endTime: number, startTime: number) {
+  const times = (endTime - startTime) / 1000;
+  // js获取剩余天数
+  const d = parseInt(String(times / 60 / 60 / 24));
+  // js获取剩余小时
+  let h = parseInt(String((times / 60 / 60) % 24));
+  // js获取剩余分钟
+  let m = parseInt(String((times / 60) % 60));
+  // js获取剩余秒
+  let s = parseInt(String(times % 60));
+  let ms = new Date(endTime).getMilliseconds();
+
+  if (h < 10) {
+    // @ts-ignore
+    h = `0${h}`;
+  }
+  if (m < 10) {
+    // @ts-ignore
+    m = `0${m}`;
+  }
+  if (s < 10) {
+    // @ts-ignore
+    s = `0${s}`;
+  }
+  if (Number(ms) < 100) {
+    if (ms < 10) {
+      // @ts-ignore
+      ms = `00${ms}`;
+    } else {
+      // @ts-ignore
+      ms = `0${ms}`;
+    }
+  }
+  if (d > 0) {
+    return `${d}:${h}:${m}:${s}.${ms}`;
+  } else if (h > 0) {
+    return `${h}:${m}:${s}.${ms}`;
+  } else {
+    return `${m}:${s}.${ms}`;
+  }
+}
+
 /**
  * requestFileSystem保存文件,成功返回code:1,失败返回code:2
  * @param data

+ 0 - 1
src/views/h5/room/index.vue

@@ -138,7 +138,6 @@ const {
 } = usePull({
   localVideoRef,
   liveType: liveTypeEnum.srsHlsPull,
-  isSRS: false,
 });
 
 watch(

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

@@ -208,11 +208,6 @@ const remoteVideoRef = ref<HTMLDivElement>();
 const { handleHlsPlay, videoLoading, remoteVideo } = usePull({
   localVideoRef,
   liveType: route.query.liveType as liveTypeEnum,
-  isSRS: [
-    liveTypeEnum.srsWebrtcPull,
-    liveTypeEnum.srsFlvPull,
-    liveTypeEnum.srsHlsPull,
-  ].includes(route.query.liveType as liveTypeEnum),
 });
 
 watch(

+ 1 - 7
src/views/pull/index.vue

@@ -218,7 +218,6 @@ const bottomRef = ref<HTMLDivElement>();
 const danmuListRef = ref<HTMLDivElement>();
 const remoteVideoRef = ref<HTMLDivElement>();
 const containerRef = ref<HTMLDivElement>();
-const localVideoRef = ref<HTMLVideoElement[]>([]);
 const {
   initPull,
   closeWs,
@@ -236,13 +235,8 @@ const {
   liveRoomInfo,
   anchorInfo,
 } = usePull({
-  localVideoRef,
+  remoteVideoRef,
   liveType: route.query.liveType as liveTypeEnum,
-  isSRS: [
-    liveTypeEnum.srsWebrtcPull,
-    liveTypeEnum.srsFlvPull,
-    liveTypeEnum.srsHlsPull,
-  ].includes(route.query.liveType as liveTypeEnum),
 });
 
 onUnmounted(() => {

+ 3 - 52
src/views/push/rtc/index.vue

@@ -272,23 +272,18 @@ import {
   ref,
   watch,
 } from 'vue';
-import { useRoute } from 'vue-router';
 import * as workerTimers from 'worker-timers';
 
 import { mediaTypeEnumMap } from '@/constant';
 import { usePush } from '@/hooks/use-push';
 import { useRTCParams } from '@/hooks/use-rtc-params';
-import {
-  DanmuMsgTypeEnum,
-  LiveRoomTypeEnum,
-  MediaTypeEnum,
-  liveTypeEnum,
-} from '@/interface';
+import { DanmuMsgTypeEnum, LiveRoomTypeEnum, MediaTypeEnum } from '@/interface';
 import { AppRootState, useAppStore } from '@/store/app';
 import { useResourceCacheStore } from '@/store/cache';
 import { useUserStore } from '@/store/user';
 import {
   createVideo,
+  formatDownTime,
   generateBase64,
   getRandomEnglishString,
   readFile,
@@ -300,7 +295,6 @@ import MediaModalCpt from '../mediaModal/index.vue';
 import OpenMicophoneTipCpt from '../openMicophoneTip/index.vue';
 import SelectMediaModalCpt from '../selectMediaModal/index.vue';
 
-const route = useRoute();
 const userStore = useUserStore();
 const appStore = useAppStore();
 const resourceCacheStore = useResourceCacheStore();
@@ -348,7 +342,6 @@ const wrapSize = reactive({
 const workerTimerId = ref(-1);
 const videoRatio = ref(16 / 9);
 const bodyAppendChildElArr = ref<HTMLElement[]>([]);
-const isSRS = route.query.liveType === liveTypeEnum.srsPush;
 
 watch(
   () => damuList.value.length,
@@ -405,48 +398,6 @@ function initUserMedia() {
     });
 }
 
-function formatDownTime(endTime: number, startTime: number) {
-  const times = (endTime - startTime) / 1000;
-  // js获取剩余天数
-  const d = parseInt(String(times / 60 / 60 / 24));
-  // js获取剩余小时
-  let h = parseInt(String((times / 60 / 60) % 24));
-  // js获取剩余分钟
-  let m = parseInt(String((times / 60) % 60));
-  // js获取剩余秒
-  let s = parseInt(String(times % 60));
-  let ms = new Date(endTime).getMilliseconds();
-
-  if (h < 10) {
-    // @ts-ignore
-    h = `0${h}`;
-  }
-  if (m < 10) {
-    // @ts-ignore
-    m = `0${m}`;
-  }
-  if (s < 10) {
-    // @ts-ignore
-    s = `0${s}`;
-  }
-  if (Number(ms) < 100) {
-    if (ms < 10) {
-      // @ts-ignore
-      ms = `00${ms}`;
-    } else {
-      // @ts-ignore
-      ms = `0${ms}`;
-    }
-  }
-  if (d > 0) {
-    return `${d}:${h}:${m}:${s}.${ms}`;
-  } else if (h > 0) {
-    return `${h}:${m}:${s}.${ms}`;
-  } else {
-    return `${m}:${s}.${ms}`;
-  }
-}
-
 function renderAll() {
   timeCanvasDom.value.forEach((item) => {
     item.text = new Date().toLocaleString();
@@ -577,7 +528,7 @@ function handleStartLive() {
   }
   handleMixedAudio();
   lastCoverImg.value = generateBase64(pushCanvasRef.value!);
-  startLive(isSRS ? LiveRoomTypeEnum.user_srs : LiveRoomTypeEnum.user_wertc);
+  startLive({ type: LiveRoomTypeEnum.user_wertc, receiver: mySocketId });
 }
 
 function handleScale({ width, height }: { width: number; height: number }) {

+ 2 - 43
src/views/push/srs/index.vue

@@ -289,6 +289,7 @@ import { useResourceCacheStore } from '@/store/cache';
 import { useUserStore } from '@/store/user';
 import {
   createVideo,
+  formatDownTime,
   generateBase64,
   getRandomEnglishString,
   readFile,
@@ -405,48 +406,6 @@ function initUserMedia() {
     });
 }
 
-function formatDownTime(endTime: number, startTime: number) {
-  const times = (endTime - startTime) / 1000;
-  // js获取剩余天数
-  const d = parseInt(String(times / 60 / 60 / 24));
-  // js获取剩余小时
-  let h = parseInt(String((times / 60 / 60) % 24));
-  // js获取剩余分钟
-  let m = parseInt(String((times / 60) % 60));
-  // js获取剩余秒
-  let s = parseInt(String(times % 60));
-  let ms = new Date(endTime).getMilliseconds();
-
-  if (h < 10) {
-    // @ts-ignore
-    h = `0${h}`;
-  }
-  if (m < 10) {
-    // @ts-ignore
-    m = `0${m}`;
-  }
-  if (s < 10) {
-    // @ts-ignore
-    s = `0${s}`;
-  }
-  if (Number(ms) < 100) {
-    if (ms < 10) {
-      // @ts-ignore
-      ms = `00${ms}`;
-    } else {
-      // @ts-ignore
-      ms = `0${ms}`;
-    }
-  }
-  if (d > 0) {
-    return `${d}:${h}:${m}:${s}.${ms}`;
-  } else if (h > 0) {
-    return `${h}:${m}:${s}.${ms}`;
-  } else {
-    return `${m}:${s}.${ms}`;
-  }
-}
-
 function renderAll() {
   timeCanvasDom.value.forEach((item) => {
     item.text = new Date().toLocaleString();
@@ -577,7 +536,7 @@ function handleStartLive() {
   }
   handleMixedAudio();
   lastCoverImg.value = generateBase64(pushCanvasRef.value!);
-  startLive(isSRS ? LiveRoomTypeEnum.user_srs : LiveRoomTypeEnum.user_wertc);
+  startLive({ type: LiveRoomTypeEnum.user_srs, receiver: 'srs' });
 }
 
 function handleScale({ width, height }: { width: number; height: number }) {