|
@@ -3,7 +3,7 @@ import { ClientGrpc, Client } from '@nestjs/microservices';
|
|
|
import { grpcClientOptions } from './grpc-scene.options';
|
|
|
import { Logger } from '@nestjs/common';
|
|
|
import { DataChannel } from 'node-datachannel';
|
|
|
-import { BehaviorSubject } from 'rxjs';
|
|
|
+import { BehaviorSubject, EMPTY, ignoreElements, take } from 'rxjs';
|
|
|
// import * as streamBuffers from 'stream-buffers';
|
|
|
import { ActionType } from './actionType';
|
|
|
import { CacheService } from 'src/cache/cache.service';
|
|
@@ -11,7 +11,7 @@ import { StreamService } from './stream/stream.service';
|
|
|
// import { InjectQueue } from '@nestjs/bull';
|
|
|
// import { Queue } from 'bull';
|
|
|
import { RotateService } from 'src/rotate/rotate.service';
|
|
|
-import { DelayQueue, RxQueue, ThrottleQueue, DebounceQueue } from 'rx-queue';
|
|
|
+import { DelayQueue, RxQueue, DebounceQueue } from 'rx-queue';
|
|
|
import { MoveService } from 'src/move/move.service';
|
|
|
import { GetRouterService } from 'src/get-router/get-router.service';
|
|
|
import { ConfigService } from '@nestjs/config';
|
|
@@ -73,12 +73,15 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
|
|
|
private requestIFrameQueueSub: any;
|
|
|
private roRequestQueueSub: any;
|
|
|
private rotateTimeStamp: number;
|
|
|
- private lastMoveCnt = -1;
|
|
|
|
|
|
private firstRender = false;
|
|
|
private latestBreakPointId: number;
|
|
|
private isHoldingStream = false;
|
|
|
private lastMovingPointArray: MovingLastUpdateType[] = [];
|
|
|
+ private latestWalkingRequest: any; // 最新waking的接收值
|
|
|
+
|
|
|
+ private moveSliceLastFrame = new BehaviorSubject<MovingLastUpdateType>(null);
|
|
|
+ private moveSliceLastFrameSub: any;
|
|
|
|
|
|
public lastMoveStreamFrame = new BehaviorSubject<StreamFrameType>({
|
|
|
frame: -1,
|
|
@@ -259,7 +262,6 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
|
|
|
const start = performance.now();
|
|
|
// 当move时处理
|
|
|
if (this.onMoving.value) {
|
|
|
- this.onMoving.next(false);
|
|
|
const lastStreamFrame = this.lastMoveStreamFrame.getValue();
|
|
|
const metaData: StreamReplyType = JSON.parse(
|
|
|
lastStreamFrame.metaData,
|
|
@@ -273,6 +275,7 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
|
|
|
const cameraAngle = newUserStates.playerState.camera.angle;
|
|
|
const playerAngle = newUserStates.playerState.player.angle;
|
|
|
console.log('stop-data', trace_id, userId, cameraAngle, cameraAngle);
|
|
|
+ //debugger;
|
|
|
redisMeta = await this.moveService.stop(
|
|
|
trace_id,
|
|
|
userId,
|
|
@@ -281,6 +284,8 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
|
|
|
playerAngle,
|
|
|
);
|
|
|
console.log('stop-redisMeta', redisMeta);
|
|
|
+ this.onMoving.next(false);
|
|
|
+ this.cleanMoveSteam();
|
|
|
// redisMeta = await this.rotateService.rotate(request);
|
|
|
} else {
|
|
|
// 正常rotate
|
|
@@ -335,95 +340,144 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
|
|
|
// );
|
|
|
}
|
|
|
|
|
|
- async walking(req) {
|
|
|
- try {
|
|
|
- // if (this.clickQueueSub) {
|
|
|
- // this.clickQueueSub.unsubscribe();
|
|
|
- // this.clickQueueSub = null;
|
|
|
- // }
|
|
|
- // this.clickQueue.next(req);
|
|
|
- // console.log('walking', this.clickQueueSub, JSON.stringify(req));
|
|
|
- // if (!this.clickQueueSub) {
|
|
|
- // this.clickQueueSub = this.clickQueue.subscribe(async (request) => {
|
|
|
+ async walking(request: MoveRequest) {
|
|
|
+ this.latestWalkingRequest = request;
|
|
|
+ console.log('walking', request);
|
|
|
+ // 进入正常walking流程
|
|
|
+ if (!this.onMoving.getValue()) {
|
|
|
+ this.latestWalkingRequest = null;
|
|
|
+ this.handleWalking(request);
|
|
|
+ }
|
|
|
+ // 监听每小段最后一zhen
|
|
|
+ if (!this.moveSliceLastFrameSub) {
|
|
|
+ this.moveSliceLastFrameSub = this.moveSliceLastFrame.subscribe(
|
|
|
+ async (frame: MovingLastUpdateType) => {
|
|
|
+ //TODO 正在行走时,有新的reqest
|
|
|
+ if (this.latestWalkingRequest && this.onMoving.value) {
|
|
|
+ console.log('中断的小段', frame);
|
|
|
+ // this.moveQueue.complete();
|
|
|
+ // this.moveQueue.of('');
|
|
|
+ // TODO 中断move队列 ?优化如何清空
|
|
|
+ // this.moveQueue.pipe(ignoreElements());
|
|
|
+ this.moveQueueSubscription.unsubscribe();
|
|
|
+ this.moveQueueSubscription = null;
|
|
|
+ //step1 执行stop方法
|
|
|
+ const metaData: StreamReplyType = frame.metaData;
|
|
|
+ const newUserStates: NewUserStatesType =
|
|
|
+ metaData.newUserStates.find(
|
|
|
+ (item) => item.userId === this.user_id,
|
|
|
+ );
|
|
|
+ const trace_id = metaData.traceIds[0];
|
|
|
+ const userId = newUserStates.userId;
|
|
|
+ const breakPointId = metaData.endBreakPointId;
|
|
|
+ const cameraAngle = newUserStates.playerState.camera.angle;
|
|
|
+ const playerAngle = newUserStates.playerState.player.angle;
|
|
|
+ console.log(
|
|
|
+ 'stop-data',
|
|
|
+ trace_id,
|
|
|
+ userId,
|
|
|
+ cameraAngle,
|
|
|
+ cameraAngle,
|
|
|
+ );
|
|
|
+ const redisMeta = await this.moveService.stop(
|
|
|
+ trace_id,
|
|
|
+ userId,
|
|
|
+ breakPointId,
|
|
|
+ cameraAngle,
|
|
|
+ playerAngle,
|
|
|
+ );
|
|
|
+ console.log('stop-redisMeta', redisMeta);
|
|
|
+ // 2. 中断重新walking
|
|
|
+ this.handleReWalking(this.latestWalkingRequest);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if (!this.onMoving.getValue()) {
|
|
|
- const start = performance.now();
|
|
|
- const user = this.moveService.users[this.user_id];
|
|
|
- console.log('进入1 - searchRoad');
|
|
|
- console.log('path-start' + user.breakPointId);
|
|
|
- const path = await this.getRouterService.searchRoad(
|
|
|
- user.appId,
|
|
|
- user.breakPointId,
|
|
|
- req.clicking_action.clicking_point,
|
|
|
- );
|
|
|
- console.log('walking-path', path);
|
|
|
- if (!path) {
|
|
|
- console.log('不存在--path', path);
|
|
|
- this.resumeStream();
|
|
|
- return;
|
|
|
+ /**
|
|
|
+ * 行走队列处理器
|
|
|
+ * @param request MoveRequest
|
|
|
+ * @returns void
|
|
|
+ */
|
|
|
+
|
|
|
+ async handleWalking(request: MoveRequest): Promise<void> {
|
|
|
+ try {
|
|
|
+ // if (!this.onMoving.getValue()) {
|
|
|
+ const start = performance.now();
|
|
|
+ const user = this.moveService.users[this.user_id];
|
|
|
+ console.log('进入1 - searchRoad');
|
|
|
+ console.log('path-start' + user.breakPointId);
|
|
|
+ const path = await this.getRouterService.searchRoad(
|
|
|
+ user.appId,
|
|
|
+ user.breakPointId,
|
|
|
+ request.clicking_action.clicking_point,
|
|
|
+ );
|
|
|
+ console.log('walking-path', path);
|
|
|
+ if (!path) {
|
|
|
+ console.log('不存在--path', path);
|
|
|
+ this.resumeStream();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // debugger;
|
|
|
+ const walkingRes = await this.moveService.move(path, request);
|
|
|
+
|
|
|
+ // console.log('walking', walkingRes);
|
|
|
+ // debugger;
|
|
|
+ if (walkingRes && !this.onMoving.value) {
|
|
|
+ // console.log('walkingRes-front', walkingRes);
|
|
|
+ // shift出前第一个镜头数据
|
|
|
+ const rotateCamData = walkingRes[0];
|
|
|
+ console.log('rotateCamData', rotateCamData.length);
|
|
|
+ if (rotateCamData?.length) {
|
|
|
+ // 头数组[0] rotate 序列, 头是关键key
|
|
|
+ walkingRes[0].forEach((item: StreamReplyType, index: number) => {
|
|
|
+ item.mType = 'rotate';
|
|
|
+ item.DIR = index === 0 ? 1 : 3;
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ console.log('rotateCamData无数据');
|
|
|
}
|
|
|
- // debugger;
|
|
|
- const walkingRes = await this.moveService.move(path, req);
|
|
|
-
|
|
|
- // console.log('walking', walkingRes);
|
|
|
- // debugger;
|
|
|
- if (walkingRes && !this.onMoving.value) {
|
|
|
- // console.log('walkingRes-front', walkingRes);
|
|
|
- // shift出前第一个镜头数据
|
|
|
- const rotateCamData = walkingRes[0];
|
|
|
- console.log('rotateCamData', rotateCamData.length);
|
|
|
- if (rotateCamData?.length) {
|
|
|
- // 头数组[0] rotate 序列, 头是关键key
|
|
|
- walkingRes[0].forEach((item: StreamReplyType, index: number) => {
|
|
|
- item.mType = 'rotate';
|
|
|
- item.DIR = index === 0 ? 1 : 3;
|
|
|
- });
|
|
|
- } else {
|
|
|
- console.log('rotateCamData无数据');
|
|
|
- }
|
|
|
|
|
|
- // 二维数组 做move 序列, move类型
|
|
|
- if (walkingRes?.length >= 1) {
|
|
|
- for (let i = 1; i < walkingRes.length; i++) {
|
|
|
- console.log('walkingRes', walkingRes[i]);
|
|
|
- Array.from(walkingRes[i]).forEach(
|
|
|
- (item: StreamReplyType, index: number) => {
|
|
|
- const dir = this.isHeaderOrLast(
|
|
|
- index,
|
|
|
- walkingRes[i].length - 1,
|
|
|
- );
|
|
|
- item.DIR = dir ? 1 : 3;
|
|
|
- //将每段最后一个推入lastMovingPointArray
|
|
|
- if (index === walkingRes[i].length - 1) {
|
|
|
- this.lastMovingPointArray.push({
|
|
|
- mediaSrc: item.mediaSrc,
|
|
|
- metaData: item,
|
|
|
- });
|
|
|
- }
|
|
|
- },
|
|
|
- );
|
|
|
- }
|
|
|
+ // 二维数组 做move 序列, move类型
|
|
|
+ if (walkingRes && walkingRes?.length >= 1) {
|
|
|
+ for (let i = 1; i < walkingRes.length; i++) {
|
|
|
+ Array.from(walkingRes[i]).forEach(
|
|
|
+ (item: StreamReplyType, index: number) => {
|
|
|
+ const dir = this.isHeaderOrLast(
|
|
|
+ index,
|
|
|
+ walkingRes[i].length - 1,
|
|
|
+ );
|
|
|
+ item.DIR = dir ? 1 : 3;
|
|
|
+ //将每段最后一个推入lastMovingPointArray
|
|
|
+ if (index === walkingRes[i].length - 1) {
|
|
|
+ this.lastMovingPointArray.push({
|
|
|
+ mediaSrc: item.mediaSrc,
|
|
|
+ metaData: item,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ );
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // walkingRes marker to everybody
|
|
|
- const seqs = Array.from(
|
|
|
- walkingRes,
|
|
|
- ).flat() as any as StreamReplyType[];
|
|
|
-
|
|
|
- if (seqs?.length) {
|
|
|
- console.log('walking --总序列--seqs-2', seqs.length);
|
|
|
- const stop = performance.now();
|
|
|
- const inMillSeconds = stop - start;
|
|
|
- const rounded = Number(inMillSeconds).toFixed(3);
|
|
|
- console.log(`[timer]-move-入队列前:-->${rounded}ms`);
|
|
|
-
|
|
|
- this.handleSeqMoving(seqs);
|
|
|
- } else {
|
|
|
- console.error('walking-move无数据');
|
|
|
- this.cleanMoveSteam();
|
|
|
- this.resumeStream();
|
|
|
- }
|
|
|
+ // walkingRes marker to everybody
|
|
|
+ const seqs = Array.from(walkingRes).flat() as any as StreamReplyType[];
|
|
|
+
|
|
|
+ if (seqs?.length) {
|
|
|
+ console.log('walking --总序列--seqs-2', seqs.length);
|
|
|
+ const stop = performance.now();
|
|
|
+ const inMillSeconds = stop - start;
|
|
|
+ const rounded = Number(inMillSeconds).toFixed(3);
|
|
|
+ console.log(`[timer]-move-入队列前:-->${rounded}ms`);
|
|
|
+
|
|
|
+ this.handleSeqMoving(seqs);
|
|
|
+ } else {
|
|
|
+ console.error('walking-move无数据');
|
|
|
+ this.cleanMoveSteam();
|
|
|
+ this.resumeStream();
|
|
|
}
|
|
|
+ // }
|
|
|
}
|
|
|
// });
|
|
|
// }
|
|
@@ -434,67 +488,67 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 改变路线后的walking队列处理(中转)
|
|
|
+ * @param request MoveRequest
|
|
|
+ */
|
|
|
+ handleReWalking(request: MoveRequest) {
|
|
|
+ this.latestWalkingRequest = null;
|
|
|
+ this.handleWalking(request);
|
|
|
+ }
|
|
|
+
|
|
|
+ /***
|
|
|
+ * joystick
|
|
|
+ */
|
|
|
+
|
|
|
async joystick(request: JoystickRequest) {
|
|
|
try {
|
|
|
- this.joystickQueue.next(request);
|
|
|
- if (!this.joystickSub) {
|
|
|
- this.joystickSub = this.joystickQueue.subscribe(
|
|
|
- async (joystickRequest) => {
|
|
|
- const joystickRes = await this.moveService.joystick(
|
|
|
- joystickRequest,
|
|
|
- );
|
|
|
-
|
|
|
- // 有数据 [0]是rotate数据,[1-infinity]是walking数据
|
|
|
- if (Array.isArray(joystickRes)) {
|
|
|
- // shift出前第一个镜头数据
|
|
|
-
|
|
|
- const rotateCamData = joystickRes.shift();
|
|
|
- console.log('rotateCamData', rotateCamData.length);
|
|
|
- if (rotateCamData?.length) {
|
|
|
- // 头数组[0] rotate 序列, 头是关键key
|
|
|
- joystickRes[0].forEach(
|
|
|
- (item: StreamReplyType, index: number) => {
|
|
|
- item.mType = 'rotate';
|
|
|
- item.DIR = index === 0 ? 1 : 3;
|
|
|
- },
|
|
|
+ //const joystickRes = await this.moveService.joystick(request);
|
|
|
+ const joystickRes = await this.moveService.seqExeJoystick(request);
|
|
|
+ // 有数据 [0]是rotate数据,[1-infinity]是walking数据
|
|
|
+ if (Array.isArray(joystickRes)) {
|
|
|
+ // shift出前第一个镜头数据
|
|
|
+
|
|
|
+ const rotateCamData = joystickRes.shift();
|
|
|
+ console.log('rotateCamData', rotateCamData.length);
|
|
|
+ if (rotateCamData?.length) {
|
|
|
+ // 头数组[0] rotate 序列, 头是关键key
|
|
|
+ joystickRes[0].forEach((item: StreamReplyType, index: number) => {
|
|
|
+ item.mType = 'rotate';
|
|
|
+ item.DIR = index === 0 ? 1 : 3;
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ console.log('rotateCamData无数据');
|
|
|
+ }
|
|
|
+ // 二维数组 做move 序列, move类型
|
|
|
+ if (joystickRes?.length >= 1) {
|
|
|
+ for (let i = 1; i < joystickRes.length; i++) {
|
|
|
+ console.log('joystickRes', joystickRes[i]);
|
|
|
+ Array.from(joystickRes[i]).forEach(
|
|
|
+ (item: StreamReplyType, index: number) => {
|
|
|
+ const dir = this.isHeaderOrLast(
|
|
|
+ index,
|
|
|
+ joystickRes[i].length - 1,
|
|
|
);
|
|
|
- } else {
|
|
|
- console.log('rotateCamData无数据');
|
|
|
- }
|
|
|
- // 二维数组 做move 序列, move类型
|
|
|
- if (joystickRes?.length >= 1) {
|
|
|
- for (let i = 1; i < joystickRes.length; i++) {
|
|
|
- console.log('joystickRes', joystickRes[i]);
|
|
|
- Array.from(joystickRes[i]).forEach(
|
|
|
- (item: StreamReplyType, index: number) => {
|
|
|
- const dir = this.isHeaderOrLast(
|
|
|
- index,
|
|
|
- joystickRes[i].length - 1,
|
|
|
- );
|
|
|
- item.DIR = dir ? 1 : 3;
|
|
|
- },
|
|
|
- );
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- const seqs = Array.from(
|
|
|
- joystickRes,
|
|
|
- ).flat() as any as StreamReplyType[];
|
|
|
+ item.DIR = dir ? 1 : 3;
|
|
|
+ },
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const seqs = Array.from(joystickRes).flat() as any as StreamReplyType[];
|
|
|
|
|
|
- if (seqs?.length) {
|
|
|
- console.log('joystickRes-seqs', seqs.length);
|
|
|
- this.handleSeqMoving(seqs);
|
|
|
- } else {
|
|
|
- console.warn('joystick-move无数据');
|
|
|
- }
|
|
|
- } else {
|
|
|
- console.log('转交数据');
|
|
|
- this.streamService.pushNormalDataToStream(request);
|
|
|
- }
|
|
|
- },
|
|
|
- );
|
|
|
+ if (seqs?.length) {
|
|
|
+ console.log('joystickRes-seqs', seqs.length);
|
|
|
+ this.handleSeqMoving(seqs);
|
|
|
+ } else {
|
|
|
+ console.warn('joystick-move无数据');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.log('转交数据');
|
|
|
+ // this.streamService.pushNormalDataToStream(request);
|
|
|
}
|
|
|
} catch (error) {
|
|
|
+ console.error('joystick错误', error);
|
|
|
this.logger.error('joystick', error);
|
|
|
}
|
|
|
}
|
|
@@ -532,7 +586,6 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
|
|
|
cleanMoveSteam() {
|
|
|
if (this.moveQueueSubscription) {
|
|
|
this.moveQueueSubscription.unsubscribe();
|
|
|
- this.lastMoveCnt = -1;
|
|
|
this.moveQueueSubscription = null;
|
|
|
}
|
|
|
if (this.walkingSub) {
|
|
@@ -591,23 +644,14 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
|
|
|
// console.log('path-update', breakPointId);
|
|
|
this.moveService.updateUser(userId, breakPointId, lastReply);
|
|
|
this.lastMovingPointArray.splice(isLastFrameIndex, 1);
|
|
|
+ //TODO 队列每一段最后one frame
|
|
|
+ this.moveSliceLastFrame.next(currentMeta);
|
|
|
}
|
|
|
|
|
|
if (res.done) {
|
|
|
clearTimeout(this._moveTimeout);
|
|
|
this._moveTimeout = setTimeout(() => {
|
|
|
console.log('move 交权给空流,当前pts', res.frame);
|
|
|
- //TODO 每个结束点 updateUser metaData
|
|
|
- // const lastFrame = this.lastMoveStreamFrame.getValue();
|
|
|
- // const lastFrameMeta: StreamReplyType = JSON.parse(
|
|
|
- // lastFrame.metaData,
|
|
|
- // );
|
|
|
-
|
|
|
- // const userId = this.user_id;
|
|
|
- // const breakPointId = lastFrameMeta.endBreakPointId;
|
|
|
- // const lastReply = lastFrameMeta;
|
|
|
- // console.log('path-update', breakPointId);
|
|
|
- // this.moveService.updateUser(userId, breakPointId, lastReply);
|
|
|
this.frameCnt.next(res.frame);
|
|
|
this.resumeStream();
|
|
|
this.rotateframeCnt = -1;
|
|
@@ -655,7 +699,7 @@ export class SceneService implements OnModuleInit, OnModuleDestroy {
|
|
|
const msg: RTCMessageRequest = JSON.parse(message);
|
|
|
switch (msg.action_type) {
|
|
|
case ActionType.walk:
|
|
|
- const walk = msg;
|
|
|
+ const walk = msg as any as MoveRequest;
|
|
|
this.walking(walk);
|
|
|
break;
|
|
|
case ActionType.joystick:
|