scene.service.ts 37 KB

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