@desklink/host 0.5.7 → 0.5.9
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/dist/protocol.d.ts +1 -0
- package/dist/protocol.d.ts.map +1 -1
- package/docs/PROTOCOL.md +49 -5
- package/engine/Cargo.lock +2 -1
- package/engine/Cargo.toml +5 -2
- package/engine/native/agent_overlay_wayland.c +46 -18
- package/engine/src/hyprland.rs +38 -3
- package/engine/src/indicator.rs +34 -10
- package/engine/src/main.rs +115 -15
- package/engine/src/peer.rs +290 -18
- package/engine/src/session.rs +257 -23
- package/engine/vendor/rtc-ice/DESKLINK-PATCH.md +2 -2
- package/engine/vendor/rtc-ice/src/agent/agent_selector.rs +1 -1
- package/engine/vendor/rtc-ice/src/agent/mod.rs +1 -1
- package/engine/vendor/rtc-ice/src/dl_trace.rs +1 -1
- package/engine/vendor/rtc-ice/src/lib.rs +1 -1
- package/package.json +3 -3
package/dist/protocol.d.ts
CHANGED
package/dist/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAChD,sFAAsF;IACtF,GAAG,EAAE;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;KAAE,CAAC;IAC3D,OAAO,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;QAClB,0EAA0E;QAC1E,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,YAAY,CAAC,EAAE,KAAK,CAAC,UAAU,GAAG,QAAQ,CAAC,CAAC;QAC5C,gBAAgB,CAAC,EAAE;YAAE,GAAG,EAAE,OAAO,CAAC;YAAC,OAAO,EAAE,2BAA2B,CAAA;SAAE,CAAC;QAC1E,KAAK,EAAE,OAAO,CAAC;QACf;wEACgE;QAChE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,kDAAkD;QAClD,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,QAAQ,CAAC,EAAE,KAAK,CAAC;YACb,EAAE,EAAE,MAAM,CAAC;YACX,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;YACf,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE;gBAAE,KAAK,EAAE,MAAM,CAAC;gBAAC,MAAM,EAAE,MAAM,CAAA;aAAE,CAAC;YAC1C,MAAM,EAAE;gBAAE,CAAC,EAAE,MAAM,CAAC;gBAAC,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC;YACjC,IAAI,EAAE,OAAO,CAAC;SACjB,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,kBAAkB,CAAC,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC;KAClE,CAAC;IACF,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IAChD,KAAK,EAAE;QACH,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,OAAO,CAAC;QACjB,KAAK,EAAE,OAAO,CAAC;QACf,QAAQ,EAAE,OAAO,CAAC;QAClB,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,kBAAkB,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC;QAC9D,KAAK,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,SAAS,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CAClF;AAED,MAAM,WAAW,eAAe;IAC5B,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,MAAM,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACpC;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExC,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,aAAa,CAAC;IACzD,SAAS,EAAE,OAAO,CAAC;IACnB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,2BAA2B,CAAC;IACrC,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACtB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IAC/B,6EAA6E;IAC7E,MAAM,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAC;IAC/B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,SAAS,GAAG,WAAW,CAAC,CAAC;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yGAAyG;IACzG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,+EAA+E;IAC/E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;KACpC,CAAC;IACF,QAAQ,EAAE,eAAe,CAAC;CAC7B;AAED,MAAM,MAAM,WAAW,GACjB;IAAE,KAAK,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAA;CAAE,GAC5J;IAAE,KAAK,EAAE,qBAAqB,CAAC;IAAC,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE;YAAE,IAAI,EAAE,OAAO,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
package/docs/PROTOCOL.md
CHANGED
|
@@ -265,6 +265,20 @@ rate and X11 capture loop; portal capture offers it as the preferred PipeWire
|
|
|
265
265
|
frame rate, and macOS sets its ScreenCaptureKit stream minimum frame interval.
|
|
266
266
|
A source may still supply fewer frames.
|
|
267
267
|
|
|
268
|
+
`ice_servers` carries the STUN/TURN servers the user brought, one object per
|
|
269
|
+
server with every URL that server lists. Each URL an entry lists reaches the
|
|
270
|
+
WebRTC stack with that entry's `username` and `credential` — listing
|
|
271
|
+
`stun:a` and `stun:b` in one entry uses both, so a fallback behind an
|
|
272
|
+
unreachable primary still gathers candidates. A TURN URL (`turn:`/`turns:`)
|
|
273
|
+
whose transport is not UDP — `?transport=tcp`, or a bare `turns:` URL, which
|
|
274
|
+
is TLS over TCP by default — is one the WebRTC stack cannot dial: the engine
|
|
275
|
+
leaves it out of the configuration and reports it once with a
|
|
276
|
+
`session.iceServerSkipped` warning event naming the URL, so a skipped URL is
|
|
277
|
+
never a silent drop. Everything else in the entry — including a URL the
|
|
278
|
+
parser cannot read — is handed to the WebRTC stack unchanged, whose own
|
|
279
|
+
verdict then applies: for example a `turn:` URL on an entry without both a
|
|
280
|
+
`username` and a `credential` refuses the open in the stack's own words.
|
|
281
|
+
|
|
268
282
|
`agent_indicator` is opt-in local feedback for an agent controller; desklink-axi
|
|
269
283
|
sets it for sessions it drives (except Windows); human phone control omits it. On
|
|
270
284
|
Linux it adds an eased arrow inside a halo that brightens on clicks and keys,
|
|
@@ -272,9 +286,14 @@ animating in and out, with light and dark keylines so it reads on any content.
|
|
|
272
286
|
On Wayland it uses a click-through layer-shell surface with an edge glow, drawn
|
|
273
287
|
at the highest announced output integer scale, capped at 4; its bounded area is
|
|
274
288
|
masked before capture/diff (pixels behind the effect can remain briefly stale).
|
|
275
|
-
On a located Hyprland window share
|
|
276
|
-
the
|
|
277
|
-
|
|
289
|
+
On a located Hyprland window share each pointer cue goes to the desktop point
|
|
290
|
+
the pointer landed on — the window's place plus the tapped point (see Input and
|
|
291
|
+
clipboard) — and the window's picture holds no layer surface, so nothing is
|
|
292
|
+
masked; a refused tap draws no cue. When a tap lands on another output than
|
|
293
|
+
the cue helper is on, the engine moves the helper there — respawning it with
|
|
294
|
+
the landed layout point, which selects that output exactly like a point
|
|
295
|
+
marker — and the cue draws at the landed point with its edge glow; a tap on
|
|
296
|
+
the helper's own output reuses it with no new process. On bare X11 it is an override-redirect, click-through window that follows the
|
|
278
297
|
pointer, so it stays
|
|
279
298
|
visible over windows that set their own cursor and never replaces the cursor.
|
|
280
299
|
Its size follows `Xft.dpi` from 96–384 DPI, defaulting to 1x otherwise;
|
|
@@ -313,6 +332,17 @@ the SDP and candidates to the client and brings back the answer.
|
|
|
313
332
|
"description":{"type":"offer","sdp":"v=0\r\n…"}}}
|
|
314
333
|
```
|
|
315
334
|
|
|
335
|
+
A renegotiation offer may include `geometry` when the captured source changes
|
|
336
|
+
size. It uses the same shape as the `session.open` result; consumers should
|
|
337
|
+
apply its encoded dimensions to the presented surface. Older hosts omit it.
|
|
338
|
+
|
|
339
|
+
```jsonc
|
|
340
|
+
{"event":"session.description","params":{"sessionId":"…","generation":1,
|
|
341
|
+
"description":{"type":"offer","sdp":"v=0\r\n…"},
|
|
342
|
+
"geometry":{"source":{"width":1200,"height":600},
|
|
343
|
+
"encoded":{"width":1200,"height":600},"origin":{"x":0,"y":0}}}}
|
|
344
|
+
```
|
|
345
|
+
|
|
316
346
|
```jsonc
|
|
317
347
|
{"id":5,"method":"session.description","params":{"session_id":"…","generation":1,
|
|
318
348
|
"description":{"type":"answer","sdp":"v=0\r\n…"}}}
|
|
@@ -382,6 +412,12 @@ lease, or guarantee recovery within 2 seconds. Engine-side ends remain terminal.
|
|
|
382
412
|
// "description":{"type":"offer","sdp":"v=0\r\n…"}}}
|
|
383
413
|
```
|
|
384
414
|
|
|
415
|
+
The engine offers UDP host candidates on every IPv4 interface and, when this
|
|
416
|
+
computer has an IPv6 address other than loopback and link-local, on every such
|
|
417
|
+
IPv6 address too. A phone off home Wi-Fi often has only a carrier IPv6 address,
|
|
418
|
+
and that is its one direct path here. Loopback and link-local addresses are
|
|
419
|
+
never offered.
|
|
420
|
+
|
|
385
421
|
With `loopback_tcp`, the engine also listens for ICE over TCP on
|
|
386
422
|
`127.0.0.1` and offers that passive candidate. It is for a client whose only
|
|
387
423
|
way to this computer is a forward of its loopback, such as an SSH tunnel: the
|
|
@@ -491,7 +527,9 @@ FIR), and when the coded size changes that way, so a receiver never has to scale
|
|
|
491
527
|
references across a size change. `target_kbps` is the current rate target after
|
|
492
528
|
any back-off: for a standing queue on the path, measured from the receiver's
|
|
493
529
|
transport-wide congestion feedback (RTP `transport-cc`), and for the loss
|
|
494
|
-
its receiver reports carry.
|
|
530
|
+
its receiver reports carry. A path that runs over ICE-TCP backs off only on a
|
|
531
|
+
queue above 100 ms, not 25 ms, so a relay's delivery jitter does not pull the
|
|
532
|
+
target to its floor. It starts at the requested ceiling capped at
|
|
495
533
|
3000 kbps on an unknown link, then grows toward the ceiling on clean
|
|
496
534
|
loss/delay feedback. `codec` is what frames go out in
|
|
497
535
|
(`vp9` or `h264`) and `encoder` what codes them (`libvpx`, `videotoolbox`,
|
|
@@ -600,7 +638,13 @@ label. A new point replaces the previous one and restarts its timer.
|
|
|
600
638
|
Coordinates are integers in the **selected desktop's original pixels**, top-left
|
|
601
639
|
origin, before video scaling (`geometry.source`, not `geometry.encoded`). On X11
|
|
602
640
|
this is the root screen; on macOS it is the selected display, with native pixels
|
|
603
|
-
converted to display points.
|
|
641
|
+
converted to display points. On a located Hyprland window share (see Input and
|
|
642
|
+
clipboard) they are the window's own pixels, and the ring shows on the desktop
|
|
643
|
+
point a press there would land, on the output holding it; when a later point
|
|
644
|
+
lands on another output the helper moves there, and a point on its own output
|
|
645
|
+
reuses it with no new process. A point the window
|
|
646
|
+
cannot take there is refused with `indicator-unavailable` and the reason. Both
|
|
647
|
+
coordinates must be within its bounds. The
|
|
604
648
|
ring may clip at an edge; its label stays inside the display. `timeout_ms`
|
|
605
649
|
defaults to 3000 and must be an integer from 1 to 120000. Labels are at most 96
|
|
606
650
|
printable ASCII bytes, including spaces; other labels are refused rather than
|
package/engine/Cargo.lock
CHANGED
|
@@ -536,7 +536,7 @@ checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
|
|
536
536
|
|
|
537
537
|
[[package]]
|
|
538
538
|
name = "desklink-host"
|
|
539
|
-
version = "0.5.
|
|
539
|
+
version = "0.5.9"
|
|
540
540
|
dependencies = [
|
|
541
541
|
"anyhow",
|
|
542
542
|
"ashpd",
|
|
@@ -557,6 +557,7 @@ dependencies = [
|
|
|
557
557
|
"pipewire",
|
|
558
558
|
"rand 0.8.8",
|
|
559
559
|
"rtc",
|
|
560
|
+
"rtc-ice",
|
|
560
561
|
"serde",
|
|
561
562
|
"serde_json",
|
|
562
563
|
"sha2",
|
package/engine/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "desklink-host"
|
|
3
|
-
version = "0.5.
|
|
3
|
+
version = "0.5.9"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
rust-version = "1.97.1"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -18,7 +18,7 @@ base64 = "0.22"
|
|
|
18
18
|
|
|
19
19
|
[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))'.dependencies]
|
|
20
20
|
anyhow = "1"
|
|
21
|
-
tokio = { version = "1", features = ["rt-multi-thread", "macros", "io-util", "io-std", "sync", "time", "signal"] }
|
|
21
|
+
tokio = { version = "1", features = ["rt-multi-thread", "macros", "io-util", "io-std", "sync", "time", "signal", "net"] }
|
|
22
22
|
libc = "0.2"
|
|
23
23
|
bytes = "1"
|
|
24
24
|
# rtc-sctp 0.21.1 is required through this stack: 0.21.0 replaces an
|
|
@@ -27,6 +27,9 @@ bytes = "1"
|
|
|
27
27
|
# session. Cargo.lock pins 0.21.1; drop the pin when a later release carries it.
|
|
28
28
|
webrtc = { version = "0.21", default-features = false, features = ["runtime-tokio", "crypto-ring"] }
|
|
29
29
|
rtc = { version = "0.21", default-features = false, features = ["crypto-ring"] }
|
|
30
|
+
# Parses ice server URLs when the engine sorts out which ones the WebRTC
|
|
31
|
+
# stack can dial; the [patch.crates-io] entry below keeps this the vendored copy.
|
|
32
|
+
rtc-ice = { version = "0.21", default-features = false }
|
|
30
33
|
log = "0.4"
|
|
31
34
|
async-trait = "0.1"
|
|
32
35
|
rand = "0.8"
|
|
@@ -97,7 +97,26 @@ struct Overlay {
|
|
|
97
97
|
struct wl_surface *surface;
|
|
98
98
|
struct Buffer buffers[2];
|
|
99
99
|
int width, height, scale, source_w, source_h, configured, closed;
|
|
100
|
+
// Desktop mode: points are compositor layout coordinates, drawn only on
|
|
101
|
+
// the output this surface is on (`mine`), never scaled onto another.
|
|
102
|
+
int desktop; struct Output *mine;
|
|
100
103
|
};
|
|
104
|
+
static int locate(struct Overlay *o, double px, double py, double *x, double *y) {
|
|
105
|
+
if(!o->desktop)return desklink_wayland_geometry(o->source_w,o->source_h,o->width,o->height,px,py,x,y);
|
|
106
|
+
struct Output *m=o->mine;
|
|
107
|
+
if(!m||!m->valid||px<m->x||py<m->y||px>=m->x+m->w||py>=m->y+m->h)return 0;
|
|
108
|
+
*x=px-m->x;*y=py-m->y;
|
|
109
|
+
return 1;
|
|
110
|
+
}
|
|
111
|
+
static void surface_enter(void *data, struct wl_surface *surface, struct wl_output *output) {
|
|
112
|
+
(void)surface;struct Overlay *o=data;
|
|
113
|
+
for(int i=0;i<o->output_count;i++)if(o->outputs[i].handle==output)o->mine=&o->outputs[i];
|
|
114
|
+
}
|
|
115
|
+
static void surface_leave(void *data, struct wl_surface *surface, struct wl_output *output) {
|
|
116
|
+
(void)surface;struct Overlay *o=data;
|
|
117
|
+
if(o->mine&&o->mine->handle==output)o->mine=NULL;
|
|
118
|
+
}
|
|
119
|
+
static const struct wl_surface_listener surface_listener={.enter=surface_enter,.leave=surface_leave};
|
|
101
120
|
static double now(void) { struct timespec t; clock_gettime(CLOCK_MONOTONIC,&t); return t.tv_sec+t.tv_nsec/1e9; }
|
|
102
121
|
static void registry_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) {
|
|
103
122
|
struct Overlay *o=data;
|
|
@@ -214,9 +233,9 @@ static void draw_point(struct Overlay *o,struct Buffer *b,double x,double y,cons
|
|
|
214
233
|
}
|
|
215
234
|
}
|
|
216
235
|
|
|
217
|
-
static int overlay_main(int source_w,int source_h,int point_mode,int origin_known,int origin_x,int origin_y) {
|
|
236
|
+
static int overlay_main(int source_w,int source_h,int point_mode,int origin_known,int origin_x,int origin_y,int desktop) {
|
|
218
237
|
|
|
219
|
-
struct Overlay o={.source_w=source_w,.source_h=source_h,.scale=1};
|
|
238
|
+
struct Overlay o={.source_w=source_w,.source_h=source_h,.scale=1,.desktop=desktop};
|
|
220
239
|
o.display=wl_display_connect(NULL);
|
|
221
240
|
if(!o.display)return 2;
|
|
222
241
|
struct wl_registry *registry=wl_display_get_registry(o.display);
|
|
@@ -225,18 +244,20 @@ static int overlay_main(int source_w,int source_h,int point_mode,int origin_know
|
|
|
225
244
|
if(!o.shell){puts("layer_shell_unavailable");fflush(stdout);wl_display_disconnect(o.display);return 2;}
|
|
226
245
|
if(!o.compositor||!o.shm){wl_display_disconnect(o.display);return 2;}
|
|
227
246
|
struct wl_output *selected=NULL;int matches=0;
|
|
228
|
-
if(point_mode) {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
wl_proxy_add_listener(out->logical,logical_listener,out);
|
|
234
|
-
}
|
|
235
|
-
if(wl_display_roundtrip(o.display)<0)return 2;
|
|
247
|
+
if((point_mode||desktop) && o.output_manager) {
|
|
248
|
+
for(int i=0;i<o.output_count;i++) {
|
|
249
|
+
struct Output *out=&o.outputs[i];
|
|
250
|
+
out->logical=wl_proxy_marshal_flags(o.output_manager,1,&xdg_output_interface,wl_proxy_get_version(o.output_manager),0,NULL,out->handle);
|
|
251
|
+
wl_proxy_add_listener(out->logical,logical_listener,out);
|
|
236
252
|
}
|
|
253
|
+
if(wl_display_roundtrip(o.display)<0)return 2;
|
|
254
|
+
}
|
|
255
|
+
// Point markers always name their output; a desktop agent cue does once
|
|
256
|
+
// the engine has seen a press land, so the cue opens on that output.
|
|
257
|
+
if(point_mode || (desktop && origin_known)) {
|
|
237
258
|
for(int i=0;i<o.output_count;i++) {
|
|
238
259
|
struct Output *out=&o.outputs[i];
|
|
239
|
-
if(origin_known && out->valid && origin_x>=out->x && origin_y>=out->y && origin_x<out->x+out->w && origin_y<out->y+out->h){selected=out->handle;matches++;}
|
|
260
|
+
if(origin_known && out->valid && origin_x>=out->x && origin_y>=out->y && origin_x<out->x+out->w && origin_y<out->y+out->h){selected=out->handle;o.mine=out;matches++;}
|
|
240
261
|
}
|
|
241
262
|
if(matches>1)selected=NULL;
|
|
242
263
|
if(!selected && o.output_count==1 && (!origin_known || !o.output_manager))selected=o.outputs[0].handle;
|
|
@@ -250,6 +271,9 @@ static int overlay_main(int source_w,int source_h,int point_mode,int origin_know
|
|
|
250
271
|
FT_Library library=NULL;FT_Face font=point_mode?point_font(&library):NULL;
|
|
251
272
|
if(point_mode&&!font){wl_display_disconnect(o.display);return 2;}
|
|
252
273
|
o.surface=wl_compositor_create_surface(o.compositor);
|
|
274
|
+
// A desktop surface learns which output it is on, whether the compositor
|
|
275
|
+
// placed it or a layout origin selected it.
|
|
276
|
+
if(desktop)wl_surface_add_listener(o.surface,&surface_listener,&o);
|
|
253
277
|
o.layer=wl_proxy_marshal_flags(o.shell,0,&layer_surface_interface,1,0,NULL,o.surface,selected,3,point_mode?"desklink-point":"desklink-agent");
|
|
254
278
|
wl_proxy_add_listener(o.layer,layer_listener,&o);
|
|
255
279
|
uint32_t anchor,keyboard_focus,empty_input;
|
|
@@ -289,19 +313,23 @@ static int overlay_main(int source_w,int source_h,int point_mode,int origin_know
|
|
|
289
313
|
if(point_mode && kind=='P') {
|
|
290
314
|
unsigned timeout=0;int offset=0;
|
|
291
315
|
if(sscanf(pending,"P %lf %lf %u %n",&px,&py,&timeout,&offset)==3 && offset && timeout>=1 && timeout<=120000 && strlen(pending+offset)<=96) {
|
|
292
|
-
|
|
293
|
-
|
|
316
|
+
snprintf(label,sizeof(label),"%s",pending+offset);deadline=now()+timeout/1000.0;active=1;dirty=1;
|
|
317
|
+
visible=locate(&o,px,py,&x,&y);
|
|
294
318
|
}
|
|
295
319
|
}
|
|
296
320
|
else if(kind=='S')ending=now();
|
|
297
321
|
else if(kind=='M'||kind=='C'||kind=='T'||kind=='A') {
|
|
322
|
+
int placed=1;
|
|
298
323
|
if(px>=0&&py>=0) {
|
|
299
|
-
|
|
300
|
-
|
|
324
|
+
placed=locate(&o,px,py,&tx,&ty);
|
|
325
|
+
if(placed && !positioned){x=tx;y=ty;positioned=1;cue_started=now();}
|
|
326
|
+
// A desktop point off this output has no place here:
|
|
327
|
+
// the cue hides rather than show anywhere else.
|
|
328
|
+
if(!placed && o.desktop){positioned=0;cue_started=0;}
|
|
301
329
|
}
|
|
302
330
|
if(!active)started=now();
|
|
303
331
|
active=1;
|
|
304
|
-
if(kind=='C')click=now();
|
|
332
|
+
if(kind=='C' && (placed||!o.desktop))click=now();
|
|
305
333
|
if(kind=='T')typed=now();
|
|
306
334
|
}
|
|
307
335
|
}
|
|
@@ -331,8 +359,8 @@ static int overlay_main(int source_w,int source_h,int point_mode,int origin_know
|
|
|
331
359
|
return 0;
|
|
332
360
|
}
|
|
333
361
|
|
|
334
|
-
int desklink_agent_overlay_wayland(int w,int h){return overlay_main(w,h,0,
|
|
335
|
-
int desklink_point_overlay_wayland(int w,int h,int known,int x,int y){return overlay_main(w,h,1,known,x,y);}
|
|
362
|
+
int desklink_agent_overlay_wayland(int w,int h,int desktop,int known,int x,int y){return overlay_main(w,h,0,known,x,y,desktop);}
|
|
363
|
+
int desklink_point_overlay_wayland(int w,int h,int known,int x,int y,int desktop){return overlay_main(w,h,1,known,x,y,desktop);}
|
|
336
364
|
|
|
337
365
|
// Read-only capability probe for idempotent clear before a helper exists.
|
|
338
366
|
int desklink_wayland_layer_shell_available(void) {
|
package/engine/src/hyprland.rs
CHANGED
|
@@ -84,8 +84,18 @@ impl WindowLocator {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
/// Put the pointer on `(x, y)` in the shared window's own pixels
|
|
88
|
-
|
|
87
|
+
/// Put the pointer on `(x, y)` in the shared window's own pixels, and say
|
|
88
|
+
/// which desktop point that was.
|
|
89
|
+
pub fn place(&self, x: i64, y: i64) -> Result<(i64, i64), String> {
|
|
90
|
+
let (px, py) = self.locate(x, y)?;
|
|
91
|
+
let point = (px.floor() as i64, py.floor() as i64);
|
|
92
|
+
self.warp(point)?;
|
|
93
|
+
Ok(point)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/// The desktop point `(x, y)` in the shared window's own pixels shows
|
|
97
|
+
/// at, when a press there would reach the window.
|
|
98
|
+
pub fn locate(&self, x: i64, y: i64) -> Result<(f64, f64), String> {
|
|
89
99
|
let (clients, monitors) = (query("j/clients")?, query("j/monitors")?);
|
|
90
100
|
let clients = clients.as_array().map(Vec::as_slice).unwrap_or_default();
|
|
91
101
|
// A window nobody sees has no point on the screen.
|
|
@@ -222,7 +232,7 @@ impl WindowLocator {
|
|
|
222
232
|
"a shared window cannot take taps where an overlay covers it",
|
|
223
233
|
));
|
|
224
234
|
}
|
|
225
|
-
|
|
235
|
+
Ok((px, py))
|
|
226
236
|
}
|
|
227
237
|
|
|
228
238
|
/// The address of the one window Hyprland said it is sharing.
|
|
@@ -293,6 +303,31 @@ impl WindowLocator {
|
|
|
293
303
|
}
|
|
294
304
|
}
|
|
295
305
|
|
|
306
|
+
/// The name of the monitor holding desktop point `(px, py)`, if any.
|
|
307
|
+
/// Geometry math matches `WindowLocator::locate`'s on-screen check, so a
|
|
308
|
+
/// point a press landed on maps to the output whose overlay must draw it.
|
|
309
|
+
pub fn monitor_containing(px: f64, py: f64) -> Result<Option<String>, String> {
|
|
310
|
+
let monitors = query("j/monitors")?;
|
|
311
|
+
for monitor in monitors.as_array().into_iter().flatten() {
|
|
312
|
+
if monitor["disabled"].as_bool() == Some(true) {
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
let scale = monitor["scale"].as_f64().filter(|scale| *scale > 0.0);
|
|
316
|
+
if let (Some(mx), Some(my), Some(mw), Some(mh), Some(scale)) = (
|
|
317
|
+
monitor["x"].as_f64(),
|
|
318
|
+
monitor["y"].as_f64(),
|
|
319
|
+
monitor["width"].as_f64(),
|
|
320
|
+
monitor["height"].as_f64(),
|
|
321
|
+
scale,
|
|
322
|
+
) {
|
|
323
|
+
if (mx..mx + mw / scale).contains(&px) && (my..my + mh / scale).contains(&py) {
|
|
324
|
+
return Ok(monitor["name"].as_str().map(str::to_owned));
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
Ok(None)
|
|
329
|
+
}
|
|
330
|
+
|
|
296
331
|
/// A window's box in the layout: left, top, width, height.
|
|
297
332
|
fn bounds(window: &Value) -> Option<(f64, f64, f64, f64)> {
|
|
298
333
|
let pair = |key: &str| Some((window[key][0].as_f64()?, window[key][1].as_f64()?));
|
package/engine/src/indicator.rs
CHANGED
|
@@ -157,11 +157,14 @@ impl Indicator {
|
|
|
157
157
|
)
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
/// `desktop`: points are compositor layout coordinates, drawn on the
|
|
161
|
+
/// output that holds `position`.
|
|
160
162
|
#[cfg(target_os = "linux")]
|
|
161
163
|
pub fn start_point_wayland(
|
|
162
164
|
width: i32,
|
|
163
165
|
height: i32,
|
|
164
166
|
position: Option<(i32, i32)>,
|
|
167
|
+
desktop: bool,
|
|
165
168
|
) -> Result<Self> {
|
|
166
169
|
let (x, y) = position.unwrap_or_default();
|
|
167
170
|
Self::spawn(
|
|
@@ -173,6 +176,7 @@ impl Indicator {
|
|
|
173
176
|
i32::from(position.is_some()).to_string(),
|
|
174
177
|
x.to_string(),
|
|
175
178
|
y.to_string(),
|
|
179
|
+
i32::from(desktop).to_string(),
|
|
176
180
|
]),
|
|
177
181
|
1.0,
|
|
178
182
|
1.0,
|
|
@@ -217,17 +221,30 @@ impl Indicator {
|
|
|
217
221
|
}
|
|
218
222
|
}
|
|
219
223
|
|
|
224
|
+
/// `desktop`: cues are compositor layout coordinates, drawn only where
|
|
225
|
+
/// they fall on the output the overlay opened on. `origin` selects that
|
|
226
|
+
/// output by layout point, reusing the point helper's xdg-output
|
|
227
|
+
/// selection; without one the compositor places the surface.
|
|
220
228
|
#[cfg(target_os = "linux")]
|
|
221
|
-
pub fn start_wayland(
|
|
229
|
+
pub fn start_wayland(
|
|
230
|
+
width: usize,
|
|
231
|
+
height: usize,
|
|
232
|
+
desktop: bool,
|
|
233
|
+
origin: Option<(i32, i32)>,
|
|
234
|
+
) -> Result<Self> {
|
|
222
235
|
let executable = std::env::current_exe()?;
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
236
|
+
let mut command = Command::new(executable);
|
|
237
|
+
command
|
|
238
|
+
.arg("agent-overlay-wayland")
|
|
239
|
+
.arg(width.to_string())
|
|
240
|
+
.arg(height.to_string());
|
|
241
|
+
if desktop {
|
|
242
|
+
command.arg("desktop");
|
|
243
|
+
if let Some((x, y)) = origin {
|
|
244
|
+
command.arg(x.to_string()).arg(y.to_string());
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
Self::spawn(&mut command, 1.0, 1.0)
|
|
231
248
|
}
|
|
232
249
|
|
|
233
250
|
#[cfg(target_os = "linux")]
|
|
@@ -362,7 +379,14 @@ mod tests {
|
|
|
362
379
|
};
|
|
363
380
|
let mut drained = vec![];
|
|
364
381
|
for _ in 0..200 {
|
|
365
|
-
|
|
382
|
+
// Each drain re-reports the last two remembered states, so the
|
|
383
|
+
// same state can arrive in several drains when the helper's lines
|
|
384
|
+
// are split across reads. Keep each state once, in pipe order.
|
|
385
|
+
for cue in feed.drain() {
|
|
386
|
+
if !drained.contains(&cue.x) {
|
|
387
|
+
drained.push(cue.x);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
366
390
|
if drained.len() >= 3 {
|
|
367
391
|
break;
|
|
368
392
|
}
|
package/engine/src/main.rs
CHANGED
|
@@ -136,9 +136,23 @@ use tokio::sync::mpsc as tokio_mpsc;
|
|
|
136
136
|
unsafe extern "C" {
|
|
137
137
|
fn desklink_point_overlay_main(display: *const std::ffi::c_char) -> i32;
|
|
138
138
|
fn desklink_agent_overlay_main(display: *const std::ffi::c_char) -> i32;
|
|
139
|
-
fn desklink_agent_overlay_wayland(
|
|
139
|
+
fn desklink_agent_overlay_wayland(
|
|
140
|
+
source_w: i32,
|
|
141
|
+
source_h: i32,
|
|
142
|
+
desktop: i32,
|
|
143
|
+
origin_known: i32,
|
|
144
|
+
origin_x: i32,
|
|
145
|
+
origin_y: i32,
|
|
146
|
+
) -> i32;
|
|
140
147
|
fn desklink_wayland_layer_shell_available() -> i32;
|
|
141
|
-
fn desklink_point_overlay_wayland(
|
|
148
|
+
fn desklink_point_overlay_wayland(
|
|
149
|
+
w: i32,
|
|
150
|
+
h: i32,
|
|
151
|
+
known: i32,
|
|
152
|
+
x: i32,
|
|
153
|
+
y: i32,
|
|
154
|
+
desktop: i32,
|
|
155
|
+
) -> i32;
|
|
142
156
|
}
|
|
143
157
|
|
|
144
158
|
#[cfg(target_os = "linux")]
|
|
@@ -183,12 +197,17 @@ fn main() {
|
|
|
183
197
|
},
|
|
184
198
|
"point-overlay-wayland" => {
|
|
185
199
|
let values: Vec<i32> = args.iter().skip(1).filter_map(|v| v.parse().ok()).collect();
|
|
186
|
-
if values.len()
|
|
200
|
+
if !(5..=6).contains(&values.len()) || values[0] <= 0 || values[1] <= 0 {
|
|
187
201
|
2
|
|
188
202
|
} else {
|
|
189
203
|
unsafe {
|
|
190
204
|
desklink_point_overlay_wayland(
|
|
191
|
-
values[0],
|
|
205
|
+
values[0],
|
|
206
|
+
values[1],
|
|
207
|
+
values[2],
|
|
208
|
+
values[3],
|
|
209
|
+
values[4],
|
|
210
|
+
values.get(5).copied().unwrap_or(0),
|
|
192
211
|
)
|
|
193
212
|
}
|
|
194
213
|
}
|
|
@@ -199,7 +218,22 @@ fn main() {
|
|
|
199
218
|
if width <= 0 || height <= 0 {
|
|
200
219
|
2
|
|
201
220
|
} else {
|
|
202
|
-
|
|
221
|
+
let desktop = i32::from(args.get(3).map(String::as_str) == Some("desktop"));
|
|
222
|
+
// A desktop cue respawned after a press names the layout
|
|
223
|
+
// point that chose its output: `w h desktop ox oy`.
|
|
224
|
+
let (known, ox, oy) = match (args.get(4), args.get(5)) {
|
|
225
|
+
(Some(x), Some(y)) => match (x.parse(), y.parse()) {
|
|
226
|
+
(Ok(x), Ok(y)) => (1, x, y),
|
|
227
|
+
_ => (0, 0, 0),
|
|
228
|
+
},
|
|
229
|
+
_ => (0, 0, 0),
|
|
230
|
+
};
|
|
231
|
+
let (known, ox, oy) = if desktop == 1 {
|
|
232
|
+
(known, ox, oy)
|
|
233
|
+
} else {
|
|
234
|
+
(0, 0, 0)
|
|
235
|
+
};
|
|
236
|
+
unsafe { desklink_agent_overlay_wayland(width, height, desktop, known, ox, oy) }
|
|
203
237
|
}
|
|
204
238
|
}
|
|
205
239
|
"capabilities" => {
|
|
@@ -529,6 +563,47 @@ async fn serve() -> Result<()> {
|
|
|
529
563
|
Ok(())
|
|
530
564
|
}
|
|
531
565
|
|
|
566
|
+
/// Splits the requested ICE servers into the configuration the peer gets and
|
|
567
|
+
/// the URLs this engine leaves out. Every URL the WebRTC stack can dial goes
|
|
568
|
+
/// through with its entry's username and credential — all of an entry's URLs,
|
|
569
|
+
/// so a fallback behind an unreachable primary still gathers candidates. A
|
|
570
|
+
/// TURN URL whose transport is not UDP is one the stack cannot dial, so it is
|
|
571
|
+
/// skipped here and reported once by the caller, never dropped silently. A
|
|
572
|
+
/// URL the parser cannot read is forwarded unchanged: the peer connection
|
|
573
|
+
/// owns that verdict and refuses the open in its own words.
|
|
574
|
+
#[cfg(any(
|
|
575
|
+
target_os = "linux",
|
|
576
|
+
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
577
|
+
))]
|
|
578
|
+
fn usable_ice_servers(
|
|
579
|
+
servers: Vec<protocol::IceServerParam>,
|
|
580
|
+
) -> (
|
|
581
|
+
Vec<(Vec<String>, Option<String>, Option<String>)>,
|
|
582
|
+
Vec<String>,
|
|
583
|
+
) {
|
|
584
|
+
use rtc_ice::url::{ProtoType, SchemeType, Url};
|
|
585
|
+
let mut usable = Vec::new();
|
|
586
|
+
let mut skipped = Vec::new();
|
|
587
|
+
for server in servers {
|
|
588
|
+
let mut urls = Vec::with_capacity(server.urls.len());
|
|
589
|
+
for url in server.urls {
|
|
590
|
+
let undialable = Url::parse_url(&url).is_ok_and(|parsed| {
|
|
591
|
+
matches!(parsed.scheme, SchemeType::Turn | SchemeType::Turns)
|
|
592
|
+
&& parsed.proto != ProtoType::Udp
|
|
593
|
+
});
|
|
594
|
+
if undialable {
|
|
595
|
+
skipped.push(url);
|
|
596
|
+
} else {
|
|
597
|
+
urls.push(url);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
if !urls.is_empty() {
|
|
601
|
+
usable.push((urls, server.username, server.credential));
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
(usable, skipped)
|
|
605
|
+
}
|
|
606
|
+
|
|
532
607
|
#[cfg(any(
|
|
533
608
|
target_os = "linux",
|
|
534
609
|
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
@@ -603,6 +678,10 @@ fn render_event(notice: session::Notice) -> Option<String> {
|
|
|
603
678
|
"session.capture.stopped",
|
|
604
679
|
serde_json::json!({ "sessionId": session_id, "reason": reason }),
|
|
605
680
|
),
|
|
681
|
+
session::SessionEvent::IceServerSkipped { url } => (
|
|
682
|
+
"session.iceServerSkipped",
|
|
683
|
+
serde_json::json!({ "sessionId": session_id, "url": url }),
|
|
684
|
+
),
|
|
606
685
|
session::SessionEvent::Revoked { reason, code } => (
|
|
607
686
|
"session.revoked",
|
|
608
687
|
serde_json::json!({ "sessionId": session_id, "reason": reason, "code": code }),
|
|
@@ -659,6 +738,7 @@ async fn dispatch(
|
|
|
659
738
|
}
|
|
660
739
|
let params: protocol::OpenParams = serde_json::from_value(request.params.clone())
|
|
661
740
|
.map_err(|error| ErrorBody::new("malformed", error.to_string()))?;
|
|
741
|
+
let usable = usable_ice_servers(params.ice_servers);
|
|
662
742
|
let open = session::OpenRequest {
|
|
663
743
|
source: params.source,
|
|
664
744
|
cursor: params.cursor,
|
|
@@ -672,16 +752,7 @@ async fn dispatch(
|
|
|
672
752
|
agent_indicator: params.agent_indicator,
|
|
673
753
|
local_frames: params.local_frames,
|
|
674
754
|
audio: params.audio,
|
|
675
|
-
ice_servers:
|
|
676
|
-
.ice_servers
|
|
677
|
-
.into_iter()
|
|
678
|
-
.filter_map(|server| {
|
|
679
|
-
server
|
|
680
|
-
.urls
|
|
681
|
-
.first()
|
|
682
|
-
.map(|url| (url.clone(), server.username, server.credential))
|
|
683
|
-
})
|
|
684
|
-
.collect(),
|
|
755
|
+
ice_servers: usable.0,
|
|
685
756
|
};
|
|
686
757
|
let session = session::Session::open(open, events.clone())
|
|
687
758
|
.await
|
|
@@ -700,6 +771,15 @@ async fn dispatch(
|
|
|
700
771
|
"agentIndicator": session.agent_indicator(),
|
|
701
772
|
"audio": session.audio_info(),
|
|
702
773
|
});
|
|
774
|
+
// URLs the WebRTC stack cannot dial were left out of the peer's
|
|
775
|
+
// configuration; each skipped one is named once instead of
|
|
776
|
+
// vanishing from a multi-URL entry without a trace.
|
|
777
|
+
for url in usable.1 {
|
|
778
|
+
let _ = events.send(session::Notice {
|
|
779
|
+
session_id: session.id().to_owned(),
|
|
780
|
+
event: session::SessionEvent::IceServerSkipped { url },
|
|
781
|
+
});
|
|
782
|
+
}
|
|
703
783
|
*current = Some(session);
|
|
704
784
|
Ok(result)
|
|
705
785
|
}
|
|
@@ -934,6 +1014,26 @@ mod tests {
|
|
|
934
1014
|
);
|
|
935
1015
|
}
|
|
936
1016
|
|
|
1017
|
+
#[test]
|
|
1018
|
+
fn the_skipped_ice_server_warning_names_the_url_once() {
|
|
1019
|
+
let line = render_event(session::Notice {
|
|
1020
|
+
session_id: String::from("session-1"),
|
|
1021
|
+
event: session::SessionEvent::IceServerSkipped {
|
|
1022
|
+
url: String::from("turn:turn.example.com:3478?transport=tcp"),
|
|
1023
|
+
},
|
|
1024
|
+
})
|
|
1025
|
+
.expect("a skipped-URL warning is renderable");
|
|
1026
|
+
let parsed: serde_json::Value = serde_json::from_str(&line).unwrap();
|
|
1027
|
+
assert_eq!(parsed["event"], "session.iceServerSkipped");
|
|
1028
|
+
assert_eq!(
|
|
1029
|
+
parsed["params"],
|
|
1030
|
+
serde_json::json!({
|
|
1031
|
+
"sessionId": "session-1",
|
|
1032
|
+
"url": "turn:turn.example.com:3478?transport=tcp"
|
|
1033
|
+
})
|
|
1034
|
+
);
|
|
1035
|
+
}
|
|
1036
|
+
|
|
937
1037
|
#[tokio::test]
|
|
938
1038
|
async fn the_state_notification_carries_exactly_what_the_document_promises() {
|
|
939
1039
|
let line = render_event(session::Notice {
|