@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,602 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Cast 2.0 Protocol Reference
|
|
3
|
+
layout: default
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cast 2.0 Protocol Reference
|
|
7
|
+
|
|
8
|
+
Cast 2.0 (codename "Magic Island") is a compositor-level VR streaming protocol
|
|
9
|
+
used by Meta Quest headsets. It streams live H.264 video from the headset to a
|
|
10
|
+
desktop host, with support for remote pose injection, resolution control, and
|
|
11
|
+
input forwarding.
|
|
12
|
+
|
|
13
|
+
## Architecture
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
+------------------+ ADB/TCP +---------------------+
|
|
17
|
+
| Desktop Client | <------ XRSP -------> | Quest Headset |
|
|
18
|
+
| (quest-dev) | MGIK messages | (Casting Service) |
|
|
19
|
+
+------------------+ +---------------------+
|
|
20
|
+
| |
|
|
21
|
+
H.264 decoder OpenXR Capture Layer
|
|
22
|
+
+ Web dashboard + H.264 HW Encoder
|
|
23
|
+
+ Pose controller + XRSP Participant
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Protocol Stack
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
┌─────────────────────────────┐
|
|
30
|
+
│ MUD Messages │ Application layer
|
|
31
|
+
├─────────────────────────────┤
|
|
32
|
+
│ MGIK Sub-Header (24B) │ Session framing
|
|
33
|
+
├─────────────────────────────┤
|
|
34
|
+
│ MGIK Header (8B) │ Quest → Desktop only
|
|
35
|
+
├─────────────────────────────┤
|
|
36
|
+
│ XRSP Packet (8B header) │ Transport framing
|
|
37
|
+
├─────────────────────────────┤
|
|
38
|
+
│ TCP │ Reliable delivery
|
|
39
|
+
└─────────────────────────────┘
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## TCP Connections
|
|
43
|
+
|
|
44
|
+
Cast 2.0 uses two unidirectional TCP connections, both initiated by the Quest
|
|
45
|
+
to the desktop on port 4445:
|
|
46
|
+
|
|
47
|
+
| Connection | Direction | Carries | MGIK header? |
|
|
48
|
+
|---|---|---|---|
|
|
49
|
+
| Control (first SYN, lower source port) | Desktop → Quest | MUD commands | No |
|
|
50
|
+
| Video (second SYN, higher source port) | Quest → Desktop | Video, LayerConfig, ACKs | Yes |
|
|
51
|
+
|
|
52
|
+
The control connection can be identified because it does **not** carry MGIK
|
|
53
|
+
headers. The video connection can be identified by the TRANSPORT string sent
|
|
54
|
+
as its first message.
|
|
55
|
+
|
|
56
|
+
### TRANSPORT String
|
|
57
|
+
|
|
58
|
+
The first message on the video connection is a TRANSPORT identification string:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
0 1 2 3
|
|
62
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
63
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
64
|
+
| 0x00000001 |
|
|
65
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
66
|
+
| type (BE u32) |
|
|
67
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
68
|
+
| string length (BE u32) |
|
|
69
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
70
|
+
| ASCII string data ... |
|
|
71
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Example: `"tcpclient,localhost,4445"`
|
|
75
|
+
|
|
76
|
+
## XRSP Packet Format
|
|
77
|
+
|
|
78
|
+
Each XRSP packet consists of an 8-byte little-endian header followed by
|
|
79
|
+
a payload padded to 4-byte alignment.
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
0 1 2 3
|
|
83
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
84
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
85
|
+
| flags | topic_id | word_count (LE u16) |
|
|
86
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
87
|
+
| sequence_number (LE u16) | padding (LE u16) |
|
|
88
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
89
|
+
| |
|
|
90
|
+
| payload (variable) |
|
|
91
|
+
| |
|
|
92
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
- **flags**: `0x10` = standard, `0x18` = has alignment padding
|
|
96
|
+
- **topic_id**: always `2` for Cast 2.0
|
|
97
|
+
- **word_count**: total packet size = `word_count × 4` bytes
|
|
98
|
+
- **payload size**: `(word_count - 1) × 4` bytes
|
|
99
|
+
|
|
100
|
+
Cast 2.0 uses only topic 2 (Command) for all traffic — both video and control
|
|
101
|
+
flow through the same topic. This is simpler than Quest Link, which uses 34+
|
|
102
|
+
topics with Cap'n Proto serialization.
|
|
103
|
+
|
|
104
|
+
## MGIK Header (8 bytes, Quest → Desktop only)
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
0 1 2 3
|
|
108
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
109
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
110
|
+
| 'M' | 'G' | 'I' | 'K' |
|
|
111
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
112
|
+
| version | reserved |
|
|
113
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
- **magic**: `0x4D47494B` ("MGIK" as big-endian u32)
|
|
117
|
+
- **version**: `0x02` = control message, `0x03` = video data
|
|
118
|
+
|
|
119
|
+
The desktop does **not** send MGIK headers — only the sub-header + payload.
|
|
120
|
+
|
|
121
|
+
## MGIK Sub-Header (24 bytes, both directions)
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
0 1 2 3
|
|
125
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
126
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
127
|
+
| appId (BE u32) |
|
|
128
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
129
|
+
| datagramId (BE u32) |
|
|
130
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
131
|
+
| messageId (BE u32) |
|
|
132
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
133
|
+
| partIndex (BE u32) |
|
|
134
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
135
|
+
| partCount (BE u32) |
|
|
136
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
137
|
+
| qos (BE u32) |
|
|
138
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
- **appId**: session-specific magic, learned from the Quest's first message, echoed in all replies
|
|
142
|
+
- **datagramId**: monotonic per-datagram sequence number
|
|
143
|
+
- **messageId**: monotonic per-message sequence number
|
|
144
|
+
- **partIndex**: fragment index (`0` for unfragmented messages)
|
|
145
|
+
- **partCount**: total fragment count (`1` for unfragmented messages)
|
|
146
|
+
- **qos**: always `2` (HIGH)
|
|
147
|
+
|
|
148
|
+
For unfragmented messages (the common case), the last 12 bytes are always
|
|
149
|
+
`0x00000000 0x00000001 0x00000002`.
|
|
150
|
+
|
|
151
|
+
## Cast Session Handshake
|
|
152
|
+
|
|
153
|
+
After the TCP connections are established, the MGIK-level handshake follows
|
|
154
|
+
this sequence:
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
Quest Desktop
|
|
158
|
+
| |
|
|
159
|
+
|--- TRANSPORT string (video) ----->| identifies video connection
|
|
160
|
+
|--- Sub-header (control) --------->| desktop learns appId
|
|
161
|
+
| |
|
|
162
|
+
|<-- INIT (×4) --------------------| cmd 0x258, 16 zero bytes
|
|
163
|
+
|<-- START_CAST --------------------| cmd 0x07, width/height/UUID/timestamp
|
|
164
|
+
|<-- CONFIRM (×1) -----------------| cmd 0x12D
|
|
165
|
+
|<-- READY (×1) -------------------| cmd 0x65
|
|
166
|
+
| |
|
|
167
|
+
|--- LayerConfig ------------------>| reports layer info (type, resolution)
|
|
168
|
+
|--- VideoMeta + H.264 NAL ------->| video frames begin flowing
|
|
169
|
+
| |
|
|
170
|
+
|<-- KEEPALIVE ---------------------| cmd 0x04, periodic
|
|
171
|
+
|<-- POSE --------------------------| cmd 0xCE, continuous
|
|
172
|
+
|--- ACK --------------------------->| cumulative acknowledgment
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### CONFIRM Rules
|
|
176
|
+
|
|
177
|
+
CONFIRM messages (cmd 0x12D) follow specific rules:
|
|
178
|
+
|
|
179
|
+
- **1×** after START_CAST (always, initial stream setup)
|
|
180
|
+
- **2×** after a RES_CHANGE that changes width or height (encoder reallocation)
|
|
181
|
+
- **0×** after a RES_CHANGE that only changes eye selection (same dimensions)
|
|
182
|
+
|
|
183
|
+
## MUD Message Types
|
|
184
|
+
|
|
185
|
+
MUD ("Messages Under Delivery") is the application-level message layer carried
|
|
186
|
+
inside MGIK framing.
|
|
187
|
+
|
|
188
|
+
### Quest → Desktop
|
|
189
|
+
|
|
190
|
+
| Message | Purpose |
|
|
191
|
+
|---|---|
|
|
192
|
+
| Config | Layer configuration (resolution, serial, APK name) |
|
|
193
|
+
| VideoSegment | H.264 NAL units (main payload) |
|
|
194
|
+
| AudioSegment | Audio data (48kHz stereo PCM) |
|
|
195
|
+
| ACK | Cumulative acknowledgment |
|
|
196
|
+
| Ping | Latency measurement |
|
|
197
|
+
| AppStateChange | App state transitions |
|
|
198
|
+
| MediaAvailable | Media readiness notification |
|
|
199
|
+
| StopCasting | Quest-initiated stop |
|
|
200
|
+
| DestroyLayer | Layer teardown |
|
|
201
|
+
|
|
202
|
+
### Desktop → Quest
|
|
203
|
+
|
|
204
|
+
| Message | Purpose |
|
|
205
|
+
|---|---|
|
|
206
|
+
| INIT | Session initialization |
|
|
207
|
+
| StartCasting | Begin casting (resolution, bitrate, fps) |
|
|
208
|
+
| StopCasting | End casting |
|
|
209
|
+
| UpdateCastingConfig | Change resolution/bitrate at runtime |
|
|
210
|
+
| Pose | 6DoF virtual camera position and orientation |
|
|
211
|
+
| RES_CHANGE | Resolution and eye selection |
|
|
212
|
+
| CONFIRM | Acknowledge stream setup |
|
|
213
|
+
| KEEPALIVE | Session keepalive |
|
|
214
|
+
| SetProperty | Key-value configuration |
|
|
215
|
+
| SetDeviceEyeFov | FOV parameters |
|
|
216
|
+
| Screenshot | Request screenshot |
|
|
217
|
+
| AudioState | Enable/disable audio |
|
|
218
|
+
| InputForwardingState | Enable/disable input forwarding |
|
|
219
|
+
| StartInputForwarding | Begin input forwarding |
|
|
220
|
+
| VirtualMouse | Mouse cursor position/clicks |
|
|
221
|
+
| ActivateLayer | Select active layer |
|
|
222
|
+
|
|
223
|
+
## Desktop → Quest Wire Formats
|
|
224
|
+
|
|
225
|
+
All Desktop → Quest messages are framed as:
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
0 1 2 3
|
|
229
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
230
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
231
|
+
| |
|
|
232
|
+
| MGIK Sub-Header (24 bytes) |
|
|
233
|
+
| |
|
|
234
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
235
|
+
| command ID (BE u32) |
|
|
236
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
237
|
+
| |
|
|
238
|
+
| command payload (variable) |
|
|
239
|
+
| |
|
|
240
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### INIT (cmd 0x258)
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
247
|
+
| 0x00000258 (INIT) |
|
|
248
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
249
|
+
| |
|
|
250
|
+
| 16 zero bytes |
|
|
251
|
+
| |
|
|
252
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Sent 4 times during handshake.
|
|
256
|
+
|
|
257
|
+
### START_CAST (cmd 0x07)
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
261
|
+
| 0x00000007 (START_CAST) |
|
|
262
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
263
|
+
| width (BE u32) |
|
|
264
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
265
|
+
| height (BE u32) |
|
|
266
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
267
|
+
| 0x00000000 |
|
|
268
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
269
|
+
| 0x00000001 |
|
|
270
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
271
|
+
| 0x00000000 |
|
|
272
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
273
|
+
| 0x00000000 |
|
|
274
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
275
|
+
| UUID (MUD string) |
|
|
276
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
277
|
+
| timestamp (MUD string) |
|
|
278
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### KEEPALIVE (cmd 0x04)
|
|
282
|
+
|
|
283
|
+
```
|
|
284
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
285
|
+
| 0x00000004 (KEEPALIVE) |
|
|
286
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
287
|
+
| ack_value (BE u32) |
|
|
288
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
289
|
+
| UUID (MUD string) |
|
|
290
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
291
|
+
| timestamp (MUD string) |
|
|
292
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
`ack_value` starts at `0xC8` (200) and increments by `0xC8` each keepalive.
|
|
296
|
+
|
|
297
|
+
### RES_CHANGE (cmd 0x09)
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
301
|
+
| 0x00000009 (RES_CHANGE) |
|
|
302
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
303
|
+
| width (BE u32) |
|
|
304
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
305
|
+
| height (BE u32) |
|
|
306
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
307
|
+
| 0x00000000 |
|
|
308
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
309
|
+
| eye selector (BE u32) |
|
|
310
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
311
|
+
| 0x00000000 |
|
|
312
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
313
|
+
| 0x00000000 |
|
|
314
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Eye selector: `0` = right, `1` = left (default), `2` = stereo (side-by-side).
|
|
318
|
+
|
|
319
|
+
### POSE (cmd 0xCE)
|
|
320
|
+
|
|
321
|
+
```
|
|
322
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
323
|
+
| 0x000000CE (POSE) |
|
|
324
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
325
|
+
| type (i32) — 0=VIRTUAL_CAMERA |
|
|
326
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
327
|
+
| posX (BE f32) |
|
|
328
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
329
|
+
| posY (BE f32) |
|
|
330
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
331
|
+
| posZ (BE f32) |
|
|
332
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
333
|
+
| qW (BE f32) |
|
|
334
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
335
|
+
| qX (BE f32) |
|
|
336
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
337
|
+
| qY (BE f32) |
|
|
338
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
339
|
+
| qZ (BE f32) |
|
|
340
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Coordinates follow OpenXR convention: +X=right, +Y=up, -Z=forward. Position
|
|
344
|
+
is relative to the headset's position when casting started (not world space).
|
|
345
|
+
|
|
346
|
+
The desktop sends pose continuously; the Quest does not report pose back.
|
|
347
|
+
|
|
348
|
+
### SET_PROPERTY (cmd 0x0A)
|
|
349
|
+
|
|
350
|
+
```
|
|
351
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
352
|
+
| 0x0000000A (SET_PROPERTY) |
|
|
353
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
354
|
+
| key (MUD string) |
|
|
355
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
356
|
+
| value (MUD string) |
|
|
357
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### VIRTUAL_MOUSE (cmd 0xC8)
|
|
361
|
+
|
|
362
|
+
```
|
|
363
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
364
|
+
| 0x000000C8 (VIRTUAL_MOUSE) |
|
|
365
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
366
|
+
| layerId (BE u32) |
|
|
367
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
368
|
+
| action (BE u32) |
|
|
369
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
370
|
+
| x (BE f32) |
|
|
371
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
372
|
+
| y (BE f32) |
|
|
373
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Mouse actions: `1` = move, `3` = button down, `4` = button up.
|
|
377
|
+
|
|
378
|
+
### Simple Commands
|
|
379
|
+
|
|
380
|
+
| cmd | Name | Payload |
|
|
381
|
+
|-----|------|---------|
|
|
382
|
+
| 0x65 (101) | READY | u32(0) |
|
|
383
|
+
| 0x08 (8) | STOP | (empty) |
|
|
384
|
+
| 0xCD (205) | INPUT_FWD_STATE | u32(state) — 0=normal, 1=camera |
|
|
385
|
+
| 0xCF (207) | START_INPUT_FWD | (empty) |
|
|
386
|
+
| 0x12D (301) | CONFIRM / ACTIVATE_LAYER | u32(0) or u32(layerId) |
|
|
387
|
+
| 0x130 (304) | SCREENSHOT | u32(0) + u32(type) — 1=composite, 2=raw |
|
|
388
|
+
|
|
389
|
+
## Quest → Desktop Wire Formats
|
|
390
|
+
|
|
391
|
+
### ACK
|
|
392
|
+
|
|
393
|
+
Quest ACKs are bare 8-byte messages with **no** MGIK header and **no** sub-header:
|
|
394
|
+
|
|
395
|
+
```
|
|
396
|
+
0 1 2 3
|
|
397
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
398
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
399
|
+
| 0x00000003 (ACK) |
|
|
400
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
401
|
+
| cumulative_ack_counter (BE u32) |
|
|
402
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
ACKs are infrequent (~1 per 13 seconds) and cumulative.
|
|
406
|
+
|
|
407
|
+
### LayerConfig (cmd 0x12C)
|
|
408
|
+
|
|
409
|
+
```
|
|
410
|
+
0 1 2 3
|
|
411
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
412
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
413
|
+
| 0x0000012C (LAYER_CONFIG) |
|
|
414
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
415
|
+
| layer id (BE u32) |
|
|
416
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
417
|
+
| width (BE u32) |
|
|
418
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
419
|
+
| height (BE u32) |
|
|
420
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
421
|
+
| posX (BE f32) |
|
|
422
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
423
|
+
| posY (BE f32) |
|
|
424
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
425
|
+
| depth (BE f32) |
|
|
426
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
427
|
+
| layer type (BE u32) |
|
|
428
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
429
|
+
| app name (MUD string) |
|
|
430
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
431
|
+
| layer name (MUD string) |
|
|
432
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
433
|
+
| device serial (MUD string) |
|
|
434
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
435
|
+
| package name (MUD string) |
|
|
436
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Layer types: `0` = PANEL_APP, `1` = EYE_BUFFER, `2` = AETHER_APP, `3` = VOLUMETRIC_WINDOW
|
|
440
|
+
|
|
441
|
+
### VideoMeta + H.264 NAL
|
|
442
|
+
|
|
443
|
+
Each video frame on the wire is:
|
|
444
|
+
|
|
445
|
+
```
|
|
446
|
+
MGIK header (8B) + sub-header (24B) + VideoMeta (16B) + H.264 NAL data
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
```
|
|
450
|
+
0 1 2 3
|
|
451
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
452
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
453
|
+
| 0x00000064 (VIDEO_META) |
|
|
454
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
455
|
+
| chunk_type (BE u32) |
|
|
456
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
457
|
+
| frame_index (BE u32) |
|
|
458
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
459
|
+
| reserved |
|
|
460
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
461
|
+
| |
|
|
462
|
+
| H.264 NAL data (Annex B format) |
|
|
463
|
+
| 0x00000001 start codes |
|
|
464
|
+
| |
|
|
465
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
Chunk types: `1` = SPS/PPS, `2` = IDR (keyframe), `3` = P-frame
|
|
469
|
+
|
|
470
|
+
## MUD String Encoding
|
|
471
|
+
|
|
472
|
+
Strings in MUD messages use a length-prefixed encoding with 4-byte alignment:
|
|
473
|
+
|
|
474
|
+
```
|
|
475
|
+
0 1 2 3
|
|
476
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
477
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
478
|
+
| byte length (BE u32) |
|
|
479
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
480
|
+
| |
|
|
481
|
+
| UTF-8 string data |
|
|
482
|
+
| |
|
|
483
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
484
|
+
| padding (0-3 zero bytes to align) |
|
|
485
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
## Video Stream
|
|
489
|
+
|
|
490
|
+
The Quest sends H.264 video with these characteristics:
|
|
491
|
+
|
|
492
|
+
- **Profile**: High, Level 5.0
|
|
493
|
+
- **Pixel format**: YUV420P, BT.709 color space
|
|
494
|
+
- **NAL format**: Annex B (0x00000001 start codes)
|
|
495
|
+
- **Frame types**: SPS/PPS, IDR (keyframes), P-frames
|
|
496
|
+
- **Default resolution**: 2064×1162 (16:9 mono)
|
|
497
|
+
- **Default bitrate**: 40 Mbps
|
|
498
|
+
|
|
499
|
+
### Eye View
|
|
500
|
+
|
|
501
|
+
Eye selection is controlled via RES_CHANGE (cmd 0x09):
|
|
502
|
+
|
|
503
|
+
| Eye | Value | Resolution | Layout |
|
|
504
|
+
|---|---|---|---|
|
|
505
|
+
| Right | 0 | 2064×2208 or 2064×1162 | Single eye |
|
|
506
|
+
| Left (default) | 1 | 2064×2208 or 2064×1162 | Single eye |
|
|
507
|
+
| Stereo | 2 | 4128×2208 | Both eyes side-by-side |
|
|
508
|
+
|
|
509
|
+
START_CAST does not include the eye field — initial eye defaults to left.
|
|
510
|
+
|
|
511
|
+
### Resolution Presets
|
|
512
|
+
|
|
513
|
+
| Key | Display | Aspect |
|
|
514
|
+
|---|---|---|
|
|
515
|
+
| `1024p36fps` | 1024p @ 36fps | 1:1 (default) |
|
|
516
|
+
| `1024p60fps` | 1024p @ 60fps | 1:1 |
|
|
517
|
+
| `1080p36fps` | 1080p @ 36fps | 16:9 |
|
|
518
|
+
| `1080p60fps` | 1080p @ 60fps | 16:9 |
|
|
519
|
+
| `1440p36fps` | 1440p @ 36fps | 16:9 |
|
|
520
|
+
| `1440p60fps` | 1440p @ 60fps | 16:9 |
|
|
521
|
+
| `2160p36fps` | 2160p @ 36fps | 16:9 |
|
|
522
|
+
| `2160p60fps` | 2160p @ 60fps | 16:9 |
|
|
523
|
+
|
|
524
|
+
### Bitrate
|
|
525
|
+
|
|
526
|
+
| Value | Quality |
|
|
527
|
+
|---|---|
|
|
528
|
+
| 5 Mbps | Very low (default) |
|
|
529
|
+
| 8 Mbps | Low |
|
|
530
|
+
| 25 Mbps | High |
|
|
531
|
+
| 40 Mbps | Very high |
|
|
532
|
+
|
|
533
|
+
## ADB Setup
|
|
534
|
+
|
|
535
|
+
### Casting Lifecycle
|
|
536
|
+
|
|
537
|
+
```bash
|
|
538
|
+
# Set media capture mode (required before casting)
|
|
539
|
+
adb shell setprop debug.oculus.command_line_media_capture Casting
|
|
540
|
+
|
|
541
|
+
# Disable proximity sensor (prevents sleep when headset removed)
|
|
542
|
+
adb shell am broadcast -a com.oculus.vrpowermanager.prox_close --ei duration 600000
|
|
543
|
+
|
|
544
|
+
# Disable guardian boundaries
|
|
545
|
+
adb shell setprop debug.oculus.guardian_pause 1
|
|
546
|
+
|
|
547
|
+
# Stop casting
|
|
548
|
+
adb shell am broadcast -a com.oculus.magicislandcastingservice.STOP_CASTING
|
|
549
|
+
|
|
550
|
+
# Re-enable proximity sensor
|
|
551
|
+
adb shell am broadcast -a com.oculus.vrpowermanager.automation_disable
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### Casting Service Intents
|
|
555
|
+
|
|
556
|
+
```
|
|
557
|
+
com.oculus.magicislandcastingservice.START_CASTING
|
|
558
|
+
com.oculus.magicislandcastingservice.STOP_CASTING
|
|
559
|
+
com.oculus.magicislandcastingservice.CONNECT
|
|
560
|
+
com.oculus.magicislandcastingservice.START_RECORDING
|
|
561
|
+
com.oculus.magicislandcastingservice.STOP_RECORDING
|
|
562
|
+
com.oculus.magicislandcastingservice.UPDATE_CASTING_CONFIG
|
|
563
|
+
com.oculus.magicislandcastingservice.SET_DEVICE_EYE_FOV
|
|
564
|
+
com.oculus.magicislandcastingservice.ENABLE_PANEL_STREAMING
|
|
565
|
+
com.oculus.magicislandcastingservice.DISABLE_PANEL_STREAMING
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### Feature Flags
|
|
569
|
+
|
|
570
|
+
Feature flags control optional capabilities:
|
|
571
|
+
|
|
572
|
+
- `wireless_casting_2` — WiFi casting
|
|
573
|
+
- `input_forwarding_2` — Keyboard/mouse forwarding
|
|
574
|
+
- `gaze_click` — Gaze-based click input
|
|
575
|
+
- `text_forwarding` — Text input forwarding
|
|
576
|
+
- `mic_audio` — Microphone audio
|
|
577
|
+
- `image_stabilization` — Image stabilization
|
|
578
|
+
- `obs_support` — OBS integration
|
|
579
|
+
- `panel_streaming` — 2D panel streaming
|
|
580
|
+
|
|
581
|
+
### Configuration Properties
|
|
582
|
+
|
|
583
|
+
Runtime configuration via SET_PROPERTY (cmd 0x0A). All keys are in the
|
|
584
|
+
`debug.oculus.magic.*` namespace and can also be set via
|
|
585
|
+
`adb shell setprop debug.oculus.magic.<key> <value>`.
|
|
586
|
+
|
|
587
|
+
| Property | Default | Unit |
|
|
588
|
+
|----------|---------|------|
|
|
589
|
+
| `serverPort` | 4445 | TCP port |
|
|
590
|
+
| `captureEncoderBitrate` | 40,000,000 | bits/sec |
|
|
591
|
+
| `maxEncoderFps` | 60 | fps |
|
|
592
|
+
| `minEncoderFps` | 30 | fps |
|
|
593
|
+
| `scalingFactor` | 1.0 | multiplier |
|
|
594
|
+
| `remoteInputFrameValidDuration` | 5.0 | seconds |
|
|
595
|
+
| `targetAudioLatency` | 0.05 | seconds |
|
|
596
|
+
| `audioCaptureBitrate` | 160,000 | bits/sec |
|
|
597
|
+
| `congestionControlWindow` | 1.0 | seconds |
|
|
598
|
+
| `congestionControlMultiplicativeDecrease` | 0.85 | multiplier |
|
|
599
|
+
| `congestionControlAdditiveIncrease` | 250,000 | bits/sec |
|
|
600
|
+
| `transportConnectTimeout` | 5,000 | ms |
|
|
601
|
+
| `transportConnectRetryInterval` | 5,000 | ms |
|
|
602
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@myerscarpenter/cast2-protocol",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Cast 2.0 protocol implementation for Meta Quest video casting — XRSP framing, MGIK sub-headers, MUD message builders, pose math, and resolution presets",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./build/index.js",
|
|
7
|
+
"types": "./build/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./build/index.d.ts",
|
|
11
|
+
"import": "./build/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"build",
|
|
16
|
+
"docs"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"clean": "rm -rf build",
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"test": "vitest run"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"cast2",
|
|
25
|
+
"meta-quest",
|
|
26
|
+
"xrsp",
|
|
27
|
+
"mgik",
|
|
28
|
+
"vr",
|
|
29
|
+
"xr",
|
|
30
|
+
"protocol"
|
|
31
|
+
],
|
|
32
|
+
"author": "Myers Carpenter <myers@maski.org>",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/myers/quest-dev",
|
|
37
|
+
"directory": "packages/cast2-protocol"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"typescript": "^5.9.2",
|
|
41
|
+
"vitest": "^4.0.3"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18.0.0"
|
|
45
|
+
}
|
|
46
|
+
}
|