@desklink/host 0.2.0 → 0.3.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.
Files changed (69) hide show
  1. package/NOTICE +23 -0
  2. package/README.md +78 -48
  3. package/bin/desklink-host.mjs +1 -1
  4. package/dist/bridge.d.ts +1 -0
  5. package/dist/bridge.d.ts.map +1 -1
  6. package/dist/bridge.js +12 -4
  7. package/dist/bridge.js.map +1 -1
  8. package/dist/engineProcess.d.ts.map +1 -1
  9. package/dist/engineProcess.js +1 -0
  10. package/dist/engineProcess.js.map +1 -1
  11. package/dist/protocol.d.ts +26 -0
  12. package/dist/protocol.d.ts.map +1 -1
  13. package/dist/protocol.js.map +1 -1
  14. package/dist/resolveEngine.d.ts +1 -1
  15. package/dist/resolveEngine.d.ts.map +1 -1
  16. package/dist/resolveEngine.js +22 -9
  17. package/dist/resolveEngine.js.map +1 -1
  18. package/docs/BOUNDARY.md +15 -7
  19. package/docs/PROTOCOL.md +150 -23
  20. package/engine/Cargo.lock +46 -1
  21. package/engine/Cargo.toml +12 -2
  22. package/engine/build.rs +28 -2
  23. package/engine/native/nvenc_shim.c +453 -0
  24. package/engine/native/vaapi_shim.c +727 -0
  25. package/engine/native/vpx_shim.c +54 -4
  26. package/engine/native/vt_shim.c +448 -0
  27. package/engine/src/capture.rs +75 -55
  28. package/engine/src/capture_mac.rs +24 -14
  29. package/engine/src/convert.rs +286 -61
  30. package/engine/src/encoder.rs +122 -13
  31. package/engine/src/h264.rs +188 -0
  32. package/engine/src/h264_nvenc.rs +308 -0
  33. package/engine/src/h264_openh264.rs +735 -0
  34. package/engine/src/h264_vaapi.rs +263 -0
  35. package/engine/src/h264_vt.rs +368 -0
  36. package/engine/src/mac.rs +6 -3
  37. package/engine/src/main.rs +22 -4
  38. package/engine/src/peer.rs +466 -28
  39. package/engine/src/protocol.rs +15 -2
  40. package/engine/src/session.rs +790 -93
  41. package/engine/src/x11.rs +210 -9
  42. package/engine/src/x11_mac.rs +12 -0
  43. package/engine/vendor/libva/COPYING +19 -0
  44. package/engine/vendor/libva/va/va.h +5450 -0
  45. package/engine/vendor/libva/va/va_dec_av1.h +695 -0
  46. package/engine/vendor/libva/va/va_dec_hevc.h +616 -0
  47. package/engine/vendor/libva/va/va_dec_jpeg.h +157 -0
  48. package/engine/vendor/libva/va/va_dec_vp8.h +249 -0
  49. package/engine/vendor/libva/va/va_dec_vp9.h +312 -0
  50. package/engine/vendor/libva/va/va_dec_vvc.h +688 -0
  51. package/engine/vendor/libva/va/va_drm.h +61 -0
  52. package/engine/vendor/libva/va/va_enc_av1.h +1010 -0
  53. package/engine/vendor/libva/va/va_enc_h264.h +659 -0
  54. package/engine/vendor/libva/va/va_enc_hevc.h +958 -0
  55. package/engine/vendor/libva/va/va_enc_jpeg.h +162 -0
  56. package/engine/vendor/libva/va/va_enc_mpeg2.h +308 -0
  57. package/engine/vendor/libva/va/va_enc_vp8.h +350 -0
  58. package/engine/vendor/libva/va/va_enc_vp9.h +639 -0
  59. package/engine/vendor/libva/va/va_fei.h +170 -0
  60. package/engine/vendor/libva/va/va_fei_h264.h +505 -0
  61. package/engine/vendor/libva/va/va_fei_hevc.h +254 -0
  62. package/engine/vendor/libva/va/va_prot.h +525 -0
  63. package/engine/vendor/libva/va/va_version.h +87 -0
  64. package/engine/vendor/libva/va/va_vpp.h +1590 -0
  65. package/engine/vendor/nv-codec-headers/LICENSE +24 -0
  66. package/engine/vendor/nv-codec-headers/README +7 -0
  67. package/engine/vendor/nv-codec-headers/include/ffnvcodec/nvEncodeAPI.h +3825 -0
  68. package/examples/reference-client.html +1 -1
  69. package/package.json +3 -2
@@ -1 +1 @@
1
- {"version":3,"file":"resolveEngine.js","sourceRoot":"","sources":["../src/resolveEngine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolveEngine.js","sourceRoot":"","sources":["../src/resolveEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAsBzC,mDAAmD;AACnD,MAAM,kBAAkB,GAAG,CAAC,eAAe,EAAE,cAAc,CAAC,CAAC;AAE7D,MAAM,UAAU,kBAAkB,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc;IAC7F,OAAO,QAAQ,KAAK,QAAQ,IAAI,IAAI,KAAK,GAAG,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC7B,OAAO,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACvB,WAAmB,OAAO,CAAC,QAAQ,EACnC,OAAe,OAAO,CAAC,IAAI,EAC3B,QAA6B,QAAQ,EAAE;IAEvC,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,SAAS,IAAI,IAAI,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IACrF,OAAO,GAAG,QAAQ,IAAI,IAAI,EAAE,CAAC;AACjC,CAAC;AAED,yEAAyE;AACzE,SAAS,QAAQ;IACb,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO,SAAS,CAAC;IACnD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,EAA+D,CAAC;IAC1G,OAAO,MAAM,EAAE,MAAM,EAAE,mBAAmB,KAAK,SAAS,CAAC;AAC7D,CAAC;AAED,SAAS,cAAc;IACnB,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,kBAAkB,WAAW,EAAE,EAAE,CAAC;IAC/C,IAAI,CAAC;QACD,mEAAmE;QACnE,2DAA2D;QAC3D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,IAAI,eAAe,CAA0D,CAAC;QAC1G,MAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU,IAAI,QAAQ,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC;QACxE,IAAI,OAAO,QAAQ,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QACzE,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CAAC,IAAY;IACjC,OAAO;QACH,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,CAAC;QAC1D,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,CAAC;QACxD,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,eAAe,CAAC;KACrC,CAAC;AACN,CAAC;AAED;;;;;;GAMG;AACH,SAAS,oBAAoB;IACzB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC/C,IAAI,UAAU,KAAK,SAAS,IAAI,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,UAAU,CAAC;IAC5E,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,UAAU,GAAG,oBAAoB,EAAE,EAAE,IAAI,GAAG,iBAAiB,EAAE;IACzF,IAAI,CAAC,kBAAkB,EAAE;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,UAAU,KAAK,SAAS,IAAI,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC;YAAE,OAAO,IAAI,CAAC;QAC3C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IAC1E,CAAC;IACD,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;IAClC,IAAI,QAAQ,KAAK,IAAI,IAAI,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IACtE,CAAC;IACD,KAAK,MAAM,SAAS,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5C,IAAI,YAAY,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QACtE,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAC9B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;QAAE,OAAO,KAAK,CAAC;IACjC,6EAA6E;IAC7E,mDAAmD;IACnD,OAAO,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAChC,UAAU,GAAG,oBAAoB,EAAE,EACnC,IAAI,GAAG,iBAAiB,EAAE;IAE1B,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC;QACxB,OAAO,0FAA0F,CAAC;IACtG,CAAC;IACD,MAAM,QAAQ,GAAG,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IACjD,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,UAAU,KAAK,SAAS,IAAI,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC1B,OAAO,qDAAqD,UAAU,IAAI,CAAC;QAC/E,CAAC;QACD,OAAO,yBAAyB,UAAU,6BAA6B,CAAC;IAC5E,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,WAAW,EAAE,CAAC;QAC1B,IAAI,kBAAkB,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACnC,OAAO,mCAAmC,GAAG,qEAAqE,GAAG,8GAA8G,CAAC;QACxO,CAAC;QACD,OAAO,2CAA2C,GAAG,iGAAiG,CAAC;IAC3J,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAC/B,OAAO,+CAA+C,OAAO,CAAC,QAAQ,wBAAwB,CAAC;IACnG,CAAC;IACD,MAAM,GAAG,GAAG,WAAW,EAAE,CAAC;IAC1B,IAAI,kBAAkB,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,OAAO,mCAAmC,GAAG,qEAAqE,GAAG,8GAA8G,CAAC;IACxO,CAAC;IACD,OAAO,2CAA2C,GAAG,iGAAiG,CAAC;AAC3J,CAAC"}
package/docs/BOUNDARY.md CHANGED
@@ -20,8 +20,9 @@ apply authenticated input to the same desktop".
20
20
  - In: `session.open`, SDP/ICE, scoped WebRTC control-channel input, explicit
21
21
  clipboard read/write, close — and `session.feed`, which supplies the access
22
22
  units of a consumer-encoded `encoded` source. See `docs/PROTOCOL.md`.
23
- - Out: one video track — VP9 the engine encodes from a captured desktop, or
24
- H.264 it only packetizes for a consumer-fed `encoded` source, whose control
23
+ - Out: one video track — VP9 or H.264 (the receiver's answer picks) the engine
24
+ encodes from a captured desktop, or H.264 it only packetizes for a
25
+ consumer-fed `encoded` source, whose control
25
26
  messages are forwarded to the consumer instead of applied — and session
26
27
  notifications. Metrics are a request, not an event; the wire contract is in
27
28
  `docs/PROTOCOL.md`.
@@ -31,6 +32,9 @@ apply authenticated input to the same desktop".
31
32
  - Never: decides identity, installs rules, grants capabilities, carries audio,
32
33
  arbitrates two controllers, remembers a session across a restart.
33
34
 
35
+ For prebuilt platform support and macOS installation, see the
36
+ [host installation guide](../README.md#install-and-run).
37
+
34
38
  The public surface carries no consumer concepts. A machine id, a chat, a pane or
35
39
  an account never appears in the protocol or in the engine's state.
36
40
 
@@ -47,8 +51,10 @@ local gestures into that session's input".
47
51
  - `session.showKeyboard()/hideKeyboard()`,
48
52
  `session.copyRemoteToLocal()/pasteLocalToRemote()` are the control primitives
49
53
  the app mounts wherever it wants.
50
- - Native side owns the video decoder factory selection (hardware VP9 rather
51
- than the underlying wrapper's software default), the renderer and the IME/text
54
+ - Native side owns the video decoder factory selection (on Android, hardware
55
+ VP9 rather than the underlying wrapper's software default; on iOS, whose
56
+ WebRTC decodes VP9 only in software, the receiver asks for H.264, which it
57
+ decodes in hardware), the renderer and the IME/text
52
58
  connection. For input enablement and release on background/unmount, see the
53
59
  [client contract](../../desktop-client/README.md#what-the-package-guarantees).
54
60
  - The app supplies `authorize()` (a short-lived, engine-scoped capability plus
@@ -73,10 +79,9 @@ local gestures into that session's input".
73
79
 
74
80
  ## Reused, not rebuilt `[decided]`
75
81
 
76
- | Need | Already in this repository |
82
+ | Need | Integration owner or consumer reference |
77
83
  |---|---|
78
- | Encrypted mobile → host request path, identity, grants | `packages/contract` control plane + `apps/host/src/requests` |
79
- | Relay stream channel (host joins as machine, client as client) | `packages/contract` `wsTickets` / preview channel pattern |
84
+ | Authenticated request channel, identity, pairing, relay and reachable addresses | The consuming app's kits; see the [BYOKit integration guidance](../../../README.md#why-desklink-exists) |
80
85
  | A reference for a "live surface inside a conversation" | `apps/mobile/sources/desktop` |
81
86
  | Flow-test style for the packages | `apps/mobile/sources/catalog/application/sessionSync.integration.spec.ts` |
82
87
 
@@ -88,6 +93,9 @@ local gestures into that session's input".
88
93
  | Portal ScreenCast + PipeWire fd | `ashpd` (zbus) | MIT |
89
94
  | PipeWire stream client | `pipewire` | MIT |
90
95
  | VP9 encode | libvpx | BSD-3-Clause |
96
+ | H.264 encode (macOS) | VideoToolbox (system framework) | Apple SDK |
97
+ | H.264 encode (Linux GPU) | NVENC, VA-API — loaded at runtime from the driver | NVIDIA driver / libva MIT |
98
+ | H.264 encode (Linux, no GPU encoder) | Cisco's prebuilt openh264, downloaded at runtime, never built or shipped | BSD-2-Clause (Cisco's binary licence) |
91
99
  | Virtual mouse/keyboard | inputtino (uinput/libevdev) | MIT |
92
100
  | Clipboard read/write | `wl-clipboard-rs` | MIT |
93
101
  | Keyboard layout mapping | `xkbcommon` | MIT |
package/docs/PROTOCOL.md CHANGED
@@ -66,7 +66,7 @@ Request parameters use the engine's own snake_case names (`session_id`,
66
66
  Result:
67
67
 
68
68
  ```jsonc
69
- {"protocol":3,"engine":"desklink-host/0.2.0","platform":"linux", /* the rest of Capabilities */ }
69
+ {"protocol":3,"engine":"desklink-host/0.3.0","platform":"linux", /* the rest of Capabilities */ }
70
70
  ```
71
71
 
72
72
  The consumer must send `hello` first, and a version the engine does not speak is
@@ -76,8 +76,12 @@ arrives, every other request is refused the same way; `capabilities` and
76
76
 
77
77
  ## macOS
78
78
 
79
+ For engine installation and the macOS resolution opt-out, see the
80
+ [host installation guide](../README.md#macos).
81
+
79
82
  macOS speaks protocol 3 and shares the session lifecycle below. It captures the
80
- selected display with ScreenCaptureKit, encodes VP9, and uses the same WebRTC
83
+ selected display with ScreenCaptureKit, encodes VP9 (and H.264 through
84
+ VideoToolbox, for a receiver that asks for it), and uses the same WebRTC
81
85
  offer, ICE, control-channel, lease, and metrics flow as Linux. Capture currently
82
86
  uses one bounded ScreenCaptureKit stream (three-frame queue); the backend may
83
87
  supply fewer frames. Audio is not captured.
@@ -108,7 +112,7 @@ session may require fresh consent. The macOS engine requires a VP9-enabled build
108
112
  ```jsonc
109
113
  {
110
114
  "protocol": 3,
111
- "engine": "desklink-host/0.2.0",
115
+ "engine": "desklink-host/0.3.0",
112
116
  "platform": "linux",
113
117
  "session": {"kind": "wayland"},
114
118
  "x11": {"available": true, "size": [2560, 1440]},
@@ -119,7 +123,8 @@ session may require fresh consent. The macOS engine requires a VP9-enabled build
119
123
  "cursor": "embedded",
120
124
  "audio": false
121
125
  },
122
- "encode": {"codecs": ["vp9"], "hardware": false},
126
+ "encode": {"codecs": ["vp9", "h264"], "hardware": false,
127
+ "h264": {"encoder": "vaapi", "hardware": true}},
123
128
  "input": {
124
129
  "mechanism": "inputtino/uinput",
125
130
  "pointer": true, "wheel": true, "keyboard": true,
@@ -133,6 +138,28 @@ session may require fresh consent. The macOS engine requires a VP9-enabled build
133
138
  }
134
139
  ```
135
140
 
141
+ `encode` describes what the engine codes from a captured desktop. VP9 (libvpx,
142
+ software; `hardware` describes it) is always there and is the default. `h264`
143
+ appears in `codecs` when an H.264 encoder starts on this machine right now, and
144
+ `encode.h264.encoder` names it: `videotoolbox` on macOS; on Linux `nvenc` or
145
+ `vaapi` when the GPU has an H.264 encoder, else `openh264`, Cisco's prebuilt
146
+ library. `encoder` is `null` when there is none. The answer to the offer picks
147
+ between them (see *Codecs* below).
148
+
149
+ openh264 is never part of this package: the engine loads only Cisco's own
150
+ binary, checked against its published SHA-256, from
151
+ `$XDG_CACHE_HOME/desklink/openh264/` (else `~/.cache/desklink/openh264/`). When a
152
+ Linux machine has no hardware H.264 encoder and the library is not there yet,
153
+ the first captured `session.open` downloads it from Cisco
154
+ (`ciscobinary.openh264.org`) before making its offer; that session is offered
155
+ VP9 alone if the download fails. `capabilities` itself never downloads.
156
+ `DESKLINK_OPENH264=off` in the engine's environment disables openh264 (no
157
+ download, no load); `DESKLINK_OPENH264=<path>` loads that file instead, still
158
+ only if its hash is Cisco's. `DESKLINK_H264_ENCODER=<name>` restricts the engine
159
+ to one H.264 encoder (`off` for none), for measuring one backend. Cisco's
160
+ licence asks that this be stated: OpenH264 Video Codec provided by Cisco
161
+ Systems, Inc.
162
+
136
163
  `encoded` lists the codecs this build will carry when the consumer supplies the
137
164
  video itself (see *Encoded sources*): a consumer reads it rather than inferring
138
165
  support from the engine's version string.
@@ -168,12 +195,13 @@ trigger a capture request.
168
195
  "permissions": ["view","control","clipboard"],
169
196
  "max_width": 3840, "max_height": 2160, // encode box (default); never upscales
170
197
  "bitrate_kbps": 0, // 0 (default): sized to the encoded surface
171
- "max_fps": 30,
198
+ "max_fps": 60,
172
199
  "ice_servers": [{"urls":["stun:..."],"username":null,"credential":null}],
173
200
  "restore_token": null, // from a previous session.restoreToken
174
201
  "ttl_seconds": 3600, // session lease; default 3600
175
202
  "loopback_tcp": false, // also offer ICE over TCP on 127.0.0.1; default false
176
- "agent_indicator": false // local input feedback; default false (phone control)
203
+ "agent_indicator": false, // local input feedback; default false (phone control)
204
+ "local_frames": true // keep frames for session.frame; default true
177
205
  }}
178
206
  ```
179
207
 
@@ -201,7 +229,7 @@ clipboard action and never infers them from a source, a peer or an SDP.
201
229
  `control` without a working input backend is refused at `session.open` with
202
230
  `error.code = "input-unavailable"` — the consumer must ask for `view` explicitly instead.
203
231
 
204
- `max_fps` defaults to 30 and is bounded to 1–60. It caps the encoded frame
232
+ `max_fps` defaults to 60 and is bounded to 1–60. It caps the encoded frame
205
233
  rate and X11 capture loop; portal capture offers it as the preferred PipeWire
206
234
  frame rate, and macOS sets its ScreenCaptureKit stream minimum frame interval.
207
235
  A source may still supply fewer frames.
@@ -211,11 +239,19 @@ sets it for control sessions, never for view-only or human phone control. It
211
239
  adds an eased pointer halo, click ripple, and typing pulse. On Wayland it uses
212
240
  a click-through layer-shell surface with an edge glow; its bounded area is
213
241
  masked before capture/diff (pixels behind the effect can remain briefly stale).
214
- On bare X11 it replaces the pointer sprite instead, which XGetImage excludes:
242
+ On bare X11 it replaces the pointer sprite instead, which the X11 grab excludes:
215
243
  there is no edge glow on that path. macOS uses a nonactivating, click-through
216
244
  window excluded by the ScreenCaptureKit content filter. Closing the session
217
245
  fades and removes the indicator.
218
246
 
247
+ `local_frames` keeps the latest pre-encode frame and its tile hashes for
248
+ `session.frame` and `session.frame.changed` (see "Latest frame over the local
249
+ protocol"). A consumer that only streams sets it to `false`: each captured
250
+ frame is then converted once, for the encoder, no frame is kept, no
251
+ `session.frame.changed` is emitted, and `session.frame` is refused with
252
+ `error.code = "operation"`. The WebSocket bridge sets it to `false` unless its
253
+ host listens to engine events, because neither travels past the socket.
254
+
219
255
  `session.open` is where the capture request happens, which is where the user's
220
256
  consent appears. It is not implicit and it is not retried silently.
221
257
 
@@ -243,6 +279,36 @@ the SDP and candidates to the client and brings back the answer.
243
279
 
244
280
  A candidate that arrives before the remote description is buffered, not dropped.
245
281
 
282
+ #### Codecs
283
+
284
+ For a captured desktop the offer's video section lists VP9 (payload type 98)
285
+ and, when `capabilities.encode.codecs` has `h264` and the encoded surface is
286
+ within H.264 level 5.2 (at most 36864 16x16 macroblocks, e.g. 4096x2304 — a
287
+ 5K surface is offered VP9 alone), H.264 after it (payload type
288
+ 102, `packetization-mode=1`, Constrained Baseline, `profile-level-id=42e034`
289
+ with `level-asymmetry-allowed=1`). The engine codes whichever of the two the
290
+ answer lists first. A receiver that applies the offer as it comes answers in
291
+ the offer's order and gets VP9, as before; a receiver that wants H.264 puts it
292
+ first — with `setCodecPreferences` before `createAnswer`, or by moving its
293
+ payload type to the front of the offer's `m=video` line before applying it.
294
+ The iOS receiver in `@desklink/client` does the latter, because iOS decodes
295
+ H.264 in hardware and VP9 in software; the web and Android receivers keep VP9.
296
+ The choice is made by the first answer and kept for the session, ICE restarts
297
+ included; the encoder starts after that answer, so the first frame sent is
298
+ already in the chosen codec. H.264 is coded at the full encoded size throughout
299
+ (no half-size motion), with an IDR carrying its SPS and PPS only for the first
300
+ frame and on a receiver's request. An `encoded` source offers H.264 alone, as
301
+ described under *Encoded sources*.
302
+
303
+ The offer negotiates the `playout-delay` RTP header extension
304
+ (`http://www.webrtc.org/experiments/rtp-hdrext/playout-delay`), and every video
305
+ packet asks for a playout delay of 0: a receiver that honours it shows each
306
+ frame when it is decoded instead of buffering frames to smooth playback. A
307
+ receiver may decline the extension in its answer; its packets then carry no
308
+ playout delay and it buffers as usual. The iOS receiver in
309
+ `@desklink/react-native` declines it, because `RTCView` draws a frame only when
310
+ its timestamp is new and zero-delay frames all carry the same one.
311
+
246
312
  A client whose ICE connection goes `disconnected` may restart ICE on the same
247
313
  peer connection instead of opening a new session: it sends
248
314
  `session.restart_ice` with the session's id and generation, and the engine
@@ -278,8 +344,9 @@ always does.
278
344
 
279
345
  `disconnected` is ICE losing the path: the picture is frozen but the session
280
346
  is alive, and a client should show reconnecting and may restart ICE (above)
281
- rather than open a new session. `failed` is terminal: the engine revokes and
282
- closes the session, and only a new `session.open` recovers it.
347
+ rather than open a new session. `failed` is terminal: the engine revokes the
348
+ session with code `transport` and closes it, and only a new `session.open`
349
+ recovers it.
283
350
 
284
351
  While its control channel is open the engine also sends a heartbeat twice a
285
352
  second, `{"kind":"ping"}`. It lets a client notice a stalled path within
@@ -310,10 +377,26 @@ picker; restoration is silent only where the backend supports it. Cancellation
310
377
  is an error, not a reason to retry or bypass consent.
311
378
 
312
379
  ```jsonc
313
- {"event":"session.revoked","params":{"sessionId":"…","reason":"…"}}
380
+ {"event":"session.revoked","params":{"sessionId":"…","reason":"…",
381
+ "code":"transport"}} // transport|lease|error
314
382
  ```
315
383
 
316
384
  The session ended on the engine's side; there is nothing further to drain.
385
+ `reason` is prose for people; `code` is what a client acts on:
386
+
387
+ | `code` | Meaning | A client should |
388
+ |---|---|---|
389
+ | `transport` | The path to the client's peer was lost (ICE `failed`, or the track refused a frame) | open a new session with fresh authority; the desktop is still available |
390
+ | `lease` | The session's `ttl_seconds` ran out | end; the grant is spent |
391
+ | `error` | The engine could not keep serving it, such as an encoder refusing a frame | end and report |
392
+
393
+ A session the consumer closes or replaces (`session.close`, a new
394
+ `session.open`, the consumer leaving) sends no `session.revoked`: the consumer
395
+ asked for it, and signaling sees `session.state` with `capture` `ended`. Only
396
+ its control channel is told, with code `closed` (below).
397
+
398
+ A code a client does not know is terminal. Engines before this field sent no
399
+ `code`; treat its absence as terminal too.
317
400
 
318
401
  Metrics are a request, not a notification:
319
402
 
@@ -323,17 +406,56 @@ Metrics are a request, not a notification:
323
406
 
324
407
  ```jsonc
325
408
  {"id":7,"result":{"captured_frames":812,"dropped_frames":3,"encoded_frames":809,
326
- "encoded_bytes":12345678,"key_frames":1,"refined_frames":37,
409
+ "encoded_bytes":12345678,"key_frames":1,"refined_frames":37,"halved_frames":0,"motion_frames":770,
327
410
  "encode_micros":7390000,"target_kbps":16430,"input_applied":44,"input_rejected":0,
328
- "fed_frames":0,"input_forwarded":0}}
411
+ "fed_frames":0,"input_forwarded":0,"codec":"vp9","encoder":"libvpx",
412
+ "capture_micros":14100000,"convert_micros":3200000,
413
+ "queue_micros":410000,"send_micros":180000}}
329
414
  ```
330
415
 
331
416
  `dropped_frames` counts frames superseded by a newer one before they were coded;
332
- the newest frame is always coded. `refined_frames` counts refinement passes: a
417
+ the newest frame is always coded. That includes frames that arrived while a
418
+ large one (a key frame, a refinement) was still crossing the link: the stream
419
+ runs at most about 60 ms of its rate target ahead of it, so frames never queue
420
+ behind a burst. `refined_frames` counts refinement passes: a
333
421
  desktop that stops changing is coded once more at a fine quantizer, so it reads
334
- sharp. Key frames are sent only for the first frame and when the receiver asks
335
- (RTCP PLI or FIR). `target_kbps` is the current rate target after any back-off
336
- for loss the receiver reported.
422
+ sharp. `halved_frames` counts motion frames coded at half width and height: when
423
+ full-size frames that change much of the picture take longer to code than a
424
+ frame interval while a newer frame is already waiting, several frames in a row,
425
+ motion is coded at half size until the desktop stops or its changes shrink to
426
+ small ones that code in time; the refinement pass is always full size. Key
427
+ frames are sent only for the first frame, when the receiver asks (RTCP PLI or
428
+ FIR), and when the coded size changes that way, so a receiver never has to scale
429
+ references across a size change. `target_kbps` is the current rate target after
430
+ any back-off: for a standing queue on the path, measured from the receiver's
431
+ transport-wide congestion feedback (RTP `transport-cc`), and for the loss
432
+ its receiver reports carry. `codec` is what frames go out in
433
+ (`vp9` or `h264`) and `encoder` what codes them (`libvpx`, `videotoolbox`,
434
+ `nvenc`, `vaapi` or `openh264`); both are empty for an encoded source.
435
+
436
+ Per-stage timings (the L0 lab harness reads these, and every later lane cites
437
+ them). Each is a cumulative microsecond counter; divide by the frame count
438
+ named beside it for the per-frame mean:
439
+
440
+ - `capture_micros` / `captured_frames`: grabbing a frame and converting it on
441
+ the capture thread (on X11: an MIT-SHM grab, falling back to socket
442
+ `GetImage` where the server lacks MIT-SHM, plus the downscale to I420), over
443
+ forwarded (changed) frames only — unchanged polls are excluded.
444
+ - `convert_micros` / `captured_frames`: tile hashing and damage computation on
445
+ the capture thread, after the grab; the hash branch runs only with
446
+ `local_frames` on.
447
+ - `queue_micros` / `motion_frames`: how long a freshly captured frame waited
448
+ between the capture handoff and the start of its encode. Refinement,
449
+ keepalive and receiver-requested re-encodes re-code a picture that was
450
+ already sent; they queue nothing and stay out of this mean.
451
+ - `send_micros` / `encoded_frames`: packetizing a frame and handing it to the
452
+ transport.
453
+ - `encode_micros` / `encoded_frames`: the encoder alone.
454
+
455
+ `capture + convert` per captured frame plus `queue` per motion-coded frame and
456
+ `encode + send` per encoded frame reconciles against engine-side wall time per
457
+ frame within measurement noise; a stage that will not reconcile is a stage
458
+ whose accounting is wrong.
337
459
 
338
460
  ## Input and clipboard: the session's control channel
339
461
 
@@ -373,7 +495,7 @@ The engine answers on the same channel, and sends two things unprompted:
373
495
  {"kind":"ack","seq":44}
374
496
  {"kind":"rejected","seq":44,"code":"coordinates","message":"(9000,4) is outside the 1280x720 surface"}
375
497
  {"kind":"clipboard","request":"…","text":"…","truncated":false} // an empty "text" with "error" when the read failed
376
- {"kind":"revoked","reason":"…"}
498
+ {"kind":"revoked","reason":"…","code":"closed"} // closed, or a session.revoked code
377
499
  ```
378
500
 
379
501
  Refusal codes: `permission`, `session`, `input-replay`, `coordinates`,
@@ -494,9 +616,12 @@ is the consumer's to carry.
494
616
 
495
617
  `session.frame` and `session.wait_frame` are refused with `error.code =
496
618
  "operation"` — there is no lossless frame to read — and `captured_frames`,
497
- `refined_frames` and `target_kbps` stay at zero while `fed_frames` counts what
498
- the consumer handed over and `encoded_frames`, `encoded_bytes`, `key_frames`
499
- and `encode_micros` describe what was packetized and sent.
619
+ `refined_frames`, `halved_frames`, `motion_frames`, `target_kbps`, `capture_micros`,
620
+ `convert_micros`, `queue_micros` and `send_micros` stay at zero while
621
+ `fed_frames` counts what the consumer handed over and `encoded_frames`,
622
+ `encoded_bytes`, `key_frames` and `encode_micros` describe what was packetized
623
+ and sent — on this path `encode_micros` covers packetizing and sending too,
624
+ because packetization is the only stage the engine itself runs.
500
625
 
501
626
  ## Latest frame over the local protocol
502
627
 
@@ -516,7 +641,8 @@ of stillness. When both are supplied, both conditions must hold.
516
641
  Each changed capture emits a local `session.frame.changed` event with `sessionId`,
517
642
  `seq` and `damage`, allowing a co-located consumer to track animation across
518
643
  observations. Neither the event nor this file-writing method is forwarded by
519
- the remote WebSocket bridge.
644
+ the remote WebSocket bridge. A session opened with `local_frames: false` keeps
645
+ no frame: both are refused with `error.code = "operation"` (see `session.open`).
520
646
 
521
647
  ```json
522
648
  {"id":20,"method":"session.frame","params":{"session_id":"…","since":7,"path":"/run/user/1000/frame.raw"}}
@@ -616,7 +742,8 @@ anything to show.
616
742
 
617
743
  - It does not decide *who* the user is. It trusts the consumer's local
618
744
  permission decision and enforces the resulting scope; there is no second
619
- account, token or pairing ceremony.
745
+ account, token or pairing ceremony. For consumer integration, see the
746
+ [BYOKit guidance](../../../README.md#why-desklink-exists).
620
747
  - It does not open ports, register a service, install udev rules, join groups or
621
748
  raise capabilities. Kernel input access is a separate, explicit, guided step
622
749
  (`desklink-host setup-input` reports what is missing; it does not change it).
package/engine/Cargo.lock CHANGED
@@ -307,6 +307,16 @@ version = "1.12.1"
307
307
  source = "registry+https://github.com/rust-lang/crates.io-index"
308
308
  checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
309
309
 
310
+ [[package]]
311
+ name = "bzip2-rs"
312
+ version = "0.1.2"
313
+ source = "registry+https://github.com/rust-lang/crates.io-index"
314
+ checksum = "beeb59e7e4c811ab37cc73680c798c7a5da77fc9989c62b09138e31ee740f735"
315
+ dependencies = [
316
+ "crc32fast",
317
+ "tinyvec",
318
+ ]
319
+
310
320
  [[package]]
311
321
  name = "cc"
312
322
  version = "1.4.7"
@@ -449,6 +459,15 @@ dependencies = [
449
459
  "rustc_version",
450
460
  ]
451
461
 
462
+ [[package]]
463
+ name = "crc32fast"
464
+ version = "1.5.2"
465
+ source = "registry+https://github.com/rust-lang/crates.io-index"
466
+ checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78"
467
+ dependencies = [
468
+ "cfg-if",
469
+ ]
470
+
452
471
  [[package]]
453
472
  name = "crossbeam-utils"
454
473
  version = "0.8.23"
@@ -517,7 +536,7 @@ checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
517
536
 
518
537
  [[package]]
519
538
  name = "desklink-host"
520
- version = "0.2.0"
539
+ version = "0.3.0"
521
540
  dependencies = [
522
541
  "anyhow",
523
542
  "ashpd",
@@ -525,6 +544,7 @@ dependencies = [
525
544
  "base64 0.22.1",
526
545
  "block2",
527
546
  "bytes",
547
+ "bzip2-rs",
528
548
  "cc",
529
549
  "futures-util",
530
550
  "libc",
@@ -534,12 +554,16 @@ dependencies = [
534
554
  "objc2-core-media",
535
555
  "objc2-foundation",
536
556
  "objc2-screen-capture-kit",
557
+ "openh264-sys2",
537
558
  "pipewire",
538
559
  "rand 0.8.8",
539
560
  "rtc",
540
561
  "serde",
541
562
  "serde_json",
563
+ "sha2",
542
564
  "tokio",
565
+ "wayland-client",
566
+ "wayland-protocols",
543
567
  "webrtc",
544
568
  "wl-clipboard-rs",
545
569
  "x11rb",
@@ -1430,6 +1454,16 @@ version = "1.21.4"
1430
1454
  source = "registry+https://github.com/rust-lang/crates.io-index"
1431
1455
  checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
1432
1456
 
1457
+ [[package]]
1458
+ name = "openh264-sys2"
1459
+ version = "0.9.8"
1460
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1461
+ checksum = "6ada29a4cadc13d4d326737af87c13e224210d7d99fe47594e9f3f9b0102fd70"
1462
+ dependencies = [
1463
+ "libloading",
1464
+ "sha2",
1465
+ ]
1466
+
1433
1467
  [[package]]
1434
1468
  name = "ordered-stream"
1435
1469
  version = "0.2.0"
@@ -2239,6 +2273,17 @@ dependencies = [
2239
2273
  "digest",
2240
2274
  ]
2241
2275
 
2276
+ [[package]]
2277
+ name = "sha2"
2278
+ version = "0.10.9"
2279
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2280
+ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
2281
+ dependencies = [
2282
+ "cfg-if",
2283
+ "cpufeatures 0.2.17",
2284
+ "digest",
2285
+ ]
2286
+
2242
2287
  [[package]]
2243
2288
  name = "shlex"
2244
2289
  version = "1.3.0"
package/engine/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "desklink-host"
3
- version = "0.2.0"
3
+ version = "0.3.0"
4
4
  edition = "2021"
5
5
  rust-version = "1.97.1"
6
6
  license = "Apache-2.0"
@@ -30,8 +30,18 @@ rand = "0.8"
30
30
  ashpd = { version = "0.11", default-features = false, features = ["tokio"] }
31
31
  pipewire = { version = "0.10", features = ["v0_3_44"] }
32
32
  xkbcommon = "0.8"
33
- x11rb = { version = "0.14", default-features = false, features = ["allow-unsafe-code", "xtest"] }
33
+ x11rb = { version = "0.14", default-features = false, features = ["allow-unsafe-code", "xtest", "shm", "damage"] }
34
34
  wl-clipboard-rs = "0.9"
35
+ # H.264 fallback: Cisco's prebuilt openh264, loaded at runtime (never built
36
+ # from source), fetched once as bzip2 and checked against a pinned sha256.
37
+ openh264-sys2 = { version = "0.9.8", default-features = false, features = ["libloading"] }
38
+ sha2 = "0.10"
39
+ bzip2-rs = "0.1.2"
40
+
41
+ [target.'cfg(target_os = "linux")'.dev-dependencies]
42
+ # The Wayland stamp example only; already in the tree through wl-clipboard-rs.
43
+ wayland-client = "0.31"
44
+ wayland-protocols = { version = "0.32", features = ["client"] }
35
45
 
36
46
  [target.'cfg(target_os = "macos")'.dependencies]
37
47
  anyhow = "1"
package/engine/build.rs CHANGED
@@ -1,8 +1,8 @@
1
1
  //! Native dependencies of the engine.
2
2
  //!
3
3
  //! The Linux build uses two permissive C libraries, both built or linked from
4
- //! this machine's own sources — no prebuilt binary is fetched, and nothing is
5
- //! installed:
4
+ //! this machine's own sources — no prebuilt binary is fetched at build time, and
5
+ //! nothing is installed:
6
6
  //!
7
7
  //! * libvpx (BSD-3-Clause) — VP9 encode, through `native/vpx_shim.c` so the
8
8
  //! versioned encoder config struct is laid out by a C compiler.
@@ -10,6 +10,12 @@
10
10
  //! over `uinput`/`libevdev`, built by its own CMake project into a static
11
11
  //! library and called through its documented C API.
12
12
  //!
13
+ //! H.264 encoding adds no link-time dependency: NVENC and VA-API are loaded with
14
+ //! `dlopen` from the machine's driver at run time, compiled against vendored
15
+ //! MIT headers (`vendor/nv-codec-headers`, `vendor/libva`); openh264 is Cisco's
16
+ //! prebuilt library, fetched by the engine at run time (see `src/h264.rs`). The
17
+ //! macOS build links the VideoToolbox system framework.
18
+ //!
13
19
  //! macOS builds only the libvpx shim; ScreenCaptureKit, Quartz input and
14
20
  //! AppKit clipboard use native frameworks. Linux runtime input access is still
15
21
  //! checked through `/dev/uinput`.
@@ -25,6 +31,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
25
31
  println!("cargo:rustc-check-cfg=cfg(desklink_vpx)");
26
32
  println!("cargo:rustc-check-cfg=cfg(desklink_macos_cli)");
27
33
  println!("cargo:rerun-if-changed=native/vpx_shim.c");
34
+ println!("cargo:rerun-if-changed=native/nvenc_shim.c");
35
+ println!("cargo:rerun-if-changed=native/vaapi_shim.c");
36
+ println!("cargo:rerun-if-changed=native/vt_shim.c");
28
37
  println!("cargo:rerun-if-changed=native/inputtino_shim.cpp");
29
38
  println!("cargo:rerun-if-changed=native/mac_stream.mm");
30
39
  println!("cargo:rerun-if-changed=native/agent_overlay_mac.m");
@@ -69,6 +78,18 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
69
78
  }
70
79
 
71
80
  if target_os == "linux" {
81
+ // H.264 through NVENC and VA-API: the driver libraries are dlopen'd at
82
+ // run time, so building needs only their vendored MIT headers, and a
83
+ // machine without them still runs the engine.
84
+ cc::Build::new()
85
+ .file("native/nvenc_shim.c")
86
+ .include("vendor/nv-codec-headers/include")
87
+ .compile("dlnvenc");
88
+ cc::Build::new()
89
+ .file("native/vaapi_shim.c")
90
+ .include("vendor/libva")
91
+ .compile("dlvaapi");
92
+ println!("cargo:rustc-link-lib=dl");
72
93
  cc::Build::new()
73
94
  .file("native/agent_overlay_x11.c")
74
95
  .file("native/agent_overlay_wayland.c")
@@ -114,6 +135,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
114
135
  );
115
136
  println!("cargo:rustc-link-lib=static=vpx");
116
137
  println!("cargo:rustc-cfg=desklink_vpx");
138
+ // H.264 for receivers that decode it in hardware; VideoToolbox is a
139
+ // system framework, so linking it adds no dependency.
140
+ cc::Build::new().file("native/vt_shim.c").compile("dlvt");
141
+ println!("cargo:rustc-link-lib=framework=VideoToolbox");
142
+ println!("cargo:rustc-link-lib=framework=CoreFoundation");
117
143
  }
118
144
  println!("cargo:rustc-link-lib=framework=CoreGraphics");
119
145
  println!("cargo:rustc-link-lib=framework=ApplicationServices");