use-pull.ts 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. import { Ref, nextTick, ref, watch } from 'vue';
  2. import { useRoute } from 'vue-router';
  3. import { useFlvPlay, useHlsPlay } from '@/hooks/use-play';
  4. import { useWs } from '@/hooks/use-ws';
  5. import { DanmuMsgTypeEnum, IDanmu, IMessage, liveTypeEnum } from '@/interface';
  6. import { WsMsgTypeEnum } from '@/network/webSocket';
  7. import { useAppStore } from '@/store/app';
  8. import { useNetworkStore } from '@/store/network';
  9. import { useUserStore } from '@/store/user';
  10. import { createVideo, videoToCanvas } from '@/utils';
  11. export function usePull({
  12. localVideoRef,
  13. canvasRef,
  14. isSRS,
  15. liveType,
  16. }: {
  17. localVideoRef: Ref<HTMLVideoElement[]>;
  18. canvasRef: Ref<Element | undefined>;
  19. isSRS: boolean;
  20. liveType: liveTypeEnum;
  21. }) {
  22. const route = useRoute();
  23. const userStore = useUserStore();
  24. const networkStore = useNetworkStore();
  25. const appStore = useAppStore();
  26. const roomId = ref(route.params.roomId as string);
  27. const roomLiveType = ref<liveTypeEnum>(liveType);
  28. const danmuStr = ref('');
  29. const autoplayVal = ref(false);
  30. const videoLoading = ref(false);
  31. const flvurl = ref('');
  32. const hlsurl = ref('');
  33. const sidebarList = ref<
  34. {
  35. socketId: string;
  36. }[]
  37. >([]);
  38. const videoElArr = ref<HTMLVideoElement[]>([]);
  39. const {
  40. getSocketId,
  41. initWs,
  42. roomLiveing,
  43. liveRoomInfo,
  44. roomNoLive,
  45. heartbeatTimer,
  46. localStream,
  47. liveUserList,
  48. damuList,
  49. maxBitrate,
  50. maxFramerate,
  51. resolutionRatio,
  52. currentMaxFramerate,
  53. currentMaxBitrate,
  54. currentResolutionRatio,
  55. addTrack,
  56. delTrack,
  57. } = useWs();
  58. const { flvVideoEl, startFlvPlay } = useFlvPlay();
  59. const { hlsVideoEl, startHlsPlay } = useHlsPlay();
  60. async function handleHlsPlay() {
  61. console.log('handleHlsPlay');
  62. videoLoading.value = true;
  63. const { width, height } = await startHlsPlay({
  64. hlsurl: hlsurl.value,
  65. });
  66. videoToCanvas({
  67. videoEl: hlsVideoEl.value!,
  68. targetEl: canvasRef.value!,
  69. width,
  70. height,
  71. });
  72. videoLoading.value = false;
  73. }
  74. async function handlePlay() {
  75. if (roomLiveType.value === liveTypeEnum.srsFlvPull) {
  76. console.log('srsFlvPull', autoplayVal.value);
  77. if (!autoplayVal.value) return;
  78. const { width, height } = await startFlvPlay({
  79. flvurl: flvurl.value,
  80. });
  81. videoToCanvas({
  82. videoEl: flvVideoEl.value!,
  83. targetEl: canvasRef.value!,
  84. width,
  85. height,
  86. });
  87. videoLoading.value = false;
  88. } else if (roomLiveType.value === liveTypeEnum.srsHlsPull) {
  89. console.log('srsHlsPull', autoplayVal.value);
  90. if (!autoplayVal.value) return;
  91. handleHlsPlay();
  92. }
  93. }
  94. watch(
  95. () => autoplayVal.value,
  96. (val) => {
  97. console.log('autoplayVal变了', val);
  98. if (val && roomLiveType.value === liveTypeEnum.webrtcPull) {
  99. handlePlay();
  100. }
  101. }
  102. );
  103. watch(
  104. () => roomLiveing.value,
  105. (val) => {
  106. console.log(val, roomLiveType.value, '-------');
  107. if (val) {
  108. flvurl.value = val.live?.live_room?.flv_url!;
  109. hlsurl.value = val.live?.live_room?.hls_url!;
  110. // if (val && roomLiveType.value === liveTypeEnum.webrtcPull) {
  111. handlePlay();
  112. // }
  113. }
  114. }
  115. );
  116. watch(
  117. () => appStore.muted,
  118. (newVal) => {
  119. console.log('muted变了', newVal);
  120. videoElArr.value.forEach((el) => {
  121. el.muted = newVal;
  122. });
  123. }
  124. );
  125. watch(
  126. () => localStream,
  127. (stream) => {
  128. if (stream.value) {
  129. console.log('localStream变了');
  130. console.log('音频轨:', stream.value?.getAudioTracks());
  131. console.log('视频轨:', stream.value?.getVideoTracks());
  132. if (roomLiveType.value === liveTypeEnum.webrtcPull) {
  133. videoElArr.value.forEach((dom) => {
  134. dom.remove();
  135. });
  136. stream.value?.getVideoTracks().forEach((track) => {
  137. console.log('视频轨enabled:', track.id, track.enabled);
  138. const video = createVideo({});
  139. video.id = track.id;
  140. video.srcObject = new MediaStream([track]);
  141. canvasRef.value?.appendChild(video);
  142. videoElArr.value.push(video);
  143. });
  144. stream.value?.getAudioTracks().forEach((track) => {
  145. console.log('音频轨enabled:', track.id, track.enabled);
  146. const video = createVideo({});
  147. video.id = track.id;
  148. video.srcObject = new MediaStream([track]);
  149. canvasRef.value?.appendChild(video);
  150. videoElArr.value.push(video);
  151. });
  152. videoLoading.value = false;
  153. } else if (roomLiveType.value === liveTypeEnum.srsWebrtcPull) {
  154. videoElArr.value.forEach((dom) => {
  155. dom.remove();
  156. });
  157. stream.value?.getVideoTracks().forEach((track) => {
  158. console.log('视频轨enabled:', track.id, track.enabled);
  159. const video = createVideo({});
  160. video.id = track.id;
  161. video.srcObject = new MediaStream([track]);
  162. canvasRef.value?.appendChild(video);
  163. videoElArr.value.push(video);
  164. });
  165. stream.value?.getAudioTracks().forEach((track) => {
  166. console.log('音频轨enabled:', track.id, track.enabled);
  167. const video = createVideo({});
  168. video.id = track.id;
  169. video.srcObject = new MediaStream([track]);
  170. canvasRef.value?.appendChild(video);
  171. videoElArr.value.push(video);
  172. });
  173. videoLoading.value = false;
  174. }
  175. } else {
  176. videoElArr.value?.forEach((item) => {
  177. item.remove();
  178. });
  179. }
  180. },
  181. { deep: true }
  182. );
  183. watch(
  184. [
  185. () => userStore.userInfo,
  186. () => networkStore.wsMap.get(roomId.value)?.socketIo?.connected,
  187. ],
  188. ([userInfo, connected]) => {
  189. if (userInfo && connected) {
  190. const instance = networkStore.wsMap.get(roomId.value);
  191. if (!instance) return;
  192. }
  193. }
  194. );
  195. function initPull(autolay = true) {
  196. autoplayVal.value = autolay;
  197. if (autoplayVal.value) {
  198. videoLoading.value = true;
  199. }
  200. initWs({
  201. roomId: roomId.value,
  202. isSRS,
  203. isAnchor: false,
  204. isPull: true,
  205. roomLiveType: roomLiveType.value,
  206. });
  207. }
  208. function closeWs() {
  209. const instance = networkStore.wsMap.get(roomId.value);
  210. instance?.close();
  211. }
  212. function closeRtc() {
  213. networkStore.rtcMap.forEach((rtc) => {
  214. rtc.close();
  215. });
  216. }
  217. function addVideo() {
  218. sidebarList.value.push({ socketId: getSocketId() });
  219. nextTick(() => {
  220. liveUserList.value.forEach((item) => {
  221. const socketId = item.id;
  222. if (socketId === getSocketId()) {
  223. localVideoRef.value[getSocketId()].srcObject = localStream.value;
  224. }
  225. });
  226. });
  227. }
  228. function keydownDanmu(event: KeyboardEvent) {
  229. const key = event.key.toLowerCase();
  230. if (key === 'enter') {
  231. event.preventDefault();
  232. sendDanmu();
  233. }
  234. }
  235. function sendDanmu() {
  236. if (!danmuStr.value.trim().length) {
  237. window.$message.warning('请输入弹幕内容!');
  238. return;
  239. }
  240. const instance = networkStore.wsMap.get(roomId.value);
  241. if (!instance) return;
  242. const danmu: IDanmu = {
  243. socket_id: getSocketId(),
  244. userInfo: userStore.userInfo,
  245. msgType: DanmuMsgTypeEnum.danmu,
  246. msg: danmuStr.value,
  247. };
  248. const messageData: IMessage['data'] = {
  249. msg: danmuStr.value,
  250. msgType: DanmuMsgTypeEnum.danmu,
  251. live_room_id: Number(roomId.value),
  252. };
  253. instance.send({
  254. msgType: WsMsgTypeEnum.message,
  255. data: messageData,
  256. });
  257. damuList.value.push(danmu);
  258. danmuStr.value = '';
  259. }
  260. return {
  261. initPull,
  262. closeWs,
  263. closeRtc,
  264. getSocketId,
  265. keydownDanmu,
  266. sendDanmu,
  267. addVideo,
  268. handleHlsPlay,
  269. roomLiveType,
  270. roomLiveing,
  271. autoplayVal,
  272. videoLoading,
  273. roomNoLive,
  274. damuList,
  275. liveUserList,
  276. sidebarList,
  277. danmuStr,
  278. liveRoomInfo,
  279. };
  280. }