|
@@ -1,13 +1,186 @@
|
|
|
import { Injectable } from '@nestjs/common';
|
|
|
import { DataChannel } from 'node-datachannel';
|
|
|
-
|
|
|
+import * as path from 'path';
|
|
|
+import { readFileSync } from 'fs';
|
|
|
+import * as streamBuffers from 'stream-buffers';
|
|
|
@Injectable()
|
|
|
export class StreamService {
|
|
|
private channel: DataChannel;
|
|
|
+ private readonly chunk_size = 16000;
|
|
|
+ private readonly block = 36;
|
|
|
|
|
|
setChannel(channel: DataChannel) {
|
|
|
this.channel = channel;
|
|
|
}
|
|
|
+ closeChannel() {
|
|
|
+ this.channel = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ pushNormalDataToStream(data: any) {
|
|
|
+ const replyBin = JSON.stringify(data).replace(/\s/g, '');
|
|
|
+ const buff = Buffer.from(replyBin, 'utf-8');
|
|
|
+ if (this.channel && this.channel.isOpen()) {
|
|
|
+ this.channel.sendMessageBinary(buff);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
pushFrameToSteam(stream: StreamFrameType) {}
|
|
|
+
|
|
|
+ pushTheFirstFrame() {
|
|
|
+ const chunk_size = 16000;
|
|
|
+ const block = 36;
|
|
|
+ console.log('首屏--数据');
|
|
|
+ const paths = path.join(__dirname, '../ws/video');
|
|
|
+ // const clipPath = paths + `/1.v2.h264`;
|
|
|
+ const testClipPath = paths + `/2.h264`;
|
|
|
+ const metaData = {
|
|
|
+ traceIds: [],
|
|
|
+ vehicle: null,
|
|
|
+ newUserStates: [
|
|
|
+ {
|
|
|
+ userId: '1e3fa84d5c29a',
|
|
|
+ playerState: {
|
|
|
+ roomTypeId: '',
|
|
|
+ person: 0,
|
|
|
+ avatarId: 'KGe_Boy',
|
|
|
+ skinId: '10089',
|
|
|
+ roomId: '',
|
|
|
+ isHost: false,
|
|
|
+ isFollowHost: false,
|
|
|
+ skinDataVersion: '1008900008',
|
|
|
+ avatarComponents: '',
|
|
|
+ nickName: '1e3fa84d5c29a',
|
|
|
+ movingMode: 0,
|
|
|
+ attitude: 'walk',
|
|
|
+ areaName: 'LQC',
|
|
|
+ pathName: 'thirdwalk',
|
|
|
+ pathId: 'thirdwalk',
|
|
|
+ avatarSize: 1,
|
|
|
+ extra: '{"removeWhenDisconnected":true}',
|
|
|
+ prioritySync: false,
|
|
|
+ player: {
|
|
|
+ position: { x: -755, y: -1450, z: -34 },
|
|
|
+ angle: { pitch: 0, yaw: 0, roll: 0 },
|
|
|
+ },
|
|
|
+ camera: {
|
|
|
+ position: { x: -1075, y: -1450, z: 86 },
|
|
|
+ angle: { pitch: 0, yaw: 0, roll: 0 },
|
|
|
+ },
|
|
|
+ cameraCenter: null,
|
|
|
+ },
|
|
|
+ renderInfo: {
|
|
|
+ renderType: 0,
|
|
|
+ videoFrame: null,
|
|
|
+ cameraStateType: 0,
|
|
|
+ isMoving: 0,
|
|
|
+ needIfr: 0,
|
|
|
+ isVideo: 0,
|
|
|
+ stillFrame: 0,
|
|
|
+ isRotating: 0,
|
|
|
+ isFollowing: 0,
|
|
|
+ clientPanoTitlesBitmap: [],
|
|
|
+ clientPanoTreceId: '',
|
|
|
+ prefetchVideoId: '',
|
|
|
+ noMedia: false,
|
|
|
+ },
|
|
|
+ event: {
|
|
|
+ id: '',
|
|
|
+ type: 0,
|
|
|
+ points: [],
|
|
|
+ rotateEvent: null,
|
|
|
+ removeVisitorEvent: null,
|
|
|
+ },
|
|
|
+ relation: 1,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ actionResponses: [],
|
|
|
+ getStateType: 0,
|
|
|
+ code: 0,
|
|
|
+ msg: 'OK',
|
|
|
+ };
|
|
|
+ const metaDataString = JSON.stringify(metaData).replace(/\s/g, '');
|
|
|
+
|
|
|
+ const coordBuff = Buffer.from(metaDataString, 'utf-8');
|
|
|
+
|
|
|
+ console.warn('coordBuff', coordBuff.byteLength);
|
|
|
+
|
|
|
+ // const steamStat = statSync(clipPath);
|
|
|
+
|
|
|
+ // const steamTotalSize = metaData.length + steamStat.size;
|
|
|
+ const clipBuffer = readFileSync(testClipPath);
|
|
|
+ // console.log('clipBuffer', clipBuffer);
|
|
|
+ // const fullBufferList = Buffer.concat([coordBuff, clipBuffer]);
|
|
|
+
|
|
|
+ // const steam = createReadStream(clipPath, {
|
|
|
+ // highWaterMark: chunk_size - block,
|
|
|
+ // });
|
|
|
+
|
|
|
+ // console.log('fullBufferList', fullBufferList);
|
|
|
+
|
|
|
+ // const steam1 = createReadStream(fullBufferList.toString(), {
|
|
|
+ // highWaterMark: chunk_size - block,
|
|
|
+ // });
|
|
|
+ const steam = new streamBuffers.ReadableStreamBuffer({
|
|
|
+ frequency: 1, // in milliseconds.
|
|
|
+ chunkSize: chunk_size - block, // in bytes.
|
|
|
+ });
|
|
|
+ steam.put(coordBuff);
|
|
|
+ steam.put(clipBuffer);
|
|
|
+
|
|
|
+ let steamByteLength = 0;
|
|
|
+
|
|
|
+ steam.on('data', (data: Buffer) => {
|
|
|
+ // console.log('data', data, data.byteLength);
|
|
|
+ // console.log('data-size', data);
|
|
|
+ const blockBuffStart = Buffer.alloc(block);
|
|
|
+
|
|
|
+ const packBuffer = Buffer.concat([blockBuffStart, data]);
|
|
|
+
|
|
|
+ // const isLastFrame = packBuffer.byteLength - chunk_size < 0;
|
|
|
+ // console.log('packBuffer', packBuffer.byteLength);
|
|
|
+ // if (isLastFrame) {
|
|
|
+ // // last frame
|
|
|
+ // packBuffer = Buffer.concat([packBuffer, coordBuff]);
|
|
|
+ // console.log('last frame', packBuffer.byteLength);
|
|
|
+ // }
|
|
|
+
|
|
|
+ const framePack = new DataView(
|
|
|
+ packBuffer.buffer.slice(
|
|
|
+ packBuffer.byteOffset,
|
|
|
+ packBuffer.byteOffset + packBuffer.byteLength,
|
|
|
+ ),
|
|
|
+ );
|
|
|
+
|
|
|
+ // 16 bit slot
|
|
|
+ // framePack.setUint32(4)
|
|
|
+ framePack.setUint16(6, block);
|
|
|
+ framePack.setUint16(8, 1); // first render cnt
|
|
|
+ framePack.setUint16(10, 1); // isDIR
|
|
|
+ framePack.setUint16(24, 0);
|
|
|
+ framePack.setUint16(26, 0);
|
|
|
+
|
|
|
+ // 32 bit slot
|
|
|
+ // statusPack.setUint32(12, buff.byteLength);
|
|
|
+ // console.log('metaLen', coordBuff.byteLength);
|
|
|
+ // console.log('metaLen', clipBuffer.byteLength);
|
|
|
+
|
|
|
+ framePack.setUint32(0, 1437227610);
|
|
|
+ framePack.setUint32(12, coordBuff.byteLength); // metaLen
|
|
|
+ framePack.setUint32(16, clipBuffer.byteLength); // mediaLen
|
|
|
+ framePack.setUint32(20, 754871824); //server_time
|
|
|
+ framePack.setUint32(24, 0);
|
|
|
+ framePack.setUint32(28, 0);
|
|
|
+ framePack.setUint32(block - 4, steamByteLength);
|
|
|
+
|
|
|
+ // console.log('statusPack', statusPack);
|
|
|
+ if (this.channel && this.channel.isOpen()) {
|
|
|
+ this.channel.sendMessageBinary(Buffer.from(framePack.buffer));
|
|
|
+ }
|
|
|
+ steamByteLength += data.byteLength;
|
|
|
+ });
|
|
|
+ steam.on('end', () => {
|
|
|
+ steamByteLength = 0;
|
|
|
+ // this.onSteaming = false;
|
|
|
+ });
|
|
|
+ }
|
|
|
}
|