shuisheng 2 gadi atpakaļ
vecāks
revīzija
069327575c

+ 1 - 0
package.json

@@ -47,6 +47,7 @@
     "naive-ui": "^2.34.3",
     "pinia": "^2.0.33",
     "qrcode": "^1.5.3",
+    "sdp-transform": "^2.14.1",
     "socket.io-client": "^4.6.1",
     "unplugin-vue-components": "^0.24.1",
     "vconsole": "^3.15.0",

+ 3 - 0
pnpm-lock.yaml

@@ -50,6 +50,9 @@ dependencies:
   qrcode:
     specifier: ^1.5.3
     version: 1.5.3
+  sdp-transform:
+    specifier: ^2.14.1
+    version: 2.14.1
   socket.io-client:
     specifier: ^4.6.1
     version: 4.6.1

+ 40 - 25
src/hooks/use-pull.ts

@@ -3,13 +3,7 @@ import { useRoute } from 'vue-router';
 
 import { useFlvPlay, useHlsPlay } from '@/hooks/use-play';
 import { useWs } from '@/hooks/use-ws';
-import {
-  DanmuMsgTypeEnum,
-  IDanmu,
-  IMessage,
-  IUpdateJoinInfo,
-  liveTypeEnum,
-} from '@/interface';
+import { DanmuMsgTypeEnum, IDanmu, IMessage, liveTypeEnum } from '@/interface';
 import { WsMsgTypeEnum } from '@/network/webSocket';
 import { useAppStore } from '@/store/app';
 import { useNetworkStore } from '@/store/network';
@@ -43,6 +37,7 @@ export function usePull({
       socketId: string;
     }[]
   >([]);
+  const videoElArr = ref<HTMLVideoElement[]>([]);
 
   const {
     getSocketId,
@@ -70,6 +65,9 @@ export function usePull({
     () => localStream,
     async (stream) => {
       if (stream.value) {
+        console.log('localStream变了');
+        console.log('音频轨:', stream.value?.getAudioTracks());
+        console.log('视频轨:', stream.value?.getVideoTracks());
         if (roomLiveType.value === liveTypeEnum.srsFlvPull) {
           if (!autoplayVal.value) return;
           const { width, height } = await startFlvPlay({
@@ -95,21 +93,38 @@ export function usePull({
           });
           videoLoading.value = false;
         } else if (roomLiveType.value === liveTypeEnum.webrtcPull) {
-          const videoEl = createVideo({
-            muted: appStore.muted,
-            autoplay: true,
+          videoElArr.value.forEach((dom) => {
+            dom.remove();
           });
-          videoEl.srcObject = stream.value;
-          canvasRef.value?.childNodes?.forEach((item) => {
-            item.remove();
+          stream.value?.getVideoTracks().forEach((track) => {
+            console.log('视频轨enabled:', track.id, track.enabled);
+            const video = createVideo({});
+            video.id = track.id;
+            video.srcObject = new MediaStream([track]);
+            canvasRef.value?.appendChild(video);
+            videoElArr.value.push(video);
           });
-          canvasRef.value?.appendChild(videoEl);
-          videoLoading.value = false;
-        } else {
-          canvasRef.value?.childNodes?.forEach((item) => {
-            item.remove();
+          stream.value?.getAudioTracks().forEach((track) => {
+            console.log('音频轨enabled:', track.id, track.enabled);
+            const video = createVideo({});
+            video.id = track.id;
+            video.srcObject = new MediaStream([track]);
+            canvasRef.value?.appendChild(video);
+            videoElArr.value.push(video);
           });
+          // videoEl.srcObject = stream.value;
+          // canvasRef.value?.childNodes?.forEach((item) => {
+          //   item.remove();
+          // });
+          // canvasRef.value?.appendChild(videoEl);
+          videoLoading.value = false;
+        } else if (roomLiveType.value === liveTypeEnum.srsWebrtcPull) {
+          console.log('lllll');
         }
+      } else {
+        videoElArr.value?.forEach((item) => {
+          item.remove();
+        });
       }
     },
     { deep: true }
@@ -124,13 +139,13 @@ export function usePull({
       if (userInfo && connected) {
         const instance = networkStore.wsMap.get(roomId.value);
         if (!instance) return;
-        const data: IUpdateJoinInfo['data'] = {
-          live_room_id: Number(roomId.value),
-        };
-        instance.send({
-          msgType: WsMsgTypeEnum.updateJoinInfo,
-          data,
-        });
+        // const data: IUpdateJoinInfo['data'] = {
+        //   live_room_id: Number(roomId.value),
+        // };
+        // instance.send({
+        //   msgType: WsMsgTypeEnum.updateJoinInfo,
+        //   data,
+        // });
       }
     }
   );

+ 7 - 8
src/hooks/use-pull22.ts

@@ -16,7 +16,6 @@ import {
   IMessage,
   IOffer,
   IOtherJoin,
-  IUpdateJoinInfo,
   LiveRoomTypeEnum,
   liveTypeEnum,
 } from '@/interface';
@@ -144,13 +143,13 @@ export function usePull({
       if (userInfo && connected) {
         const instance = networkStore.wsMap.get(roomId.value);
         if (!instance) return;
-        const data: IUpdateJoinInfo['data'] = {
-          live_room_id: Number(roomId.value),
-        };
-        instance.send({
-          msgType: WsMsgTypeEnum.updateJoinInfo,
-          data,
-        });
+        // const data: IUpdateJoinInfo['data'] = {
+        //   live_room_id: Number(roomId.value),
+        // };
+        // instance.send({
+        //   msgType: WsMsgTypeEnum.updateJoinInfo,
+        //   data,
+        // });
       }
     }
   );

+ 108 - 22
src/hooks/use-ws.ts

@@ -155,6 +155,15 @@ export const useWs = () => {
       console.log('旧的allTrack音频轨', localStream.value?.getAudioTracks());
       console.log('旧的allTrack视频轨', localStream.value?.getVideoTracks());
       localStream.value = mixedStream;
+      if (isSRS.value) {
+        networkStore.rtcMap.forEach((rtc) => {
+          rtc.close();
+        });
+        startNewWebRtc({
+          receiver: 'srs',
+          videoEl: localVideo.value,
+        });
+      }
     },
     { deep: true }
   );
@@ -206,7 +215,7 @@ export const useWs = () => {
       networkStore.rtcMap.forEach((rtc) => {
         const sender = rtc.peerConnection
           ?.getSenders()
-          .find((sender) => sender.track === addTrackInfo.track);
+          .find((sender) => sender.track?.id === addTrackInfo.track.id);
         if (!sender) {
           rtc.peerConnection?.addTrack(addTrackInfo.track, addTrackInfo.stream);
         }
@@ -219,27 +228,49 @@ export const useWs = () => {
     console.log('addTrack后结果的音频轨', mixedStream.getAudioTracks());
     console.log('addTrack后结果的视频轨', mixedStream.getVideoTracks());
     localStream.value = mixedStream;
+    let resUrl = '';
+    const rtmpUrl = userStore.userInfo?.live_rooms?.[0].rtmp_url!;
+    if (rtmpUrl.indexOf('type=') === -1) {
+      resUrl += `${rtmpUrl}&type=${
+        isSRS.value ? LiveRoomTypeEnum.user_srs : LiveRoomTypeEnum.user_wertc
+      }`;
+    } else {
+      resUrl = rtmpUrl.replace(
+        /type=([0-9]+)/,
+        `type=${
+          isSRS.value ? LiveRoomTypeEnum.user_srs : LiveRoomTypeEnum.user_wertc
+        }`
+      );
+    }
     const data: IUpdateJoinInfo['data'] = {
       live_room_id: Number(roomId.value),
       track: {
         audio: appStore.getTrackInfo().audio > 0 ? 1 : 2,
         video: appStore.getTrackInfo().video > 0 ? 1 : 2,
       },
+      rtmp_url: resUrl,
     };
     networkStore.wsMap.get(roomId.value)?.send({
       msgType: WsMsgTypeEnum.updateJoinInfo,
       data,
     });
+    setTimeout(() => {
+      networkStore.wsMap.get(roomId.value)?.send({
+        msgType: WsMsgTypeEnum.updateJoinInfo,
+        data,
+      });
+    }, 1000);
   }
   function delTrack(delTrackInfo: AppRootState['allTrack'][0]) {
     if (isAnchor.value) {
       networkStore.rtcMap.forEach((rtc) => {
         const sender = rtc.peerConnection
           ?.getSenders()
-          .find((sender) => sender.track === delTrackInfo.track);
+          .find((sender) => sender.track?.id === delTrackInfo.track.id);
         if (sender) {
-          console.log('删除track', sender);
+          console.log('删除track', delTrackInfo, sender);
           rtc.peerConnection?.removeTrack(sender);
+          sender.replaceTrack(null);
         }
       });
     }
@@ -251,12 +282,27 @@ export const useWs = () => {
     console.log('delTrack后结果的音频轨', mixedStream.getAudioTracks());
     console.log('delTrack后结果的视频轨', mixedStream.getVideoTracks());
     localStream.value = mixedStream;
+    let resUrl = '';
+    const rtmpUrl = userStore.userInfo?.live_rooms?.[0].rtmp_url!;
+    if (rtmpUrl.indexOf('type=') === -1) {
+      resUrl += `${rtmpUrl}&type=${
+        isSRS.value ? LiveRoomTypeEnum.user_srs : LiveRoomTypeEnum.user_wertc
+      }`;
+    } else {
+      resUrl = rtmpUrl.replace(
+        /type=([0-9]+)/,
+        `type=${
+          isSRS.value ? LiveRoomTypeEnum.user_srs : LiveRoomTypeEnum.user_wertc
+        }`
+      );
+    }
     const data: IUpdateJoinInfo['data'] = {
       live_room_id: Number(roomId.value),
       track: {
         audio: appStore.getTrackInfo().audio > 0 ? 1 : 2,
         video: appStore.getTrackInfo().video > 0 ? 1 : 2,
       },
+      rtmp_url: resUrl,
     };
     networkStore.wsMap.get(roomId.value)?.send({
       msgType: WsMsgTypeEnum.updateJoinInfo,
@@ -319,6 +365,10 @@ export const useWs = () => {
         ),
         tid: getRandomString(10),
       });
+      if (res.data.code !== 0) {
+        console.error('/rtc/v1/publish/拿不到sdp');
+        return;
+      }
       await rtc.setRemoteDescription(
         new RTCSessionDescription({ type: 'answer', sdp: res.data.sdp })
       );
@@ -344,6 +394,20 @@ export const useWs = () => {
   function sendJoin() {
     const instance = networkStore.wsMap.get(roomId.value);
     if (!instance) return;
+    let resUrl = '';
+    const rtmpUrl = userStore.userInfo?.live_rooms?.[0].rtmp_url!;
+    if (rtmpUrl.indexOf('type=') === -1) {
+      resUrl += `${rtmpUrl}&type=${
+        isSRS.value ? LiveRoomTypeEnum.user_srs : LiveRoomTypeEnum.user_wertc
+      }`;
+    } else {
+      resUrl = rtmpUrl.replace(
+        /type=([0-9]+)/,
+        `type=${
+          isSRS.value ? LiveRoomTypeEnum.user_srs : LiveRoomTypeEnum.user_wertc
+        }`
+      );
+    }
     const joinData: IJoin['data'] = {
       live_room: {
         id: Number(roomId.value),
@@ -352,6 +416,7 @@ export const useWs = () => {
         type: isSRS.value
           ? LiveRoomTypeEnum.user_srs
           : LiveRoomTypeEnum.user_wertc,
+        rtmp_url: resUrl,
       },
       track: {
         audio: appStore.getTrackInfo().audio > 0 ? 1 : 2,
@@ -368,6 +433,7 @@ export const useWs = () => {
     console.warn(`${data.roomId},开始监听pc的negotiationneeded`);
     const rtc = networkStore.getRtcMap(data.roomId);
     if (!rtc) return;
+    console.warn(`监听pc的negotiationneeded`);
     rtc.peerConnection?.addEventListener('negotiationneeded', (event) => {
       console.warn(`${data.roomId},pc收到negotiationneeded`, event);
       sendOffer({
@@ -392,25 +458,35 @@ export const useWs = () => {
         maxBitrate: currentMaxBitrate.value,
         maxFramerate: currentMaxFramerate.value,
         resolutionRatio: currentResolutionRatio.value,
-        roomId: `${roomId.value}___${getSocketId()}`,
+        roomId: `${roomId.value}___${receiver!}`,
         videoEl,
         isSRS: true,
         direction: 'sendonly',
         receiver,
       });
-      handleNegotiationneeded({
-        roomId: `${roomId.value}___${receiver}`,
-        isSRS: true,
-      });
+      // handleNegotiationneeded({
+      //   roomId: `${roomId.value}___${receiver}`,
+      //   isSRS: true,
+      // });
+      rtc.peerConnection?.addTransceiver('audio', { direction: 'sendonly' });
+      // rtc.peerConnection?.addTransceiver('video', { direction: 'sendonly' });
       rtc.localStream = localStream.value;
       localStream.value?.getTracks().forEach((track) => {
-        console.warn('srs startNewWebRtc,pc插入track');
+        console.warn(
+          'srs startNewWebRtc,pc插入track',
+          track.id,
+          localStream.value?.id
+        );
         // rtc.peerConnection?.addTransceiver(track, {
         //   streams: [localStream.value!],
         //   direction: 'sendonly',
         // });
         rtc.peerConnection?.addTrack(track, localStream.value!);
       });
+      sendOffer({
+        sender: getSocketId(),
+        receiver,
+      });
     } else {
       console.warn('开始new WebRTCClass', `${roomId.value}___${receiver!}`);
       rtc = new WebRTCClass({
@@ -423,19 +499,20 @@ export const useWs = () => {
         direction: 'sendonly',
         receiver,
       });
-      handleNegotiationneeded({
-        roomId: `${roomId.value}___${receiver}`,
-        isSRS: false,
-      });
-      rtc.localStream = localStream.value;
-      localStream.value?.getTracks().forEach((track) => {
-        console.warn('startNewWebRtc,pc插入track');
-        // rtc.peerConnection?.addTransceiver(track, {
-        //   streams: [localStream.value!],
-        //   direction: 'sendonly',
-        // });
-        rtc.peerConnection?.addTrack(track, localStream.value!);
-      });
+      if (isAnchor.value) {
+        handleNegotiationneeded({
+          roomId: `${roomId.value}___${receiver}`,
+          isSRS: false,
+        });
+        rtc.localStream = localStream.value;
+        localStream.value?.getTracks().forEach((track) => {
+          // rtc.peerConnection?.addTransceiver(track, {
+          //   streams: [localStream.value!],
+          //   direction: 'sendonly',
+          // });
+          rtc.peerConnection?.addTrack(track, localStream.value!);
+        });
+      }
     }
     return rtc;
   }
@@ -592,6 +669,13 @@ export const useWs = () => {
       if (!isAnchor.value) {
         liveRoomInfo.value = data.data;
       }
+      // 如果是srs开播,则不需要等有人进来了才new webrtc,只要Websocket连上了就开始new webrtc
+      if (isSRS.value) {
+        startNewWebRtc({
+          receiver: 'srs',
+          videoEl: localVideo.value,
+        });
+      }
     });
 
     // 其他用户加入房间
@@ -608,6 +692,8 @@ export const useWs = () => {
         msg: '',
       };
       damuList.value.push(danmu);
+      // 如果是srs开播,且进来的用户不是srs-webrtc-pull,则不能再new webrtc了
+      if (isSRS.value) return;
       if (joined.value) {
         startNewWebRtc({
           receiver: data.data.join_socket_id,

+ 1 - 0
src/interface.ts

@@ -338,6 +338,7 @@ export interface IUpdateJoinInfo {
   data: {
     live_room_id: number;
     track?: { audio: number; video: number };
+    rtmp_url: string;
   };
 }
 

+ 104 - 46
src/network/webRTC.ts

@@ -90,53 +90,81 @@ export class WebRTCClass {
     console.log('原本旧track的音频轨', this.localStream?.getAudioTracks());
 
     const appStore = useAppStore();
-    const allTrack: AppRootState['allTrack'] = [];
+    if (isCb) {
+      stream.onremovetrack = (event) => {
+        console.log('onremovetrack事件', event);
+        const res = appStore.allTrack.filter((info) => {
+          if (info.track.id === event.track.id) {
+            return false;
+          }
+          return true;
+        });
+        appStore.setAllTrack(res);
+      };
+    }
+
+    const addTrack: AppRootState['allTrack'] = [];
 
     this.localStream?.getVideoTracks().forEach((track) => {
-      allTrack.push({
-        id: getRandomString(8),
-        track,
-        stream,
-        audio: 2,
-        video: 1,
-        type: MediaTypeEnum.screen,
-        mediaName: '',
-      });
+      if (!appStore.allTrack.find((info) => info.track.id === track.id)) {
+        addTrack.push({
+          id: getRandomString(8),
+          track,
+          stream,
+          audio: 2,
+          video: 1,
+          type: MediaTypeEnum.screen,
+          mediaName: '',
+          streamid: stream.id,
+        });
+      }
     });
     this.localStream?.getAudioTracks().forEach((track) => {
-      allTrack.push({
-        id: getRandomString(8),
-        track,
-        stream,
-        audio: 1,
-        video: 2,
-        type: MediaTypeEnum.microphone,
-        mediaName: '',
-      });
+      if (!appStore.allTrack.find((info) => info.track.id === track.id)) {
+        addTrack.push({
+          id: getRandomString(8),
+          track,
+          stream,
+          audio: 1,
+          video: 2,
+          type: MediaTypeEnum.microphone,
+          mediaName: '',
+          streamid: stream.id,
+        });
+      }
     });
-    stream.getVideoTracks().forEach((track) =>
-      allTrack.push({
-        id: getRandomString(8),
-        track,
-        stream,
-        audio: 2,
-        video: 1,
-        type: MediaTypeEnum.screen,
-        mediaName: '',
-      })
-    );
-    stream.getAudioTracks().forEach((track) =>
-      allTrack.push({
-        id: getRandomString(8),
-        track,
-        stream,
-        audio: 1,
-        video: 2,
-        type: MediaTypeEnum.microphone,
-        mediaName: '',
-      })
-    );
-    appStore.setAllTrack(allTrack);
+    stream.getVideoTracks().forEach((track) => {
+      if (!appStore.allTrack.find((info) => info.track.id === track.id)) {
+        addTrack.push({
+          id: getRandomString(8),
+          track,
+          stream,
+          audio: 2,
+          video: 1,
+          type: MediaTypeEnum.screen,
+          mediaName: '',
+          streamid: stream.id,
+        });
+      }
+    });
+    stream.getAudioTracks().forEach((track) => {
+      if (!appStore.allTrack.find((info) => info.track.id === track.id)) {
+        addTrack.push({
+          id: getRandomString(8),
+          track,
+          stream,
+          audio: 1,
+          video: 2,
+          type: MediaTypeEnum.microphone,
+          mediaName: '',
+          streamid: stream.id,
+        });
+      }
+    });
+    console.log(addTrack.length, 'pppppo');
+    if (addTrack.length) {
+      appStore.setAllTrack([...appStore.allTrack, ...addTrack]);
+    }
     this.localStream = stream;
 
     if (this.maxBitrate !== -1) {
@@ -238,7 +266,37 @@ export class WebRTCClass {
       const description = await this.peerConnection.createOffer({
         iceRestart: true,
       });
-      this.prettierLog('createOffer成功', 'warn');
+      this.prettierLog('createOffer成功', 'warn', description);
+      // const sdpStr = description.sdp;
+
+      // const sdpObj = SDPTransform.parse(sdpStr);
+
+      // // Get all m-lines
+      // const mlines = sdpObj.media;
+
+      // // Map to store unique m-lines
+      // const mLineMap = new Map();
+
+      // mlines.forEach((mLine) => {
+      //   const key = `${mLine.type}_${mLine.port}`;
+      //   if (!mLineMap.has(key)) {
+      //     mLineMap.set(key, mLine);
+      //   }
+      // });
+
+      // // Clear media array and only keep m-lines from map
+      // sdpObj.media = [];
+
+      // mLineMap.forEach((mLine) => {
+      //   sdpObj.media.push(mLine);
+      // });
+
+      // // Write new SDP string
+      // const newSdpStr = SDPTransform.write(sdpObj);
+      // console.log('old', description.sdp);
+      // console.log('newSdpStr', newSdpStr);
+      // Use new SDP string ...
+      // description.sdp = newSdpStr;
       return description;
     } catch (error) {
       this.prettierLog('createOffer失败', 'error');
@@ -252,7 +310,7 @@ export class WebRTCClass {
     this.prettierLog('createAnswer开始', 'warn');
     try {
       const description = await this.peerConnection.createAnswer();
-      this.prettierLog('createAnswer成功', 'warn');
+      this.prettierLog('createAnswer成功', 'warn', description);
       return description;
     } catch (error) {
       this.prettierLog('createAnswer失败', 'error');
@@ -266,7 +324,7 @@ export class WebRTCClass {
     this.prettierLog('setLocalDescription开始', 'warn');
     try {
       await this.peerConnection.setLocalDescription(desc);
-      this.prettierLog('setLocalDescription成功', 'warn');
+      this.prettierLog('setLocalDescription成功', 'warn', desc);
     } catch (error) {
       this.prettierLog('setLocalDescription失败', 'error');
       console.error('setLocalDescription', desc);
@@ -280,7 +338,7 @@ export class WebRTCClass {
     this.prettierLog(`setRemoteDescription开始`, 'warn');
     try {
       await this.peerConnection.setRemoteDescription(desc);
-      this.prettierLog('setRemoteDescription成功', 'warn');
+      this.prettierLog('setRemoteDescription成功', 'warn', desc);
     } catch (error) {
       this.prettierLog('setRemoteDescription失败', 'error');
       console.error('setRemoteDescription', desc);

+ 1 - 0
src/store/app/index.ts

@@ -16,6 +16,7 @@ export type AppRootState = {
     type: MediaTypeEnum;
     track: MediaStreamTrack;
     stream: MediaStream;
+    streamid: string;
   }[];
 };
 

+ 10 - 3
src/views/home/index.vue

@@ -32,15 +32,22 @@
           >
             <div
               v-if="
-                currentLiveRoom.live_room?.type ===
-                  LiveRoomTypeEnum.user_wertc ||
-                currentLiveRoom.live_room?.type === LiveRoomTypeEnum.user_srs
+                currentLiveRoom.live_room?.type === LiveRoomTypeEnum.user_wertc
               "
               class="btn webrtc"
               @click="joinRoom()"
             >
               进入直播(webrtc)
             </div>
+            <div
+              v-if="
+                currentLiveRoom.live_room?.type === LiveRoomTypeEnum.user_srs
+              "
+              class="btn webrtc"
+              @click="joinRoom()"
+            >
+              进入直播(srs-webrtc)
+            </div>
             <div
               v-if="
                 currentLiveRoom.live_room?.type !== LiveRoomTypeEnum.user_wertc

+ 38 - 19
src/views/pull/index.vue

@@ -42,7 +42,12 @@
                 })`,
               }"
             ></div>
-            <div ref="canvasRef"></div>
+            <!-- <div ref="canvasRef"></div> -->
+            <div
+              ref="canvasRef"
+              class="media-list"
+              :class="{ item: appStore.allTrack.length > 1 }"
+            ></div>
             <AudioRoomTip></AudioRoomTip>
             <VideoControls></VideoControls>
           </div>
@@ -223,12 +228,14 @@ import {
   IGoods,
   liveTypeEnum,
 } from '@/interface';
+import { useAppStore } from '@/store/app';
 import { useUserStore } from '@/store/user';
 
 import RechargeCpt from './recharge/index.vue';
 
 const route = useRoute();
 const userStore = useUserStore();
+const appStore = useAppStore();
 
 const giftGoodsList = ref<IGoods[]>([]);
 const giftLoading = ref(false);
@@ -422,26 +429,38 @@ onMounted(() => {
 
           inset: 0;
         }
-        :deep(canvas) {
-          position: absolute;
-          top: 0;
-          left: 50%;
-          width: 100%;
-          height: 100%;
-          transform: translate(-50%);
-
-          user-select: none;
+        .media-list {
+          :deep(video) {
+            width: 100%;
+            height: 100%;
+          }
+          &.item {
+            :deep(video) {
+              width: 50%;
+              height: initial !important;
+            }
+          }
         }
-        :deep(video) {
-          position: absolute;
-          top: 0;
-          left: 50%;
-          width: 100%;
-          height: 100%;
-          transform: translate(-50%);
+        // :deep(canvas) {
+        //   position: absolute;
+        //   top: 0;
+        //   left: 50%;
+        //   width: 100%;
+        //   height: 100%;
+        //   transform: translate(-50%);
 
-          user-select: none;
-        }
+        //   user-select: none;
+        // }
+        // :deep(video) {
+        //   position: absolute;
+        //   top: 0;
+        //   left: 50%;
+        //   width: 100%;
+        //   height: 100%;
+        //   transform: translate(-50%);
+
+        //   user-select: none;
+        // }
 
         .controls {
           display: none;

+ 30 - 5
src/views/push/index.vue

@@ -13,6 +13,7 @@
           <div
             ref="localVideoRef"
             class="media-list"
+            :class="{ item: appStore.allTrack.length > 1 }"
           ></div>
           <!-- <video
             id="localVideo"
@@ -285,14 +286,13 @@ const appStore = useAppStore();
 const currentMediaType = ref(MediaTypeEnum.camera);
 const showSelectMediaModalCpt = ref(false);
 const showMediaModalCpt = ref(false);
-const liveType = route.query.liveType;
 const topRef = ref<HTMLDivElement>();
 const bottomRef = ref<HTMLDivElement>();
 const danmuListRef = ref<HTMLDivElement>();
 const containerRef = ref<HTMLDivElement>();
 const localVideoRef = ref<HTMLVideoElement>();
 const remoteVideoRef = ref<HTMLVideoElement[]>([]);
-
+const isSRS = route.query.liveType === liveTypeEnum.srsPush;
 const {
   confirmRoomName,
   getSocketId,
@@ -318,7 +318,7 @@ const {
 } = usePush({
   localVideoRef,
   remoteVideoRef,
-  isSRS: liveType === liveTypeEnum.srsPush,
+  isSRS,
 });
 
 watch(
@@ -362,7 +362,6 @@ async function addMediaOk(val: {
       },
       audio: true,
     });
-    const audio = event.getAudioTracks();
     const videoTrack = {
       id: getRandomString(8),
       audio: 2,
@@ -371,8 +370,17 @@ async function addMediaOk(val: {
       type: MediaTypeEnum.screen,
       track: event.getVideoTracks()[0],
       stream: event,
+      streamid: event.id,
     };
+    const audio = event.getAudioTracks();
     if (audio.length) {
+      if (
+        isSRS &&
+        appStore.allTrack.filter((item) => item.audio === 1).length >= 1
+      ) {
+        window.$message.error('srs模式最多只能有一个音频');
+        return;
+      }
       const autioTrack = {
         id: getRandomString(8),
         audio: 1,
@@ -381,6 +389,7 @@ async function addMediaOk(val: {
         type: MediaTypeEnum.screen,
         track: event.getAudioTracks()[0],
         stream: event,
+        streamid: event.id,
       };
       appStore.setAllTrack([...appStore.allTrack, videoTrack, autioTrack]);
       addTrack(videoTrack);
@@ -408,6 +417,7 @@ async function addMediaOk(val: {
       type: MediaTypeEnum.camera,
       track: event.getVideoTracks()[0],
       stream: event,
+      streamid: event.id,
     };
     appStore.setAllTrack([...appStore.allTrack, track]);
     addTrack(track);
@@ -417,6 +427,13 @@ async function addMediaOk(val: {
       video: false,
       audio: { deviceId: val.deviceId },
     });
+    if (
+      isSRS &&
+      appStore.allTrack.filter((item) => item.audio === 1).length >= 1
+    ) {
+      window.$message.error('srs模式最多只能有一个音频');
+      return;
+    }
     const track = {
       id: getRandomString(8),
       audio: 1,
@@ -425,6 +442,7 @@ async function addMediaOk(val: {
       type: MediaTypeEnum.microphone,
       track: event.getAudioTracks()[0],
       stream: event,
+      streamid: event.id,
     };
     appStore.setAllTrack([...appStore.allTrack, track]);
     addTrack(track);
@@ -478,7 +496,14 @@ function handleStartMedia(item: { type: MediaTypeEnum; txt: string }) {
         background-color: rgba($color: #000000, $alpha: 0.5);
         .media-list {
           :deep(video) {
-            width: 50%;
+            width: 100%;
+            height: 100%;
+          }
+          &.item {
+            :deep(video) {
+              width: 50%;
+              height: initial !important;
+            }
           }
         }