scene.service.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. import { Injectable, 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 * as path from 'path';
  7. import { statSync, createReadStream, readFileSync } from 'fs';
  8. // import { Readable } from 'stream';
  9. import { BehaviorSubject } from 'rxjs';
  10. import * as streamBuffers from 'stream-buffers';
  11. import { ActionType } from './actionType';
  12. import { CacheService } from 'src/cache/cache.service';
  13. import { StreamService } from './stream/stream.service';
  14. const frameMetaReply = {
  15. traceIds: [],
  16. vehicle: null,
  17. newUserStates: [
  18. {
  19. userId: 'a2aaaed1fffe6',
  20. playerState: {
  21. roomTypeId: '',
  22. person: 0,
  23. avatarId: '',
  24. skinId: '',
  25. roomId: '',
  26. isHost: false,
  27. isFollowHost: false,
  28. skinDataVersion: '',
  29. avatarComponents: '',
  30. nickName: '',
  31. movingMode: 0,
  32. attitude: '',
  33. areaName: '',
  34. pathName: '',
  35. pathId: '',
  36. avatarSize: 1,
  37. extra: '',
  38. prioritySync: false,
  39. player: {
  40. position: { x: -755, y: -1450, z: -34 },
  41. angle: { pitch: 0, yaw: 0, roll: 0 },
  42. },
  43. camera: {
  44. position: { x: -1075, y: -1450, z: 86 },
  45. angle: { pitch: 0, yaw: 0, roll: 0 },
  46. },
  47. cameraCenter: { x: -755, y: -1450, z: -34 },
  48. },
  49. renderInfo: {
  50. renderType: 0,
  51. videoFrame: null,
  52. cameraStateType: 0,
  53. isMoving: 0,
  54. needIfr: 0,
  55. isVideo: 0,
  56. stillFrame: 0,
  57. isRotating: 0,
  58. isFollowing: 0,
  59. clientPanoTitlesBitmap: [],
  60. clientPanoTreceId: '',
  61. prefetchVideoId: '',
  62. noMedia: false,
  63. },
  64. event: null,
  65. relation: 1,
  66. },
  67. ],
  68. actionResponses: [],
  69. getStateType: 0,
  70. code: 0,
  71. msg: 'OK',
  72. };
  73. @Injectable()
  74. export class SceneService implements OnModuleInit {
  75. constructor(
  76. private cacheService: CacheService,
  77. private streamService: StreamService,
  78. ) { }
  79. @Client(grpcClientOptions) private readonly client: ClientGrpc;
  80. private sceneGrpcService: SceneGrpcService;
  81. private logger: Logger = new Logger('SceneService');
  82. private frameCnt = -1;
  83. private frameCntInterval = 1000;
  84. public _frameInteval: NodeJS.Timeout;
  85. private channel: DataChannel;
  86. public onSteaming = new BehaviorSubject<boolean>(false);
  87. public user_id: string;
  88. public roomId: string;
  89. onModuleInit() {
  90. this.sceneGrpcService =
  91. this.client.getService<SceneGrpcService>('SceneGrpcService');
  92. this.logger.log('init SceneGrpcService');
  93. }
  94. getRoute(request: RouteRequest) {
  95. return this.sceneGrpcService.getRoute(request);
  96. }
  97. getBreakPoint(request: GetBreakPointRequest) {
  98. return this.sceneGrpcService.getBreakPoint(request);
  99. }
  100. test(request: TestRequest) {
  101. return this.sceneGrpcService.test(request);
  102. }
  103. init(request: InitRequest) {
  104. try {
  105. const initReply = this.sceneGrpcService.init(request);
  106. initReply.subscribe((reply) => {
  107. console.log('initReply', reply);
  108. });
  109. } catch (error) {
  110. console.log('error', error);
  111. }
  112. }
  113. move(request: MoveRequest) {
  114. return this.sceneGrpcService.move(request);
  115. }
  116. rotate(request: RotateRequest) {
  117. const reply = this.sceneGrpcService.rotate(request);
  118. console.log('reply', reply);
  119. reply.subscribe((res) => {
  120. console.log('rotate-reply', res);
  121. });
  122. // console.log('this.frameCnt', this.frameCnt);
  123. // const stream: StreamFrameType = {
  124. // frame: this.frameCnt,
  125. // clipPath: path.join(__dirname, '../ws/video/254.h264'),
  126. // metaData: JSON.stringify(frameMetaReply),
  127. // };
  128. // this.streamService.pushFrameToSteam(stream);
  129. }
  130. joystick(request: JoystickRequest) {
  131. return this.sceneGrpcService.joystick(request);
  132. }
  133. handleDataChanelOpen(channel: DataChannel): void {
  134. this.channel = channel;
  135. this.streamService.setChannel(channel);
  136. this.handleStartCountingFrame();
  137. this.onSteaming.next(true);
  138. }
  139. handleDataChanelClose(): void {
  140. this.stopCountingFrame();
  141. this.onSteaming.next(false);
  142. this.streamService.closeChannel();
  143. }
  144. handleMessage(message: string | Buffer) {
  145. try {
  146. if (typeof message === 'string') {
  147. const msg: RTCMessageRequest = JSON.parse(message);
  148. switch (msg.action_type) {
  149. case ActionType.rotate:
  150. console.log('rotate', msg);
  151. const rotateRequest: RotateRequest = msg;
  152. this.rotate(rotateRequest);
  153. break;
  154. case ActionType.userStatus:
  155. this.updateUserStatus();
  156. break;
  157. case ActionType.status:
  158. this.updateStatus();
  159. break;
  160. default:
  161. break;
  162. }
  163. }
  164. // console.log('get rtc message', message);
  165. } catch (error) {
  166. this.logger.error('handleMessage:rtc', error);
  167. }
  168. }
  169. updateStatus() {
  170. const reply = {
  171. data: { action_type: 1009, echo_msg: { echoMsg: '1652857098550' } },
  172. track: false,
  173. };
  174. this.streamService.pushNormalDataToStream(reply);
  175. }
  176. updateUserStatus() {
  177. const reply = {
  178. actionType: 1024,
  179. pointType: 100,
  180. extra: '',
  181. traceId: '65db8e1b-2261-42eb-8bc5-8dc97bfe0b0e',
  182. packetId: '',
  183. nps: [],
  184. peopleNum: 0,
  185. zoneId: '',
  186. echoMsg: '',
  187. reserveDetail: null,
  188. userWithAvatarList: [],
  189. newUserStates: [
  190. {
  191. userId: 'e497b92704f5a',
  192. playerState: {
  193. roomTypeId: '',
  194. person: 0,
  195. avatarId: 'KGe_Boy',
  196. skinId: '10089',
  197. roomId: 'e629ef3e-022d-4e64-8654-703bb96410eb',
  198. isHost: false,
  199. isFollowHost: false,
  200. skinDataVersion: '1008900008',
  201. avatarComponents: '',
  202. nickName: 'e497b92704f5a',
  203. movingMode: 0,
  204. attitude: 'walk',
  205. areaName: '',
  206. pathName: 'thirdwalk',
  207. pathId: 'thirdwalk',
  208. avatarSize: 1,
  209. extra: '{"removeWhenDisconnected":true}',
  210. prioritySync: false,
  211. avatarURL: '',
  212. micStatus: 0,
  213. player: {
  214. position: { x: -755, y: -1450, z: -34 },
  215. angle: { pitch: 0, yaw: 0, roll: 0 },
  216. },
  217. camera: null,
  218. cameraCenter: null,
  219. },
  220. renderInfo: {
  221. renderType: 0,
  222. videoFrame: null,
  223. cameraStateType: 0,
  224. isMoving: 0,
  225. needIfr: 0,
  226. isVideo: 0,
  227. stillFrame: 0,
  228. isRotating: 0,
  229. isFollowing: 0,
  230. clientPanoTitlesBitmap: [],
  231. clientPanoTreceId: '',
  232. prefetchVideoId: '',
  233. noMedia: false,
  234. },
  235. event: {
  236. id: '',
  237. type: 0,
  238. points: [],
  239. rotateEvent: null,
  240. removeVisitorEvent: null,
  241. },
  242. relation: 0,
  243. },
  244. ],
  245. code: 0,
  246. msg: '',
  247. };
  248. this.streamService.pushNormalDataToStream(reply);
  249. }
  250. handleStartCountingFrame() {
  251. this._frameInteval = setInterval(async () => {
  252. this.frameCnt += 1;
  253. try {
  254. if (this.frameCnt === 1) {
  255. // this.pushTheFirstFrame();
  256. const stream: StreamFrameType = {
  257. frame: 1,
  258. clipPath: path.join(__dirname, '../ws/video/254.h264'),
  259. metaData: JSON.stringify(frameMetaReply),
  260. };
  261. this.streamService.pushFrameToSteam(stream);
  262. }
  263. // console.log('11', await this.redisService.get('test'));
  264. // console.log('data', data);
  265. if (this.frameCnt > 1) {
  266. const streamMeta: StreamMetaType = {
  267. frame: this.frameCnt,
  268. metaData: JSON.stringify(frameMetaReply),
  269. };
  270. this.streamService.pushMetaDataToSteam(streamMeta);
  271. }
  272. } catch (error) {
  273. console.log('error', error);
  274. }
  275. }, this.frameCntInterval);
  276. }
  277. stopCountingFrame(): void {
  278. clearInterval(this._frameInteval);
  279. this.frameCnt = -1;
  280. }
  281. // 首屏渲染
  282. // pushTheFirstFrame() {
  283. // const chunk_size = 16000;
  284. // const block = 36;
  285. // console.log('首屏--数据');
  286. // const paths = path.join(__dirname, '../ws/video');
  287. // // const clipPath = paths + `/1.v2.h264`;
  288. // const testClipPath = paths + `/2.h264`;
  289. // const metaData = {
  290. // traceIds: [],
  291. // vehicle: null,
  292. // newUserStates: [
  293. // {
  294. // userId: '1e3fa84d5c29a',
  295. // playerState: {
  296. // roomTypeId: '',
  297. // person: 0,
  298. // avatarId: 'KGe_Boy',
  299. // skinId: '10089',
  300. // roomId: '',
  301. // isHost: false,
  302. // isFollowHost: false,
  303. // skinDataVersion: '1008900008',
  304. // avatarComponents: '',
  305. // nickName: '1e3fa84d5c29a',
  306. // movingMode: 0,
  307. // attitude: 'walk',
  308. // areaName: 'LQC',
  309. // pathName: 'thirdwalk',
  310. // pathId: 'thirdwalk',
  311. // avatarSize: 1,
  312. // extra: '{"removeWhenDisconnected":true}',
  313. // prioritySync: false,
  314. // player: {
  315. // position: { x: -755, y: -1450, z: -34 },
  316. // angle: { pitch: 0, yaw: 0, roll: 0 },
  317. // },
  318. // camera: {
  319. // position: { x: -1075, y: -1450, z: 86 },
  320. // angle: { pitch: 0, yaw: 0, roll: 0 },
  321. // },
  322. // cameraCenter: null,
  323. // },
  324. // renderInfo: {
  325. // renderType: 0,
  326. // videoFrame: null,
  327. // cameraStateType: 0,
  328. // isMoving: 0,
  329. // needIfr: 0,
  330. // isVideo: 0,
  331. // stillFrame: 0,
  332. // isRotating: 0,
  333. // isFollowing: 0,
  334. // clientPanoTitlesBitmap: [],
  335. // clientPanoTreceId: '',
  336. // prefetchVideoId: '',
  337. // noMedia: false,
  338. // },
  339. // event: {
  340. // id: '',
  341. // type: 0,
  342. // points: [],
  343. // rotateEvent: null,
  344. // removeVisitorEvent: null,
  345. // },
  346. // relation: 1,
  347. // },
  348. // ],
  349. // actionResponses: [],
  350. // getStateType: 0,
  351. // code: 0,
  352. // msg: 'OK',
  353. // };
  354. // const metaDataString = JSON.stringify(metaData).replace(/\s/g, '');
  355. // const coordBuff = Buffer.from(metaDataString, 'utf-8');
  356. // console.warn('coordBuff', coordBuff.byteLength);
  357. // // const steamStat = statSync(clipPath);
  358. // // const steamTotalSize = metaData.length + steamStat.size;
  359. // const clipBuffer = readFileSync(testClipPath);
  360. // // console.log('clipBuffer', clipBuffer);
  361. // // const fullBufferList = Buffer.concat([coordBuff, clipBuffer]);
  362. // // const steam = createReadStream(clipPath, {
  363. // // highWaterMark: chunk_size - block,
  364. // // });
  365. // // console.log('fullBufferList', fullBufferList);
  366. // // const steam1 = createReadStream(fullBufferList.toString(), {
  367. // // highWaterMark: chunk_size - block,
  368. // // });
  369. // const steam = new streamBuffers.ReadableStreamBuffer({
  370. // frequency: 1, // in milliseconds.
  371. // chunkSize: chunk_size - block, // in bytes.
  372. // });
  373. // steam.put(coordBuff);
  374. // steam.put(clipBuffer);
  375. // let steamByteLength = 0;
  376. // steam.on('data', (data: Buffer) => {
  377. // // console.log('data', data, data.byteLength);
  378. // // console.log('data-size', data);
  379. // const blockBuffStart = Buffer.alloc(block);
  380. // const packBuffer = Buffer.concat([blockBuffStart, data]);
  381. // // const isLastFrame = packBuffer.byteLength - chunk_size < 0;
  382. // // console.log('packBuffer', packBuffer.byteLength);
  383. // // if (isLastFrame) {
  384. // // // last frame
  385. // // packBuffer = Buffer.concat([packBuffer, coordBuff]);
  386. // // console.log('last frame', packBuffer.byteLength);
  387. // // }
  388. // const framePack = new DataView(
  389. // packBuffer.buffer.slice(
  390. // packBuffer.byteOffset,
  391. // packBuffer.byteOffset + packBuffer.byteLength,
  392. // ),
  393. // );
  394. // // 16 bit slot
  395. // // framePack.setUint32(4)
  396. // framePack.setUint16(6, block);
  397. // framePack.setUint16(8, 1); // first render cnt
  398. // framePack.setUint16(10, 1); // isDIR
  399. // framePack.setUint16(24, 0);
  400. // framePack.setUint16(26, 0);
  401. // // 32 bit slot
  402. // // statusPack.setUint32(12, buff.byteLength);
  403. // // console.log('metaLen', coordBuff.byteLength);
  404. // // console.log('metaLen', clipBuffer.byteLength);
  405. // framePack.setUint32(0, 1437227610);
  406. // framePack.setUint32(12, coordBuff.byteLength); // metaLen
  407. // framePack.setUint32(16, clipBuffer.byteLength); // mediaLen
  408. // framePack.setUint32(20, 754871824); //server_time
  409. // framePack.setUint32(24, 0);
  410. // framePack.setUint32(28, 0);
  411. // framePack.setUint32(block - 4, steamByteLength);
  412. // // console.log('statusPack', statusPack);
  413. // if (this.channel && this.channel.isOpen()) {
  414. // this.channel.sendMessageBinary(Buffer.from(framePack.buffer));
  415. // }
  416. // steamByteLength += data.byteLength;
  417. // });
  418. // steam.on('end', () => {
  419. // steamByteLength = 0;
  420. // // this.onSteaming = false;
  421. // });
  422. // }
  423. }