scene.service.ts 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  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-0',
  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('stop-data-1', 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-2',
  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. console.log('move-walkingRes:'+JSON.stringify(walkingRes));
  414. if (walkingRes && walkingRes?.length >= 1) {
  415. for (let i = 1; i < walkingRes.length; i++) {
  416. Array.from(walkingRes[i]).forEach(
  417. (item: StreamReplyType, index: number) => {
  418. const IDRflag = index % 5 === 0 ? 1 : 3;
  419. const dir = this.isHeaderOrLast(
  420. index,
  421. walkingRes[i].length - 1,
  422. );
  423. item.DIR = dir ? 1 : IDRflag;
  424. //将每段最后一个推入lastMovingPointArray
  425. if (index === walkingRes[i].length - 1) {
  426. this.lastMovingPointArray.push({
  427. mediaSrc: item.mediaSrc,
  428. metaData: item,
  429. });
  430. }
  431. },
  432. );
  433. }
  434. }
  435. // walkingRes marker to everybody
  436. const seqs = Array.from(walkingRes).flat() as any as StreamReplyType[];
  437. if (seqs?.length) {
  438. this.logger.log('walking --总序列--seqs-2:'+ seqs.length);
  439. const stop = performance.now();
  440. const inMillSeconds = stop - start;
  441. const rounded = Number(inMillSeconds).toFixed(3);
  442. this.logger.log(`[timer]-move-入队列前:-->${rounded}ms`);
  443. this.handleSeqMoving(seqs);
  444. } else {
  445. console.error('walking-move无数据');
  446. this.cleanMoveSteam();
  447. this.resumeStream();
  448. }
  449. // }
  450. }
  451. // });
  452. // }
  453. } catch (error) {
  454. this.logger.error('walking', error.message);
  455. this.cleanMoveSteam();
  456. this.resumeStream();
  457. }
  458. }
  459. /**
  460. * 改变路线后的walking队列处理(中转)
  461. * @param request MoveRequest
  462. */
  463. handleReWalking(request: MoveRequest) {
  464. this.latestWalkingRequest = null;
  465. this.handleWalking(request);
  466. }
  467. /***
  468. * joystick main core
  469. */
  470. async joystick(request: JoystickRequest) {
  471. // TODO hasJoystickMoveRequest中断
  472. this.logger.log('this.hasJoystickMoveRequest', this.hasJoystickMoveRequest);
  473. if (!this.hasJoystickMoveRequest) {
  474. this.handlejoystick(request);
  475. }
  476. }
  477. /***
  478. * joystick
  479. */
  480. async handlejoystick(request: JoystickRequest) {
  481. try {
  482. //const joystickRes = await this.moveService.joystick(request);
  483. const joystickRes = await this.moveService.seqExeJoystick(request);
  484. this.logger.log(
  485. 'joystick-breakPointId:' +
  486. this.moveService.users[this.user_id].breakPointId,
  487. );
  488. // 有数据 [0]是rotate数据,[1-infinity]是walking数据
  489. this.logger.log('joystickRes-1', joystickRes);
  490. this.onJoysticking.next(true);
  491. if (Array.isArray(joystickRes)) {
  492. // 处理第一个镜头数据
  493. const rotateCamData = joystickRes[0];
  494. this.logger.log('rotateCamData', rotateCamData.length);
  495. if (rotateCamData?.length) {
  496. // 头数组[0] rotate 序列, 头是关键key
  497. joystickRes[0].forEach((item: StreamReplyType, index: number) => {
  498. const IDRflag = index % 5 === 0 ? 1 : 3;
  499. const dir = this.isHeaderOrLast(index, joystickRes[0].length - 1);
  500. item.DIR = dir ? 1 : IDRflag;
  501. item.mType = 'rotate';
  502. });
  503. } else {
  504. this.logger.log('rotateCamData无数据');
  505. }
  506. // 二维数组 做move 序列, move类型
  507. if (joystickRes?.length >= 1) {
  508. for (let i = 1; i < joystickRes.length; i++) {
  509. this.logger.log('joystickRes-2', joystickRes[i]);
  510. Array.from(joystickRes[i]).forEach(
  511. (item: StreamReplyType, index: number) => {
  512. const IDRflag = index % 5 === 0 ? 1 : 3;
  513. const dir = this.isHeaderOrLast(
  514. index,
  515. joystickRes[i].length - 1,
  516. );
  517. item.DIR = dir ? 1 : IDRflag;
  518. // 将每段最后一个推入lastMovingPointArray
  519. if (index === joystickRes[i].length - 1) {
  520. this.lastMovingPointArray.push({
  521. mediaSrc: item.mediaSrc,
  522. metaData: item,
  523. });
  524. }
  525. //this.logger.log(
  526. // 'joystick:' +
  527. // JSON.stringify(
  528. // joystickRes[i][index]['newUserStates'][0].playerState
  529. // .camera.position,
  530. // ),
  531. // );
  532. },
  533. );
  534. }
  535. }
  536. const seqs = Array.from(joystickRes).flat() as any as StreamReplyType[];
  537. if (seqs?.length > 1) {
  538. this.logger.log('joystick:-seqs', seqs.length);
  539. //TODO joystick中断逻辑
  540. this.hasJoystickMoveRequest = true;
  541. this.handleSeqMoving(seqs);
  542. } else {
  543. console.warn('joystick-move无数据');
  544. }
  545. } else {
  546. this.logger.log('joystick-接收人物数据', this.onMoving.getValue());
  547. if (!this.onMoving.getValue()) {
  548. // 在非行走时接受
  549. this.holdSteam();
  550. if (this.joystickFrameCnt === -1) {
  551. this.joystickFrameCnt = this.frameCnt.getValue();
  552. }
  553. this.joystickFrameCnt += 1;
  554. const stream: StreamMetaType = {
  555. frame: this.joystickFrameCnt,
  556. metaData: JSON.stringify(joystickRes),
  557. };
  558. //this.logger.log('rotate', stream, Date.now());
  559. const res = await this.streamService.pushMetaDataToSteam(stream);
  560. if (res.done) {
  561. this.logger.log('joystick-frame', res.frame);
  562. this.frameCnt.next(res.frame);
  563. clearTimeout(this._JoyStickingTimeout);
  564. this._JoyStickingTimeout = setTimeout(() => {
  565. this.logger.log('joystick opt done');
  566. this.logger.log('joystick 交权给空流,当前pts', res.frame);
  567. // this.frameCnt.next(res.frame);
  568. this.onJoysticking.next(false);
  569. this.resumeStream();
  570. this.joystickFrameCnt = -1;
  571. }, 100);
  572. }
  573. }
  574. }
  575. } catch (error) {
  576. console.error('joystick错误', error);
  577. this.logger.error('joystick', error.message);
  578. }
  579. }
  580. /**
  581. * 主要处理moving的序列动作
  582. * @param seqs StreamReplyType[]
  583. */
  584. handleSeqMoving(seqs: StreamReplyType[]) {
  585. if (!this.moveQueueSubscription) {
  586. this.handleMoveSteam();
  587. }
  588. this.logger.log('moving-seqs', seqs.length);
  589. this.onMoving.next(true);
  590. this.holdSteam();
  591. //TODO Remove
  592. // clearTimeout(this._JoyStickingTimeout);
  593. seqs.forEach((frame: StreamReplyType) => {
  594. const mediaSrc = frame.mediaSrc;
  595. const src = mediaSrc.split('?')[0];
  596. const clipPath = this.configService.get('app.prefix') + src;
  597. const type = frame.mType?.length ? frame.mType.slice() : 'move';
  598. const stream: StreamFrameType = {
  599. frame: -1,
  600. clipPath: clipPath,
  601. metaData: JSON.stringify(frame),
  602. serverTime: this.mockserverTime,
  603. DIR: frame.DIR,
  604. mType: type,
  605. };
  606. this.moveQueue.next(stream);
  607. });
  608. }
  609. cleanMoveSteam() {
  610. if (this.moveQueueSubscription) {
  611. this.moveQueueSubscription.unsubscribe();
  612. this.moveQueueSubscription = null;
  613. }
  614. if (this.walkingSub) {
  615. this.walkingSub.unsubscribe();
  616. this.walkingSub = null;
  617. }
  618. // if (this.clickQueueSub) {
  619. // this.clickQueueSub.unsubscribe();
  620. // this.clickQueueSub = null;
  621. // }
  622. }
  623. handleMoveSteam() {
  624. this.moveQueueSubscription = this.moveQueue.subscribe(
  625. async (stream: StreamFrameType) => {
  626. const metaData: StreamReplyType = JSON.parse(stream.metaData);
  627. if (this.moveframeCnt === -1) {
  628. this.moveframeCnt = this.frameCnt.getValue();
  629. }
  630. this.moveframeCnt += 1;
  631. this.latestBreakPointId = metaData.endBreakPointId;
  632. const streamData: StreamFrameType = {
  633. frame: this.moveframeCnt,
  634. clipPath: stream.clipPath,
  635. metaData: stream.metaData,
  636. serverTime: this.mockserverTime,
  637. DIR: stream.DIR,
  638. };
  639. this.logger.log(
  640. '[media-move]: ' +
  641. ', moveframeCnt: ' +
  642. this.moveframeCnt +
  643. ', clipPath: ' +
  644. stream.clipPath +
  645. ', mType: ' +
  646. stream.mType +
  647. ', DIR: ' +
  648. stream.DIR,
  649. // stream.metaData,
  650. );
  651. this.logger.log(
  652. '[media-move-lastMovingPointArray]',
  653. this.lastMovingPointArray?.length,
  654. );
  655. this.lastMoveStreamFrame.next(streamData);
  656. const res = await this.streamService.pushFrameToSteam(streamData);
  657. const isLastFrameIndex = this.lastMovingPointArray.findIndex(
  658. (item) => item.mediaSrc === metaData.mediaSrc,
  659. );
  660. //this.logger.log('path-update-index', isLastFrameIndex);
  661. //每一段的最后一帧
  662. if (isLastFrameIndex > -1) {
  663. //this.logger.log('path-update-array', this.lastMovingPointArray);
  664. const currentMeta = this.lastMovingPointArray[isLastFrameIndex];
  665. const userId = this.user_id;
  666. const breakPointId = currentMeta.metaData.endBreakPointId;
  667. const lastReply = currentMeta.metaData;
  668. this.moveService.updateUser(userId, breakPointId, lastReply);
  669. //debugger
  670. this.lastMovingPointArray.splice(isLastFrameIndex, 1);
  671. //TODO 队列每一段最后one frame
  672. this.moveSliceLastFrame.next(currentMeta);
  673. }
  674. if (res.done) {
  675. clearTimeout(this._moveTimeout);
  676. this._moveTimeout = setTimeout(() => {
  677. this.logger.log('move 交权给空流,当前pts', res.frame);
  678. this.frameCnt.next(res.frame);
  679. this.resumeStream();
  680. this.rotateframeCnt = -1;
  681. this.onMoving.next(false);
  682. this.onJoysticking.next(false);
  683. this.cleanMoveSteam();
  684. this.lastMovingPointArray = [];
  685. this.hasJoystickMoveRequest = false;
  686. this.logger.log('move end');
  687. }, 300);
  688. }
  689. },
  690. );
  691. }
  692. handleDataChanelOpen(channel: DataChannel): void {
  693. this.channel = channel;
  694. this.streamService.setChannel(channel);
  695. }
  696. handleDataChanelClose(): void {
  697. this.stopStream();
  698. this.startSteaming.next(false);
  699. this.streamService.closeChannel();
  700. // const exitRequest: ExitRequest = {
  701. // action_type: 1002,
  702. // user_id: this.user_id,
  703. // trace_id: '',
  704. // };
  705. this.exit();
  706. }
  707. handleMessage(message: string | Buffer) {
  708. try {
  709. if (typeof message === 'string') {
  710. // wasm:特例, requestIframe
  711. if (message.includes('wasm:')) {
  712. const parseData = message
  713. ? String(message).replace('wasm:', '')
  714. : `{"MstType":1}`;
  715. const msg: RTCMessageRequest = JSON.parse(parseData);
  716. this.logger.error('lostIframe-message', JSON.stringify(msg));
  717. if (msg.MstType === 0) {
  718. this.handleIframeRequest();
  719. }
  720. } else {
  721. const msg: RTCMessageRequest = JSON.parse(message);
  722. console.log('msg.action_type:'+msg.action_type);
  723. switch (msg.action_type) {
  724. case ActionType.walk:
  725. const walk = msg as any as MoveRequest;
  726. this.walking(walk);
  727. break;
  728. case ActionType.joystick:
  729. const JoystickRequest = msg as any as JoystickRequest;
  730. this.joystick(JoystickRequest);
  731. break;
  732. case ActionType.breathPoint:
  733. this.handleBreath(msg);
  734. break;
  735. case ActionType.rotate:
  736. const rotateRequest: RotateRequest = msg;
  737. this.rotate(rotateRequest);
  738. break;
  739. case ActionType.userStatus:
  740. this.updateUserStatus(msg);
  741. break;
  742. case ActionType.status:
  743. this.updateStatus();
  744. break;
  745. default:
  746. break;
  747. }
  748. }
  749. }
  750. } catch (error) {
  751. this.logger.error('handleMessage:rtc--error', error.message);
  752. }
  753. }
  754. async handleIframeRequest() {
  755. //TODO Iframe 最终传什么?
  756. this.requestIFrameQueue.next(this.streamService.lastStreamFrame.getValue());
  757. if (!this.requestIFrameQueueSub) {
  758. this.requestIFrameQueueSub = this.requestIFrameQueue.subscribe(
  759. (frameData: StreamFrameType) => {
  760. const nextFrame = this.frameCnt.getValue() + 1;
  761. this.logger.warn('lostIframe', nextFrame);
  762. frameData.frame = nextFrame;
  763. this.streamService.pushFrameToSteam(frameData);
  764. this.frameCnt.next(nextFrame);
  765. this.resumeStream();
  766. },
  767. );
  768. }
  769. }
  770. handleBreath(request) {
  771. const npsRes = this.moveService.getBreakPoints(request);
  772. //this.logger.log('npsRes', npsRes.nps);
  773. this.streamService.pushNormalDataToStream(npsRes);
  774. }
  775. updateStatus(): void {
  776. const reply = {
  777. data: { action_type: 1009, echo_msg: { echoMsg: Date.now() } },
  778. track: false,
  779. };
  780. this.streamService.pushNormalDataToStream(reply);
  781. }
  782. updateUserStatus(request) {
  783. try {
  784. const usersData = this.rotateService.getNewUserStateRequest(request);
  785. if (usersData) {
  786. usersData.actionType = 1024;
  787. //this.logger.log(
  788. // 'joystick:->updateUserStatus' +
  789. // 'playerPosition:' +
  790. // JSON.stringify(
  791. // redisMeta['newUserStates'][0].playerState.player.position,
  792. // ),
  793. // );
  794. this.streamService.pushNormalDataToStream(usersData);
  795. } else {
  796. this.logger.error('updateUserStatus::function-empty');
  797. }
  798. } catch (error) {
  799. this.logger.error('updateUserStatus::function', error.message);
  800. }
  801. }
  802. /**
  803. * rotate 推送队列
  804. */
  805. handleRotateStream() {
  806. if (!this.roQueueSubscription) {
  807. this.roQueueSubscription = this.roQueue.subscribe(
  808. async (stream: StreamFrameType) => {
  809. this.rotateTimeStamp = Date.now();
  810. if (this.rotateframeCnt === -1) {
  811. this.rotateframeCnt = this.frameCnt.value;
  812. }
  813. this.rotateframeCnt += 1;
  814. stream.frame = this.rotateframeCnt;
  815. this._rotateCurrentFame += 1;
  816. const IDRflag = this._rotateCurrentFame % 5 === 0 ? 1 : 3;
  817. this.logger.log(
  818. `当前rotate ,mainframeCnt:${this.frameCnt.getValue()}, _rotateCurrentFame:${
  819. this._rotateCurrentFame
  820. } IDRflag:${IDRflag}`,
  821. );
  822. stream.DIR = this.rotateFirstIDR ? 1 : IDRflag;
  823. if (this.rotateFirstIDR) {
  824. this.rotateFirstIDR = false;
  825. }
  826. this.logger.log(
  827. '[media-rotate]: ' +
  828. ', frame: ' +
  829. stream.frame +
  830. ', rotateframeCnt: ' +
  831. this.rotateframeCnt +
  832. ', clipPath: ' +
  833. stream.clipPath,
  834. // stream.metaData,
  835. );
  836. // this.logger.log(
  837. // `roQueueSubscription:frame:${this.rotateframeCnt} ` +
  838. // JSON.stringify(stream.metaData),
  839. // );
  840. const res = await this.streamService.pushFrameToSteam(stream);
  841. if (res.done) {
  842. clearTimeout(this._rotateTimeout);
  843. this._rotateTimeout = setTimeout(() => {
  844. this.logger.log('rotate end', Date.now());
  845. this.frameCnt.next(res.frame);
  846. this.resumeStream();
  847. this.rotateframeCnt = -1;
  848. this._rotateCurrentFame = -1;
  849. this.onMoving.next(false);
  850. this.onRotating.next(false);
  851. this.rotateFirstIDR = true;
  852. //TODO rotate完后清除request队列
  853. if (this.roRequestQueueSub) {
  854. this.roRequestQueueSub.unsubscribe();
  855. this.roRequestQueueSub = null;
  856. }
  857. }, 300);
  858. }
  859. },
  860. );
  861. }
  862. }
  863. pushFirstRender(clipPath: string, metaData: string): Promise<boolean> {
  864. return new Promise<boolean>(async (resolve, reject) => {
  865. try {
  866. const streamData: StreamFrameType = {
  867. frame: 1,
  868. clipPath: clipPath,
  869. metaData: metaData,
  870. serverTime: this.mockserverTime,
  871. DIR: 1,
  872. };
  873. const hasPush = await this.streamService.pushFrameToSteam(streamData);
  874. return resolve(hasPush.done);
  875. } catch (error) {
  876. return reject(false);
  877. }
  878. });
  879. }
  880. handleStream() {
  881. this.logger.log('this.frameCntSubscription', this.frameCntSubscription);
  882. if (!this.frameCntSubscription) {
  883. this.frameCntSubscription = this.frameCnt.subscribe(async (frame) => {
  884. try {
  885. this.logger.log('frame', frame);
  886. if (frame === 1) {
  887. const redisData = await this.rotateService.echo(this.user_id, true);
  888. this.logger.log('获取-首屏', redisData);
  889. this.onSteaming = true;
  890. this.holdSteam();
  891. if (redisData && 'mediaSrc' in redisData) {
  892. const mediaSrc: string = redisData.mediaSrc || '';
  893. if (mediaSrc.length > 0) {
  894. const src = mediaSrc.split('?')[0];
  895. // 临时本地替换路经
  896. // src = src.replace('/10086/', '');
  897. // const clipPath = join(__dirname, `../ws/${src}`);
  898. const clipPath = this.configService.get('app.prefix') + src;
  899. delete redisData.mediaSrc;
  900. this.logger.log(
  901. `user:${this.user_id}:first render stream` +
  902. JSON.stringify({ path: clipPath, meta: redisData }),
  903. );
  904. const status = await this.pushFirstRender(
  905. clipPath,
  906. JSON.stringify(redisData),
  907. );
  908. if (status) {
  909. this.firstRender = true;
  910. this.frameCnt.next(2);
  911. this.resumeStream();
  912. } else {
  913. this.logger.error('first render problem', status);
  914. }
  915. }
  916. } else {
  917. this.logger.error(`首屏::无数据:${frame}`);
  918. }
  919. }
  920. if (
  921. frame > 1 &&
  922. !this.onMoving.value &&
  923. !this.onRotating.value &&
  924. !this.onJoysticking.value &&
  925. this.firstRender
  926. ) {
  927. const redisDataAuto = await this.rotateService.echo(
  928. this.user_id,
  929. false,
  930. );
  931. if (redisDataAuto) {
  932. this.logger.log(`空白流::有数据:${frame}`);
  933. 'mediaSrc' in redisDataAuto && delete redisDataAuto.mediaSrc;
  934. const streamMeta: StreamMetaType = {
  935. frame: frame,
  936. metaData: JSON.stringify(redisDataAuto),
  937. };
  938. this.streamService.pushMetaDataToSteam(streamMeta);
  939. } else {
  940. this.stopStream();
  941. this.logger.log('空流无Redis数据');
  942. throw new Error('空流无Redis数据');
  943. }
  944. }
  945. } catch (error) {
  946. this.stopStream();
  947. this.logger.error('handleStream', error.message);
  948. }
  949. });
  950. }
  951. }
  952. }