浏览代码

fix: 优化

shuisheng 1 年之前
父节点
当前提交
786d7f91fe

+ 5 - 0
src/api/live.ts

@@ -6,3 +6,8 @@ export function fetchLiveList(params) {
     params,
   });
 }
+export function fetchLiveRoomOnlineUser(params) {
+  return request.get('/live/live_room_online_user', {
+    params,
+  });
+}

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

@@ -14,7 +14,11 @@ import {
 import { useAppStore } from '@/store/app';
 import { usePiniaCacheStore } from '@/store/cache';
 import { useNetworkStore } from '@/store/network';
-import { ILiveRoom, LiveRoomTypeEnum } from '@/types/ILiveRoom';
+import {
+  ILiveRoom,
+  LiveRoomTypeEnum,
+  LiveRoomUseCDNEnum,
+} from '@/types/ILiveRoom';
 import { WsMessageType, WsMsgTypeEnum } from '@/types/websocket';
 import { videoFullBox, videoToCanvas } from '@/utils';
 
@@ -37,15 +41,8 @@ export function usePull(roomId: string) {
   const isRemoteDesk = ref(false);
   const videoElArr = ref<HTMLVideoElement[]>([]);
   const remoteVideo = ref<HTMLElement[]>([]);
-  const {
-    mySocketId,
-    initWs,
-    roomLiving,
-    anchorInfo,
-    liveUserList,
-    damuList,
-    handleSendGetLiveUser,
-  } = useWebsocket();
+  const { mySocketId, initWs, roomLiving, anchorInfo, liveUserList, damuList } =
+    useWebsocket();
   const { flvVideoEl, flvIsPlaying, startFlvPlay, destroyFlv } = useFlvPlay();
   const { hlsVideoEl, hlsIsPlaying, startHlsPlay, destroyHls } = useHlsPlay();
   const stopDrawingArr = ref<any[]>([]);
@@ -214,13 +211,13 @@ export function usePull(roomId: string) {
     }
   );
 
-  function handleHlsPlay(url: string) {
-    console.log('handleHlsPlay', url);
+  function handleHlsPlay() {
+    console.log('handleHlsPlay', hlsurl.value);
     handleStopDrawing();
     videoLoading.value = true;
     appStore.setLiveLine(LiveLineEnum.hls);
     startHlsPlay({
-      hlsurl: url,
+      hlsurl: hlsurl.value,
     });
   }
 
@@ -236,13 +233,15 @@ export function usePull(roomId: string) {
 
   function handlePlay(data: ILiveRoom) {
     roomLiving.value = true;
-    flvurl.value = data.flv_url!;
-    hlsurl.value = data.hls_url!;
+    flvurl.value =
+      data.cdn === LiveRoomUseCDNEnum.yes ? data.cdn_flv_url! : data.flv_url!;
+    hlsurl.value =
+      data.cdn === LiveRoomUseCDNEnum.yes ? data.cdn_hls_url! : data.hls_url!;
     function play() {
       if (appStore.liveLine === LiveLineEnum.flv) {
         handleFlvPlay();
       } else if (appStore.liveLine === LiveLineEnum.hls) {
-        handleHlsPlay(data.hls_url!);
+        handleHlsPlay();
       }
     }
     if (LiveRoomTypeEnum.pk === data.type && !route.query.pkKey) {
@@ -319,7 +318,7 @@ export function usePull(roomId: string) {
           handleFlvPlay();
           break;
         case LiveLineEnum.hls:
-          handleHlsPlay(hlsurl.value);
+          handleHlsPlay();
           break;
         case LiveLineEnum.rtc:
           break;
@@ -471,7 +470,6 @@ export function usePull(roomId: string) {
     closeRtc,
     keydownDanmu,
     sendDanmu,
-    handleSendGetLiveUser,
     showPlayBtn,
     danmuMsgType,
     isPlaying,

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

@@ -44,7 +44,6 @@ export function usePush() {
     roomLiving,
     initWs,
     handleStartLive,
-    handleSendGetLiveUser,
     connectStatus,
     mySocketId,
     canvasVideoStream,
@@ -359,7 +358,6 @@ export function usePush() {
     sendDanmu,
     keydownDanmu,
     sendBlob,
-    handleSendGetLiveUser,
     roomId,
     msgIsFile,
     mySocketId,

+ 0 - 16
src/hooks/use-websocket.ts

@@ -32,7 +32,6 @@ import {
   WsCandidateType,
   WsConnectStatusEnum,
   WsDisableSpeakingType,
-  WsGetLiveUserType,
   WsHeartbeatType,
   WsJoinType,
   WsLeavedType,
@@ -152,20 +151,6 @@ export const useWebsocket = () => {
     }, 1000 * 5);
   }
 
-  function handleSendGetLiveUser(liveRoomId: number) {
-    loopGetLiveUserTimer.value = setInterval(() => {
-      const ws = networkStore.wsMap.get(roomId.value);
-      if (!ws) return;
-      ws.send<WsGetLiveUserType['data']>({
-        requestId: getRandomString(8),
-        msgType: WsMsgTypeEnum.getLiveUser,
-        data: {
-          live_room_id: liveRoomId,
-        },
-      });
-    }, 1000 * 5);
-  }
-
   function handleStartLive({
     name,
     type,
@@ -1000,7 +985,6 @@ export const useWebsocket = () => {
   return {
     initWs,
     handleStartLive,
-    handleSendGetLiveUser,
     connectStatus,
     mySocketId,
     canvasVideoStream,

+ 13 - 1
src/types/ILiveRoom.ts

@@ -240,6 +240,15 @@ export interface ILiveRoom {
   push_obs_stream_key?: string;
   push_webrtc_url?: string;
   push_srt_url?: string;
+  cdn_rtmp_url?: string;
+  cdn_flv_url?: string;
+  cdn_hls_url?: string;
+  cdn_webrtc_url?: string;
+  cdn_push_rtmp_url?: string;
+  cdn_push_obs_server?: string;
+  cdn_push_obs_stream_key?: string;
+  cdn_push_webrtc_url?: string;
+  cdn_push_srt_url?: string;
   forward_bilibili_url?: string;
   forward_douyu_url?: string;
   forward_huya_url?: string;
@@ -261,7 +270,10 @@ export interface ILiveRoom {
   live?: ILive;
   user_live_room?: IUserLiveRoom & { user: IUser };
 
-  hidden_cover_img?: boolean;
+  /** 是否假直播间,1是,2否 */
+  is_fake?: number;
+
+  exclude_key?: boolean;
 
   created_at?: string;
   updated_at?: string;

+ 2 - 2
src/types/websocket.ts

@@ -87,10 +87,10 @@ export interface IWsFormat<T> {
   request_id: string;
   /** 用户socket_id */
   socket_id: string;
-  /** 是否是主播 */
-  is_anchor: boolean;
   /** 用户信息 */
   user_info?: IUser;
+  /** 用户id */
+  user_id?: number;
   /** 用户token */
   user_token?: string;
   data: T;

+ 1 - 1
src/utils/network/webSocket.ts

@@ -72,8 +72,8 @@ export class WebSocketClass {
     const sendData: IWsFormat<any> = {
       request_id: requestId,
       socket_id: this.socketIo.id,
-      is_anchor: this.isAnchor,
       user_info: userStore.userInfo,
+      user_id: userStore.userInfo?.id || undefined,
       user_token: userStore.token || undefined,
       data: data || {},
     };

+ 141 - 2
src/views/h5/room/index.vue

@@ -156,6 +156,45 @@
             </div>
           </div>
         </n-tab-pane>
+        <n-tab-pane
+          name="liveUser"
+          :tab="`在线用户`"
+        >
+          <div
+            class="liveUser-wrap"
+            :style="{ height: containerHeight + 'px' }"
+          >
+            <div
+              v-for="(item, index) in liveUserList"
+              :key="index"
+              class="item"
+            >
+              <div
+                class="info"
+                v-if="item.value?.userInfo"
+              >
+                <div
+                  class="avatar"
+                  :style="{
+                    backgroundImage: `url(${item.value.userInfo.avatar})`,
+                  }"
+                ></div>
+                <div class="username">
+                  {{ item.value.userInfo.username }}
+                </div>
+              </div>
+              <div
+                class="info"
+                v-else
+              >
+                <div class="avatar"></div>
+                <div class="username">
+                  {{ item.value?.socketId }}
+                </div>
+              </div>
+            </div>
+          </div>
+        </n-tab-pane>
       </n-tabs>
     </div>
 
@@ -203,12 +242,19 @@
 import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
 import { useRoute } from 'vue-router';
 
+import { fetchLiveRoomOnlineUser } from '@/api/live';
 import { fetchFindLiveRoom } from '@/api/liveRoom';
+import { fetchGetWsMessageList } from '@/api/wsMessage';
 import { THEME_COLOR } from '@/constant';
 import { emojiArray } from '@/emoji';
 import { useFullScreen, usePictureInPicture } from '@/hooks/use-play';
 import { usePull } from '@/hooks/use-pull';
-import { DanmuMsgTypeEnum, WsMessageMsgIsFileEnum } from '@/interface';
+import {
+  DanmuMsgTypeEnum,
+  WsMessageMsgIsFileEnum,
+  WsMessageMsgIsShowEnum,
+  WsMessageMsgIsVerifyEnum,
+} from '@/interface';
 import router, { mobileRouterName } from '@/router';
 import { useAppStore } from '@/store/app';
 import { usePiniaCacheStore } from '@/store/cache';
@@ -227,6 +273,8 @@ const containerHeight = ref(0);
 const videoWrapHeight = ref(0);
 const remoteVideoRef = ref<HTMLDivElement>();
 const roomId = ref(route.params.roomId as string);
+const loopGetLiveUserTimer = ref();
+
 const {
   videoWrapRef,
   handlePlay,
@@ -235,7 +283,7 @@ const {
   sendDanmu,
   closeRtc,
   closeWs,
-  handleSendGetLiveUser,
+  liveUserList,
   showPlayBtn,
   autoplayVal,
   videoLoading,
@@ -250,6 +298,7 @@ onUnmounted(() => {
   closeWs();
   closeRtc();
   appStore.showLoginModal = false;
+  clearInterval(loopGetLiveUserTimer.value);
 });
 
 onMounted(() => {
@@ -270,8 +319,68 @@ onMounted(() => {
   });
   getLiveRoomInfo();
   handleSendGetLiveUser(Number(roomId.value));
+  handleHistoryMsg();
 });
 
+async function handleHistoryMsg() {
+  try {
+    const res = await fetchGetWsMessageList({
+      nowPage: 1,
+      pageSize: appStore.liveRoomInfo?.history_msg_total || 10,
+      orderName: 'created_at',
+      orderBy: 'desc',
+      live_room_id: Number(roomId.value),
+      is_show: WsMessageMsgIsShowEnum.yes,
+      is_verify: WsMessageMsgIsVerifyEnum.yes,
+    });
+    if (res.code === 200) {
+      res.data.rows.forEach((v) => {
+        damuList.value.unshift({
+          ...v,
+          live_room_id: v.live_room_id!,
+          msg_id: v.id!,
+          socket_id: '',
+          msgType: v.msg_type!,
+          msgIsFile: v.msg_is_file!,
+          userInfo: v.user,
+          msg: v.content!,
+          username: v.username!,
+          send_msg_time: Number(v.send_msg_time),
+          redbag_send_id: v.redbag_send_id,
+        });
+      });
+      if (
+        appStore.liveRoomInfo?.system_msg &&
+        appStore.liveRoomInfo?.system_msg !== ''
+      ) {
+        damuList.value.push({
+          live_room_id: Number(roomId.value),
+          socket_id: '',
+          msgType: DanmuMsgTypeEnum.system,
+          msgIsFile: WsMessageMsgIsFileEnum.no,
+          msg: appStore.liveRoomInfo.system_msg,
+          send_msg_time: Number(+new Date()),
+        });
+      }
+    }
+  } catch (error) {
+    console.log(error);
+  }
+}
+
+function handleSendGetLiveUser(liveRoomId: number) {
+  async function main() {
+    const res = await fetchLiveRoomOnlineUser({ live_room_id: liveRoomId });
+    if (res.code === 200) {
+      liveUserList.value = res.data;
+    }
+  }
+  main();
+  loopGetLiveUserTimer.value = setInterval(() => {
+    main();
+  }, 1000 * 3);
+}
+
 function handlePushStr(str) {
   danmuStr.value += str;
   showEmoji.value = false;
@@ -520,6 +629,36 @@ function startPull() {
       height: 200px;
     }
   }
+  .liveUser-wrap {
+    overflow-y: scroll;
+    box-sizing: border-box;
+    height: 100px;
+
+    @extend %customScrollbar;
+    .item {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin-bottom: 10px;
+      font-size: 12px;
+      .info {
+        display: flex;
+        align-items: center;
+        cursor: pointer;
+        .avatar {
+          margin-right: 5px;
+          width: 25px;
+          height: 25px;
+          border-radius: 50%;
+
+          @extend %containBg;
+        }
+        .username {
+          color: white;
+        }
+      }
+    }
+  }
   .send-msg {
     position: fixed;
     bottom: 0;

+ 91 - 45
src/views/profile/index.vue

@@ -60,7 +60,7 @@
               (v) => v.auth_value === DEFAULT_AUTH_INFO.LIVE_PUSH.auth_value
             )
           "
-          class="rtmp-url-wrap"
+          class="url-wrap"
           v-loading="updateKeyLoading"
         >
           <div
@@ -70,6 +70,7 @@
             更新地址
           </div>
           <div
+            class="cdn"
             v-if="
               userStore.userInfo?.auths?.find(
                 (v) =>
@@ -77,47 +78,69 @@
               )
             "
           >
-            <span>
-              CDN推流地址:{{ handleReplaceCDNUrl(pushRes?.push_rtmp_url!) }},
-            </span>
-            <span
-              class="link"
-              @click="handleCopy(handleReplaceCDNUrl(pushRes?.push_rtmp_url!))"
-            >
-              复制
-            </span>
-          </div>
-          <div>
-            <span>
-              RTMP推流地址:{{
-                handleReplaceRtmpUrl(pushRes?.push_rtmp_url!)
-              }},
-            </span>
-            <span
-              class="link"
-              @click="handleCopy(handleReplaceRtmpUrl(pushRes?.push_rtmp_url!))"
-            >
-              复制
-            </span>
+            <div>
+              <span>
+                RTMP推流地址(CDN):{{ liveRoomInfo?.cdn_push_rtmp_url! }},
+              </span>
+              <span
+                class="link"
+                @click="handleCopy(liveRoomInfo?.cdn_push_rtmp_url!)"
+              >
+                复制
+              </span>
+            </div>
+            <div>
+              <span>
+                OBS服务器(CDN):{{ liveRoomInfo?.cdn_push_obs_server! }},
+              </span>
+              <span
+                class="link"
+                @click="handleCopy(liveRoomInfo?.cdn_push_obs_server!)"
+              >
+                复制
+              </span>
+            </div>
+            <div>
+              <span>
+                OBS推流码(CDN):{{ liveRoomInfo?.cdn_push_obs_stream_key! }},
+              </span>
+              <span
+                class="link"
+                @click="handleCopy(liveRoomInfo?.cdn_push_obs_stream_key!)"
+              >
+                复制
+              </span>
+            </div>
           </div>
 
-          <div>
-            <span>OBS服务器:{{ pushRes?.push_obs_server! }},</span>
-            <span
-              class="link"
-              @click="handleCopy(pushRes?.push_obs_server!)"
-            >
-              复制
-            </span>
-          </div>
-          <div>
-            <span>OBS推流码:{{ pushRes?.push_obs_stream_key! }},</span>
-            <span
-              class="link"
-              @click="handleCopy(pushRes?.push_obs_stream_key!)"
-            >
-              复制
-            </span>
+          <div class="srs">
+            <div>
+              <span> RTMP推流地址:{{ liveRoomInfo?.push_rtmp_url! }}, </span>
+              <span
+                class="link"
+                @click="handleCopy(liveRoomInfo?.push_rtmp_url!)"
+              >
+                复制
+              </span>
+            </div>
+            <div>
+              <span>OBS服务器:{{ liveRoomInfo?.push_obs_server! }},</span>
+              <span
+                class="link"
+                @click="handleCopy(liveRoomInfo?.push_obs_server!)"
+              >
+                复制
+              </span>
+            </div>
+            <div>
+              <span>OBS推流码:{{ liveRoomInfo?.push_obs_stream_key! }},</span>
+              <span
+                class="link"
+                @click="handleCopy(liveRoomInfo?.push_obs_stream_key!)"
+              >
+                复制
+              </span>
+            </div>
           </div>
         </div>
       </div>
@@ -136,7 +159,7 @@ import { DEFAULT_AUTH_INFO } from '@/constant';
 import { loginTip } from '@/hooks/use-login';
 import { routerName } from '@/router';
 import { useUserStore } from '@/store/user';
-import { LiveRoomTypeEnum } from '@/types/ILiveRoom';
+import { ILiveRoom, LiveRoomTypeEnum } from '@/types/ILiveRoom';
 import { IUser } from '@/types/IUser';
 import { getLiveRoomPageUrl } from '@/utils';
 
@@ -144,7 +167,7 @@ const userStore = useUserStore();
 const route = useRoute();
 const router = useRouter();
 
-const pushRes = ref();
+const liveRoomInfo = ref<ILiveRoom>();
 const userId = ref(-1);
 const userInfo = ref<IUser>();
 const getUserLoading = ref(false);
@@ -161,7 +184,7 @@ watch(
   () => userStore.userInfo,
   (newval) => {
     if (newval) {
-      pushRes.value = newval.live_rooms?.[0];
+      liveRoomInfo.value = newval.live_rooms?.[0];
     }
   },
   { immediate: true }
@@ -172,6 +195,7 @@ function handleReplaceCDNUrl(url: string) {
   console.log(url.replace(reg, 'pushtype=3'));
   return url.replace(reg, `pushtype=${LiveRoomTypeEnum.tencent_css}`);
 }
+
 function handleReplaceRtmpUrl(url: string) {
   const reg = /pushtype=([0-9]+)/g;
   console.log(url.replace(reg, 'pushtype=3'));
@@ -213,7 +237,25 @@ async function handleUpdateKey() {
     updateKeyLoading.value = true;
     const res = await fetchUpdateLiveRoomKey();
     if (res.code === 200) {
-      pushRes.value = res.data;
+      if (liveRoomInfo.value) {
+        liveRoomInfo.value.push_obs_server =
+          res.data.srsPushRes.push_obs_server;
+        liveRoomInfo.value.push_obs_stream_key =
+          res.data.srsPushRes.push_obs_stream_key;
+        liveRoomInfo.value.push_rtmp_url = res.data.srsPushRes.push_rtmp_url;
+        liveRoomInfo.value.push_srt_url = res.data.srsPushRes.push_srt_url;
+        liveRoomInfo.value.push_webrtc_url =
+          res.data.srsPushRes.push_webrtc_url;
+        liveRoomInfo.value.cdn_push_obs_server =
+          res.data.srsPushRes.push_obs_server;
+        liveRoomInfo.value.cdn_push_obs_stream_key =
+          res.data.cdnPushRes.push_obs_stream_key;
+        liveRoomInfo.value.cdn_push_rtmp_url =
+          res.data.cdnPushRes.push_rtmp_url;
+        liveRoomInfo.value.cdn_push_srt_url = res.data.cdnPushRes.push_srt_url;
+        liveRoomInfo.value.cdn_push_webrtc_url =
+          res.data.cdnPushRes.push_webrtc_url;
+      }
     }
   } catch (error) {
     console.error(error);
@@ -239,8 +281,12 @@ async function handleUpdateKey() {
       margin-right: 10px;
     }
   }
-  .rtmp-url-wrap {
+  .url-wrap {
     position: relative;
+    margin-top: 10px;
+    .cdn {
+      margin-bottom: 10px;
+    }
   }
 }
 </style>

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

@@ -413,6 +413,7 @@ import {
   fetchGiftRecordList,
 } from '@/api/giftRecord';
 import { fetchGoodsList } from '@/api/goods';
+import { fetchLiveRoomOnlineUser } from '@/api/live';
 import { fetchGetWsMessageList } from '@/api/wsMessage';
 import { QINIU_RESOURCE, liveRoomTypeEnumMap } from '@/constant';
 import { emojiArray } from '@/emoji';
@@ -464,6 +465,8 @@ const danmuListRef = ref<HTMLDivElement>();
 const remoteVideoRef = ref<HTMLDivElement>();
 const uploadRef = ref<HTMLInputElement>();
 const danmuIptRef = ref<HTMLTextAreaElement>();
+const loopGetLiveUserTimer = ref();
+
 const {
   initPull,
   closeWs,
@@ -471,7 +474,6 @@ const {
   keydownDanmu,
   sendDanmu,
   handlePlay,
-  handleSendGetLiveUser,
   videoWrapRef,
   danmuMsgType,
   msgIsFile,
@@ -536,8 +538,22 @@ onMounted(() => {
 onUnmounted(() => {
   closeWs();
   closeRtc();
+  clearInterval(loopGetLiveUserTimer.value);
 });
 
+function handleSendGetLiveUser(liveRoomId: number) {
+  async function main() {
+    const res = await fetchLiveRoomOnlineUser({ live_room_id: liveRoomId });
+    if (res.code === 200) {
+      liveUserList.value = res.data;
+    }
+  }
+  main();
+  loopGetLiveUserTimer.value = setInterval(() => {
+    main();
+  }, 1000 * 3);
+}
+
 function handleSendDanmu() {
   danmuMsgType.value = DanmuMsgTypeEnum.danmu;
   sendDanmu();

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

@@ -463,6 +463,7 @@ import {
 } from 'vue';
 import { useRoute } from 'vue-router';
 
+import { fetchLiveRoomOnlineUser } from '@/api/live';
 import { fetchGetWsMessageList } from '@/api/wsMessage';
 import {
   QINIU_RESOURCE,
@@ -530,7 +531,6 @@ const {
   sendDanmu,
   keydownDanmu,
   sendBlob,
-  handleSendGetLiveUser,
   roomId,
   msgIsFile,
   mySocketId,
@@ -587,6 +587,7 @@ const suggestedName = ref('');
 const recordVideoTimer = ref();
 const recordVideoTime = ref('00:00:00');
 let avRecorder: AVRecorder | null = null;
+const loopGetLiveUserTimer = ref();
 
 const rtcRtt = computed(() => {
   const arr: any[] = [];
@@ -869,7 +870,6 @@ watch(
   () => roomId.value,
   (newval) => {
     if (newval) {
-      handleSendGetLiveUser(Number(newval));
       handleHistoryMsg();
     }
   }
@@ -884,6 +884,7 @@ onMounted(() => {
   initUserMedia();
   initCanvas();
   handleCache();
+  handleSendGetLiveUser(Number(roomId.value));
 });
 
 onUnmounted(() => {
@@ -904,8 +905,22 @@ onUnmounted(() => {
       v.stream?.removeTrack(track);
     });
   });
+  clearInterval(loopGetLiveUserTimer.value);
 });
 
+function handleSendGetLiveUser(liveRoomId: number) {
+  async function main() {
+    const res = await fetchLiveRoomOnlineUser({ live_room_id: liveRoomId });
+    if (res.code === 200) {
+      liveUserList.value = res.data;
+    }
+  }
+  main();
+  loopGetLiveUserTimer.value = setInterval(() => {
+    main();
+  }, 1000 * 3);
+}
+
 async function initUserMedia() {
   const res1 = await handleUserMedia({ video: true, audio: true });
   console.log('初始化获取摄像头成功', res1);