rotate.service.ts 17 KB

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