rotate.service.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. import { Injectable, Logger } from '@nestjs/common';
  2. import { ConfigService } from '@nestjs/config';
  3. import { CacheService } from 'src/cache/cache.service';
  4. // import { SceneService } from 'src/scene/scene.service';
  5. const seqExeAsyncFn = (asyncFn) => {
  6. let runPromise = null;
  7. return function seq(...args) {
  8. if (!runPromise) {
  9. //debugger;
  10. runPromise = asyncFn.apply(this, args);
  11. runPromise.then((data) => {
  12. //debugger;
  13. // console.log('seq result', data);
  14. });
  15. runPromise.then(() => (runPromise = null));
  16. return runPromise;
  17. } else {
  18. return runPromise.then(() => seq.apply(this, args));
  19. }
  20. };
  21. };
  22. @Injectable()
  23. export class RotateService {
  24. constructor(
  25. private cacheService: CacheService, // private sceneService: SceneService,
  26. private configService: ConfigService,
  27. ) {}
  28. private actionRequestPool = {};
  29. private logger: Logger = new Logger('rotateService');
  30. private Actions = {
  31. Clicking: 1,
  32. Rotation: 1014,
  33. Joystick: 15,
  34. };
  35. public users = {};
  36. private replies = {};
  37. private firstPoint = {
  38. player: {
  39. position: { x: -600.0, y: -250.0, z: 0.0 }, //position: { x: -560.0, y: 320.0, z: 0.0 }, //{ x: -800.0, y: 100.0, z: 0.0 },
  40. angle: {
  41. pitch: 0,
  42. yaw: 0,
  43. roll: 0,
  44. },
  45. },
  46. camera: {
  47. position: { x: -1038.0, y: -249.99996948242188, z: 119.99998474121094 }, //{ x: -1141.6719970703125, y: 94.03607940673828, z: 120.0 }, //{ x: -998.0, y: 319.9999694824219, z: 120.0 }
  48. angle: {
  49. pitch: 0,
  50. yaw: 0,
  51. roll: 0,
  52. },
  53. },
  54. };
  55. init(app_id: string, userId: string,skinId: string,roomId: string,avatar_id: string) {
  56. const user = {
  57. appId: null,
  58. userId: null,
  59. breakPointId: null,
  60. roomId: null,
  61. skinId: null,
  62. avatar_id: null,
  63. player: {
  64. position: { x: -560.0, y: 320.0, z: 0.0 }, //{ x: -800.0, y: 100.0, z: 0.0 },
  65. angle: {
  66. pitch: 0,
  67. yaw: 0,
  68. roll: 0,
  69. },
  70. },
  71. camera: {
  72. position: { x: -998.0, y: 319.9999694824219, z: 120.0 }, //{ x: -1141.6719970703125, y: 94.03607940673828, z: 120.0 },
  73. angle: {
  74. pitch: 0,
  75. yaw: 0,
  76. roll: 0,
  77. },
  78. },
  79. rotateInfo: {
  80. frameIndex: 0,
  81. horizontal_move: 0,
  82. },
  83. moveInfo: {},
  84. // traceIds: [],
  85. // actionResponses:[]
  86. };
  87. user.appId = app_id;
  88. user.userId = userId;
  89. user.breakPointId = Number(this.configService.get('app.startPoint')) || 0;
  90. user.skinId = skinId;
  91. user.roomId = roomId;
  92. user.avatar_id = avatar_id;
  93. user.player.position = JSON.parse(
  94. JSON.stringify(this.firstPoint.player.position),
  95. );
  96. user.camera.position = JSON.parse(
  97. JSON.stringify(this.firstPoint.camera.position),
  98. );
  99. console.log('user-init', user);
  100. this.users[userId] = user;
  101. const reply = {
  102. traceIds: [],
  103. vehicle: null,
  104. mediaSrc: null,
  105. newUserStates: [
  106. {
  107. userId: 'dcff36ae4fc1d',
  108. playerState: {
  109. roomTypeId: '',
  110. person: 0,
  111. avatarId: '',
  112. skinId: '',
  113. roomId: '',
  114. isHost: false,
  115. isFollowHost: false,
  116. skinDataVersion: '',
  117. avatarComponents: '',
  118. nickName: '',
  119. movingMode: 0,
  120. attitude: '',
  121. areaName: '',
  122. pathName: '',
  123. pathId: '',
  124. avatarSize: 1,
  125. extra: '',
  126. prioritySync: false,
  127. player: {
  128. position: { x: 100.0, y: 100.0, z: 0.0 },
  129. angle: {
  130. pitch: 0,
  131. yaw: 0,
  132. roll: 0,
  133. },
  134. },
  135. camera: {
  136. position: { x: -338.0, y: 100, z: 120.0 },
  137. angle: {
  138. pitch: 0,
  139. yaw: 0,
  140. roll: 0,
  141. },
  142. },
  143. cameraCenter: { x: 100.0, y: 100.0, z: 0.0 },
  144. },
  145. renderInfo: {
  146. renderType: 0,
  147. videoFrame: null,
  148. cameraStateType: 3,
  149. isMoving: 0,
  150. needIfr: 0,
  151. isVideo: 0,
  152. stillFrame: 0,
  153. isRotating: 0,
  154. isFollowing: 0,
  155. clientPanoTitlesBitmap: [],
  156. clientPanoTreceId: '',
  157. prefetchVideoId: '',
  158. noMedia: false,
  159. },
  160. event: null,
  161. relation: 1,
  162. },
  163. ],
  164. actionResponses: [
  165. {
  166. // "actionType": 15,
  167. // "pointType": 100,
  168. extra: '',
  169. // "traceId": "d0864cd0-378d-4d49-b7b0-3e8e1b9494c3",
  170. // "packetId": "d44bd2f5-f877-4dd7-868b-803c64f99082",
  171. nps: [],
  172. peopleNum: 0,
  173. zoneId: '',
  174. echoMsg: '',
  175. reserveDetail: null,
  176. userWithAvatarList: [],
  177. newUserStates: [],
  178. code: 0,
  179. msg: '',
  180. },
  181. ],
  182. getStateType: 0,
  183. code: 0,
  184. msg: 'OK',
  185. };
  186. reply['newUserStates'][0].playerState.player.position = JSON.parse(
  187. JSON.stringify(this.firstPoint.player.position),
  188. );
  189. reply['newUserStates'][0].playerState.camera.position = JSON.parse(
  190. JSON.stringify(this.firstPoint.camera.position),
  191. );
  192. this.replies[userId] = reply;
  193. return reply;
  194. }
  195. //首帧
  196. getFirstStreamData(appId, userId) {
  197. const user = this.users[userId];
  198. const reply = this.replies[userId];
  199. reply.traceIds = [];
  200. reply['newUserStates'][0].userId = userId;
  201. reply['newUserStates'][0].playerState.player.position = JSON.parse(
  202. JSON.stringify(this.firstPoint.player.position),
  203. );
  204. reply['newUserStates'][0].playerState.player.angle = JSON.parse(
  205. JSON.stringify(this.firstPoint.player.angle),
  206. );
  207. reply['newUserStates'][0].playerState.camera.position = JSON.parse(
  208. JSON.stringify(this.firstPoint.camera.position),
  209. );
  210. reply['newUserStates'][0].playerState.camera.angle = JSON.parse(
  211. JSON.stringify(this.firstPoint.camera.angle),
  212. );
  213. reply['newUserStates'][0].playerState.cameraCenter = JSON.parse(
  214. JSON.stringify(this.firstPoint.player.position),
  215. );
  216. reply['actionResponses'][0].traceId = null;
  217. reply.mediaSrc =
  218. '/' +
  219. appId +
  220. '/' +
  221. user.breakPointId +
  222. '/' +
  223. user.breakPointId +
  224. '/' +
  225. user.breakPointId +
  226. '.0000.h264' +
  227. '?m=' +
  228. new Date().getTime();
  229. reply['newUserStates'][0].renderInfo.isMoving = 0;
  230. this.replies[userId] = reply;
  231. return reply;
  232. }
  233. /**
  234. * delete User object
  235. * @param userId
  236. */
  237. deleteUser(userId: string) {
  238. if (userId in this.users) {
  239. delete this.users[userId];
  240. console.log('[delete User]--存在用户 %s', userId);
  241. }
  242. }
  243. // 顺序旋转请求
  244. seqExeRotate = seqExeAsyncFn(this.rotate);
  245. //旋转请求
  246. async rotate(actionRequest) {
  247. // return new Promise(async (resolve, reject) => {
  248. try {
  249. const userId = actionRequest['user_id'];
  250. if (this.actionRequestPool[userId]) {
  251. this.actionRequestPool[userId].push(actionRequest);
  252. } else {
  253. this.actionRequestPool[userId] = [];
  254. this.actionRequestPool[userId].push(actionRequest);
  255. }
  256. let reply = this.replies[userId];
  257. const actionRequests = this.actionRequestPool[userId];
  258. const user = this.users[userId];
  259. // debugger;
  260. let horizontal_move = user.rotateInfo.horizontal_move;
  261. //const traceIds = user.traceIds;
  262. let sub = 0;
  263. for (let i = 0; i < actionRequests.length; ++i) {
  264. if (actionRequests[i].action_type == this.Actions.Rotation) {
  265. horizontal_move += actionRequests[i].rotation_action.horizontal_move;
  266. reply.traceIds.push(actionRequests[i].trace_id);
  267. const actionResponse = this.createActionResponse(
  268. actionRequests[i].action_type,
  269. actionRequests[i].trace_id,
  270. );
  271. reply.actionResponses.push(actionResponse);
  272. ++sub;
  273. } else {
  274. break;
  275. }
  276. }
  277. actionRequests.splice(0, sub);
  278. const hAngle = horizontal_move * 90;
  279. if (Math.abs(hAngle) < 1) {
  280. user.rotateInfo.horizontal_move = horizontal_move;
  281. //user.traceIds = traceIds;
  282. this.replies[userId] = reply;
  283. return null;
  284. }
  285. reply = await this.rotateForAngle(userId, Math.floor(hAngle));
  286. // console.log('rotate-cameraAngle:, yaw: %s, ', user.camera.angle.yaw);
  287. return reply;
  288. // return resolve(reply);
  289. } catch (error) {
  290. throw error;
  291. // console.log('RotateService', error);
  292. // return reject(error);
  293. }
  294. // });
  295. }
  296. // test(){
  297. // while(true){
  298. // if(this.actionRequests.length>0){
  299. // let actionRequest = this.actionRequests[0];
  300. // //执行
  301. // //添加队列
  302. // }
  303. // }
  304. // }
  305. // receiveRotate(actionRequest){
  306. // this.actionRequests.push(actionRequest)
  307. // }
  308. async rotateForAngle(userId, hAngle): Promise<any> {
  309. return new Promise(async (resolve, reject) => {
  310. try {
  311. const user = this.users[userId];
  312. // console.log(
  313. // '当前镜头角度, yaw: %s, hAngle: %s',
  314. // user.camera.angle.yaw,
  315. // hAngle,
  316. // );
  317. // console.time('当前镜头角度 %s', user.camera.angle.yaw, '旋转角度:', hAngle);
  318. user.camera.angle.yaw += Math.floor(hAngle);
  319. if (user.camera.angle.yaw < 0) {
  320. user.camera.angle.yaw = 360 + user.camera.angle.yaw;
  321. } else if (user.camera.angle.yaw > 359) {
  322. user.camera.angle.yaw -= 360;
  323. }
  324. const reply = JSON.parse(JSON.stringify(this.replies[userId]));
  325. reply['newUserStates'][0]['userId'] = userId;
  326. //从redis里取
  327. //let key = user.appId + "-"+user.breakPointId+"-"+user.rotateInfo.frameIndex;
  328. let key =
  329. 'rotateframe:app_id:' +
  330. user.appId +
  331. ':frame_index:' +
  332. user.camera.angle.yaw +
  333. ':break_point_id:' +
  334. user.breakPointId;
  335. // const value = null;
  336. console.log('rotateForAngle-3:' + user.breakPointId);
  337. console.log('rotateForAngle-3-key:' + key);
  338. this.logger.log('rotateForAngle-3-key', key);
  339. let redisData = await this.cacheService.get(key);
  340. //if (redisData && redisData.length > 0) {
  341. let value = JSON.parse(redisData); //redisData ? JSON.parse(redisData) : null;
  342. //console.log('rotateForAngle-4:'+user.breakPointId+','+value.directory+','+value.fileName);
  343. if (value.directory != user.breakPointId) {
  344. key =
  345. 'rotateframe:app_id:' +
  346. user.appId +
  347. ':frame_index:' +
  348. user.camera.angle.yaw +
  349. ':break_point_id:' +
  350. user.breakPointId;
  351. redisData = await this.cacheService.get(key);
  352. value = JSON.parse(redisData);
  353. }
  354. // console.log('rotate-service', value);
  355. user.camera['position'] = JSON.parse(
  356. JSON.stringify(value.cameraPosition),
  357. ); //value ? value.cameraPosition : '';
  358. user.camera['angle'] = JSON.parse(JSON.stringify(value.cameraAngle)); //value ? value.cameraAngle : '';
  359. reply['newUserStates'][0]['playerState'].player.position = JSON.parse(
  360. JSON.stringify(user.player.position),
  361. );
  362. reply['newUserStates'][0]['playerState'].player.angle = JSON.parse(
  363. JSON.stringify(user.player.angle),
  364. );
  365. //this.reply['newUserStates'][0]['playerState'] .player
  366. reply['newUserStates'][0]['playerState'].camera.position = JSON.parse(
  367. JSON.stringify(value.cameraPosition),
  368. );
  369. reply['newUserStates'][0]['playerState'].camera.angle = JSON.parse(
  370. JSON.stringify(value.cameraAngle),
  371. );
  372. reply['newUserStates'][0]['playerState'].cameraCenter = JSON.parse(
  373. JSON.stringify(user.player.position),
  374. );
  375. // debugger
  376. reply.mediaSrc =
  377. '/' +
  378. user.appId +
  379. '/' +
  380. user.breakPointId +
  381. '/' +
  382. value.directory +
  383. '/' +
  384. value.fileName +
  385. '?m=' +
  386. new Date().getTime();
  387. console.log(
  388. 'rotateForAngle-5:' +
  389. user.breakPointId +
  390. ',' +
  391. value.directory +
  392. ',' +
  393. value.fileName,
  394. );
  395. reply.breakPointId = user.breakPointId;
  396. this.replies[userId].traceIds = [];
  397. this.replies[userId].actionResponses = [];
  398. user.rotateInfo.horizontal_move = 0;
  399. return resolve(reply);
  400. //}
  401. // else {
  402. // return null;
  403. // }
  404. } catch (error) {
  405. debugger;
  406. this.logger.error('rotateForAngle::function', error);
  407. return reject(error);
  408. }
  409. });
  410. }
  411. createActionResponse(actionType, traceId) {
  412. const actionResponse = {
  413. actionType: actionType,
  414. pointType: 100,
  415. extra: '',
  416. traceId: traceId,
  417. packetId: '',
  418. nps: [],
  419. peopleNum: 0,
  420. zoneId: '',
  421. echoMsg: '',
  422. reserveDetail: null,
  423. userWithAvatarList: [],
  424. newUserStates: [],
  425. code: 0,
  426. msg: '',
  427. };
  428. return actionResponse;
  429. }
  430. getNewUserStateRequest(actionRequest) {
  431. try {
  432. const userId = actionRequest['user_id'];
  433. const actionType = actionRequest['action_type'];
  434. const traceId = actionRequest['trace_id'];
  435. const reply = {
  436. actionType: actionType,
  437. pointType: 100,
  438. extra: '',
  439. traceId: traceId,
  440. packetId: '',
  441. nps: [],
  442. peopleNum: 0,
  443. zoneId: '',
  444. echoMsg: '',
  445. reserveDetail: null,
  446. userWithAvatarList: [],
  447. newUserStates: [],
  448. code: 0,
  449. msg: '',
  450. };
  451. const userIds = Object.keys(this.users);
  452. for (let i = 0; i < userIds.length; ++i) {
  453. const _user = this.users[userIds[i]];
  454. const newUserState = {
  455. userId: userIds[i],
  456. playerState: {
  457. roomTypeId: '',
  458. person: 0,
  459. avatarId: _user.avatar_id,
  460. skinId: _user.skinId,
  461. roomId: _user.roomId,
  462. isHost: false,
  463. isFollowHost: false,
  464. skinDataVersion: '1008900008',
  465. avatarComponents: '',
  466. nickName: userIds[i],
  467. movingMode: 0,
  468. attitude: 'walk',
  469. areaName: '',
  470. pathName: 'thirdwalk',
  471. pathId: 'thirdwalk',
  472. avatarSize: 1,
  473. extra: '{"removeWhenDisconnected":true}',
  474. prioritySync: false,
  475. player: {
  476. position: _user.player.position,
  477. angle: _user.player.angle,
  478. },
  479. camera: null,
  480. cameraCenter: null,
  481. },
  482. renderInfo: {
  483. renderType: 0,
  484. videoFrame: null,
  485. cameraStateType: 0,
  486. isMoving: 0,
  487. needIfr: 0,
  488. isVideo: 0,
  489. stillFrame: 0,
  490. isRotating: 0,
  491. isFollowing: 0,
  492. clientPanoTitlesBitmap: [],
  493. clientPanoTreceId: '',
  494. prefetchVideoId: '',
  495. noMedia: false,
  496. },
  497. event: {
  498. id: '',
  499. type: 0,
  500. points: [],
  501. rotateEvent: null,
  502. removeVisitorEvent: null,
  503. },
  504. relation: 0,
  505. };
  506. reply['newUserStates'].push(newUserState);
  507. }
  508. return reply;
  509. } catch (error) {
  510. this.logger.error('getNewUserStateRequest::function', error);
  511. }
  512. }
  513. async echo(userId: string, isFirst: boolean) {
  514. const user = this.users[userId];
  515. const reply = JSON.parse(JSON.stringify(this.replies[userId]));
  516. reply['newUserStates'][0]['userId'] = userId;
  517. reply['newUserStates'][0]['playerState'].player.position =
  518. user.player.position;
  519. reply['newUserStates'][0]['playerState'].player.angle = user.player.angle;
  520. reply['newUserStates'][0]['playerState'].camera.position =
  521. user.camera['position'];
  522. reply['newUserStates'][0]['playerState'].camera.angle =
  523. user.camera['angle'];
  524. reply['newUserStates'][0]['playerState'].cameraCenter =
  525. user.player.position;
  526. if (isFirst) {
  527. reply.mediaSrc =
  528. '/' +
  529. user.appId +
  530. '/' +
  531. user.breakPointId +
  532. '/' +
  533. user.breakPointId +
  534. '/' +
  535. `${user.breakPointId}.0000.h264` +
  536. '?m=' +
  537. new Date().getTime();
  538. reply.breakPointId = user.breakPointId;
  539. return reply;
  540. } else {
  541. /*
  542. const key =
  543. 'rotateframe:app_id:' +
  544. user.appId +
  545. ':frame_index:' +
  546. user.camera.angle.yaw +
  547. ':break_point_id:' +
  548. user.breakPointId;
  549. const redisData = await this.cacheService.get(key);
  550. if (redisData && redisData.length > 0) {
  551. const value = redisData ? JSON.parse(redisData) : null;
  552. reply.mediaSrc =
  553. '/' +
  554. user.appId +
  555. '/' +
  556. user.breakPointId +
  557. '/' +
  558. value.directory +
  559. '/' +
  560. value.fileName +
  561. '?m=' +
  562. new Date().getTime();
  563. reply.breakPointId = user.breakPointId;
  564. // console.log(
  565. // 'joystick:->echo' +
  566. // 'playerPosition:' +
  567. // JSON.stringify(
  568. // reply['newUserStates'][0].playerState.player.position,
  569. // ) +
  570. // ',cameraPosition:' +
  571. // JSON.stringify(
  572. // reply['newUserStates'][0].playerState.camera.position,
  573. // ),
  574. // );
  575. */
  576. let fileName = user.camera.angle.yaw + '.h264';
  577. if (fileName.length == 8) {
  578. fileName = '0' + fileName;
  579. } else if (fileName.length == 7) {
  580. fileName = '00' + fileName;
  581. } else if (fileName.length == 6) {
  582. fileName = '000' + fileName;
  583. }
  584. reply.mediaSrc =
  585. '/' +
  586. user.appId +
  587. '/' +
  588. user.breakPointId +
  589. '/' +
  590. user.breakPointId +
  591. '/' +
  592. user.breakPointId +
  593. '.' +
  594. fileName +
  595. '?m=' +
  596. new Date().getTime();
  597. reply.breakPointId = user.breakPointId;
  598. return reply;
  599. // } else {
  600. // this.logger.error('echo返回null', key);
  601. // return {};
  602. }
  603. }
  604. }