shuisheng 2 سال پیش
والد
کامیت
1703fca1e0

+ 19 - 0
src/hooks/use-play.ts

@@ -0,0 +1,19 @@
+import flvJs from 'flv.js';
+
+export function useFlvPlay(flvurl: string, videoEl: HTMLVideoElement) {
+  if (flvJs.isSupported()) {
+    const flvPlayer = flvJs.createPlayer({
+      type: 'flv',
+      url: flvurl,
+    });
+    flvPlayer.attachMediaElement(videoEl);
+    flvPlayer.load();
+    try {
+      flvPlayer.play();
+    } catch (error) {
+      console.log(error);
+    }
+  } else {
+    console.error('不支持flv');
+  }
+}

+ 14 - 0
src/interface.ts

@@ -1,4 +1,18 @@
 // 这里放项目里面的类型
+export interface ILive {
+  id?: number;
+  system?: number;
+  socketId?: string;
+  roomId?: string;
+  roomName?: string;
+  coverImg?: string;
+  streamurl?: string;
+  flvurl?: string;
+  created_at?: string;
+  updated_at?: string;
+  deleted_at?: string;
+}
+
 export enum LiveTypeEnum {
   camera,
   screen,

+ 6 - 0
src/router/index.ts

@@ -15,6 +15,7 @@ export const routerName = {
   webrtcPull: 'webrtcPull',
   srsWebRtcPush: 'srsWebRtcPush',
   srsWebRtcPull: 'srsWebRtcPull',
+  srsFlvPull: 'srsFlvPull',
 };
 
 // 默认路由
@@ -63,6 +64,11 @@ export const defaultRoutes: RouteRecordRaw[] = [
         path: '/srs-webrtc-pull/:roomId',
         component: () => import('@/views/srs-webrtc-pull/index.vue'),
       },
+      {
+        name: routerName.srsFlvPull,
+        path: '/srs-flv-pull/:roomId',
+        component: () => import('@/views/srs-flv-pull/index.vue'),
+      },
     ],
   },
   {

+ 78 - 43
src/views/home/index.vue

@@ -4,13 +4,37 @@
       class="left"
       :style="{ backgroundImage: `url(${currentLiveRoom?.coverImg})` }"
     >
-      <video src=""></video>
+      <video
+        v-if="currentLiveRoom?.flvurl"
+        id="localVideo"
+        ref="localVideoRef"
+        autoplay
+        webkit-playsinline="true"
+        playsinline
+        x-webkit-airplay="allow"
+        x5-video-player-type="h5"
+        x5-video-player-fullscreen="true"
+        x5-video-orientation="portraint"
+        muted
+        controls
+      ></video>
       <div
-        v-if="liveRoomList.length"
-        class="btn"
-        @click="joinRoom()"
+        v-if="currentLiveRoom"
+        class="btn-wrap"
       >
-        进入直播
+        <div
+          class="btn webrtc"
+          @click="joinRoom()"
+        >
+          进入直播(webrtc)
+        </div>
+        <div
+          v-if="currentLiveRoom?.flvurl"
+          class="btn flv"
+          @click="joinFlvRoom()"
+        >
+          进入直播(flv)
+        </div>
       </div>
     </div>
     <div class="right">
@@ -49,22 +73,18 @@
 </template>
 
 <script lang="ts" setup>
-import { onMounted, ref } from 'vue';
+import { nextTick, onMounted, ref } from 'vue';
 import { useRouter } from 'vue-router';
 
 import { fetchLiveList } from '@/api/live';
+import { useFlvPlay } from '@/hooks/use-play';
+import { ILive } from '@/interface';
 import { routerName } from '@/router';
 
-interface IRoom {
-  roomId: string;
-  roomName: string;
-  srs?: { streamurl: string };
-  coverImg: string;
-}
-
 const router = useRouter();
-const liveRoomList = ref<IRoom[]>([]);
-const currentLiveRoom = ref<IRoom>();
+const liveRoomList = ref<ILive[]>([]);
+const currentLiveRoom = ref<ILive>();
+const localVideoRef = ref<HTMLVideoElement>();
 
 async function getLiveRoomList() {
   try {
@@ -73,22 +93,14 @@ async function getLiveRoomList() {
       orderBy: 'desc',
     });
     if (res.code === 200) {
-      liveRoomList.value = res.data.rows.map((item) => {
-        return {
-          roomId: item.roomId,
-          roomName: JSON.parse(item.data).data.roomName,
-          coverImg: JSON.parse(item.data).data.coverImg,
-          srs: JSON.parse(item.data).data.srs,
-        };
-      });
+      liveRoomList.value = res.data.rows;
       if (res.data.total) {
-        const item = res.data.rows[0].data;
-        currentLiveRoom.value = {
-          roomId: res.data.rows[0].roomId,
-          roomName: JSON.parse(item).data.roomName,
-          coverImg: JSON.parse(item).data.coverImg,
-          srs: JSON.parse(item).data.srs,
-        };
+        currentLiveRoom.value = res.data.rows[0];
+        nextTick(() => {
+          if (currentLiveRoom.value?.flvurl) {
+            useFlvPlay(currentLiveRoom.value.flvurl, localVideoRef.value!);
+          }
+        });
       }
     }
   } catch (error) {
@@ -101,7 +113,7 @@ onMounted(() => {
 });
 
 function joinRoom() {
-  if (currentLiveRoom.value?.srs) {
+  if (currentLiveRoom.value?.streamurl) {
     router.push({
       name: routerName.srsWebRtcPull,
       params: { roomId: currentLiveRoom.value.roomId },
@@ -113,6 +125,13 @@ function joinRoom() {
     });
   }
 }
+
+function joinFlvRoom() {
+  router.push({
+    name: routerName.srsFlvPull,
+    params: { roomId: currentLiveRoom.value?.roomId },
+  });
+}
 </script>
 
 <style lang="scss" scoped>
@@ -133,27 +152,43 @@ function joinRoom() {
     background-color: papayawhip;
     vertical-align: top;
 
+    #localVideo {
+      width: 100%;
+      height: 100%;
+    }
+
     @extend %coverBg;
 
     &:hover {
-      .btn {
-        display: inline-block;
+      .btn-wrap {
+        display: inline-flex;
       }
     }
-    .btn {
+    .btn-wrap {
       position: absolute;
       top: 50%;
       left: 50%;
       display: none;
-      padding: 14px 26px;
-      border: 1px solid rgba($color: skyblue, $alpha: 0.3);
-      border-radius: 4px;
-      color: skyblue;
-      font-size: 16px;
-      cursor: pointer;
+      align-items: center;
       transform: translate(-50%, -50%);
-      &:hover {
-        background-color: rgba($color: skyblue, $alpha: 0.3);
+
+      .btn {
+        cursor: pointer;
+
+        padding: 14px 26px;
+        border: 2px solid rgba($color: skyblue, $alpha: 0.5);
+        border-radius: 6px;
+        background-color: rgba(0, 0, 0, 0.3);
+        color: skyblue;
+        font-size: 16px;
+        &:hover {
+          background-color: rgba($color: skyblue, $alpha: 0.5);
+        }
+        &.webrtc {
+          margin-right: 10px;
+        }
+        &.flv {
+        }
       }
     }
   }
@@ -230,6 +265,7 @@ function joinRoom() {
           box-sizing: border-box;
           padding: 4px 8px;
           width: 100%;
+          border-radius: 0 0 4px 4px;
           background-image: linear-gradient(
             -180deg,
             rgba(0, 0, 0, 0),
@@ -238,7 +274,6 @@ function joinRoom() {
           color: white;
           text-align: initial;
           font-size: 13px;
-          border-radius: 0 0 4px 4px;
         }
       }
     }

+ 562 - 0
src/views/srs-flv-pull/index.vue

@@ -0,0 +1,562 @@
+<template>
+  <div class="srt-webrtc-pull-wrap">
+    <template v-if="roomNoLive">当前房间没在直播~</template>
+    <template v-else>
+      <div class="left">
+        <div
+          ref="topRef"
+          class="head"
+        >
+          <div class="info">
+            <div class="avatar"></div>
+            <div class="detail">
+              <div class="top">房间名:{{ roomName }}</div>
+              <div class="bottom">
+                <span>你的socketId:{{ getSocketId() }}</span>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="video-wrap">
+          <video
+            id="localVideo"
+            ref="localVideoRef"
+            autoplay
+            webkit-playsinline="true"
+            playsinline
+            x-webkit-airplay="allow"
+            x5-video-player-type="h5"
+            x5-video-player-fullscreen="true"
+            x5-video-orientation="portraint"
+            muted
+            controls
+          ></video>
+        </div>
+        <div
+          ref="bottomRef"
+          class="gift"
+        >
+          <div
+            v-for="(item, index) in giftList"
+            :key="index"
+            class="item"
+          >
+            <div class="ico"></div>
+            <div class="name">{{ item.name }}</div>
+            <div class="price">{{ item.price }}</div>
+          </div>
+        </div>
+      </div>
+      <div class="right">
+        <div class="tab">
+          <span>在线用户</span>
+          <span> | </span>
+          <span>大航海</span>
+        </div>
+        <div class="user-list">
+          <div
+            v-for="(item, index) in liveUserList"
+            :key="index"
+            class="item"
+          >
+            <div class="info">
+              <div class="avatar"></div>
+              <div class="nickname">{{ item.socketId }}</div>
+            </div>
+            <div class="expr">{{ item.expr }}</div>
+          </div>
+        </div>
+        <div class="danmu-list">
+          <div
+            v-for="(item, index) in damuList"
+            :key="index"
+            class="item"
+          >
+            <template v-if="item.msgType === DanmuMsgTypeEnum.danmu">
+              <span class="name">{{ item.socketId }}:</span>
+              <span class="msg">{{ item.msg }}</span>
+            </template>
+            <template v-else-if="item.msgType === DanmuMsgTypeEnum.otherJoin">
+              <span class="name system">系统通知:</span>
+              <span class="msg">{{ item.socketId }}进入直播!</span>
+            </template>
+            <template v-else-if="item.msgType === DanmuMsgTypeEnum.userLeaved">
+              <span class="name system">系统通知:</span>
+              <span class="msg">{{ item.socketId }}离开直播!</span>
+            </template>
+          </div>
+        </div>
+        <div class="send-msg">
+          <textarea
+            v-model="danmuStr"
+            class="ipt"
+          ></textarea>
+          <div
+            class="btn"
+            @click="sendDanmu"
+          >
+            发送
+          </div>
+        </div>
+      </div>
+    </template>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { onMounted, onUnmounted, reactive, ref } from 'vue';
+import { useRoute } from 'vue-router';
+
+import { useFlvPlay } from '@/hooks/use-play';
+import { DanmuMsgTypeEnum, IAdminIn, IDanmu, ILiveUser } from '@/interface';
+import {
+  WebSocketClass,
+  WsConnectStatusEnum,
+  WsMsgTypeEnum,
+} from '@/network/webSocket';
+import { useNetworkStore } from '@/store/network';
+
+const networkStore = useNetworkStore();
+const route = useRoute();
+
+const topRef = ref<HTMLDivElement>();
+const bottomRef = ref<HTMLDivElement>();
+const localVideoRef = ref<HTMLVideoElement>();
+const track = reactive({
+  audio: true,
+  video: true,
+});
+const streamurl = ref();
+const flvurl = ref();
+const roomNoLive = ref(false);
+const roomId = ref('');
+const roomName = ref('');
+const danmuStr = ref('');
+const websocketInstant = ref<WebSocketClass>();
+const damuList = ref<IDanmu[]>([]);
+const liveUserList = ref<ILiveUser[]>([]);
+const giftList = ref([
+  { name: '鲜花', ico: '', price: '免费' },
+  { name: '肥宅水', ico: '', price: '2元' },
+  { name: '小鸡腿', ico: '', price: '3元' },
+  { name: '大鸡腿', ico: '', price: '5元' },
+  { name: '一杯咖啡', ico: '', price: '10元' },
+]);
+
+function closeWs() {
+  const instance = networkStore.wsMap.get(roomId.value);
+  if (!instance) return;
+  instance.close();
+}
+
+function closeRtc() {
+  networkStore.rtcMap.forEach((rtc) => {
+    rtc.close();
+  });
+}
+
+function getSocketId() {
+  return networkStore.wsMap.get(roomId.value!)?.socketIo?.id || '-1';
+}
+
+function sendJoin() {
+  const instance = networkStore.wsMap.get(roomId.value);
+  if (!instance) return;
+  instance.send({ msgType: WsMsgTypeEnum.join, data: {} });
+}
+
+function sendDanmu() {
+  if (!danmuStr.value.length) {
+    alert('请输入弹幕内容!');
+  }
+  if (!websocketInstant.value) return;
+  websocketInstant.value.send({
+    msgType: WsMsgTypeEnum.message,
+    data: { msg: danmuStr.value },
+  });
+  damuList.value.push({
+    socketId: getSocketId(),
+    msgType: DanmuMsgTypeEnum.danmu,
+    msg: danmuStr.value,
+  });
+  danmuStr.value = '';
+}
+
+function initReceive() {
+  const instance = websocketInstant.value;
+  if (!instance?.socketIo) return;
+  // websocket连接成功
+  instance.socketIo.on(WsConnectStatusEnum.connect, () => {
+    console.log('【websocket】websocket连接成功', instance.socketIo?.id);
+    if (!instance) return;
+    instance.status = WsConnectStatusEnum.connect;
+    instance.update();
+  });
+
+  // websocket连接断开
+  instance.socketIo.on(WsConnectStatusEnum.disconnect, () => {
+    console.log('【websocket】websocket连接断开', instance);
+    if (!instance) return;
+    instance.status = WsConnectStatusEnum.disconnect;
+    instance.update();
+  });
+
+  // 当前所有在线用户
+  instance.socketIo.on(WsMsgTypeEnum.roomLiveing, (data: IAdminIn) => {
+    console.log('【websocket】收到管理员正在直播', data);
+  });
+
+  // 当前所有在线用户
+  instance.socketIo.on(WsMsgTypeEnum.roomNoLive, (data: IAdminIn) => {
+    console.log('【websocket】收到管理员不在直播', data);
+    roomNoLive.value = true;
+    closeRtc();
+  });
+
+  // 当前所有在线用户
+  instance.socketIo.on(WsMsgTypeEnum.liveUser, (data) => {
+    console.log('【websocket】当前所有在线用户', data);
+    if (!instance) return;
+    liveUserList.value = data.map((item) => ({
+      avatar: 'red',
+      socketId: item.id,
+      expr: 1,
+    }));
+  });
+
+  // 收到用户发送消息
+  instance.socketIo.on(WsMsgTypeEnum.message, (data) => {
+    console.log('【websocket】收到用户发送消息', data);
+    if (!instance) return;
+    damuList.value.push({
+      socketId: data.socketId,
+      msgType: DanmuMsgTypeEnum.danmu,
+      msg: data.data.msg,
+    });
+  });
+
+  // 用户加入房间
+  instance.socketIo.on(WsMsgTypeEnum.joined, (data) => {
+    console.log('【websocket】用户加入房间完成', data);
+    roomName.value = data.roomName;
+    track.audio = data.track_audio;
+    track.video = data.track_video;
+    streamurl.value = data.streamurl;
+    flvurl.value = data.flvurl;
+    useFlvPlay(flvurl.value, localVideoRef.value!);
+  });
+
+  // 其他用户加入房间
+  instance.socketIo.on(WsMsgTypeEnum.otherJoin, (data) => {
+    console.log('【websocket】其他用户加入房间', data);
+    damuList.value.push({
+      socketId: data.socketId,
+      msgType: DanmuMsgTypeEnum.otherJoin,
+      msg: '',
+    });
+  });
+
+  // 用户离开房间
+  instance.socketIo.on(WsMsgTypeEnum.leave, (data) => {
+    console.log('【websocket】用户离开房间', data);
+    if (!instance) return;
+    instance.socketIo?.emit(WsMsgTypeEnum.leave, {
+      roomId: instance.roomId,
+    });
+  });
+
+  // 用户离开房间完成
+  instance.socketIo.on(WsMsgTypeEnum.leaved, (data) => {
+    console.log('【websocket】用户离开房间完成', data);
+    if (!instance) return;
+    const res = liveUserList.value.filter(
+      (item) => item.socketId !== data.socketId
+    );
+    liveUserList.value = res;
+    damuList.value.push({
+      socketId: data.socketId,
+      msgType: DanmuMsgTypeEnum.userLeaved,
+      msg: '',
+    });
+  });
+}
+
+onUnmounted(() => {
+  closeWs();
+});
+
+onMounted(() => {
+  if (topRef.value && bottomRef.value && localVideoRef.value) {
+    const res =
+      bottomRef.value.getBoundingClientRect().top -
+      (topRef.value.getBoundingClientRect().top +
+        topRef.value.getBoundingClientRect().height);
+    localVideoRef.value.style.height = `${res}px`;
+  }
+  roomId.value = route.params.roomId as string;
+  console.warn('开始new WebSocketClass');
+  websocketInstant.value = new WebSocketClass({
+    roomId: roomId.value,
+    url:
+      process.env.NODE_ENV === 'development'
+        ? 'ws://localhost:4300'
+        : 'wss://live.hsslive.cn',
+    isAdmin: false,
+  });
+  websocketInstant.value.update();
+  initReceive();
+  sendJoin();
+
+  localVideoRef.value?.addEventListener('loadstart', () => {
+    console.warn('视频流-loadstart');
+    const rtc = networkStore.getRtcMap(roomId.value);
+    if (!rtc) return;
+    rtc.rtcStatus.loadstart = true;
+    rtc.update();
+  });
+
+  localVideoRef.value?.addEventListener('loadedmetadata', () => {
+    console.warn('视频流-loadedmetadata');
+    const rtc = networkStore.getRtcMap(roomId.value);
+    if (!rtc) return;
+    rtc.rtcStatus.loadedmetadata = true;
+    rtc.update();
+  });
+});
+</script>
+
+<style lang="scss" scoped>
+.srt-webrtc-pull-wrap {
+  margin: 20px auto 0;
+  min-width: $large-width;
+  height: 700px;
+  text-align: center;
+  .left {
+    position: relative;
+    display: inline-block;
+    box-sizing: border-box;
+    width: $large-left-width;
+    height: 100%;
+    border-radius: 10px;
+    background-color: white;
+    color: #9499a0;
+    vertical-align: top;
+    .head {
+      display: flex;
+      justify-content: space-between;
+      padding: 20px;
+      background-color: papayawhip;
+      .tag {
+        display: inline-block;
+        margin-right: 5px;
+        padding: 1px 4px;
+        border: 1px solid;
+        border-radius: 2px;
+        color: #9499a0;
+        font-size: 12px;
+      }
+
+      .info {
+        display: flex;
+        align-items: center;
+        text-align: initial;
+
+        .avatar {
+          margin-right: 20px;
+          width: 64px;
+          height: 64px;
+          border-radius: 50%;
+          background-color: skyblue;
+        }
+        .detail {
+          .top {
+            margin-bottom: 10px;
+            color: #18191c;
+          }
+          .bottom {
+            font-size: 14px;
+          }
+        }
+      }
+      .other {
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        font-size: 12px;
+        .top {
+          display: flex;
+          align-items: center;
+          .item {
+            display: flex;
+            align-items: center;
+            margin-right: 20px;
+            .ico {
+              display: inline-block;
+              margin-right: 4px;
+              width: 10px;
+              height: 10px;
+              border-radius: 50%;
+              background-color: skyblue;
+            }
+          }
+        }
+        .bottom {
+          margin-top: 10px;
+        }
+      }
+    }
+    .video-wrap {
+      // height: 100px;
+      // height: 550px;
+      background-color: #18191c;
+      #localVideo {
+        max-width: 100%;
+        max-height: 100%;
+      }
+    }
+    .gift {
+      position: absolute;
+      right: 0;
+      bottom: 0;
+      left: 0;
+      display: flex;
+      align-items: center;
+      justify-content: space-around;
+      height: 100px;
+      background-color: papayawhip;
+      .item {
+        margin-right: 10px;
+        text-align: center;
+
+        .ico {
+          width: 50px;
+          height: 50px;
+          background-color: skyblue;
+        }
+        .name {
+          color: #18191c;
+          font-size: 12px;
+        }
+        .price {
+          color: #9499a0;
+          font-size: 12px;
+        }
+      }
+    }
+  }
+  .right {
+    position: relative;
+    display: inline-block;
+    box-sizing: border-box;
+    margin-left: 10px;
+    min-width: 300px;
+    height: 100%;
+    border-radius: 6px;
+    background-color: papayawhip;
+    color: #9499a0;
+    .tab {
+      display: flex;
+      align-items: center;
+      justify-content: space-evenly;
+      padding: 5px 0;
+      font-size: 12px;
+    }
+    .user-list {
+      overflow-y: scroll;
+      padding: 0 15px;
+      height: 100px;
+      background-color: papayawhip;
+      .item {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        margin-bottom: 10px;
+        font-size: 12px;
+        .info {
+          display: flex;
+          align-items: center;
+          .avatar {
+            margin-right: 5px;
+            width: 25px;
+            height: 25px;
+            border-radius: 50%;
+            background-color: skyblue;
+          }
+          .nickname {
+            color: black;
+          }
+        }
+      }
+    }
+    .danmu-list {
+      overflow-y: scroll;
+      padding: 0 15px;
+      height: 450px;
+      text-align: initial;
+      .item {
+        margin-bottom: 10px;
+        font-size: 12px;
+        .name {
+          color: #9499a0;
+          &.system {
+            color: red;
+          }
+        }
+        .msg {
+          color: #61666d;
+        }
+      }
+    }
+    .send-msg {
+      position: absolute;
+      bottom: 15px;
+      box-sizing: border-box;
+      padding: 0 10px;
+      width: 100%;
+      .ipt {
+        display: block;
+        box-sizing: border-box;
+        margin: 0 auto;
+        padding: 10px;
+        width: 100%;
+        height: 60px;
+        outline: none;
+        border: 1px solid hsla(0, 0%, 60%, 0.2);
+        border-radius: 4px;
+        background-color: #f1f2f3;
+        font-size: 14px;
+      }
+      .btn {
+        box-sizing: border-box;
+        margin-top: 10px;
+        margin-left: auto;
+        padding: 5px;
+        width: 80px;
+        border-radius: 4px;
+        background-color: skyblue;
+        color: white;
+        text-align: center;
+        font-size: 12px;
+        cursor: pointer;
+      }
+    }
+  }
+}
+
+// 屏幕宽度小于$large-width的时候
+@media screen and (max-width: $large-width) {
+  .srt-webrtc-pull-wrap {
+    .left {
+      width: $medium-left-width;
+    }
+    .right {
+      .list {
+        .item {
+          width: 150px;
+          height: 80px;
+        }
+      }
+    }
+  }
+}
+</style>

+ 7 - 7
src/views/srs-webrtc-pull/index.vue

@@ -124,7 +124,7 @@ const route = useRoute();
 const topRef = ref<HTMLDivElement>();
 const bottomRef = ref<HTMLDivElement>();
 const localVideoRef = ref<HTMLVideoElement>();
-const trackInfo = reactive({
+const track = reactive({
   audio: true,
   video: true,
 });
@@ -193,10 +193,10 @@ function startNewWebRtc(receiver: string) {
 
 async function handleSrsPlay() {
   const rtc = startNewWebRtc(getSocketId());
-  if (trackInfo.video) {
+  if (track.video) {
     rtc.peerConnection?.addTransceiver('video', { direction: 'recvonly' });
   }
-  if (trackInfo.audio) {
+  if (track.audio) {
     rtc.peerConnection?.addTransceiver('audio', { direction: 'recvonly' });
   }
   try {
@@ -279,10 +279,10 @@ function initReceive() {
   // 用户加入房间
   instance.socketIo.on(WsMsgTypeEnum.joined, (data) => {
     console.log('【websocket】用户加入房间完成', data);
-    roomName.value = data.data.roomName;
-    trackInfo.audio = data.data.trackInfo.audio;
-    trackInfo.video = data.data.trackInfo.video;
-    streamurl.value = data.data.srs.streamurl;
+    roomName.value = data.roomName;
+    track.audio = data.track_audio;
+    track.video = data.track_video;
+    streamurl.value = data.streamurl;
   });
 
   // 其他用户加入房间

+ 13 - 6
src/views/srs-webrtc-push/index.vue

@@ -166,18 +166,24 @@ const roomId = ref<string>(getRandomString(15));
 const danmuStr = ref('');
 const roomName = ref('');
 const localStream = ref();
-const trackInfo = reactive({
+const track = reactive({
   audio: true,
   video: true,
 });
-// const streamurl = ref(`webrtc://localhost/live/livestream/${roomId.value}`);
 const streamurl = ref(
   `webrtc://${
     process.env.NODE_ENV === 'development'
-      ? 'localhost'
+      ? 'localhost:5001'
       : 'live.hsslive.cn:5001'
   }/live/livestream/${roomId.value}`
 );
+const flvurl = ref(
+  `http://${
+    process.env.NODE_ENV === 'development'
+      ? 'localhost:5001'
+      : 'live.hsslive.cn:5001'
+  }/live/livestream/${roomId.value}.flv`
+);
 
 const websocketInstant = ref<WebSocketClass>();
 const damuList = ref<IDanmu[]>([]);
@@ -422,8 +428,9 @@ function sendJoin() {
       coverImg: handleCoverImg(),
       srs: {
         streamurl: streamurl.value,
+        flvurl: flvurl.value,
       },
-      trackInfo,
+      track,
     },
   });
 }
@@ -504,8 +511,8 @@ async function startGetDisplayMedia() {
     });
     const audio = event.getAudioTracks();
     const video = event.getVideoTracks();
-    trackInfo.audio = !!audio.length;
-    trackInfo.video = !!video.length;
+    track.audio = !!audio.length;
+    track.video = !!video.length;
     console.log('getDisplayMedia成功', event);
     currMediaType.value = allMediaTypeList[LiveTypeEnum.screen];
     currMediaTypeList.value.push(allMediaTypeList[LiveTypeEnum.screen]);

+ 4 - 6
src/views/webrtc-push/index.vue

@@ -289,6 +289,10 @@ function sendJoin() {
     data: {
       roomName: roomName.value,
       coverImg: handleCoverImg(),
+      track: {
+        video: true,
+        audio: true,
+      },
     },
   });
 }
@@ -418,12 +422,6 @@ function initReceive() {
     });
   });
 
-  // 用户加入房间
-  instance.socketIo.on(WsMsgTypeEnum.join, (data) => {
-    console.log('【websocket】用户加入房间', data);
-    if (!instance) return;
-  });
-
   // 用户加入房间
   instance.socketIo.on(WsMsgTypeEnum.joined, (data) => {
     console.log('【websocket】用户加入房间完成', data);