scene.service.ts 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179
  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(30);
  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. clearTimeout(this._JoyStickingSteamTimeout);
  565. this._JoyStickingSteamTimeout = setTimeout(() => {
  566. // const complementFrame = this.moveService.complementFrame(
  567. // this.user_id,
  568. // ) as StreamReplyType;
  569. // console.log('has-complementFrame', complementFrame);
  570. // if (complementFrame) {
  571. // pushJoyStickSteam(complementFrame);
  572. // } else {
  573. this.frameCnt.next(hasPush.frame);
  574. this.logger.log('joystick opt done');
  575. this.logger.log('joystick 交权给空流,当前pts', hasPush.frame);
  576. // this.frameCnt.next(res.frame);
  577. this.onJoysticking.next(false);
  578. this.resumeStream();
  579. this.joystickFrameCnt = -1;
  580. this.isJoystickHasStream = false;
  581. // }
  582. }, 200);
  583. } else {
  584. console.error('joystick-流地址有误::', joystickRes.mediaSrc);
  585. this.logger.error('joystick-流地址有误::', joystickRes.mediaSrc);
  586. this.resumeStream();
  587. }
  588. return hasPush;
  589. };
  590. // 二级方法end
  591. try {
  592. //const joystickRes = await this.moveService.joystick(request);
  593. this._rotateCount = 0;
  594. const joystickRes = await this.moveService.seqExeJoystick(request);
  595. this.logger.log(
  596. 'joystick-breakPointId:' +
  597. this.moveService.users[this.user_id].breakPointId,
  598. );
  599. // 有数据 [0]是rotate数据,[1-infinity]是walking数据
  600. this.logger.log('joystickRes', JSON.stringify(joystickRes));
  601. if (joystickRes) {
  602. this.onJoysticking.next(true);
  603. // console.log(
  604. // 'handlejoystick:' +
  605. // joystickRes.mediaSrc +
  606. // ',相机坐标:' +
  607. // JSON.stringify(
  608. // joystickRes.newUserStates[0].playerState.camera.position,
  609. // ),
  610. console.log(
  611. 'handlejoysticktesttest:' +
  612. joystickRes.mediaSrc +
  613. ',相机坐标:' +
  614. JSON.stringify(
  615. joystickRes.newUserStates[0].playerState.player.position,
  616. ),
  617. );
  618. if (joystickRes.mediaSrc) {
  619. pushJoyStickSteam(joystickRes);
  620. } else {
  621. if (!this.onMoving.getValue()) {
  622. // 在非行走时接受
  623. this.holdSteam();
  624. if (this.joystickFrameCnt === -1) {
  625. this.joystickFrameCnt = this.frameCnt.getValue();
  626. }
  627. // 人物数据去掉mediaSrc以免前误会
  628. joystickRes?.mediaSrc && delete joystickRes.mediaSrc;
  629. this.joystickFrameCnt += 1;
  630. const stream: StreamMetaType = {
  631. frame: this.joystickFrameCnt,
  632. metaData: JSON.stringify(joystickRes),
  633. };
  634. //this.logger.log('rotate', stream, Date.now());
  635. const res = await this.streamService.pushMetaDataToSteam(stream);
  636. if (res.done) {
  637. this.logger.log('joystick-位置流', res.frame);
  638. this.frameCnt.next(res.frame);
  639. clearTimeout(this._JoyStickingTimeout);
  640. this._JoyStickingTimeout = setTimeout(() => {
  641. this.logger.log('joystick-位置流 opt done');
  642. this.logger.log(
  643. 'joystick-位置流 交权给空流,当前pts',
  644. res.frame,
  645. );
  646. // this.frameCnt.next(res.frame);
  647. this.onJoysticking.next(false);
  648. this.resumeStream();
  649. this.joystickFrameCnt = -1;
  650. }, 200);
  651. } else {
  652. console.error(
  653. 'joystick-位置流有误::',
  654. res.frame,
  655. joystickRes.mediaSrc,
  656. );
  657. this.logger.error(
  658. 'joystick-位置流有误::',
  659. res.frame,
  660. joystickRes.mediaSrc,
  661. );
  662. this.onJoysticking.next(false);
  663. this.joystickFrameCnt = -1;
  664. this.resumeStream();
  665. }
  666. }
  667. }
  668. } else {
  669. console.log('handlejoystick:null');
  670. this.onJoysticking.next(false);
  671. }
  672. } catch (error) {
  673. console.error('joystick错误', error);
  674. this.onJoysticking.next(false);
  675. this.logger.error('joystick', error.message);
  676. }
  677. }
  678. /**
  679. * 主要处理moving的序列动作
  680. * @param seqs StreamReplyType[]
  681. */
  682. handleSeqMoving(seqs: StreamReplyType[]) {
  683. if (!this.moveQueueSubscription) {
  684. this.handleMoveSteam();
  685. }
  686. // this.logger.log('moving-seqs', seqs.length);
  687. this.onMoving.next(true);
  688. this.holdSteam();
  689. // 保证每一段都是序列动作的前面队列是空的
  690. // this.moveQueue.clean();
  691. seqs.forEach((frame: StreamReplyType) => {
  692. const mediaSrc = frame.mediaSrc;
  693. const src = mediaSrc.split('?')[0];
  694. const clipPath = this.configService.get('app.prefix') + src;
  695. const type = frame.mType?.length ? frame.mType.slice() : 'move';
  696. const stream: StreamFrameType = {
  697. frame: -1,
  698. clipPath: clipPath,
  699. metaData: JSON.stringify(frame),
  700. serverTime: this.mockserverTime,
  701. DIR: frame.DIR,
  702. mType: type,
  703. };
  704. this.moveQueue.next(stream);
  705. });
  706. }
  707. cleanMoveSteam() {
  708. if (this.moveQueueSubscription) {
  709. this.moveQueueSubscription.unsubscribe();
  710. this.moveQueueSubscription = null;
  711. }
  712. if (this.walkingSub) {
  713. this.walkingSub.unsubscribe();
  714. this.walkingSub = null;
  715. }
  716. if (this.moveSliceLastFrameSub) {
  717. this.lastMoveStreamFrame.next(null);
  718. this.moveSliceLastFrameSub.unsubscribe();
  719. this.moveSliceLastFrameSub = null;
  720. }
  721. // if (this.clickQueueSub) {
  722. // this.clickQueueSub.unsubscribe();
  723. // this.clickQueueSub = null;
  724. // }
  725. this.rotateStopThrottle = false;
  726. }
  727. handleMoveSteam() {
  728. this.moveQueueSubscription = this.moveQueue.subscribe(
  729. async (stream: StreamFrameType) => {
  730. try {
  731. const metaData: StreamReplyType = JSON.parse(stream.metaData);
  732. if (this.moveframeCnt === -1) {
  733. this.moveframeCnt = this.frameCnt.getValue();
  734. }
  735. this.moveframeCnt += 1;
  736. this.latestBreakPointId = metaData.endBreakPointId;
  737. const streamData: StreamFrameType = {
  738. frame: this.moveframeCnt,
  739. clipPath: stream.clipPath,
  740. metaData: stream.metaData,
  741. serverTime: this.mockserverTime,
  742. DIR: stream.DIR,
  743. };
  744. this.logger.log(
  745. '[media-move]: ' +
  746. ', moveframeCnt: ' +
  747. this.moveframeCnt +
  748. ', clipPath: ' +
  749. stream.clipPath +
  750. ', mType: ' +
  751. stream.mType +
  752. ', DIR: ' +
  753. stream.DIR,
  754. // stream.metaData,
  755. );
  756. this.logger.log(
  757. '[media-move-lastMovingPointArray]',
  758. this.lastMovingPointArray?.length,
  759. );
  760. // 记录lastMoveStreamFrame给打断逻辑使用
  761. this.lastMoveStreamFrame.next(streamData);
  762. // this.lastMoveStreamFrameBk = streamData;
  763. const res = await this.streamService.pushFrameToSteam(streamData);
  764. const isLastFrameIndex = this.lastMovingPointArray.findIndex(
  765. (item) => item.mediaSrc === metaData.mediaSrc,
  766. );
  767. //this.logger.log('path-update-index', isLastFrameIndex);
  768. //每一段的最后一帧
  769. if (isLastFrameIndex > -1) {
  770. //this.logger.log('path-update-array', this.lastMovingPointArray);
  771. const currentMeta = this.lastMovingPointArray[isLastFrameIndex];
  772. const userId = this.user_id;
  773. const breakPointId = currentMeta.metaData.endBreakPointId;
  774. const lastReply = currentMeta.metaData;
  775. this.moveService.updateUser(userId, breakPointId, lastReply);
  776. //debugger
  777. this.lastMovingPointArray.splice(isLastFrameIndex, 1);
  778. //TODO 队列每一段最后one frame
  779. this.moveSliceLastFrame.next(currentMeta);
  780. }
  781. if (res.done) {
  782. clearTimeout(this._moveTimeout);
  783. this._moveTimeout = setTimeout(() => {
  784. this.logger.log('move 交权给空流,当前pts', res.frame);
  785. this.rewalking = false;
  786. this.frameCnt.next(res.frame);
  787. this.rotateframeCnt = -1;
  788. this.onMoving.next(false);
  789. this.onJoysticking.next(false);
  790. this.lastMovingPointArray = [];
  791. this.hasJoystickMoveRequest = false;
  792. this.cleanMoveSteam();
  793. this.resumeStream();
  794. this.logger.log('move end');
  795. }, 200);
  796. } else {
  797. console.error('流地址有误::', res.frame, JSON.stringify(res));
  798. this.logger.error(
  799. `movesteam::当前帧:${res.frame}` + JSON.stringify(res),
  800. );
  801. this.resumeStream();
  802. }
  803. } catch (error) {
  804. this.logger.error('handleMoveSteam::error', error);
  805. }
  806. },
  807. );
  808. }
  809. handleDataChanelOpen(channel: DataChannel, peer: PeerConnection): void {
  810. this.channel = channel;
  811. this.peer = peer;
  812. this.streamService.setChannel(channel);
  813. this.startSteaming.next(true);
  814. this.startStream();
  815. this.handleStream();
  816. }
  817. handleDataChanelClose(): void {
  818. this.stopStream();
  819. this.startSteaming.next(false);
  820. this.streamService.closeChannel();
  821. // const exitRequest: ExitRequest = {
  822. // action_type: 1002,
  823. // user_id: this.user_id,
  824. // trace_id: '',
  825. // };
  826. this.exit();
  827. }
  828. handleMessage(message: string | Buffer) {
  829. try {
  830. if (typeof message === 'string') {
  831. // wasm:特例, requestIframe
  832. if (message.includes('wasm:')) {
  833. const parseData = message
  834. ? String(message).replace('wasm:', '')
  835. : `{"MstType":1}`;
  836. const msg: RTCMessageRequest = JSON.parse(parseData);
  837. this.logger.error('lostIframe-message', JSON.stringify(msg));
  838. if (msg.MstType === 0) {
  839. this.handleIframeRequest();
  840. }
  841. } else {
  842. const msg: RTCMessageRequest = JSON.parse(message);
  843. // console.log('msg.action_type:' + msg.action_type);
  844. switch (msg.action_type) {
  845. case ActionType.walk:
  846. const walk = msg as any as MoveRequest;
  847. this.walking(walk);
  848. break;
  849. case ActionType.joystick:
  850. const JoystickRequest = msg as any as JoystickRequest;
  851. this.joystick(JoystickRequest);
  852. break;
  853. case ActionType.breathPoint:
  854. this.handleBreath(msg);
  855. break;
  856. case ActionType.rotate:
  857. const rotateRequest: RotateRequest = msg;
  858. this.rotate(rotateRequest);
  859. break;
  860. case ActionType.userStatus:
  861. this.updateUserStatus(msg);
  862. break;
  863. case ActionType.status:
  864. this.updateStatus();
  865. break;
  866. default:
  867. break;
  868. }
  869. }
  870. }
  871. } catch (error) {
  872. this.logger.error('handleMessage:rtc--error', error.message);
  873. }
  874. }
  875. async handleIframeRequest() {
  876. //TODO Iframe 最终传什么?
  877. this.requestIFrameQueue.next(this.streamService.lastStreamFrame.getValue());
  878. if (!this.requestIFrameQueueSub) {
  879. this.requestIFrameQueueSub = this.requestIFrameQueue.subscribe(
  880. (frameData: StreamFrameType) => {
  881. const nextFrame = this.frameCnt.getValue() + 1;
  882. this.logger.warn('lostIframe', nextFrame);
  883. frameData.frame = nextFrame;
  884. this.streamService.pushFrameToSteam(frameData);
  885. this.frameCnt.next(nextFrame);
  886. this.resumeStream();
  887. },
  888. );
  889. }
  890. }
  891. handleBreath(request) {
  892. const npsRes = this.moveService.getBreakPoints(request);
  893. //this.logger.log('npsRes', npsRes.nps);
  894. this.streamService.pushNormalDataToStream(npsRes);
  895. }
  896. updateStatus(): void {
  897. const reply = {
  898. data: { action_type: 1009, echo_msg: { echoMsg: Date.now() } },
  899. track: false,
  900. };
  901. this.streamService.pushNormalDataToStream(reply);
  902. }
  903. updateUserStatus(request) {
  904. try {
  905. const usersData = this.rotateService.getNewUserStateRequest(request);
  906. if (usersData) {
  907. usersData.actionType = 1024;
  908. //this.logger.log(
  909. // 'joystick:->updateUserStatus' +
  910. // 'playerPosition:' +
  911. // JSON.stringify(
  912. // redisMeta['newUserStates'][0].playerState.player.position,
  913. // ),
  914. // );
  915. this.streamService.pushNormalDataToStream(usersData);
  916. } else {
  917. this.logger.error('updateUserStatus::function-empty');
  918. }
  919. } catch (error) {
  920. this.logger.error('updateUserStatus::function', error.message);
  921. }
  922. }
  923. /**
  924. * rotate 推送队列
  925. */
  926. handleRotateStream() {
  927. if (!this.roQueueSubscription) {
  928. this.roQueueSubscription = this.roQueue.subscribe(
  929. async (stream: StreamFrameType) => {
  930. this.rotateTimeStamp = Date.now();
  931. if (this.rotateframeCnt === -1) {
  932. this.rotateframeCnt = this.frameCnt.value;
  933. }
  934. this.rotateframeCnt += 1;
  935. stream.frame = this.rotateframeCnt;
  936. this._rotateCurrentFame += 1;
  937. const IDRflag = this._rotateCurrentFame % 5 === 0 ? 1 : 3;
  938. this.logger.log(
  939. `当前rotate ,mainframeCnt:${this.frameCnt.getValue()}, _rotateCurrentFame:${this._rotateCurrentFame
  940. } IDRflag:${IDRflag}`,
  941. );
  942. stream.DIR = this.rotateFirstIDR ? 1 : IDRflag;
  943. if (this.rotateFirstIDR) {
  944. this.rotateFirstIDR = false;
  945. }
  946. this.logger.log(
  947. '[media-rotate]: ' +
  948. ', frame: ' +
  949. stream.frame +
  950. ', rotateframeCnt: ' +
  951. this.rotateframeCnt +
  952. ', clipPath: ' +
  953. stream.clipPath,
  954. // stream.metaData,
  955. );
  956. // this.logger.log(
  957. // `roQueueSubscription:frame:${this.rotateframeCnt} ` +
  958. // JSON.stringify(stream.metaData),
  959. // );
  960. const res = await this.streamService.pushFrameToSteam(stream);
  961. if (res.done) {
  962. clearTimeout(this._rotateTimeout);
  963. this._rotateTimeout = setTimeout(() => {
  964. this.logger.log('rotate end', Date.now());
  965. this.frameCnt.next(res.frame);
  966. this.resumeStream();
  967. this.rotateframeCnt = -1;
  968. this._rotateCurrentFame = -1;
  969. this.onMoving.next(false);
  970. this.onRotating.next(false);
  971. this.rotateFirstIDR = true;
  972. //TODO rotate完后清除request队列
  973. if (this.roRequestQueueSub) {
  974. this.roRequestQueueSub.unsubscribe();
  975. this.roRequestQueueSub = null;
  976. }
  977. }, 50);
  978. } else {
  979. console.error('流地址有误::', res.frame, JSON.stringify(res));
  980. this.logger.error('流地址有误::', res.frame, JSON.stringify(res));
  981. this.resumeStream();
  982. }
  983. },
  984. );
  985. }
  986. }
  987. pushFirstRender(clipPath: string, metaData: string): Promise<boolean> {
  988. return new Promise<boolean>(async (resolve, reject) => {
  989. try {
  990. const streamData: StreamFrameType = {
  991. frame: 1,
  992. clipPath: clipPath,
  993. metaData: metaData,
  994. serverTime: this.mockserverTime,
  995. DIR: 1,
  996. };
  997. const hasPush = await this.streamService.pushFrameToSteam(streamData);
  998. return resolve(hasPush.done);
  999. } catch (error) {
  1000. return reject(false);
  1001. }
  1002. });
  1003. }
  1004. handleStream() {
  1005. this.logger.log('this.frameCntSubscription', this.frameCntSubscription);
  1006. let redisData;
  1007. if (!this.frameCntSubscription) {
  1008. this.frameCntSubscription = this.frameCnt.subscribe(async (frame) => {
  1009. try {
  1010. this.logger.log('frame', frame);
  1011. console.log(
  1012. 'mock' +
  1013. ' maxMessageSize: ' +
  1014. this.channel.maxMessageSize() +
  1015. ' bytesReceived: ' +
  1016. this.peer.bytesReceived() +
  1017. ' bytesSent: ' +
  1018. this.peer.bytesSent(),
  1019. );
  1020. if (frame === 1) {
  1021. redisData = await this.rotateService.echo(this.user_id, true);
  1022. this.logger.log('获取-首屏', redisData);
  1023. this.onSteaming = true;
  1024. this.holdSteam();
  1025. if (redisData && 'mediaSrc' in redisData) {
  1026. const mediaSrc: string = redisData.mediaSrc || '';
  1027. if (mediaSrc.length > 0) {
  1028. const src = mediaSrc.split('?')[0];
  1029. const clipPath = this.configService.get('app.prefix') + src;
  1030. delete redisData.mediaSrc;
  1031. this.logger.log(
  1032. `user:${this.user_id}:first render stream` +
  1033. JSON.stringify({ path: clipPath, meta: redisData }),
  1034. );
  1035. const status = await this.pushFirstRender(
  1036. clipPath,
  1037. JSON.stringify(redisData),
  1038. );
  1039. if (status) {
  1040. this.firstRender = true;
  1041. this.frameCnt.next(2);
  1042. this.resumeStream();
  1043. } else {
  1044. this.logger.error('first render problem', status);
  1045. }
  1046. }
  1047. } else {
  1048. this.logger.error(`first render problem:${frame}`);
  1049. }
  1050. }
  1051. if (frame > 1) {
  1052. const isOk =
  1053. !this.onMoving.value &&
  1054. !this.onRotating.value &&
  1055. !this.onJoysticking.value &&
  1056. this.firstRender;
  1057. console.log(
  1058. '空白流条件-->:' +
  1059. isOk +
  1060. ' onMoving: ' +
  1061. this.onMoving.value +
  1062. ' onRotating: ' +
  1063. this.onRotating.value +
  1064. ' onJoysticking: ' +
  1065. this.onJoysticking.value +
  1066. ' firstRender: ' +
  1067. this.firstRender,
  1068. );
  1069. }
  1070. if (
  1071. frame > 1 &&
  1072. !this.onMoving.value &&
  1073. !this.onRotating.value &&
  1074. !this.onJoysticking.value &&
  1075. this.firstRender
  1076. ) {
  1077. const redisDataAuto = await this.rotateService.echo(
  1078. this.user_id,
  1079. false,
  1080. );
  1081. if (redisDataAuto) {
  1082. this.logger.log(`空白流::有数据:${frame}`);
  1083. 'mediaSrc' in redisDataAuto && delete redisDataAuto.mediaSrc;
  1084. const streamMeta: StreamMetaType = {
  1085. frame: frame,
  1086. metaData: JSON.stringify(redisDataAuto),
  1087. };
  1088. this.streamService.pushMetaDataToSteam(streamMeta);
  1089. } else {
  1090. this.stopStream();
  1091. this.logger.log('空流无Redis数据');
  1092. }
  1093. }
  1094. } catch (error) {
  1095. if (this.frameCnt.getValue() === 1) {
  1096. this.logger.error('首屏读取redis有误:', redisData, error.message);
  1097. }
  1098. this.stopStream();
  1099. this.logger.error('handleStream', error.message);
  1100. }
  1101. });
  1102. }
  1103. }
  1104. }