@myerscarpenter/quest-dev 1.4.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +7 -0
- package/.github/workflows/docs.yml +45 -0
- package/.github/workflows/publish.yml +11 -1
- package/README.md +27 -0
- package/build/cast/decoder.d.ts +48 -0
- package/build/cast/decoder.d.ts.map +1 -0
- package/build/cast/decoder.js +152 -0
- package/build/cast/decoder.js.map +1 -0
- package/build/cast/session.d.ts +87 -0
- package/build/cast/session.d.ts.map +1 -0
- package/build/cast/session.js +565 -0
- package/build/cast/session.js.map +1 -0
- package/build/commands/logcat.d.ts.map +1 -1
- package/build/commands/logcat.js +7 -6
- package/build/commands/logcat.js.map +1 -1
- package/build/commands/screenshot.d.ts.map +1 -1
- package/build/commands/screenshot.js +17 -20
- package/build/commands/screenshot.js.map +1 -1
- package/build/commands/stay-awake.d.ts +2 -15
- package/build/commands/stay-awake.d.ts.map +1 -1
- package/build/commands/stay-awake.js +14 -77
- package/build/commands/stay-awake.js.map +1 -1
- package/build/daemon/cast-manager.d.ts +42 -0
- package/build/daemon/cast-manager.d.ts.map +1 -0
- package/build/daemon/cast-manager.js +243 -0
- package/build/daemon/cast-manager.js.map +1 -0
- package/build/daemon/client.d.ts +40 -0
- package/build/daemon/client.d.ts.map +1 -0
- package/build/daemon/client.js +133 -0
- package/build/daemon/client.js.map +1 -0
- package/build/daemon/daemon.d.ts +20 -0
- package/build/daemon/daemon.d.ts.map +1 -0
- package/build/daemon/daemon.js +130 -0
- package/build/daemon/daemon.js.map +1 -0
- package/build/daemon/deploy.d.ts +44 -0
- package/build/daemon/deploy.d.ts.map +1 -0
- package/build/daemon/deploy.js +230 -0
- package/build/daemon/deploy.js.map +1 -0
- package/build/daemon/logcat-manager.d.ts +39 -0
- package/build/daemon/logcat-manager.d.ts.map +1 -0
- package/build/daemon/logcat-manager.js +194 -0
- package/build/daemon/logcat-manager.js.map +1 -0
- package/build/daemon/server.d.ts +19 -0
- package/build/daemon/server.d.ts.map +1 -0
- package/build/daemon/server.js +482 -0
- package/build/daemon/server.js.map +1 -0
- package/build/daemon/stay-awake-manager.d.ts +22 -0
- package/build/daemon/stay-awake-manager.d.ts.map +1 -0
- package/build/daemon/stay-awake-manager.js +74 -0
- package/build/daemon/stay-awake-manager.js.map +1 -0
- package/build/index.js +272 -45
- package/build/index.js.map +1 -1
- package/build/public/dashboard.js +749 -0
- package/build/public/index.html +12 -0
- package/build/public/style.css +106 -0
- package/build/utils/adb.d.ts +6 -0
- package/build/utils/adb.d.ts.map +1 -1
- package/build/utils/adb.js +62 -66
- package/build/utils/adb.js.map +1 -1
- package/build/utils/casting-apk.d.ts +40 -0
- package/build/utils/casting-apk.d.ts.map +1 -0
- package/build/utils/casting-apk.js +252 -0
- package/build/utils/casting-apk.js.map +1 -0
- package/build/utils/config.d.ts +5 -3
- package/build/utils/config.d.ts.map +1 -1
- package/build/utils/config.js +18 -38
- package/build/utils/config.js.map +1 -1
- package/build/utils/exec.d.ts +5 -0
- package/build/utils/exec.d.ts.map +1 -1
- package/build/utils/exec.js +17 -0
- package/build/utils/exec.js.map +1 -1
- package/build/utils/filename.d.ts +7 -1
- package/build/utils/filename.d.ts.map +1 -1
- package/build/utils/filename.js +17 -2
- package/build/utils/filename.js.map +1 -1
- package/build/utils/filename.test.js +33 -1
- package/build/utils/filename.test.js.map +1 -1
- package/build/utils/jpeg-comment.d.ts +14 -0
- package/build/utils/jpeg-comment.d.ts.map +1 -0
- package/build/utils/jpeg-comment.js +28 -0
- package/build/utils/jpeg-comment.js.map +1 -0
- package/build/utils/test-properties.d.ts +34 -0
- package/build/utils/test-properties.d.ts.map +1 -0
- package/build/utils/test-properties.js +73 -0
- package/build/utils/test-properties.js.map +1 -0
- package/package.json +11 -5
- package/packages/cast2-protocol/README.md +86 -0
- package/packages/cast2-protocol/docs/_config.yml +4 -0
- package/packages/cast2-protocol/docs/feature-flags.md +102 -0
- package/packages/cast2-protocol/docs/index.md +24 -0
- package/packages/cast2-protocol/docs/open-investigations.md +149 -0
- package/packages/cast2-protocol/docs/protocol.md +602 -0
- package/packages/cast2-protocol/package.json +46 -0
- package/packages/cast2-protocol/src/constants.ts +65 -0
- package/packages/cast2-protocol/src/index.ts +7 -0
- package/packages/cast2-protocol/src/mgik.ts +69 -0
- package/packages/cast2-protocol/src/mud.ts +294 -0
- package/packages/cast2-protocol/src/pose.ts +99 -0
- package/packages/cast2-protocol/src/resolutions.ts +34 -0
- package/packages/cast2-protocol/src/types.ts +64 -0
- package/packages/cast2-protocol/src/xrsp.ts +73 -0
- package/packages/cast2-protocol/tests/mgik.test.ts +80 -0
- package/packages/cast2-protocol/tests/mud.test.ts +295 -0
- package/packages/cast2-protocol/tests/pose.test.ts +173 -0
- package/packages/cast2-protocol/tests/xrsp.test.ts +90 -0
- package/packages/cast2-protocol/tsconfig.json +20 -0
- package/pnpm-workspace.yaml +2 -0
- package/src/cast/decoder.ts +178 -0
- package/src/cast/session.ts +708 -0
- package/src/commands/logcat.ts +6 -5
- package/src/commands/screenshot.ts +19 -13
- package/src/commands/stay-awake.ts +22 -91
- package/src/daemon/adbkit-apkreader.d.ts +14 -0
- package/src/daemon/cast-manager.ts +282 -0
- package/src/daemon/client.ts +166 -0
- package/src/daemon/daemon.ts +169 -0
- package/src/daemon/deploy.ts +307 -0
- package/src/daemon/logcat-manager.ts +229 -0
- package/src/daemon/server.ts +595 -0
- package/src/daemon/stay-awake-manager.ts +83 -0
- package/src/index.ts +326 -56
- package/src/public/dashboard.js +288 -0
- package/src/public/index.html +12 -0
- package/src/public/style.css +106 -0
- package/src/utils/adb.ts +70 -57
- package/src/utils/casting-apk.ts +276 -0
- package/src/utils/config.ts +18 -36
- package/src/utils/exec.ts +20 -0
- package/src/utils/filename.test.ts +41 -1
- package/src/utils/filename.ts +18 -2
- package/src/utils/jpeg-comment.ts +30 -0
- package/src/utils/test-properties.ts +94 -0
- package/tests/cast/auto-layer.test.ts +87 -0
- package/tests/cast/decoder.test.ts +82 -0
- package/tests/cast/session-restart.test.ts +107 -0
- package/tests/config.test.ts +17 -22
- package/tests/daemon/api-status.test.ts +82 -0
- package/tests/daemon/cast-manager.test.ts +69 -0
- package/tests/daemon/mjpeg-stream.test.ts +144 -0
- package/tests/daemon/pose-endpoint.test.ts +63 -0
- package/tests/daemon/start-guard.test.ts +77 -0
- package/vitest.config.ts +10 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: Deploy Documentation
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- 'packages/cast2-protocol/docs/**'
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
pages: write
|
|
12
|
+
id-token: write
|
|
13
|
+
|
|
14
|
+
concurrency:
|
|
15
|
+
group: pages
|
|
16
|
+
cancel-in-progress: true
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
build:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- name: Setup Pages
|
|
25
|
+
uses: actions/configure-pages@v5
|
|
26
|
+
|
|
27
|
+
- name: Build with Jekyll
|
|
28
|
+
uses: actions/jekyll-build-pages@v1
|
|
29
|
+
with:
|
|
30
|
+
source: packages/cast2-protocol/docs
|
|
31
|
+
destination: ./_site
|
|
32
|
+
|
|
33
|
+
- name: Upload artifact
|
|
34
|
+
uses: actions/upload-pages-artifact@v3
|
|
35
|
+
|
|
36
|
+
deploy:
|
|
37
|
+
environment:
|
|
38
|
+
name: github-pages
|
|
39
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
needs: build
|
|
42
|
+
steps:
|
|
43
|
+
- name: Deploy to GitHub Pages
|
|
44
|
+
id: deployment
|
|
45
|
+
uses: actions/deploy-pages@v4
|
|
@@ -31,6 +31,9 @@ jobs:
|
|
|
31
31
|
- name: Install dependencies
|
|
32
32
|
run: pnpm install
|
|
33
33
|
|
|
34
|
+
- name: Build workspace packages
|
|
35
|
+
run: pnpm -r run build
|
|
36
|
+
|
|
34
37
|
- name: Run tests
|
|
35
38
|
run: pnpm test
|
|
36
39
|
|
|
@@ -43,4 +46,11 @@ jobs:
|
|
|
43
46
|
- name: Create GitHub Release
|
|
44
47
|
env:
|
|
45
48
|
GH_TOKEN: ${{ github.token }}
|
|
46
|
-
run:
|
|
49
|
+
run: |
|
|
50
|
+
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
|
|
51
|
+
if [ -n "$PREV_TAG" ]; then
|
|
52
|
+
NOTES=$(git log --pretty=format:"- %s" "$PREV_TAG"..HEAD^)
|
|
53
|
+
else
|
|
54
|
+
NOTES="Initial release"
|
|
55
|
+
fi
|
|
56
|
+
gh release create "${{ github.ref_name }}" --notes "$NOTES"
|
package/README.md
CHANGED
|
@@ -23,6 +23,33 @@ npm install -g @myerscarpenter/quest-dev
|
|
|
23
23
|
npm install -g @myerscarpenter/cdp-cli
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
## Casting Setup
|
|
27
|
+
|
|
28
|
+
quest-dev can cast your Quest's screen to your computer. This requires a casting APK that ships inside Meta Quest Developer Hub (MQDH).
|
|
29
|
+
|
|
30
|
+
**One-time setup:**
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
quest-dev setup-cast
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
On macOS, this auto-detects MQDH if it's installed in `/Applications`. Otherwise, download MQDH first and point to it:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# macOS — .app bundle (easiest)
|
|
40
|
+
quest-dev setup-cast "/Applications/Meta Quest Developer Hub.app"
|
|
41
|
+
|
|
42
|
+
# macOS — .dmg download
|
|
43
|
+
quest-dev setup-cast ~/Downloads/MetaQuestDeveloperHub.dmg
|
|
44
|
+
|
|
45
|
+
# Windows/Linux — .exe.zip download (requires 7z)
|
|
46
|
+
quest-dev setup-cast ~/Downloads/Meta-Quest-Developer-Hub.exe.zip
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Download MQDH from: https://developer.oculus.com/meta-quest-developer-hub
|
|
50
|
+
|
|
51
|
+
The APK is extracted once and cached at `~/.local/share/quest-dev/`. When you start casting, it's auto-installed on your Quest if needed.
|
|
52
|
+
|
|
26
53
|
## Usage
|
|
27
54
|
|
|
28
55
|
### Screenshot
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* H.264 to JPEG frame decoder using a persistent ffmpeg subprocess.
|
|
3
|
+
*
|
|
4
|
+
* Spawns ffmpeg with H.264 stdin → MJPEG stdout, extracts individual
|
|
5
|
+
* JPEG frames by scanning for SOI (FF D8) / EOI (FF D9) markers.
|
|
6
|
+
*/
|
|
7
|
+
import { EventEmitter } from "node:events";
|
|
8
|
+
/**
|
|
9
|
+
* Extract complete JPEG frames from a buffer.
|
|
10
|
+
* Returns extracted frames and the remaining unprocessed bytes.
|
|
11
|
+
*/
|
|
12
|
+
export declare function extractJpegFrames(buf: Buffer): {
|
|
13
|
+
frames: Buffer[];
|
|
14
|
+
remainder: Buffer;
|
|
15
|
+
};
|
|
16
|
+
export interface FrameDecoderEvents {
|
|
17
|
+
frame: [jpeg: Buffer];
|
|
18
|
+
error: [err: Error];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Persistent ffmpeg-based H.264 → JPEG decoder.
|
|
22
|
+
*
|
|
23
|
+
* Usage:
|
|
24
|
+
* const decoder = new FrameDecoder();
|
|
25
|
+
* decoder.start();
|
|
26
|
+
* decoder.feed(nalData);
|
|
27
|
+
* const jpeg = decoder.getFrame();
|
|
28
|
+
* decoder.stop();
|
|
29
|
+
*/
|
|
30
|
+
export declare class FrameDecoder extends EventEmitter {
|
|
31
|
+
private proc;
|
|
32
|
+
private latestFrame;
|
|
33
|
+
private readBuffer;
|
|
34
|
+
private running;
|
|
35
|
+
/** Check that ffmpeg is available on PATH. */
|
|
36
|
+
static checkFfmpeg(): void;
|
|
37
|
+
/** Start the persistent ffmpeg decoder process. */
|
|
38
|
+
start(): void;
|
|
39
|
+
/** Feed H.264 NAL data to the decoder. */
|
|
40
|
+
feed(nalData: Buffer): void;
|
|
41
|
+
/** Get the latest decoded JPEG frame, or null if none available. */
|
|
42
|
+
getFrame(): Buffer | null;
|
|
43
|
+
/** Stop the decoder and kill the ffmpeg process. */
|
|
44
|
+
stop(): void;
|
|
45
|
+
/** Whether the decoder is currently running. */
|
|
46
|
+
get isRunning(): boolean;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=decoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decoder.d.ts","sourceRoot":"","sources":["../../src/cast/decoder.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAS3C;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG;IAC9C,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAkCA;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtB,KAAK,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,IAAI,CAA6B;IACzC,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,OAAO,CAAS;IAExB,8CAA8C;IAC9C,MAAM,CAAC,WAAW,IAAI,IAAI;IAU1B,mDAAmD;IACnD,KAAK,IAAI,IAAI;IA2Cb,0CAA0C;IAC1C,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAgB3B,oEAAoE;IACpE,QAAQ,IAAI,MAAM,GAAG,IAAI;IAIzB,oDAAoD;IACpD,IAAI,IAAI,IAAI;IAcZ,gDAAgD;IAChD,IAAI,SAAS,IAAI,OAAO,CAEvB;CACF"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* H.264 to JPEG frame decoder using a persistent ffmpeg subprocess.
|
|
3
|
+
*
|
|
4
|
+
* Spawns ffmpeg with H.264 stdin → MJPEG stdout, extracts individual
|
|
5
|
+
* JPEG frames by scanning for SOI (FF D8) / EOI (FF D9) markers.
|
|
6
|
+
*/
|
|
7
|
+
import { spawn } from "node:child_process";
|
|
8
|
+
import { EventEmitter } from "node:events";
|
|
9
|
+
import which from "which";
|
|
10
|
+
import { verbose } from "../utils/verbose.js";
|
|
11
|
+
// JPEG markers
|
|
12
|
+
const JPEG_SOI = 0xffd8;
|
|
13
|
+
const JPEG_EOI_0 = 0xff;
|
|
14
|
+
const JPEG_EOI_1 = 0xd9;
|
|
15
|
+
/**
|
|
16
|
+
* Extract complete JPEG frames from a buffer.
|
|
17
|
+
* Returns extracted frames and the remaining unprocessed bytes.
|
|
18
|
+
*/
|
|
19
|
+
export function extractJpegFrames(buf) {
|
|
20
|
+
const frames = [];
|
|
21
|
+
let data = buf;
|
|
22
|
+
while (true) {
|
|
23
|
+
// Find SOI marker (FF D8)
|
|
24
|
+
let start = -1;
|
|
25
|
+
for (let i = 0; i < data.length - 1; i++) {
|
|
26
|
+
if (data[i] === 0xff && data[i + 1] === 0xd8) {
|
|
27
|
+
start = i;
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (start < 0) {
|
|
32
|
+
// No SOI found — discard everything
|
|
33
|
+
return { frames, remainder: Buffer.alloc(0) };
|
|
34
|
+
}
|
|
35
|
+
// Find EOI marker (FF D9) after SOI
|
|
36
|
+
let end = -1;
|
|
37
|
+
for (let i = start + 2; i < data.length - 1; i++) {
|
|
38
|
+
if (data[i] === JPEG_EOI_0 && data[i + 1] === JPEG_EOI_1) {
|
|
39
|
+
end = i + 2; // include both EOI bytes
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (end < 0) {
|
|
44
|
+
// Incomplete frame — keep from SOI onward
|
|
45
|
+
return { frames, remainder: data.subarray(start) };
|
|
46
|
+
}
|
|
47
|
+
frames.push(Buffer.from(data.subarray(start, end)));
|
|
48
|
+
data = data.subarray(end);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Persistent ffmpeg-based H.264 → JPEG decoder.
|
|
53
|
+
*
|
|
54
|
+
* Usage:
|
|
55
|
+
* const decoder = new FrameDecoder();
|
|
56
|
+
* decoder.start();
|
|
57
|
+
* decoder.feed(nalData);
|
|
58
|
+
* const jpeg = decoder.getFrame();
|
|
59
|
+
* decoder.stop();
|
|
60
|
+
*/
|
|
61
|
+
export class FrameDecoder extends EventEmitter {
|
|
62
|
+
proc = null;
|
|
63
|
+
latestFrame = null;
|
|
64
|
+
readBuffer = Buffer.alloc(0);
|
|
65
|
+
running = false;
|
|
66
|
+
/** Check that ffmpeg is available on PATH. */
|
|
67
|
+
static checkFfmpeg() {
|
|
68
|
+
try {
|
|
69
|
+
which.sync("ffmpeg");
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
throw new Error("ffmpeg not found on PATH. Install ffmpeg to enable video decoding.");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** Start the persistent ffmpeg decoder process. */
|
|
76
|
+
start() {
|
|
77
|
+
if (this.running)
|
|
78
|
+
return;
|
|
79
|
+
this.running = true;
|
|
80
|
+
this.readBuffer = Buffer.alloc(0);
|
|
81
|
+
this.proc = spawn("ffmpeg", [
|
|
82
|
+
"-loglevel", "error",
|
|
83
|
+
"-f", "h264", "-i", "pipe:0",
|
|
84
|
+
"-q:v", "3",
|
|
85
|
+
"-f", "image2pipe", "-vcodec", "mjpeg", "pipe:1",
|
|
86
|
+
], { stdio: ["pipe", "pipe", "pipe"] });
|
|
87
|
+
this.proc.stdout.on("data", (chunk) => {
|
|
88
|
+
this.readBuffer = Buffer.concat([this.readBuffer, chunk]);
|
|
89
|
+
const { frames, remainder } = extractJpegFrames(this.readBuffer);
|
|
90
|
+
this.readBuffer = remainder;
|
|
91
|
+
if (frames.length > 0) {
|
|
92
|
+
this.latestFrame = frames[frames.length - 1];
|
|
93
|
+
this.emit("frame", this.latestFrame);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
this.proc.stderr.on("data", (chunk) => {
|
|
97
|
+
verbose("ffmpeg stderr:", chunk.toString().trim());
|
|
98
|
+
});
|
|
99
|
+
this.proc.on("exit", (code) => {
|
|
100
|
+
verbose("ffmpeg decoder exited with code", code);
|
|
101
|
+
this.running = false;
|
|
102
|
+
});
|
|
103
|
+
this.proc.on("error", (err) => {
|
|
104
|
+
this.emit("error", err);
|
|
105
|
+
this.running = false;
|
|
106
|
+
});
|
|
107
|
+
verbose("Started persistent ffmpeg decoder");
|
|
108
|
+
}
|
|
109
|
+
/** Feed H.264 NAL data to the decoder. */
|
|
110
|
+
feed(nalData) {
|
|
111
|
+
if (!this.proc?.stdin?.writable)
|
|
112
|
+
return;
|
|
113
|
+
try {
|
|
114
|
+
this.proc.stdin.write(nalData);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
verbose("Decoder pipe broken, restarting...");
|
|
118
|
+
this.stop();
|
|
119
|
+
this.start();
|
|
120
|
+
try {
|
|
121
|
+
this.proc?.stdin?.write(nalData);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Give up on this NAL
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/** Get the latest decoded JPEG frame, or null if none available. */
|
|
129
|
+
getFrame() {
|
|
130
|
+
return this.latestFrame;
|
|
131
|
+
}
|
|
132
|
+
/** Stop the decoder and kill the ffmpeg process. */
|
|
133
|
+
stop() {
|
|
134
|
+
this.running = false;
|
|
135
|
+
if (this.proc) {
|
|
136
|
+
try {
|
|
137
|
+
this.proc.stdin?.end();
|
|
138
|
+
this.proc.kill();
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// Already dead
|
|
142
|
+
}
|
|
143
|
+
this.proc = null;
|
|
144
|
+
}
|
|
145
|
+
this.readBuffer = Buffer.alloc(0);
|
|
146
|
+
}
|
|
147
|
+
/** Whether the decoder is currently running. */
|
|
148
|
+
get isRunning() {
|
|
149
|
+
return this.running;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=decoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decoder.js","sourceRoot":"","sources":["../../src/cast/decoder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CastSession: manages TCP connections to Quest, protocol handshake,
|
|
3
|
+
* H.264 video decoding, pose control, and stay-awake lifecycle.
|
|
4
|
+
*/
|
|
5
|
+
import { EventEmitter } from "node:events";
|
|
6
|
+
import { type LayerInfo, type PoseOffset, type PoseDelta, type PoseState } from "@myerscarpenter/cast2-protocol";
|
|
7
|
+
export interface CastSessionOptions {
|
|
8
|
+
listenPort?: number;
|
|
9
|
+
width?: number;
|
|
10
|
+
height?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare class CastSession extends EventEmitter {
|
|
13
|
+
private _listenPort;
|
|
14
|
+
private _connected;
|
|
15
|
+
private _running;
|
|
16
|
+
private server;
|
|
17
|
+
private controlSocket;
|
|
18
|
+
private videoSocket;
|
|
19
|
+
private controlSeq;
|
|
20
|
+
private subMagic;
|
|
21
|
+
private controlMsgSeq;
|
|
22
|
+
private sessionUuid;
|
|
23
|
+
private sessionTimestamp;
|
|
24
|
+
private questMsgSeq;
|
|
25
|
+
private decoder;
|
|
26
|
+
private currentSpsPps;
|
|
27
|
+
private currentIdr;
|
|
28
|
+
private _frameCount;
|
|
29
|
+
private _byteCount;
|
|
30
|
+
private startTime;
|
|
31
|
+
private _width;
|
|
32
|
+
private _height;
|
|
33
|
+
private _pose;
|
|
34
|
+
private _poseLoopTimer;
|
|
35
|
+
private _poseLoopActive;
|
|
36
|
+
private _eye;
|
|
37
|
+
private inputForwardingStarted;
|
|
38
|
+
private _layerId;
|
|
39
|
+
private _layerAutoSelected;
|
|
40
|
+
private _layers;
|
|
41
|
+
constructor(options?: CastSessionOptions);
|
|
42
|
+
get listenPort(): number;
|
|
43
|
+
get connected(): boolean;
|
|
44
|
+
get running(): boolean;
|
|
45
|
+
get frameCount(): number;
|
|
46
|
+
get byteCount(): number;
|
|
47
|
+
get width(): number;
|
|
48
|
+
get height(): number;
|
|
49
|
+
get pose(): PoseState;
|
|
50
|
+
get layers(): Map<number, LayerInfo>;
|
|
51
|
+
get layerId(): number;
|
|
52
|
+
get poseLoopActive(): boolean;
|
|
53
|
+
get eye(): number;
|
|
54
|
+
get elapsedSeconds(): number;
|
|
55
|
+
get fps(): number;
|
|
56
|
+
/** Bind the TCP server, trying successive ports on EADDRINUSE. */
|
|
57
|
+
bind(): Promise<void>;
|
|
58
|
+
private tryBind;
|
|
59
|
+
start(questIp?: string): Promise<void>;
|
|
60
|
+
stop(): Promise<void>;
|
|
61
|
+
restart(): Promise<void>;
|
|
62
|
+
adbSetup(questIp: string): Promise<void>;
|
|
63
|
+
startCastService(questIp: string): Promise<void>;
|
|
64
|
+
private waitForConnections;
|
|
65
|
+
private sendXrsp;
|
|
66
|
+
private nextSeq;
|
|
67
|
+
private handleVideo;
|
|
68
|
+
private processVideoPayload;
|
|
69
|
+
getScreenshot(): Buffer | null;
|
|
70
|
+
sendPose(pose: PoseState): void;
|
|
71
|
+
applyPoseDelta(delta: PoseDelta): void;
|
|
72
|
+
setPoseOffset(abs: PoseOffset): void;
|
|
73
|
+
/** Start periodic pose refresh at ~27 Hz (matching MQDH cadence). */
|
|
74
|
+
startPoseLoop(): void;
|
|
75
|
+
/** Stop periodic pose refresh. */
|
|
76
|
+
stopPoseLoop(): void;
|
|
77
|
+
sendDisplayConfig(width: number, height: number, eye?: number): void;
|
|
78
|
+
sendClick(x?: number, y?: number, layerId?: number, holdMs?: number): Promise<void>;
|
|
79
|
+
ensureInputForwarding(): void;
|
|
80
|
+
sendInputForwardingState(state: number): void;
|
|
81
|
+
resetView(): void;
|
|
82
|
+
sendSetProperty(name: string, value: string): void;
|
|
83
|
+
sendMud(typeId: number, payload?: Buffer): void;
|
|
84
|
+
sendRotation(pitch?: number, yaw?: number, forward?: number, strafe?: number): void;
|
|
85
|
+
private autoSelectLayer;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/cast/session.ts"],"names":[],"mappings":"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"}
|