scene.service.ts 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
  2. import { ClientGrpc, Client } from '@nestjs/microservices';
  3. import { grpcClientOptions } from './grpc-scene.options';
  4. import { Logger } from '@nestjs/common';
  5. import { DataChannel } from 'node-datachannel';
  6. import { BehaviorSubject } from 'rxjs';
  7. // import * as streamBuffers from 'stream-buffers';
  8. import { ActionType } from './actionType';
  9. import { CacheService } from 'src/cache/cache.service';
  10. import { StreamService } from './stream/stream.service';
  11. // import { InjectQueue } from '@nestjs/bull';
  12. // import { Queue } from 'bull';
  13. import { RotateService } from 'src/rotate/rotate.service';
  14. import { DelayQueue, RxQueue, ThrottleQueue, DebounceQueue } from 'rx-queue';
  15. import { MoveService } from 'src/move/move.service';
  16. import { GetRouterService } from 'src/get-router/get-router.service';
  17. import { join } from 'path';
  18. @Injectable()
  19. export class SceneService implements OnModuleInit, OnModuleDestroy {
  20. constructor(
  21. private cacheService: CacheService,
  22. private streamService: StreamService,
  23. private rotateService: RotateService,
  24. private moveService: MoveService,
  25. private getRouterService: GetRouterService, // @InjectQueue('rotate') private rotateQueue: Queue, // @InjectQueue('walking') private walkingQueue: Queue,
  26. ) { }
  27. @Client(grpcClientOptions) private readonly client: ClientGrpc;
  28. public _frameInteval: NodeJS.Timeout;
  29. public _frameTimeout: NodeJS.Timeout;
  30. public _rotateTimeout: NodeJS.Timeout;
  31. public _moveTimeout: NodeJS.Timeout;
  32. public startSteaming = new BehaviorSubject<boolean>(false);
  33. public onRotating = new BehaviorSubject<boolean>(false);
  34. public onMoving = new BehaviorSubject<boolean>(false);
  35. public frameCnt = new BehaviorSubject<number>(-1);
  36. private rotateframeCnt = -1;
  37. private moveframeCnt = -1;
  38. private sceneGrpcService: SceneGrpcService;
  39. private channel: DataChannel;
  40. private logger: Logger = new Logger('SceneService');
  41. private frameCntInterval = 1000;
  42. private user_id: string;
  43. private roomId: string;
  44. private onSteaming = false;
  45. private mockserverTime = Date.now() - 1653000000478;
  46. private lastRenderMedia = '';
  47. private frameCntSubscription: any;
  48. private roQueueSubscription: any;
  49. private moveQueueSubscription: any;
  50. private walkingSub: any;
  51. private joystickSub: any;
  52. private streamServiceSub: any;
  53. private roQueue: RxQueue = new DelayQueue(40);
  54. private clickQueue: RxQueue = new DebounceQueue(500);
  55. private moveQueue: RxQueue = new DelayQueue(10);
  56. private joystickQueue: RxQueue = new DebounceQueue(500);
  57. private rotateTimeStamp: number;
  58. private lastMoveCnt = -1;
  59. private firstRender = false;
  60. private latestBreakPointId: number;
  61. private isHoldingStream = false;
  62. public lastMoveStreamFrame = new BehaviorSubject<StreamFrameType>({
  63. frame: -1,
  64. clipPath: '',
  65. metaData: '',
  66. });
  67. public users = {};
  68. initUsers(app_id, userId) {
  69. const user = {
  70. appId: null,
  71. userId: null,
  72. breakPointId: null,
  73. roomId: null,
  74. player: {
  75. position: { x: -700, y: 0, z: 0 },
  76. angle: {
  77. pitch: 0,
  78. yaw: 0,
  79. roll: 0,
  80. },
  81. },
  82. camera: {
  83. position: { x: -1145, y: 0, z: 160 },
  84. angle: {
  85. pitch: 0,
  86. yaw: 0,
  87. roll: 0,
  88. },
  89. },
  90. rotateInfo: {
  91. frameIndex: 0,
  92. horizontal_move: 0,
  93. mediaSrc: null,
  94. },
  95. moveInfo: {},
  96. // traceIds: [],
  97. // actionResponses:[]
  98. };
  99. user.appId = app_id;
  100. user.userId = userId;
  101. user.breakPointId = 100;
  102. this.users[userId] = user;
  103. }
  104. onModuleInit(): void {
  105. this.sceneGrpcService =
  106. this.client.getService<SceneGrpcService>('SceneGrpcService');
  107. this.logger.log('init SceneGrpcService');
  108. this.streamServiceSub = this.streamService.onSteaming.subscribe((val) => {
  109. this.onSteaming = val;
  110. });
  111. Number.prototype.padLeft = function (n, str) {
  112. return Array(n - String(this).length + 1).join(str || '0') + this;
  113. };
  114. }
  115. public getConfig() {
  116. return {
  117. userId: this.user_id,
  118. roomId: this.roomId,
  119. };
  120. }
  121. public startStream(): void {
  122. clearInterval(this._frameInteval);
  123. if (this.frameCnt.value === -1) {
  124. this._frameInteval = setInterval(async () => {
  125. const next = this.frameCnt.value + 1;
  126. this.frameCnt.next(next);
  127. }, 1000);
  128. }
  129. }
  130. public holdSteam(): void {
  131. clearInterval(this._frameInteval);
  132. this.isHoldingStream = true;
  133. }
  134. public resumeStream(): void {
  135. this.onMoving.next(false);
  136. this.isHoldingStream = false;
  137. this.moveframeCnt = -1;
  138. this.rotateframeCnt = -1;
  139. clearInterval(this._frameInteval);
  140. this._frameInteval = setInterval(async () => {
  141. const next = this.frameCnt.getValue() + 1;
  142. this.frameCnt.next(next);
  143. }, 1000);
  144. }
  145. public stopStream(): void {
  146. if (this.frameCntSubscription) {
  147. this.frameCntSubscription.unsubscribe();
  148. this.frameCntSubscription = null;
  149. }
  150. if (this.roQueueSubscription) {
  151. this.roQueueSubscription.unsubscribe();
  152. this.roQueueSubscription = null;
  153. }
  154. if (this.moveQueueSubscription) {
  155. this.moveQueueSubscription.unsubscribe();
  156. this.moveQueueSubscription = null;
  157. }
  158. this.frameCnt.next(-1);
  159. clearInterval(this._frameInteval);
  160. this.rotateframeCnt = -1;
  161. }
  162. setConfig(user_id: string, roomId: string): void {
  163. this.user_id = user_id;
  164. this.roomId = roomId;
  165. }
  166. onModuleDestroy() {
  167. if ('unsubscribe' in this.streamServiceSub) {
  168. this.streamService.onSteaming.unsubscribe();
  169. }
  170. }
  171. init(request: InitRequest) {
  172. try {
  173. // const initReply = this.sceneGrpcService.init(request);
  174. // initReply.subscribe((reply) => {
  175. // console.log('initReply', reply);
  176. // });
  177. this.rotateService.init(request.app_id, request.user_id);
  178. // this.moveService.init(request.app_id, request.user_id);
  179. // this.initUsers(request.app_id, request.user_id);
  180. } catch (error) {
  181. console.log('error', error);
  182. }
  183. }
  184. exit(request: ExitRequest) {
  185. this.frameCnt.next(-1);
  186. this.stopStream();
  187. // const exitReply = this.sceneGrpcService.exit(request);
  188. // exitReply.subscribe((reply) => {
  189. // console.log('exitReply', reply);
  190. // });
  191. }
  192. async rotate(request: RotateRequest) {
  193. try {
  194. if (this.firstRender) {
  195. if (!this.roQueueSubscription) {
  196. this.handleRotateStream();
  197. }
  198. let redisMeta: StreamReplyType;
  199. this.onRotating.next(true);
  200. if (this.onMoving.value) {
  201. this.onMoving.next(false);
  202. const lastStreamFrame = this.lastMoveStreamFrame.getValue();
  203. const metaData: StreamReplyType = JSON.parse(
  204. lastStreamFrame.metaData,
  205. ) as any as StreamReplyType;
  206. const newUserStates: NewUserStatesType = metaData.newUserStates.find(
  207. (item) => item.userId === this.user_id,
  208. );
  209. const trace_id = metaData.traceIds[0];
  210. const userId = newUserStates.userId;
  211. const breakPointId = metaData.breakPointId;
  212. const cameraAngle = newUserStates.playerState.camera.angle;
  213. const playerAngle = newUserStates.playerState.player.angle;
  214. console.log('stop-data', trace_id, userId, cameraAngle, cameraAngle);
  215. redisMeta = await this.moveService.stop(
  216. trace_id,
  217. userId,
  218. breakPointId,
  219. cameraAngle,
  220. playerAngle,
  221. );
  222. console.log('stop-redisMeta', redisMeta);
  223. // redisMeta = await this.rotateService.rotate(request);
  224. } else {
  225. redisMeta = await this.rotateService.rotate(request);
  226. }
  227. if (redisMeta && 'mediaSrc' in redisMeta) {
  228. const mediaSrc: string = redisMeta.mediaSrc || '';
  229. if (mediaSrc.length > 0) {
  230. const src = mediaSrc.split('?')[0];
  231. // 临时本地替换路经
  232. // src = src.replace('/10086/', '');
  233. // 判断不是同一条源时才推出
  234. if (src.length > 0) {
  235. // console.log('不同源');
  236. // this.frameCnt += 1;
  237. this.holdSteam();
  238. this.lastRenderMedia = src;
  239. const clipPath = join(__dirname, `../ws/${src}`);
  240. // console.log('src-clipPath', src, clipPath);
  241. delete redisMeta.mediaSrc;
  242. // const nextFrame = this.frameCnt.getValue() + 1;
  243. // console.log('nextFrame', nextFrame);
  244. // this.frameCnt.next(nextFrame);
  245. const random_boolean = Math.random() < 0.3;
  246. const stream: StreamFrameType = {
  247. frame: -1,
  248. clipPath: clipPath,
  249. metaData: JSON.stringify(redisMeta),
  250. serverTime: this.mockserverTime,
  251. DIR: this.frameCnt.getValue() < 10 ? 3 : random_boolean ? 1 : 3,
  252. };
  253. // this.rotateQueue.add(stream, {
  254. // delay: 5,
  255. // jobId: `rotate:${this.user_id}:${this.frameCnt.getValue()}`,
  256. // removeOnComplete: true,
  257. // });
  258. clearTimeout(this._rotateTimeout);
  259. this.roQueue.next(stream);
  260. } else {
  261. // this.onRotating.next(false);
  262. }
  263. }
  264. }
  265. }
  266. } catch (error) {
  267. this.logger.error('rotate', error);
  268. console.log('error', error);
  269. }
  270. }
  271. async walking(req) {
  272. try {
  273. console.log('walking', req);
  274. this.clickQueue.next(req);
  275. this.walkingSub = this.clickQueue.subscribe(async (request) => {
  276. const user = this.moveService.users[this.user_id];
  277. const path = await this.getRouterService.searchRoad(
  278. user.appId,
  279. user.breakPointId,
  280. req.clicking_action.clicking_point,
  281. );
  282. const walkingRes = await this.moveService.move(path, request);
  283. // console.log('walkingRes-front', walkingRes);
  284. if (walkingRes && !this.onMoving.value) {
  285. // console.log('walkingRes-front', walkingRes);
  286. // shift出前第一个镜头数据
  287. const rotateCamData = walkingRes.shift();
  288. if (rotateCamData?.length) {
  289. rotateCamData.forEach((item: StreamReplyType) => {
  290. item.type = 'rotate';
  291. });
  292. }
  293. // walkingRes marker to everybody
  294. const seqs = Array.from(
  295. walkingRes,
  296. ).flat() as any as StreamReplyType[];
  297. if (seqs?.length) {
  298. const lastSeq = rotateCamData?.length
  299. ? (Array.from(rotateCamData).concat(
  300. seqs,
  301. ) as any as StreamReplyType[])
  302. : seqs;
  303. this.handleSeqMoving(lastSeq);
  304. } else {
  305. console.error('walking-move无数据');
  306. }
  307. // this.lastMoveCnt = this.frameCnt.value + seqs.length;
  308. }
  309. });
  310. } catch (error) {
  311. this.logger.error('walking', error);
  312. }
  313. }
  314. async joystick(request: JoystickRequest) {
  315. try {
  316. this.joystickQueue.next(request);
  317. if (!this.joystickSub) {
  318. this.joystickSub = this.joystickQueue.subscribe(
  319. async (joystickRequest) => {
  320. const joystickRes = await this.moveService.joystick(
  321. joystickRequest,
  322. );
  323. console.log('joystickRes-front', joystickRes);
  324. // 有数据 [0]是rotate数据,[1-infinity]是walking数据
  325. if (Array.isArray(joystickRes)) {
  326. // shift出前第一个镜头数据
  327. const rotateCamData = joystickRes.shift();
  328. console.log('rotateCamData', rotateCamData);
  329. if (rotateCamData?.length) {
  330. rotateCamData.forEach((item: StreamReplyType) => {
  331. item.type = 'rotate';
  332. });
  333. }
  334. const seqs = Array.from(
  335. joystickRes,
  336. ).flat() as any as StreamReplyType[];
  337. if (seqs?.length || rotateCamData?.length) {
  338. const lastSeq = rotateCamData?.length
  339. ? (Array.from(rotateCamData).concat(
  340. seqs,
  341. ) as any as StreamReplyType[])
  342. : seqs;
  343. this.handleSeqMoving(lastSeq);
  344. } else {
  345. console.warn('joystick-move无数据');
  346. }
  347. } else {
  348. console.log('转交数据');
  349. this.streamService.pushNormalDataToStream(request);
  350. }
  351. },
  352. );
  353. }
  354. } catch (error) {
  355. this.logger.error('joystick', error);
  356. }
  357. }
  358. /**
  359. * 主要处理moving的序列动作
  360. * @param seqs StreamReplyType[]
  361. */
  362. handleSeqMoving(seqs: StreamReplyType[]) {
  363. if (!this.moveQueueSubscription) {
  364. this.handleMoveSteam();
  365. }
  366. console.log('moving-seqs', seqs.length);
  367. this.onMoving.next(true);
  368. this.holdSteam();
  369. seqs.forEach((frame: StreamReplyType, index:number) => {
  370. const mediaSrc = frame.mediaSrc;
  371. const src = mediaSrc.split('?')[0];
  372. // 临时本地替换路经
  373. // src = src.replace('//', '');
  374. const clipPath = join(__dirname, `../ws/${src}`);
  375. const type = frame.type?.length ? frame.type.slice() : 'move';
  376. console.log('type', frame.type);
  377. delete frame.mediaSrc;
  378. delete frame.type;
  379. //TODO
  380. const random_boolean = Math.random() < 0.3;
  381. // const random_index === 1 ? 3 : random_boolean ? 1 : 3;
  382. const stream: StreamFrameType = {
  383. frame: -1,
  384. clipPath: clipPath,
  385. metaData: JSON.stringify(frame),
  386. serverTime: this.mockserverTime,
  387. DIR: 3,
  388. type: type,
  389. };
  390. this.moveQueue.next(stream);
  391. });
  392. }
  393. cleanMoveSteam() {
  394. if (this.moveQueueSubscription) {
  395. this.moveQueueSubscription.unsubscribe();
  396. this.lastMoveCnt = -1;
  397. this.moveQueueSubscription = null;
  398. }
  399. if (this.walkingSub) {
  400. this.walkingSub.unsubscribe();
  401. this.walkingSub = null;
  402. }
  403. }
  404. handleMoveSteam() {
  405. this.moveQueueSubscription = this.moveQueue.subscribe(
  406. async (stream: StreamFrameType) => {
  407. const metaData: StreamReplyType = JSON.parse(stream.metaData);
  408. if (this.moveframeCnt === -1) {
  409. this.moveframeCnt = this.frameCnt.value;
  410. }
  411. this.moveframeCnt += 1;
  412. this.latestBreakPointId = metaData.breakPointId;
  413. // if (this.onMoving) {
  414. // this.frameCnt.next(this.moveframeCnt);
  415. // } else {
  416. // console.log(
  417. // 'handleMoveSteam stop',
  418. // this.moveframeCnt,
  419. // this.currentMoveMaker,
  420. // );
  421. // this.cleanMoveSteam();
  422. // this.resumeStream();
  423. // return;
  424. // }
  425. const streamData: StreamFrameType = {
  426. frame: this.moveframeCnt,
  427. clipPath: stream.clipPath,
  428. metaData: stream.metaData,
  429. serverTime: this.mockserverTime,
  430. DIR: 3,
  431. };
  432. console.log(
  433. '[media-move]',
  434. this.moveframeCnt,
  435. stream.clipPath,
  436. stream.type,
  437. );
  438. this.lastMoveStreamFrame.next(streamData);
  439. const res = await this.streamService.pushFrameToSteam(streamData);
  440. if (res.done) {
  441. clearTimeout(this._moveTimeout);
  442. this._moveTimeout = setTimeout(() => {
  443. console.log('move 交权给空流,当前pts', res.frame);
  444. //TODO 每个结束点 updateUser metaData
  445. const lastFrame = this.lastMoveStreamFrame.getValue();
  446. const lastFrameMeta = JSON.parse(lastFrame.metaData);
  447. const userId = this.user_id;
  448. const breakPointId = lastFrameMeta.breakPointId;
  449. const lastReply = lastFrameMeta;
  450. this.moveService.updateUser(userId, breakPointId, lastReply);
  451. this.frameCnt.next(res.frame);
  452. this.resumeStream();
  453. this.rotateframeCnt = -1;
  454. this.onMoving.next(false);
  455. console.log('move end');
  456. }, 300);
  457. }
  458. },
  459. );
  460. }
  461. handleDataChanelOpen(channel: DataChannel): void {
  462. this.channel = channel;
  463. this.streamService.setChannel(channel);
  464. this.startSteaming.next(true);
  465. this.startStream();
  466. this.handleStream();
  467. }
  468. handleDataChanelClose(): void {
  469. this.stopStream();
  470. this.startSteaming.next(false);
  471. this.streamService.closeChannel();
  472. const exitRequest: ExitRequest = {
  473. action_type: 1002,
  474. user_id: this.user_id,
  475. trace_id: '',
  476. };
  477. this.exit(exitRequest);
  478. }
  479. handleMessage(message: string | Buffer) {
  480. try {
  481. if (typeof message === 'string') {
  482. // wasm:特例, requestIframe
  483. if (message.includes('wasm:')) {
  484. const msg: RTCMessageRequest = JSON.parse(
  485. message.replace('wasm:', ''),
  486. );
  487. if (msg.MstType === 0) {
  488. this.logger.log('lost I frame');
  489. this.handleIframeRequest();
  490. }
  491. } else {
  492. const msg: RTCMessageRequest = JSON.parse(message);
  493. switch (msg.action_type) {
  494. case ActionType.walk:
  495. const walk = msg;
  496. this.walking(walk);
  497. break;
  498. case ActionType.joystick:
  499. const JoystickRequest = msg as any as JoystickRequest;
  500. this.joystick(JoystickRequest);
  501. break;
  502. case ActionType.breathPoint:
  503. this.handleBreath(msg);
  504. break;
  505. case ActionType.rotate:
  506. const rotateRequest: RotateRequest = msg;
  507. this.rotate(rotateRequest);
  508. break;
  509. case ActionType.userStatus:
  510. this.updateUserStatus(msg);
  511. break;
  512. case ActionType.status:
  513. this.updateStatus();
  514. break;
  515. default:
  516. break;
  517. }
  518. }
  519. }
  520. } catch (error) {
  521. this.logger.error('handleMessage:rtc--error', message);
  522. }
  523. }
  524. async handleIframeRequest() {
  525. //TODO Iframe 最终传什么?
  526. // const lastStreamFrame = this.streamService.lastStreamFrame.getValue();
  527. // lastStreamFrame.DIR = 1;
  528. // console.log('lastStreamFrame', lastStreamFrame);
  529. // const nextFrame = this.frameCnt.getValue() + 1;
  530. // lastStreamFrame.frame = nextFrame;
  531. // this.frameCnt.next(nextFrame);
  532. // this.streamService.pushFrameToSteam(lastStreamFrame);
  533. // const redisDataAuto = await this.rotateService.echo(this.user_id);
  534. // if (redisDataAuto) {
  535. // 'mediaSrc' in redisDataAuto && delete redisDataAuto.mediaSrc;
  536. // const streamMeta: StreamMetaType = {
  537. // frame: nextFrame,
  538. // metaData: JSON.stringify(redisDataAuto),
  539. // };
  540. // this.streamService.pushMetaDataToSteam(streamMeta);
  541. // }
  542. }
  543. async handleBreath(request) {
  544. const npsRes = await this.moveService.getBreakPoints(request);
  545. // console.log('npsRes', npsRes);
  546. this.streamService.pushNormalDataToStream(npsRes);
  547. }
  548. updateStatus() {
  549. const reply = {
  550. data: { action_type: 1009, echo_msg: { echoMsg: Date.now() } },
  551. track: false,
  552. };
  553. this.streamService.pushNormalDataToStream(reply);
  554. }
  555. async updateUserStatus(request) {
  556. try {
  557. const redisMeta = await this.rotateService.getNewUserStateRequest(
  558. request,
  559. );
  560. if (redisMeta) {
  561. redisMeta.actionType = 1024;
  562. this.streamService.pushNormalDataToStream(redisMeta);
  563. }
  564. } catch (error) {
  565. this.logger.error('updateUserStatus::function', error);
  566. }
  567. }
  568. pushFirstRender(clipPath: string, metaData: string): Promise<boolean> {
  569. return new Promise<boolean>(async (resolve, reject) => {
  570. try {
  571. const streamData: StreamFrameType = {
  572. frame: 1,
  573. clipPath: clipPath,
  574. metaData: metaData,
  575. serverTime: this.mockserverTime,
  576. DIR: 1,
  577. };
  578. const hasPush = await this.streamService.pushFrameToSteam(streamData);
  579. return resolve(hasPush.done);
  580. } catch (error) {
  581. return reject(false);
  582. }
  583. });
  584. }
  585. handleStream() {
  586. this.frameCntSubscription = this.frameCnt.subscribe(async (frame) => {
  587. try {
  588. console.log('frame', frame);
  589. if (frame === 1) {
  590. const redisData = await this.rotateService.echo(this.user_id);
  591. this.onSteaming = true;
  592. this.holdSteam();
  593. console.log('redisData', redisData);
  594. if (redisData && 'mediaSrc' in redisData) {
  595. const mediaSrc: string = redisData.mediaSrc || '';
  596. if (mediaSrc.length > 0) {
  597. const src = mediaSrc.split('?')[0];
  598. // 临时本地替换路经
  599. // src = src.replace('/10086/', '');
  600. const clipPath = join(__dirname, `../ws/${src}`);
  601. delete redisData.mediaSrc;
  602. this.logger.log(
  603. `user:${this.user_id}:first render stream` +
  604. JSON.stringify({ path: clipPath, meta: redisData }),
  605. );
  606. const status = await this.pushFirstRender(
  607. clipPath,
  608. JSON.stringify(redisData),
  609. );
  610. if (status) {
  611. this.firstRender = true;
  612. this.frameCnt.next(2);
  613. this.resumeStream();
  614. } else {
  615. this.logger.error('first render problem', status);
  616. }
  617. }
  618. }
  619. }
  620. if (
  621. frame > 1 &&
  622. !this.onMoving.value &&
  623. !this.onRotating.value &&
  624. this.firstRender
  625. ) {
  626. const redisDataAuto = await this.rotateService.echo(this.user_id);
  627. if (redisDataAuto) {
  628. console.log(`空白流::有数据:${frame}`);
  629. 'mediaSrc' in redisDataAuto && delete redisDataAuto.mediaSrc;
  630. const streamMeta: StreamMetaType = {
  631. frame: frame,
  632. metaData: JSON.stringify(redisDataAuto),
  633. };
  634. this.streamService.pushMetaDataToSteam(streamMeta);
  635. } else {
  636. this.stopStream();
  637. console.log('空流无Redis数据');
  638. throw new Error('空流无Redis数据');
  639. }
  640. }
  641. } catch (error) {
  642. this.stopStream();
  643. this.logger.error('handleStream', error);
  644. }
  645. });
  646. }
  647. handleRotateStream() {
  648. this.roQueueSubscription = this.roQueue.subscribe(
  649. async (stream: StreamFrameType) => {
  650. this.rotateTimeStamp = Date.now();
  651. if (this.rotateframeCnt === -1) {
  652. this.rotateframeCnt = this.frameCnt.value;
  653. }
  654. this.rotateframeCnt += 1;
  655. stream.frame = this.rotateframeCnt;
  656. console.log(
  657. '[media-rotate]',
  658. stream.frame,
  659. this.rotateframeCnt,
  660. stream.clipPath,
  661. );
  662. // this.logger.log(
  663. // `roQueueSubscription:frame:${this.rotateframeCnt} ` +
  664. // JSON.stringify(stream.metaData),
  665. // );
  666. const res = await this.streamService.pushFrameToSteam(stream);
  667. if (res.done) {
  668. clearTimeout(this._rotateTimeout);
  669. this._rotateTimeout = setTimeout(() => {
  670. console.log('rotate 1秒', Date.now());
  671. console.log('rotate end');
  672. // const next = res.frame + 1;
  673. this.frameCnt.next(res.frame);
  674. this.resumeStream();
  675. this.rotateframeCnt = -1;
  676. this.onMoving.next(false);
  677. this.onRotating.next(false);
  678. }, 300);
  679. }
  680. },
  681. );
  682. }
  683. }