scene.service.ts 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
  2. import { ClientGrpc, Client } from '@nestjs/microservices';
  3. import { grpcClientOptions } from './grpc-scene.options';
  4. import { Logger } from '@nestjs/common';
  5. import { DataChannel } from 'node-datachannel';
  6. import { BehaviorSubject } from 'rxjs';
  7. // import * as streamBuffers from 'stream-buffers';
  8. import { ActionType } from './actionType';
  9. import { CacheService } from 'src/cache/cache.service';
  10. import { StreamService } from './stream/stream.service';
  11. // import { InjectQueue } from '@nestjs/bull';
  12. // import { Queue } from 'bull';
  13. import { RotateService } from 'src/rotate/rotate.service';
  14. // import { DelayQueue, RxQueue, DebounceQueue } from 'rx-queue';
  15. import { DelayQueue, RxQueue, DebounceQueue } from '../queue/mod';
  16. import { MoveService } from 'src/move/move.service';
  17. import { GetRouterService } from 'src/get-router/get-router.service';
  18. import { ConfigService } from '@nestjs/config';
  19. @Injectable()
  20. export class SceneService implements OnModuleInit, OnModuleDestroy {
  21. constructor(
  22. private configService: ConfigService,
  23. private cacheService: CacheService,
  24. private streamService: StreamService,
  25. private rotateService: RotateService,
  26. private moveService: MoveService,
  27. private getRouterService: GetRouterService, // @InjectQueue('rotate') private rotateQueue: Queue, // @InjectQueue('walking') private walkingQueue: Queue,
  28. ) {}
  29. @Client(grpcClientOptions) private readonly client: ClientGrpc;
  30. public _frameInteval: NodeJS.Timeout;
  31. public _frameTimeout: NodeJS.Timeout;
  32. public _rotateTimeout: NodeJS.Timeout;
  33. public _moveTimeout: NodeJS.Timeout;
  34. public _JoyStickingTimeout: NodeJS.Timeout;
  35. public startSteaming = new BehaviorSubject<boolean>(false);
  36. public onRotating = new BehaviorSubject<boolean>(false);
  37. public onMoving = new BehaviorSubject<boolean>(false);
  38. public onJoysticking = new BehaviorSubject<boolean>(false);
  39. public frameCnt = new BehaviorSubject<number>(-1);
  40. private rotateframeCnt = -1;
  41. private moveframeCnt = -1;
  42. private joystickFrameCnt = -1;
  43. private rotateFirstIDR = true;
  44. private sceneGrpcService: SceneGrpcService;
  45. private channel: DataChannel;
  46. private logger: Logger = new Logger('SceneService');
  47. private frameCntInterval = 1000;
  48. private user_id: string;
  49. private roomId: string;
  50. private onSteaming = false;
  51. private mockserverTime = Date.now() - 1653000000478;
  52. private lastRenderMedia = '';
  53. private frameCntSubscription: any;
  54. private roQueueSubscription: any;
  55. private moveQueueSubscription: any;
  56. private walkingSub: any;
  57. private joystickSub: any;
  58. private clickQueueSub: any;
  59. private _rotateCurrentFame = -1;
  60. private _rotateCount = -1;
  61. private streamServiceSub: any;
  62. // private roRequestQueue: RxQueue = new DelayQueue(20);
  63. private roQueue: RxQueue = new DelayQueue(
  64. Number(this.configService.get('queueConfig.rotate')) || 20,
  65. );
  66. private clickQueue: RxQueue = new DebounceQueue(500);
  67. private moveQueue: RxQueue = new DelayQueue(
  68. Number(this.configService.get('queueConfig.move')) || 20,
  69. );
  70. private joystickQueue: RxQueue = new DebounceQueue(500);
  71. private requestIFrameQueue: RxQueue = new DebounceQueue(2000);
  72. private requestIFrameQueueSub: any;
  73. private roRequestQueueSub: any;
  74. private rotateTimeStamp: number;
  75. private firstRender = false;
  76. private latestBreakPointId: number;
  77. private isHoldingStream = false;
  78. private lastMovingPointArray: MovingLastUpdateType[] = [];
  79. private latestWalkingRequest: any; // 最新waking的接收值
  80. private hasJoystickMoveRequest = false; // 最新joystick的接收值
  81. private moveSliceLastFrame = new BehaviorSubject<MovingLastUpdateType>(null);
  82. private moveSliceLastFrameSub: any;
  83. public lastMoveStreamFrame = new BehaviorSubject<StreamFrameType>({
  84. frame: -1,
  85. clipPath: '',
  86. metaData: '',
  87. });
  88. public users = {};
  89. // initUsers(app_id, userId) {
  90. // const user = {
  91. // appId: null,
  92. // userId: null,
  93. // breakPointId: null,
  94. // roomId: null,
  95. // player: {
  96. // position: { x: -700, y: 0, z: 0 },
  97. // angle: {
  98. // pitch: 0,
  99. // yaw: 0,
  100. // roll: 0,
  101. // },
  102. // },
  103. // camera: {
  104. // position: { x: -1145, y: 0, z: 160 },
  105. // angle: {
  106. // pitch: 0,
  107. // yaw: 0,
  108. // roll: 0,
  109. // },
  110. // },
  111. // rotateInfo: {
  112. // frameIndex: 0,
  113. // horizontal_move: 0,
  114. // mediaSrc: null,
  115. // },
  116. // moveInfo: {},
  117. // // traceIds: [],
  118. // // actionResponses:[]
  119. // };
  120. // user.appId = app_id;
  121. // user.userId = userId;
  122. // user.breakPointId = 100;
  123. // this.users[userId] = user;
  124. // }
  125. onModuleInit(): void {
  126. this.sceneGrpcService =
  127. this.client.getService<SceneGrpcService>('SceneGrpcService');
  128. this.logger.log('init SceneGrpcService');
  129. this.streamServiceSub = this.streamService.onSteaming.subscribe((val) => {
  130. this.onSteaming = val;
  131. });
  132. Number.prototype.padLeft = function (n, str) {
  133. return Array(n - String(this).length + 1).join(str || '0') + this;
  134. };
  135. this.logger.log('roQueue-period :' + Number(this.roQueue.period));
  136. this.logger.log('moveQueue-period :' + Number(this.moveQueue.period));
  137. }
  138. public isHeaderOrLast(index: number, length: number): boolean {
  139. if (index === 0 || index === length) {
  140. return true;
  141. } else {
  142. return false;
  143. }
  144. }
  145. public getConfig() {
  146. return {
  147. userId: this.user_id,
  148. roomId: this.roomId,
  149. };
  150. }
  151. public startStream(): void {
  152. clearInterval(this._frameInteval);
  153. if (this.frameCnt.value === -1) {
  154. this._frameInteval = setInterval(async () => {
  155. const next = this.frameCnt.value + 1;
  156. this.frameCnt.next(next);
  157. }, 1000);
  158. }
  159. }
  160. public holdSteam(): void {
  161. clearInterval(this._frameInteval);
  162. this.isHoldingStream = true;
  163. }
  164. public resumeStream(): void {
  165. this.onMoving.next(false);
  166. this.onRotating.next(false);
  167. this.isHoldingStream = false;
  168. this.moveframeCnt = -1;
  169. this.rotateframeCnt = -1;
  170. clearInterval(this._frameInteval);
  171. this._frameInteval = setInterval(async () => {
  172. const next = this.frameCnt.getValue() + 1;
  173. this.frameCnt.next(next);
  174. }, 1000);
  175. }
  176. public stopStream(): void {
  177. if (this.frameCntSubscription) {
  178. this.frameCntSubscription.unsubscribe();
  179. this.frameCntSubscription = null;
  180. }
  181. if (this.roQueueSubscription) {
  182. this.roQueueSubscription.unsubscribe();
  183. this.roQueueSubscription = null;
  184. }
  185. if (this.moveQueueSubscription) {
  186. this.moveQueueSubscription.unsubscribe();
  187. this.moveQueueSubscription = null;
  188. }
  189. this.frameCnt.next(-1);
  190. clearInterval(this._frameInteval);
  191. this.rotateframeCnt = -1;
  192. }
  193. setConfig(user_id: string, roomId: string): void {
  194. this.user_id = user_id;
  195. this.roomId = roomId;
  196. }
  197. onModuleDestroy() {
  198. if ('unsubscribe' in this.streamServiceSub) {
  199. this.streamService.onSteaming.unsubscribe();
  200. }
  201. }
  202. init(request: InitRequest) {
  203. try {
  204. this.rotateService.init(request.app_id, request.user_id);
  205. this.startSteaming.next(true);
  206. this.startStream();
  207. this.handleStream();
  208. // this.moveService.init(request.app_id, request.user_id);
  209. // this.initUsers(request.app_id, request.user_id);
  210. } catch (error) {
  211. this.logger.error('error', error);
  212. }
  213. }
  214. exit() {
  215. this.frameCnt.next(-1);
  216. this.rotateService.deleteUser(this.user_id);
  217. }
  218. async rotate(request: RotateRequest) {
  219. this.handleRotate(request);
  220. this._rotateCount += 1;
  221. //this.logger.log('request', request)
  222. // this.roRequestQueue.next(request);
  223. // if (!this.roRequestQueueSub) {
  224. // this.handleRotate();
  225. // }
  226. }
  227. /**
  228. * rotate请求队列
  229. */
  230. async handleRotate(request) {
  231. // this.roRequestQueueSub = this.roRequestQueue.subscribe(
  232. // async (request: RotateRequest) => {
  233. // try {
  234. if (this.firstRender) {
  235. if (!this.roQueueSubscription) {
  236. this.handleRotateStream();
  237. }
  238. let redisMeta: StreamReplyType;
  239. this.onRotating.next(true);
  240. const start = performance.now();
  241. // 当move时处理 _rotateCount是移动端同时触发的问题
  242. if (this.onMoving.value && this._rotateCount > 5) {
  243. const lastStreamFrame = this.lastMoveStreamFrame.getValue();
  244. const metaData: StreamReplyType = JSON.parse(
  245. lastStreamFrame.metaData,
  246. ) as any as StreamReplyType;
  247. console.log('stop-4', metaData.traceIds[0]);
  248. console.log('stop-5', request.trace_id);
  249. //判断request是否是新的
  250. if (metaData.traceIds.indexOf(request.trace_id) > -1) {
  251. return;
  252. }
  253. const newUserStates: NewUserStatesType = metaData.newUserStates.find(
  254. (item) => item.userId === this.user_id,
  255. );
  256. const trace_id = metaData.traceIds[0];
  257. const userId = newUserStates.userId;
  258. const breakPointId = metaData.endBreakPointId;
  259. const cameraAngle = newUserStates.playerState.camera.angle;
  260. const playerAngle = newUserStates.playerState.player.angle;
  261. this.logger.log(
  262. 'stop-data-0',
  263. trace_id,
  264. userId,
  265. cameraAngle,
  266. cameraAngle,
  267. );
  268. //debugger;
  269. redisMeta = await this.moveService.stop(
  270. trace_id,
  271. userId,
  272. breakPointId,
  273. cameraAngle,
  274. playerAngle,
  275. );
  276. this.logger.log('stop-redisMeta', redisMeta);
  277. this.onMoving.next(false);
  278. this.cleanMoveSteam();
  279. // redisMeta = await this.rotateService.rotate(request);
  280. } else {
  281. // 正常rotate
  282. redisMeta = await this.rotateService.seqExeRotate(request);
  283. }
  284. if (redisMeta && 'mediaSrc' in redisMeta) {
  285. const mediaSrc: string = redisMeta.mediaSrc || '';
  286. if (mediaSrc.length > 0) {
  287. const src = mediaSrc.split('?')[0];
  288. //this.logger.log('进入roQueue1', redisMeta.newUserStates[0].playerState.camera.angle.yaw);
  289. //this.logger.log('进入roQueue2', src);
  290. if (src.length > 0) {
  291. //this.logger.log('不同源');
  292. this.holdSteam();
  293. this.lastRenderMedia = src;
  294. const clipPath = this.configService.get('app.prefix') + src;
  295. //TODO 临时开出
  296. // delete redisMeta.mediaSrc;
  297. const stream: StreamFrameType = {
  298. frame: -1,
  299. clipPath: clipPath,
  300. metaData: JSON.stringify(redisMeta),
  301. serverTime: this.mockserverTime,
  302. DIR: 3,
  303. };
  304. //this.logger.log('rotate', stream, Date.now());
  305. clearTimeout(this._rotateTimeout);
  306. //this.logger.log('进入roQueue3', stream.clipPath);
  307. const stop = performance.now();
  308. const inMillSeconds = stop - start;
  309. const rounded = Number(inMillSeconds).toFixed(3);
  310. this.logger.log(`[timer]-rotate-入队列前: ${rounded}ms`);
  311. this.roQueue.next(stream);
  312. } else {
  313. // this.onRotating.next(false);
  314. }
  315. }
  316. }
  317. }
  318. // } catch (error) {
  319. // this.logger.error('rotate', error.message);
  320. // console.error('error', error);
  321. // }
  322. }
  323. async walking(request: MoveRequest) {
  324. this.latestWalkingRequest = request;
  325. this.logger.log('walking-trace_id', request.trace_id);
  326. // 进入正常walking流程
  327. if (!this.onMoving.getValue()) {
  328. console.log('walking-step-main-1', request.trace_id);
  329. this.latestWalkingRequest = null;
  330. this.handleWalking(request);
  331. }
  332. // 监听每小段最后一zhen
  333. if (!this.moveSliceLastFrameSub) {
  334. this.moveSliceLastFrameSub = this.moveSliceLastFrame.subscribe(
  335. async (frame: MovingLastUpdateType) => {
  336. // console.log('walkingStop-'+ this.latestWalkingRequest + ','+ this.onMoving.value);
  337. //TODO 正在行走时,有新的reqest
  338. if (this.latestWalkingRequest && this.onMoving.value) {
  339. this.logger.log('stop-data-1', frame);
  340. // this.moveQueue.complete();
  341. // this.moveQueue.of('');
  342. // TODO 中断move队列 ?优化如何清空
  343. this.moveQueue.clean();
  344. // this.moveQueueSubscription.unsubscribe();
  345. // this.moveQueueSubscription = null;
  346. //step1 执行stop方法
  347. const metaData: StreamReplyType = frame.metaData;
  348. const newUserStates: NewUserStatesType =
  349. metaData.newUserStates.find(
  350. (item) => item.userId === this.user_id,
  351. );
  352. const trace_id = metaData.traceIds[0];
  353. const userId = newUserStates.userId;
  354. const breakPointId = metaData.endBreakPointId;
  355. const cameraAngle = newUserStates.playerState.camera.angle;
  356. const playerAngle = newUserStates.playerState.player.angle;
  357. this.logger.log(
  358. 'stop-data-2',
  359. trace_id,
  360. userId,
  361. cameraAngle,
  362. cameraAngle,
  363. );
  364. const redisMeta = await this.moveService.stop(
  365. trace_id,
  366. userId,
  367. breakPointId,
  368. cameraAngle,
  369. playerAngle,
  370. );
  371. this.logger.log('stop-redisMeta', JSON.stringify(redisMeta));
  372. // 2. 中断重新walking
  373. console.log('walking-step-reWalking-1', request.trace_id);
  374. this.handleReWalking(this.latestWalkingRequest);
  375. }
  376. },
  377. );
  378. }
  379. }
  380. /**
  381. * 行走队列处理器
  382. * @param request MoveRequest
  383. * @returns void
  384. */
  385. async handleWalking(request: MoveRequest): Promise<void> {
  386. try {
  387. // if (!this.onMoving.getValue()) {
  388. console.log('walking-step-main-2', request.trace_id);
  389. const start = performance.now();
  390. this._rotateCount = 0;
  391. const user = this.moveService.users[this.user_id];
  392. console.log('进入1 - searchRoad');
  393. console.log('path-start' + user.breakPointId);
  394. const path = await this.getRouterService.searchRoad(
  395. user.appId,
  396. user.breakPointId,
  397. request.clicking_action.clicking_point,
  398. );
  399. this.logger.log('walking-path', path);
  400. if (!path) {
  401. console.log('不存在--path', path);
  402. this.resumeStream();
  403. return;
  404. }
  405. // debugger;
  406. const walkingRes = await this.moveService.move(path, request);
  407. //this.logger.log('walking', walkingRes);
  408. // debugger;
  409. if (walkingRes && !this.onMoving.value) {
  410. //this.logger.log('walkingRes-front', walkingRes);
  411. // shift出前第一个镜头数据
  412. const rotateCamData = walkingRes[0];
  413. this.logger.log('rotateCamData', rotateCamData.length);
  414. if (rotateCamData?.length) {
  415. // 头数组[0] rotate 序列, 头是关键key
  416. walkingRes[0].forEach((item: StreamReplyType, index: number) => {
  417. item.mType = 'rotate';
  418. // item.DIR = index === 0 ? 1 : 3;
  419. const IDRflag = index % 5 === 0 ? 1 : 3;
  420. const dir = this.isHeaderOrLast(index, walkingRes[0].length - 1);
  421. item.DIR = dir ? 1 : IDRflag;
  422. });
  423. } else {
  424. this.logger.log('rotateCamData无数据');
  425. }
  426. // 二维数组 做move 序列, move类型
  427. //console.log('move-walkingRes:' + JSON.stringify(walkingRes));
  428. if (walkingRes && walkingRes?.length >= 1) {
  429. for (let i = 1; i < walkingRes.length; i++) {
  430. Array.from(walkingRes[i]).forEach(
  431. (item: StreamReplyType, index: number) => {
  432. const IDRflag = index % 5 === 0 ? 1 : 3;
  433. const dir = this.isHeaderOrLast(
  434. index,
  435. walkingRes[i].length - 1,
  436. );
  437. item.DIR = dir ? 1 : IDRflag;
  438. //将每段最后一个推入lastMovingPointArray
  439. if (index === walkingRes[i].length - 1) {
  440. this.lastMovingPointArray.push({
  441. mediaSrc: item.mediaSrc,
  442. metaData: item,
  443. });
  444. }
  445. },
  446. );
  447. }
  448. }
  449. // walkingRes marker to everybody
  450. const seqs = Array.from(walkingRes).flat() as any as StreamReplyType[];
  451. if (seqs?.length) {
  452. this.logger.log('walking --总序列--seqs-2:' + seqs.length);
  453. const stop = performance.now();
  454. const inMillSeconds = stop - start;
  455. const rounded = Number(inMillSeconds).toFixed(3);
  456. this.logger.log(`[timer]-move-入队列前:-->${rounded}ms`);
  457. this.handleSeqMoving(seqs);
  458. } else {
  459. console.error('walking-move无数据');
  460. this.cleanMoveSteam();
  461. this.resumeStream();
  462. }
  463. // }
  464. }
  465. // });
  466. // }
  467. } catch (error) {
  468. this.logger.error('walking', error.message);
  469. this.cleanMoveSteam();
  470. this.resumeStream();
  471. }
  472. }
  473. /**
  474. * 改变路线后的walking队列处理(中转)
  475. * @param request MoveRequest
  476. */
  477. handleReWalking(request: MoveRequest) {
  478. this.latestWalkingRequest = null;
  479. this.handleWalking(request);
  480. }
  481. /***
  482. * joystick main core
  483. */
  484. async joystick(request: JoystickRequest) {
  485. // TODO hasJoystickMoveRequest中断
  486. this.logger.log('this.hasJoystickMoveRequest', this.hasJoystickMoveRequest);
  487. if (!this.hasJoystickMoveRequest) {
  488. this.handlejoystick(request);
  489. }
  490. }
  491. /***
  492. * joystick
  493. */
  494. async handlejoystick(request: JoystickRequest) {
  495. try {
  496. //const joystickRes = await this.moveService.joystick(request);
  497. this._rotateCount = 0;
  498. const joystickRes = await this.moveService.seqExeJoystick(request);
  499. this.logger.log(
  500. 'joystick-breakPointId:' +
  501. this.moveService.users[this.user_id].breakPointId,
  502. );
  503. // 有数据 [0]是rotate数据,[1-infinity]是walking数据
  504. this.logger.log('joystickRes-1', joystickRes);
  505. this.onJoysticking.next(true);
  506. if (Array.isArray(joystickRes)) {
  507. // 处理第一个镜头数据
  508. const rotateCamData = joystickRes[0];
  509. this.logger.log('rotateCamData', rotateCamData.length);
  510. if (rotateCamData?.length) {
  511. // 头数组[0] rotate 序列, 头是关键key
  512. joystickRes[0].forEach((item: StreamReplyType, index: number) => {
  513. const IDRflag = index % 5 === 0 ? 1 : 3;
  514. const dir = this.isHeaderOrLast(index, joystickRes[0].length - 1);
  515. item.DIR = dir ? 1 : IDRflag;
  516. item.mType = 'rotate';
  517. });
  518. } else {
  519. this.logger.log('rotateCamData无数据');
  520. }
  521. // 二维数组 做move 序列, move类型
  522. if (joystickRes?.length >= 1) {
  523. for (let i = 1; i < joystickRes.length; i++) {
  524. this.logger.log('joystickRes-2', joystickRes[i]);
  525. Array.from(joystickRes[i]).forEach(
  526. (item: StreamReplyType, index: number) => {
  527. const IDRflag = index % 5 === 0 ? 1 : 3;
  528. const dir = this.isHeaderOrLast(
  529. index,
  530. joystickRes[i].length - 1,
  531. );
  532. item.DIR = dir ? 1 : IDRflag;
  533. // 将每段最后一个推入lastMovingPointArray
  534. if (index === joystickRes[i].length - 1) {
  535. this.lastMovingPointArray.push({
  536. mediaSrc: item.mediaSrc,
  537. metaData: item,
  538. });
  539. }
  540. //this.logger.log(
  541. // 'joystick:' +
  542. // JSON.stringify(
  543. // joystickRes[i][index]['newUserStates'][0].playerState
  544. // .camera.position,
  545. // ),
  546. // );
  547. },
  548. );
  549. }
  550. }
  551. const seqs = Array.from(joystickRes).flat() as any as StreamReplyType[];
  552. if (seqs?.length > 1) {
  553. this.logger.log('joystick:-seqs', seqs.length);
  554. //TODO joystick中断逻辑
  555. this.hasJoystickMoveRequest = true;
  556. this.handleSeqMoving(seqs);
  557. } else {
  558. console.warn('joystick-move无数据');
  559. }
  560. } else {
  561. this.logger.log('joystick-接收人物数据', this.onMoving.getValue());
  562. if (!this.onMoving.getValue()) {
  563. // 在非行走时接受
  564. this.holdSteam();
  565. if (this.joystickFrameCnt === -1) {
  566. this.joystickFrameCnt = this.frameCnt.getValue();
  567. }
  568. this.joystickFrameCnt += 1;
  569. const stream: StreamMetaType = {
  570. frame: this.joystickFrameCnt,
  571. metaData: JSON.stringify(joystickRes),
  572. };
  573. //this.logger.log('rotate', stream, Date.now());
  574. const res = await this.streamService.pushMetaDataToSteam(stream);
  575. if (res.done) {
  576. this.logger.log('joystick-frame', res.frame);
  577. this.frameCnt.next(res.frame);
  578. clearTimeout(this._JoyStickingTimeout);
  579. this._JoyStickingTimeout = setTimeout(() => {
  580. this.logger.log('joystick opt done');
  581. this.logger.log('joystick 交权给空流,当前pts', res.frame);
  582. // this.frameCnt.next(res.frame);
  583. this.onJoysticking.next(false);
  584. this.resumeStream();
  585. this.joystickFrameCnt = -1;
  586. }, 100);
  587. }
  588. }
  589. }
  590. } catch (error) {
  591. console.error('joystick错误', error);
  592. this.logger.error('joystick', error.message);
  593. }
  594. }
  595. /**
  596. * 主要处理moving的序列动作
  597. * @param seqs StreamReplyType[]
  598. */
  599. handleSeqMoving(seqs: StreamReplyType[]) {
  600. if (!this.moveQueueSubscription) {
  601. this.handleMoveSteam();
  602. }
  603. this.logger.log('moving-seqs', seqs.length);
  604. this.onMoving.next(true);
  605. this.holdSteam();
  606. //TODO Remove
  607. // clearTimeout(this._JoyStickingTimeout);
  608. seqs.forEach((frame: StreamReplyType) => {
  609. const mediaSrc = frame.mediaSrc;
  610. const src = mediaSrc.split('?')[0];
  611. const clipPath = this.configService.get('app.prefix') + src;
  612. const type = frame.mType?.length ? frame.mType.slice() : 'move';
  613. const stream: StreamFrameType = {
  614. frame: -1,
  615. clipPath: clipPath,
  616. metaData: JSON.stringify(frame),
  617. serverTime: this.mockserverTime,
  618. DIR: frame.DIR,
  619. mType: type,
  620. };
  621. this.moveQueue.next(stream);
  622. });
  623. }
  624. cleanMoveSteam() {
  625. if (this.moveQueueSubscription) {
  626. this.moveQueueSubscription.unsubscribe();
  627. this.moveQueueSubscription = null;
  628. }
  629. if (this.walkingSub) {
  630. this.walkingSub.unsubscribe();
  631. this.walkingSub = null;
  632. }
  633. // if (this.clickQueueSub) {
  634. // this.clickQueueSub.unsubscribe();
  635. // this.clickQueueSub = null;
  636. // }
  637. }
  638. handleMoveSteam() {
  639. this.moveQueueSubscription = this.moveQueue.subscribe(
  640. async (stream: StreamFrameType) => {
  641. const metaData: StreamReplyType = JSON.parse(stream.metaData);
  642. if (this.moveframeCnt === -1) {
  643. this.moveframeCnt = this.frameCnt.getValue();
  644. }
  645. this.moveframeCnt += 1;
  646. this.latestBreakPointId = metaData.endBreakPointId;
  647. const streamData: StreamFrameType = {
  648. frame: this.moveframeCnt,
  649. clipPath: stream.clipPath,
  650. metaData: stream.metaData,
  651. serverTime: this.mockserverTime,
  652. DIR: stream.DIR,
  653. };
  654. this.logger.log(
  655. '[media-move]: ' +
  656. ', moveframeCnt: ' +
  657. this.moveframeCnt +
  658. ', clipPath: ' +
  659. stream.clipPath +
  660. ', mType: ' +
  661. stream.mType +
  662. ', DIR: ' +
  663. stream.DIR,
  664. // stream.metaData,
  665. );
  666. this.logger.log(
  667. '[media-move-lastMovingPointArray]',
  668. this.lastMovingPointArray?.length,
  669. );
  670. this.lastMoveStreamFrame.next(streamData);
  671. const res = await this.streamService.pushFrameToSteam(streamData);
  672. const isLastFrameIndex = this.lastMovingPointArray.findIndex(
  673. (item) => item.mediaSrc === metaData.mediaSrc,
  674. );
  675. //this.logger.log('path-update-index', isLastFrameIndex);
  676. //每一段的最后一帧
  677. if (isLastFrameIndex > -1) {
  678. //this.logger.log('path-update-array', this.lastMovingPointArray);
  679. const currentMeta = this.lastMovingPointArray[isLastFrameIndex];
  680. const userId = this.user_id;
  681. const breakPointId = currentMeta.metaData.endBreakPointId;
  682. const lastReply = currentMeta.metaData;
  683. this.moveService.updateUser(userId, breakPointId, lastReply);
  684. //debugger
  685. this.lastMovingPointArray.splice(isLastFrameIndex, 1);
  686. //TODO 队列每一段最后one frame
  687. this.moveSliceLastFrame.next(currentMeta);
  688. }
  689. if (res.done) {
  690. clearTimeout(this._moveTimeout);
  691. this._moveTimeout = setTimeout(() => {
  692. this.logger.log('move 交权给空流,当前pts', res.frame);
  693. this.frameCnt.next(res.frame);
  694. this.resumeStream();
  695. this.rotateframeCnt = -1;
  696. this.onMoving.next(false);
  697. this.onJoysticking.next(false);
  698. this.cleanMoveSteam();
  699. this.lastMovingPointArray = [];
  700. this.hasJoystickMoveRequest = false;
  701. this.logger.log('move end');
  702. }, 300);
  703. }
  704. },
  705. );
  706. }
  707. handleDataChanelOpen(channel: DataChannel): void {
  708. this.channel = channel;
  709. this.streamService.setChannel(channel);
  710. }
  711. handleDataChanelClose(): void {
  712. this.stopStream();
  713. this.startSteaming.next(false);
  714. this.streamService.closeChannel();
  715. // const exitRequest: ExitRequest = {
  716. // action_type: 1002,
  717. // user_id: this.user_id,
  718. // trace_id: '',
  719. // };
  720. this.exit();
  721. }
  722. handleMessage(message: string | Buffer) {
  723. try {
  724. if (typeof message === 'string') {
  725. // wasm:特例, requestIframe
  726. if (message.includes('wasm:')) {
  727. const parseData = message
  728. ? String(message).replace('wasm:', '')
  729. : `{"MstType":1}`;
  730. const msg: RTCMessageRequest = JSON.parse(parseData);
  731. this.logger.error('lostIframe-message', JSON.stringify(msg));
  732. if (msg.MstType === 0) {
  733. this.handleIframeRequest();
  734. }
  735. } else {
  736. const msg: RTCMessageRequest = JSON.parse(message);
  737. // console.log('msg.action_type:' + msg.action_type);
  738. switch (msg.action_type) {
  739. case ActionType.walk:
  740. const walk = msg as any as MoveRequest;
  741. this.walking(walk);
  742. break;
  743. case ActionType.joystick:
  744. const JoystickRequest = msg as any as JoystickRequest;
  745. this.joystick(JoystickRequest);
  746. break;
  747. case ActionType.breathPoint:
  748. this.handleBreath(msg);
  749. break;
  750. case ActionType.rotate:
  751. const rotateRequest: RotateRequest = msg;
  752. this.rotate(rotateRequest);
  753. break;
  754. case ActionType.userStatus:
  755. this.updateUserStatus(msg);
  756. break;
  757. case ActionType.status:
  758. this.updateStatus();
  759. break;
  760. default:
  761. break;
  762. }
  763. }
  764. }
  765. } catch (error) {
  766. this.logger.error('handleMessage:rtc--error', error.message);
  767. }
  768. }
  769. async handleIframeRequest() {
  770. //TODO Iframe 最终传什么?
  771. this.requestIFrameQueue.next(this.streamService.lastStreamFrame.getValue());
  772. if (!this.requestIFrameQueueSub) {
  773. this.requestIFrameQueueSub = this.requestIFrameQueue.subscribe(
  774. (frameData: StreamFrameType) => {
  775. const nextFrame = this.frameCnt.getValue() + 1;
  776. this.logger.warn('lostIframe', nextFrame);
  777. frameData.frame = nextFrame;
  778. this.streamService.pushFrameToSteam(frameData);
  779. this.frameCnt.next(nextFrame);
  780. this.resumeStream();
  781. },
  782. );
  783. }
  784. }
  785. handleBreath(request) {
  786. const npsRes = this.moveService.getBreakPoints(request);
  787. //this.logger.log('npsRes', npsRes.nps);
  788. this.streamService.pushNormalDataToStream(npsRes);
  789. }
  790. updateStatus(): void {
  791. const reply = {
  792. data: { action_type: 1009, echo_msg: { echoMsg: Date.now() } },
  793. track: false,
  794. };
  795. this.streamService.pushNormalDataToStream(reply);
  796. }
  797. updateUserStatus(request) {
  798. try {
  799. const usersData = this.rotateService.getNewUserStateRequest(request);
  800. if (usersData) {
  801. usersData.actionType = 1024;
  802. //this.logger.log(
  803. // 'joystick:->updateUserStatus' +
  804. // 'playerPosition:' +
  805. // JSON.stringify(
  806. // redisMeta['newUserStates'][0].playerState.player.position,
  807. // ),
  808. // );
  809. this.streamService.pushNormalDataToStream(usersData);
  810. } else {
  811. this.logger.error('updateUserStatus::function-empty');
  812. }
  813. } catch (error) {
  814. this.logger.error('updateUserStatus::function', error.message);
  815. }
  816. }
  817. /**
  818. * rotate 推送队列
  819. */
  820. handleRotateStream() {
  821. if (!this.roQueueSubscription) {
  822. this.roQueueSubscription = this.roQueue.subscribe(
  823. async (stream: StreamFrameType) => {
  824. this.rotateTimeStamp = Date.now();
  825. if (this.rotateframeCnt === -1) {
  826. this.rotateframeCnt = this.frameCnt.value;
  827. }
  828. this.rotateframeCnt += 1;
  829. stream.frame = this.rotateframeCnt;
  830. this._rotateCurrentFame += 1;
  831. const IDRflag = this._rotateCurrentFame % 5 === 0 ? 1 : 3;
  832. this.logger.log(
  833. `当前rotate ,mainframeCnt:${this.frameCnt.getValue()}, _rotateCurrentFame:${
  834. this._rotateCurrentFame
  835. } IDRflag:${IDRflag}`,
  836. );
  837. stream.DIR = this.rotateFirstIDR ? 1 : IDRflag;
  838. if (this.rotateFirstIDR) {
  839. this.rotateFirstIDR = false;
  840. }
  841. this.logger.log(
  842. '[media-rotate]: ' +
  843. ', frame: ' +
  844. stream.frame +
  845. ', rotateframeCnt: ' +
  846. this.rotateframeCnt +
  847. ', clipPath: ' +
  848. stream.clipPath,
  849. // stream.metaData,
  850. );
  851. // this.logger.log(
  852. // `roQueueSubscription:frame:${this.rotateframeCnt} ` +
  853. // JSON.stringify(stream.metaData),
  854. // );
  855. const res = await this.streamService.pushFrameToSteam(stream);
  856. if (res.done) {
  857. clearTimeout(this._rotateTimeout);
  858. this._rotateTimeout = setTimeout(() => {
  859. this.logger.log('rotate end', Date.now());
  860. this.frameCnt.next(res.frame);
  861. this.resumeStream();
  862. this.rotateframeCnt = -1;
  863. this._rotateCurrentFame = -1;
  864. this.onMoving.next(false);
  865. this.onRotating.next(false);
  866. this.rotateFirstIDR = true;
  867. //TODO rotate完后清除request队列
  868. if (this.roRequestQueueSub) {
  869. this.roRequestQueueSub.unsubscribe();
  870. this.roRequestQueueSub = null;
  871. }
  872. }, 300);
  873. }
  874. },
  875. );
  876. }
  877. }
  878. pushFirstRender(clipPath: string, metaData: string): Promise<boolean> {
  879. return new Promise<boolean>(async (resolve, reject) => {
  880. try {
  881. const streamData: StreamFrameType = {
  882. frame: 1,
  883. clipPath: clipPath,
  884. metaData: metaData,
  885. serverTime: this.mockserverTime,
  886. DIR: 1,
  887. };
  888. const hasPush = await this.streamService.pushFrameToSteam(streamData);
  889. return resolve(hasPush.done);
  890. } catch (error) {
  891. return reject(false);
  892. }
  893. });
  894. }
  895. handleStream() {
  896. this.logger.log('this.frameCntSubscription', this.frameCntSubscription);
  897. if (!this.frameCntSubscription) {
  898. this.frameCntSubscription = this.frameCnt.subscribe(async (frame) => {
  899. try {
  900. this.logger.log('frame', frame);
  901. if (frame === 1) {
  902. const redisData = await this.rotateService.echo(this.user_id, true);
  903. this.logger.log('获取-首屏', redisData);
  904. this.onSteaming = true;
  905. this.holdSteam();
  906. if (redisData && 'mediaSrc' in redisData) {
  907. const mediaSrc: string = redisData.mediaSrc || '';
  908. if (mediaSrc.length > 0) {
  909. const src = mediaSrc.split('?')[0];
  910. // 临时本地替换路经
  911. // src = src.replace('/10086/', '');
  912. // const clipPath = join(__dirname, `../ws/${src}`);
  913. const clipPath = this.configService.get('app.prefix') + src;
  914. delete redisData.mediaSrc;
  915. this.logger.log(
  916. `user:${this.user_id}:first render stream` +
  917. JSON.stringify({ path: clipPath, meta: redisData }),
  918. );
  919. const status = await this.pushFirstRender(
  920. clipPath,
  921. JSON.stringify(redisData),
  922. );
  923. if (status) {
  924. this.firstRender = true;
  925. this.frameCnt.next(2);
  926. this.resumeStream();
  927. } else {
  928. this.logger.error('first render problem', status);
  929. }
  930. }
  931. } else {
  932. this.logger.error(`首屏::无数据:${frame}`);
  933. }
  934. }
  935. if (
  936. frame > 1 &&
  937. !this.onMoving.value &&
  938. !this.onRotating.value &&
  939. !this.onJoysticking.value &&
  940. this.firstRender
  941. ) {
  942. const redisDataAuto = await this.rotateService.echo(
  943. this.user_id,
  944. false,
  945. );
  946. if (redisDataAuto) {
  947. this.logger.log(`空白流::有数据:${frame}`);
  948. 'mediaSrc' in redisDataAuto && delete redisDataAuto.mediaSrc;
  949. const streamMeta: StreamMetaType = {
  950. frame: frame,
  951. metaData: JSON.stringify(redisDataAuto),
  952. };
  953. this.streamService.pushMetaDataToSteam(streamMeta);
  954. } else {
  955. this.stopStream();
  956. this.logger.log('空流无Redis数据');
  957. throw new Error('空流无Redis数据');
  958. }
  959. }
  960. } catch (error) {
  961. this.stopStream();
  962. this.logger.error('handleStream', error.message);
  963. }
  964. });
  965. }
  966. }
  967. }