scene.service.ts 40 KB

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