scene.service.ts 33 KB

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