scene.service.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  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 * 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, OnModuleDestroy {
  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 startSteaming = new BehaviorSubject<boolean>(false);
  87. private user_id: string;
  88. private roomId: string;
  89. private onSteaming = false;
  90. private testFrame = -1;
  91. private RotateframeCnt = -1;
  92. setConfig(user_id: string, roomId: string) {
  93. this.user_id = user_id;
  94. this.roomId = roomId;
  95. }
  96. checkingIsRotating() {
  97. console.log('async', this.frameCnt, this.RotateframeCnt);
  98. if (this.frameCnt > 0 && this.frameCnt === this.RotateframeCnt) {
  99. return true;
  100. } else {
  101. return false;
  102. }
  103. }
  104. onModuleInit() {
  105. this.sceneGrpcService =
  106. this.client.getService<SceneGrpcService>('SceneGrpcService');
  107. this.logger.log('init SceneGrpcService');
  108. 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. onModuleDestroy() {
  116. this.streamService.onSteaming.unsubscribe();
  117. }
  118. getRoute(request: RouteRequest) {
  119. return this.sceneGrpcService.getRoute(request);
  120. }
  121. getBreakPoint(request: GetBreakPointRequest) {
  122. return this.sceneGrpcService.getBreakPoint(request);
  123. }
  124. init(request: InitRequest) {
  125. try {
  126. // const initReply = this.sceneGrpcService.init(request);
  127. // initReply.subscribe((reply) => {
  128. // console.log('initReply', reply);
  129. // });
  130. } catch (error) {
  131. console.log('error', error);
  132. }
  133. }
  134. exit(request: ExitRequest) {
  135. // const exitReply = this.sceneGrpcService.exit(request);
  136. // exitReply.subscribe((reply) => {
  137. // console.log('exitReply', reply);
  138. // });
  139. }
  140. move(request: MoveRequest) {
  141. return this.sceneGrpcService.move(request);
  142. }
  143. async rotate(request: RotateRequest) {
  144. try {
  145. // const reply = this.sceneGrpcService.rotate(request);
  146. if (!this.onSteaming) {
  147. this.frameCnt += 1;
  148. this.RotateframeCnt = this.frameCnt;
  149. this.testFrame += 1;
  150. if (this.testFrame > 358) this.testFrame = 0;
  151. const stream: StreamFrameType = {
  152. frame: this.frameCnt,
  153. clipPath: path.join(
  154. __dirname,
  155. `../ws/video/100/100.${this.testFrame.padLeft(4, '0')}.h264`,
  156. ),
  157. metaData: JSON.stringify(frameMetaReply),
  158. serverTime: 754871824,
  159. DIR: 1,
  160. };
  161. console.log('stream', this.frameCnt, stream.clipPath);
  162. this.streamService.pushFrameToSteam(stream);
  163. const redisMeta = await this.cacheService.rpop(
  164. `updateFrameMetadata:${this.user_id}`,
  165. );
  166. // this.frameCnt += 1;
  167. if (redisMeta && redisMeta.length > 0) {
  168. console.log('this.user_id', this.user_id);
  169. const meta = JSON.parse(redisMeta);
  170. if ('mediaSrc' in meta) {
  171. console.log('meta', meta);
  172. console.log('mediaSrc', meta.mediaSrc);
  173. if (meta.mediaSrc.length > 0) {
  174. // const testclipPath = meta.mediaSrc.replace(
  175. // '/mnt/oss/metaverse/scene/0000000001/100/',
  176. // '',
  177. // );
  178. // console.log('testclipPath', testclipPath);
  179. // // const demoPath =
  180. // // this.frameCnt > 10
  181. // // ? path.join(__dirname, '../ws/video/53.h264')
  182. // // : path.join(__dirname, '../ws/video/2.h264');
  183. // const demoPath = path.join(
  184. // __dirname,
  185. // `../ws/video/${testclipPath}`,
  186. // );
  187. // delete meta.mediaSrc;
  188. // const stream: StreamFrameType = {
  189. // frame: this.frameCnt,
  190. // clipPath: demoPath,
  191. // metaData: JSON.stringify(meta),
  192. // serverTime: 754873824,
  193. // DIR: 3,
  194. // };
  195. // this.streamService.pushFrameToSteam(stream);
  196. }
  197. }
  198. }
  199. }
  200. // reply.subscribe((res: NormalReply) => {
  201. // if (res.code === 200) {
  202. // }
  203. // });
  204. } catch (error) {
  205. this.logger.error('rotate', error);
  206. }
  207. }
  208. joystick(request: JoystickRequest) {
  209. return this.sceneGrpcService.joystick(request);
  210. }
  211. handleDataChanelOpen(channel: DataChannel): void {
  212. this.channel = channel;
  213. this.streamService.setChannel(channel);
  214. this.handleStartCountingFrame();
  215. this.startSteaming.next(true);
  216. }
  217. handleDataChanelClose(): void {
  218. this.stopCountingFrame();
  219. this.startSteaming.next(false);
  220. this.streamService.closeChannel();
  221. const exitRequest: ExitRequest = {
  222. action_type: 1002,
  223. user_id: this.user_id,
  224. trace_id: '',
  225. };
  226. this.exit(exitRequest);
  227. }
  228. handleMessage(message: string | Buffer) {
  229. try {
  230. if (typeof message === 'string') {
  231. // console.log('toto', message);
  232. const msg: RTCMessageRequest = JSON.parse(message);
  233. switch (msg.action_type) {
  234. case ActionType.rotate:
  235. const rotateRequest: RotateRequest = msg;
  236. this.rotate(rotateRequest);
  237. break;
  238. case ActionType.userStatus:
  239. this.updateUserStatus();
  240. break;
  241. case ActionType.status:
  242. this.updateStatus();
  243. break;
  244. default:
  245. break;
  246. }
  247. }
  248. } catch (error) {
  249. this.logger.error('handleMessage:rtc', error);
  250. }
  251. }
  252. updateStatus() {
  253. const reply = {
  254. data: { action_type: 1009, echo_msg: { echoMsg: Date.now() } },
  255. track: false,
  256. };
  257. this.streamService.pushNormalDataToStream(reply);
  258. }
  259. async updateUserStatus() {
  260. const reply = {
  261. actionType: 1024,
  262. pointType: 100,
  263. extra: '',
  264. traceId: '65db8e1b-2261-42eb-8bc5-8dc97bfe0b0e',
  265. packetId: '',
  266. nps: [],
  267. peopleNum: 0,
  268. zoneId: '',
  269. echoMsg: '',
  270. reserveDetail: null,
  271. userWithAvatarList: [],
  272. newUserStates: [
  273. {
  274. userId: 'e497b92704f5a',
  275. playerState: {
  276. roomTypeId: '',
  277. person: 0,
  278. avatarId: 'KGe_Boy',
  279. skinId: '10089',
  280. roomId: 'e629ef3e-022d-4e64-8654-703bb96410eb',
  281. isHost: false,
  282. isFollowHost: false,
  283. skinDataVersion: '1008900008',
  284. avatarComponents: '',
  285. nickName: 'e497b92704f5a',
  286. movingMode: 0,
  287. attitude: 'walk',
  288. areaName: '',
  289. pathName: 'thirdwalk',
  290. pathId: 'thirdwalk',
  291. avatarSize: 1,
  292. extra: '{"removeWhenDisconnected":true}',
  293. prioritySync: false,
  294. avatarURL: '',
  295. micStatus: 0,
  296. player: {
  297. position: { x: -755, y: -1450, z: -34 },
  298. angle: { pitch: 0, yaw: 0, roll: 0 },
  299. },
  300. camera: null,
  301. cameraCenter: null,
  302. },
  303. renderInfo: {
  304. renderType: 0,
  305. videoFrame: null,
  306. cameraStateType: 0,
  307. isMoving: 0,
  308. needIfr: 0,
  309. isVideo: 0,
  310. stillFrame: 0,
  311. isRotating: 0,
  312. isFollowing: 0,
  313. clientPanoTitlesBitmap: [],
  314. clientPanoTreceId: '',
  315. prefetchVideoId: '',
  316. noMedia: false,
  317. },
  318. event: {
  319. id: '',
  320. type: 0,
  321. points: [],
  322. rotateEvent: null,
  323. removeVisitorEvent: null,
  324. },
  325. relation: 0,
  326. },
  327. ],
  328. code: 0,
  329. msg: '',
  330. };
  331. const redisMeta = await this.cacheService.rpop(
  332. `updateFrameMetadata:${this.user_id}`,
  333. );
  334. //TODO 接入redis数据
  335. console.log('redisMeta', redisMeta);
  336. if (redisMeta && redisMeta.length > 0) {
  337. const meta = JSON.parse(redisMeta);
  338. 'mediaSrc' in meta && delete meta.mediaSrc;
  339. meta.action_type = 1024;
  340. this.streamService.pushNormalDataToStream(meta);
  341. } else {
  342. this.streamService.pushNormalDataToStream(reply);
  343. }
  344. // this.streamService.pushNormalDataToStream(reply);
  345. }
  346. handleStartCountingFrame() {
  347. this._frameInteval = setInterval(async () => {
  348. this.frameCnt += 1;
  349. try {
  350. if (this.frameCnt === 1) {
  351. // this.pushTheFirstFrame();
  352. const stream: StreamFrameType = {
  353. frame: 1,
  354. clipPath: path.join(__dirname, '../ws/video/100/100.0000.h264'),
  355. metaData: JSON.stringify(frameMetaReply),
  356. serverTime: 754871824,
  357. };
  358. this.streamService.pushFrameToSteam(stream);
  359. }
  360. // console.log('padLeft', );
  361. // if (this.frameCnt > 2) {
  362. // setInterval(() => {
  363. // this.frameCnt += 1;
  364. // const stream: StreamFrameType = {
  365. // frame: this.frameCnt,
  366. // clipPath: path.join(
  367. // __dirname,
  368. // `../ws/video/100/100.${this.frameCnt.padLeft(4, '0')}.h264`,
  369. // ),
  370. // metaData: JSON.stringify(frameMetaReply),
  371. // serverTime: 754871824,
  372. // };
  373. // this.streamService.pushFrameToSteam(stream);
  374. // }, 1000 / 30);
  375. // };
  376. if (this.frameCnt > 1 && !this.onSteaming) {
  377. const streamMeta: StreamMetaType = {
  378. frame: this.frameCnt,
  379. metaData: JSON.stringify(frameMetaReply),
  380. };
  381. this.streamService.pushMetaDataToSteam(streamMeta);
  382. };
  383. // }
  384. } catch (error) {
  385. console.log('error', error);
  386. }
  387. }, this.frameCntInterval);
  388. }
  389. stopCountingFrame(): void {
  390. clearInterval(this._frameInteval);
  391. this.frameCnt = -1;
  392. }
  393. }