Selaa lähdekoodia

fix: 修复已知问题

shuisheng 1 vuosi sitten
vanhempi
sitoutus
07c9d42d9b

+ 31 - 36
src/hooks/use-pull.ts

@@ -74,27 +74,24 @@ export function usePull(roomId: string) {
       console.log('pkStream变了', newval);
       stopDrawingArr.value = [];
       stopDrawingArr.value.forEach((cb) => cb());
-      console.log(
-        networkStore.getRtcMap(`${mySocketId.value}___${roomId}`)?.videoEl!
-      );
       if (videoWrapRef.value) {
         const rect = videoWrapRef.value.getBoundingClientRect();
-        const { canvas, stopDrawing } = videoToCanvas({
-          wrapSize: {
-            width: rect.width,
-            height: rect.height,
-          },
-          videoEl: networkStore.getRtcMap(`${mySocketId.value}___${roomId}`)
-            ?.videoEl!,
-          videoResize: ({ w, h }) => {
-            videoHeight.value = `${w}x${h}`;
-          },
-        });
-        document.body.appendChild(canvas);
-        stopDrawingArr.value.push(stopDrawing);
-        remoteVideo.value.push(canvas);
-        roomLiving.value = true;
-        videoLoading.value = false;
+        // const { canvas, stopDrawing } = videoToCanvas({
+        //   wrapSize: {
+        //     width: rect.width,
+        //     height: rect.height,
+        //   },
+        //   videoEl: networkStore.getRtcMap(`${mySocketId.value}___${roomId}`)
+        //     ?.videoEl!,
+        //   videoResize: ({ w, h }) => {
+        //     videoHeight.value = `${w}x${h}`;
+        //   },
+        // });
+        // document.body.appendChild(canvas);
+        // stopDrawingArr.value.push(stopDrawing);
+        // remoteVideo.value.push(canvas);
+        // roomLiving.value = true;
+        // videoLoading.value = false;
       }
     }
   );
@@ -291,21 +288,21 @@ export function usePull(roomId: string) {
       if (appStore.liveRoomInfo?.type === LiveRoomTypeEnum.user_wertc) {
         newVal.forEach((item) => {
           videoLoading.value = false;
-          if (videoWrapRef.value) {
-            const rect = videoWrapRef.value.getBoundingClientRect();
-            const { canvas } = videoToCanvas({
-              wrapSize: {
-                width: rect.width,
-                height: rect.height,
-              },
-              videoEl: item.videoEl,
-              videoResize: ({ w, h }) => {
-                videoHeight.value = `${w}x${h}`;
-              },
-            });
-            videoElArr.value.push(item.videoEl);
-            remoteVideo.value.push(canvas);
-          }
+          // if (videoWrapRef.value) {
+          //   const rect = videoWrapRef.value.getBoundingClientRect();
+          //   const { canvas } = videoToCanvas({
+          //     wrapSize: {
+          //       width: rect.width,
+          //       height: rect.height,
+          //     },
+          //     videoEl: item.videoEl,
+          //     videoResize: ({ w, h }) => {
+          //       videoHeight.value = `${w}x${h}`;
+          //     },
+          //   });
+          //   videoElArr.value.push(item.videoEl);
+          //   remoteVideo.value.push(canvas);
+          // }
         });
       }
     },
@@ -400,14 +397,12 @@ export function usePull(roomId: string) {
 
   function closeWs() {
     networkStore.wsMap.forEach((ws) => {
-      ws.close();
       networkStore.removeWs(ws.roomId);
     });
   }
 
   function closeRtc() {
     networkStore.rtcMap.forEach((rtc) => {
-      rtc.close();
       networkStore.removeRtc(rtc.roomId);
     });
   }

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

@@ -12,7 +12,12 @@ import { useAppStore } from '@/store/app';
 import { useNetworkStore } from '@/store/network';
 import { useUserStore } from '@/store/user';
 import { ILiveRoom } from '@/types/ILiveRoom';
-import { WsMessageType, WsMsgTypeEnum, WsMsrBlobType } from '@/types/websocket';
+import {
+  WsMessageType,
+  WsMsgTypeEnum,
+  WsMsrBlobType,
+  WsRoomNoLiveType,
+} from '@/types/websocket';
 import { createVideo, generateBase64 } from '@/utils';
 
 import { commentAuthTip, loginTip } from './use-login';
@@ -63,14 +68,12 @@ export function usePush() {
 
   function closeWs() {
     networkStore.wsMap.forEach((ws) => {
-      ws.close();
       networkStore.removeWs(ws.roomId);
     });
   }
 
   function closeRtc() {
     networkStore.rtcMap.forEach((rtc) => {
-      rtc.close();
       networkStore.removeRtc(rtc.roomId);
     });
   }
@@ -253,9 +256,12 @@ export function usePush() {
     localStream.value = undefined;
     const instance = networkStore.wsMap.get(roomId.value);
     if (instance) {
-      instance.send({
+      instance.send<WsRoomNoLiveType['data']>({
         requestId: getRandomString(8),
         msgType: WsMsgTypeEnum.roomNoLive,
+        data: {
+          live_room: appStore.liveRoomInfo!,
+        },
       });
     }
     closeRtc();

+ 123 - 103
src/hooks/use-websocket.ts

@@ -166,18 +166,18 @@ export const useWebsocket = () => {
         msrMaxDelay,
       },
     });
-    if (type === LiveRoomTypeEnum.user_msr) {
-      return;
-    }
-    isSRS.value = true;
-    if (
-      ![LiveRoomTypeEnum.user_wertc, LiveRoomTypeEnum.user_pk].includes(type)
-    ) {
-      srsWebRtc.sendOffer({
-        isPk: false,
-        sender: mySocketId.value,
-      });
-    }
+    // if (type === LiveRoomTypeEnum.user_msr) {
+    //   return;
+    // }
+    // if ([LiveRoomTypeEnum.user_srs, LiveRoomTypeEnum.user_obs].includes(type)) {
+    //   isSRS.value = true;
+    //   srsWebRtc.sendOffer({
+    //     isPk: false,
+    //     sender: mySocketId.value,
+    //   });
+    // } else {
+    //   isSRS.value = false;
+    // }
   }
 
   function sendJoin() {
@@ -223,7 +223,7 @@ export const useWebsocket = () => {
         maxFramerate: currentMaxFramerate.value,
         resolutionRatio: currentResolutionRatio.value,
         isSRS: false,
-        roomId: `${mySocketId.value}___${roomId.value}`,
+        roomId: roomId.value,
         isAnchor,
         videoEl,
         sender,
@@ -246,6 +246,9 @@ export const useWebsocket = () => {
       try {
         const ws = networkStore.wsMap.get(roomId.value);
         if (!ws) return;
+        if (networkStore.rtcMap.get(receiver)) {
+          return;
+        }
         const rtc = nativeWebRtc.newWebrtc({
           isAnchor: true,
           sender,
@@ -304,43 +307,44 @@ export const useWebsocket = () => {
       try {
         const ws = networkStore.wsMap.get(roomId.value);
         if (!ws) return;
-        const rtc = nativeWebRtc.newWebrtc({
-          isAnchor: false,
-          sender,
-          receiver,
-          videoEl: createVideo({ appendChild: true }),
-        });
-        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 rtc = networkStore.rtcMap.get(receiver);
+        if (rtc) {
+          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) => {
+                  rtc.peerConnection?.addTrack(track, stream);
+                });
+              }
             }
           }
+          const answerSdp = await rtc.createAnswer();
+          if (!answerSdp) {
+            console.error('nativeWebRtc的answerSdp为空');
+            return;
+          }
+          await rtc.setLocalDescription(answerSdp);
+          networkStore.wsMap.get(roomId.value)?.send<WsAnswerType['data']>({
+            requestId: getRandomString(8),
+            msgType: WsMsgTypeEnum.nativeWebRtcAnswer,
+            data: {
+              live_room_id: Number(roomId.value),
+              sender,
+              receiver,
+              sdp: answerSdp,
+            },
+          });
+        } else {
+          console.error('rtc不存在');
         }
-        const answerSdp = await rtc.createAnswer();
-        if (!answerSdp) {
-          console.error('nativeWebRtc的answerSdp为空');
-          return;
-        }
-        await rtc.setLocalDescription(answerSdp);
-        networkStore.wsMap.get(roomId.value)?.send<WsAnswerType['data']>({
-          requestId: getRandomString(8),
-          msgType: WsMsgTypeEnum.nativeWebRtcAnswer,
-          data: {
-            live_room_id: Number(roomId.value),
-            sender: receiver,
-            receiver: sender,
-            sdp: answerSdp,
-          },
-        });
       } catch (error) {
         console.error('nativeWebRtc的sendAnswer错误');
       }
@@ -380,11 +384,7 @@ export const useWebsocket = () => {
         const ws = networkStore.wsMap.get(roomId.value);
         if (!ws) return;
         const rtc = srsWebRtc.newWebrtc({
-          roomId: `${
-            isPk
-              ? `${mySocketId.value}___${roomId.value}___pk`
-              : `${mySocketId.value}___${roomId.value}`
-          }`,
+          roomId: `${isPk ? `${roomId.value}___pk` : `${roomId.value}`}`,
           sender,
           videoEl: createVideo({ appendChild: true }),
         });
@@ -501,7 +501,7 @@ export const useWebsocket = () => {
             maxBitrate: currentMaxBitrate.value,
             maxFramerate: currentMaxFramerate.value,
             resolutionRatio: currentResolutionRatio.value,
-            roomId: `${mySocketId.value}___${roomId.value}`,
+            roomId: roomId.value,
             videoEl,
             isSRS: true,
             sender: data.sender,
@@ -536,10 +536,8 @@ export const useWebsocket = () => {
       console.log('收到srsAnswer', data);
       if (data.receiver === mySocketId.value) {
         console.warn('是发给我的srsAnswer');
-        const rtc = networkStore.getRtcMap(
-          `${mySocketId.value}___${roomId.value}`
-        )!;
-        rtc.setRemoteDescription(data.sdp);
+        const rtc = networkStore.getRtcMap(data.sender);
+        rtc?.setRemoteDescription(data.sdp);
       } else {
         console.error('不是发给我的srsAnswer');
       }
@@ -552,10 +550,8 @@ export const useWebsocket = () => {
         console.log('收到srsCandidate', data);
         if (data.receiver === mySocketId.value) {
           console.warn('是发给我的srsCandidate');
-          const rtc = networkStore.getRtcMap(
-            `${mySocketId.value}___${roomId.value}`
-          )!;
-          rtc.addIceCandidate(data.candidate);
+          const rtc = networkStore.getRtcMap(data.sender);
+          rtc?.addIceCandidate(data.candidate);
         } else {
           console.error('不是发给我的srsCandidate');
         }
@@ -579,20 +575,31 @@ export const useWebsocket = () => {
                 content: '是否加入PK',
                 positiveText: '确认',
                 onPositiveClick() {
-                  return new Promise((resolve) => {
-                    resolve(1);
+                  async function main() {
                     if (data.receiver === mySocketId.value) {
                       console.warn('是发给我的nativeWebRtcOffer');
+                      await nativeWebRtc.newWebrtc({
+                        isAnchor: true,
+                        // 因为这里是收到offer,而offer是房主发的,所以此时的data.data.sender是房主;data.data.receiver是接收者;
+                        // 但是这里的nativeWebRtc的sender,得是自己,不能是data.data.sender,不要混淆
+                        sender: mySocketId.value,
+                        receiver: data.sender,
+                        videoEl: createVideo({
+                          appendChild: true,
+                        }),
+                      });
                       nativeWebRtc.sendAnswer({
                         isPk: true,
-                        sender: data.sender,
-                        receiver: data.receiver,
+                        sender: mySocketId.value,
+                        // data.data.receiver是接收者;我们现在new pc,发送者是自己,接收者肯定是房主,不能是data.data.receiver,因为data.data.receiver是自己
+                        receiver: data.sender,
                         sdp: data.sdp,
                       });
                     } else {
                       console.error('不是发给我的nativeWebRtcOffer');
                     }
-                  });
+                  }
+                  return main();
                 },
               });
             } else {
@@ -601,10 +608,21 @@ export const useWebsocket = () => {
           } else {
             if (data.receiver === mySocketId.value) {
               console.warn('是发给我的nativeWebRtcOffer');
+              await nativeWebRtc.newWebrtc({
+                isAnchor: true,
+                // 因为这里是收到offer,而offer是房主发的,所以此时的data.data.sender是房主;data.data.receiver是接收者;
+                // 但是这里的nativeWebRtc的sender,得是自己,不能是data.data.sender,不要混淆
+                sender: mySocketId.value,
+                receiver: data.sender,
+                videoEl: createVideo({
+                  appendChild: true,
+                }),
+              });
               nativeWebRtc.sendAnswer({
                 isPk: true,
-                sender: data.sender,
-                receiver: data.receiver,
+                sender: mySocketId.value,
+                // data.data.receiver是接收者;我们现在new pc,发送者是自己,接收者肯定是房主,不能是data.data.receiver,因为data.data.receiver是自己
+                receiver: data.sender,
                 sdp: data.sdp,
               });
             } else {
@@ -614,16 +632,28 @@ export const useWebsocket = () => {
         } else {
           if (data.receiver === mySocketId.value) {
             console.warn('是发给我的nativeWebRtcOffer');
+            await nativeWebRtc.newWebrtc({
+              isAnchor: true,
+              // 因为这里是收到offer,而offer是房主发的,所以此时的data.data.sender是房主;data.data.receiver是接收者;
+              // 但是这里的nativeWebRtc的sender,得是自己,不能是data.data.sender,不要混淆
+              sender: mySocketId.value,
+              receiver: data.sender,
+              videoEl: createVideo({
+                appendChild: true,
+              }),
+            });
             await nativeWebRtc.sendAnswer({
               isPk: false,
-              sender: data.sender,
-              receiver: data.receiver,
+              sender: mySocketId.value,
+              // data.data.receiver是接收者;我们现在new pc,发送者是自己,接收者肯定是房主,不能是data.data.receiver,因为data.data.receiver是自己
+              receiver: data.sender,
               sdp: data.sdp,
             });
           } else {
             console.error('不是发给我的nativeWebRtcOffer');
           }
         }
+        return '1';
       }
     );
 
@@ -634,10 +664,10 @@ export const useWebsocket = () => {
         console.log('收到nativeWebRtcAnswer', data);
         if (data.receiver === mySocketId.value) {
           console.warn('是发给我的nativeWebRtcAnswer');
-          const rtc = networkStore.getRtcMap(
-            `${mySocketId.value}___${roomId.value}`
-          )!;
-          await rtc.setRemoteDescription(data.sdp);
+          const rtc = networkStore.getRtcMap(data.sender);
+          if (rtc) {
+            await rtc.setRemoteDescription(data.sdp);
+          }
         } else {
           console.error('不是发给我的nativeWebRtcAnswer');
         }
@@ -651,9 +681,7 @@ export const useWebsocket = () => {
         console.log('收到nativeWebRtcCandidate', data);
         if (data.receiver === mySocketId.value) {
           console.warn('是发给我的nativeWebRtcCandidate');
-          const rtc = networkStore.getRtcMap(
-            `${mySocketId.value}___${roomId.value}`
-          )!;
+          const rtc = networkStore.getRtcMap(data.sender);
           rtc?.addIceCandidate(data.candidate);
         } else {
           console.error('不是发给我的nativeWebRtcCandidate');
@@ -772,13 +800,6 @@ export const useWebsocket = () => {
       prettierReceiveWsMsg(WsMsgTypeEnum.joined, data);
       appStore.setLiveRoomInfo(data.live_room);
       anchorInfo.value = data.anchor_info;
-      ws.send<WsGetLiveUserType['data']>({
-        requestId: getRandomString(8),
-        msgType: WsMsgTypeEnum.getLiveUser,
-        data: {
-          live_room_id: data.live_room_id,
-        },
-      });
     });
 
     // 其他用户加入房间
@@ -796,26 +817,30 @@ export const useWebsocket = () => {
         send_msg_time: +new Date(),
       };
       damuList.value.push(danmu);
-      ws.send<WsGetLiveUserType['data']>({
-        requestId,
-        msgType: WsMsgTypeEnum.getLiveUser,
-        data: {
-          live_room_id: data.live_room.id!,
-        },
-      });
-      if (!isPull.value && !isSRS.value) {
-        if (!roomLiving.value) return;
-      }
-      if (
-        [LiveRoomTypeEnum.user_wertc, LiveRoomTypeEnum.user_pk].includes(
-          data.live_room.type!
-        )
-      ) {
+      if (data.live_room.type === LiveRoomTypeEnum.user_wertc) {
         isSRS.value = false;
         nativeWebRtc.sendOffer({
           sender: mySocketId.value,
           receiver: data.join_socket_id,
         });
+      } else {
+        data.socket_list.forEach((item) => {
+          if (item !== mySocketId.value) {
+            if (
+              [
+                LiveRoomTypeEnum.user_wertc,
+                LiveRoomTypeEnum.user_wertc_meeting,
+                LiveRoomTypeEnum.user_pk,
+              ].includes(data.live_room.type!)
+            ) {
+              isSRS.value = false;
+              nativeWebRtc.sendOffer({
+                sender: mySocketId.value,
+                receiver: item,
+              });
+            }
+          }
+        });
       }
     });
 
@@ -830,12 +855,7 @@ export const useWebsocket = () => {
       if (anchorSocketId.value === data.socket_id) {
         roomLiving.value = false;
       }
-      networkStore.rtcMap.get(`${roomId.value}`)?.close();
       networkStore.removeRtc(`${roomId.value}`);
-      // const res = liveUserList.value.filter(
-      //   (item) => item.id !== data.socket_id
-      // );
-      // liveUserList.value = res;
       damuList.value.push({
         live_room_id: Number(roomId.value),
         socket_id: data.socket_id,

+ 28 - 5
src/layout/pc/head/index.vue

@@ -245,9 +245,6 @@
           </template>
           <template #list>
             <div class="list">
-              <a class="item">
-                <div class="txt">{{ t('layout.tencentCssLive') }}</div>
-              </a>
               <a
                 class="item"
                 @click.prevent="handleStartLive(LiveRoomTypeEnum.user_srs)"
@@ -260,6 +257,14 @@
               >
                 <div class="txt">{{ t('layout.webrtcLive') }}</div>
               </a>
+              <a
+                class="item"
+                @click.prevent="
+                  handleStartLive(LiveRoomTypeEnum.user_wertc_meeting)
+                "
+              >
+                <div class="txt">{{ t('layout.webrtcMeeting') }}</div>
+              </a>
               <a
                 class="item"
                 @click.prevent="handleStartLive(LiveRoomTypeEnum.user_msr)"
@@ -272,6 +277,13 @@
               >
                 <div class="txt">{{ t('layout.pkLive') }}</div>
               </a>
+              <a class="item">
+                <div class="txt">{{ t('layout.tencentCssLive') }}</div>
+              </a>
+              <a class="item">
+                <div class="txt">{{ t('layout.tencentCssPkLive') }}</div>
+              </a>
+              <div class="tip"><div class="tip-txt">有什么区别?</div></div>
             </div>
           </template>
         </Dropdown>
@@ -695,7 +707,6 @@ function handleStartLive(key: LiveRoomTypeEnum) {
 
       .start-live {
         margin-right: 20px;
-
         .btn {
           padding: 5px 15px;
           border-radius: 6px;
@@ -705,7 +716,9 @@ function handleStartLive(key: LiveRoomTypeEnum) {
           cursor: pointer;
         }
         .list {
-          width: 150px;
+          width: 180px;
+          position: relative;
+
           .item {
             display: flex;
             align-items: center;
@@ -722,6 +735,16 @@ function handleStartLive(key: LiveRoomTypeEnum) {
               cursor: not-allowed;
             }
           }
+          .tip {
+            display: flex;
+            justify-content: flex-end;
+            padding-right: 6px;
+            color: rgba(60, 60, 60, 0.7);
+            font-size: 12px;
+            .tip-txt {
+              cursor: pointer;
+            }
+          }
         }
       }
       .qqlogin {

+ 3 - 1
src/locales/en/layout.ts

@@ -32,9 +32,11 @@ export default nameSpaceWrap('layout', {
   officialGroup: 'Official Group',
   release: 'Version Release',
 
-  tencentCssLive: 'Tencent Css Live',
   srsLive: 'SRS Live',
   webrtcLive: 'WebRTC Live',
+  webrtcMeeting: 'WebRTC Meeting',
   msrLive: 'Msr Live',
   pkLive: 'PK Live',
+  tencentCssLive: 'Tencent Css Live',
+  tencentCssPkLive: 'Tencent Css PK',
 });

+ 7 - 5
src/locales/zh/layout.ts

@@ -32,9 +32,11 @@ export default nameSpaceWrap('layout', {
   officialGroup: '官方群',
   release: '版本发布',
 
-  tencentCssLive: '腾讯云开播',
-  srsLive: 'SRS开播',
-  webrtcLive: 'WebRTC开播',
-  msrLive: 'Msr开播',
-  pkLive: '一对一打PK',
+  srsLive: 'SRS直播(推荐)',
+  webrtcLive: 'WebRTC直播(低延迟)',
+  webrtcMeeting: 'WebRTC会议(低延迟)',
+  msrLive: 'Msr直播(b站实现)',
+  pkLive: '打PK直播(互动)',
+  tencentCssLive: '腾讯云直播(CDN)',
+  tencentCssPkLive: '腾讯云打PK(CDN)',
 });

+ 20 - 22
src/network/webRTC.ts

@@ -80,7 +80,7 @@ export class WebRTCClass {
   /** 分辨率 */
   resolutionRatio = -1;
 
-  localStream?: MediaStream;
+  localStream?: MediaStream | null;
 
   isSRS: boolean;
 
@@ -216,10 +216,7 @@ export class WebRTCClass {
         });
       }
     });
-    // if (addTrack.length) {
-    //   appStore.setAllTrack([...appStore.allTrack, ...addTrack]);
-    // }
-    this.localStream = stream;
+    // this.localStream = stream;
     appStore.pkStream = stream;
   };
 
@@ -407,22 +404,16 @@ export class WebRTCClass {
       if (event.candidate) {
         const networkStore = useNetworkStore();
         console.log('准备发送candidate', event.candidate.candidate);
-        const roomId = this.roomId.split('___')[1];
-        console.log({
-          roomId,
-          sender: this.sender,
-          receiver: this.receiver,
-        });
-        networkStore.wsMap.get(roomId)?.send<WsCandidateType['data']>({
+        networkStore.wsMap.get(this.roomId)?.send<WsCandidateType['data']>({
           requestId: getRandomString(8),
           msgType: this.isSRS
             ? WsMsgTypeEnum.srsCandidate
             : WsMsgTypeEnum.nativeWebRtcCandidate,
           data: {
             candidate: event.candidate,
-            sender: this.isAnchor ? this.sender : this.receiver,
-            receiver: this.isAnchor ? this.receiver : this.sender,
-            live_room_id: Number(roomId),
+            sender: this.sender,
+            receiver: this.receiver,
+            live_room_id: Number(this.roomId),
           },
         });
       } else {
@@ -447,6 +438,7 @@ export class WebRTCClass {
         if (iceConnectionState === 'connected') {
           // ICE 代理至少对每个候选发现了一个可用的连接,此时仍然会继续测试远程候选以便发现更优的连接。同时可能在继续收集候选。
           console.warn(this.roomId, 'iceConnectionState:connected', event);
+          console.warn('webrtc连接成功!');
         }
         if (iceConnectionState === 'completed') {
           // ICE 代理已经发现了可用的连接,不再测试远程候选。
@@ -551,17 +543,23 @@ export class WebRTCClass {
 
   // 手动关闭webrtc连接
   close = () => {
-    this.prettierLog('手动关闭webrtc连接', 'warn');
-    this.peerConnection?.getSenders().forEach((sender) => {
-      this.peerConnection?.removeTrack(sender);
-    });
-    this.peerConnection?.close();
-    this.peerConnection = null;
+    try {
+      this.prettierLog('手动关闭webrtc连接', 'warn');
+      this.localStream?.getTracks().forEach((track) => {
+        track.stop();
+      });
+      this.localStream = null;
+      this.peerConnection?.close();
+      this.peerConnection = null;
+      this.videoEl.remove();
+    } catch (error) {
+      console.error('手动关闭webrtc连接失败', error);
+    }
   };
 
   // 更新store
   update = () => {
     const networkStore = useNetworkStore();
-    networkStore.updateRtcMap(this.roomId, this);
+    networkStore.updateRtcMap(this.receiver, this);
   };
 }

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

@@ -33,9 +33,17 @@ export const useNetworkStore = defineStore('network', {
       }
     },
     removeRtc(roomId: string) {
+      const old = this.rtcMap.get(roomId);
+      if (old) {
+        old.close();
+      }
       this.rtcMap.delete(roomId);
     },
     removeWs(roomId: string) {
+      const old = this.wsMap.get(roomId);
+      if (old) {
+        old.close();
+      }
       this.wsMap.delete(roomId);
     },
     getRtcMap(roomId: string) {

+ 11 - 7
src/types/ILiveRoom.ts

@@ -11,20 +11,24 @@ export enum LiveRoomUseCDNEnum {
 
 /** 直播间类型 */
 export enum LiveRoomTypeEnum {
-  /** 系统直播 */
+  /** 系统推流 */
   system,
-  /** 主播使用webrtc直播 */
+  /** 主播使用webrtc推流,直播 */
   user_wertc,
-  /** 主播使用srs直播 */
+  /** 主播使用webrtc推流,会议 */
+  user_wertc_meeting,
+  /** 主播使用srs推流 */
   user_srs,
-  /** 主播使用腾讯云css直播 */
-  user_tencent_css,
-  /** 主播使用obs/ffmpeg直播 */
+  /** 主播使用obs/ffmpeg推流 */
   user_obs,
-  /** 主播使用msr直播 */
+  /** 主播使用msr推流 */
   user_msr,
   /** 主播打pk */
   user_pk,
+  /** 主播使用腾讯云css推流 */
+  user_tencent_css,
+  /** 主播使用腾讯云css推流打pk */
+  user_tencent_css_pk,
 }
 
 /** 拉流是否需要鉴权 */

+ 1 - 0
src/types/websocket.ts

@@ -169,6 +169,7 @@ export type WsOtherJoinType = IWsFormat<{
   live_room_user_info: IUser;
   join_user_info?: IUser;
   join_socket_id: string;
+  socket_list: string[];
 }>;
 
 /** 开始直播 */