@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.
@@ -208,6 +208,7 @@ export type EngineEvent = {
208
208
  type: 'offer';
209
209
  sdp: string;
210
210
  };
211
+ geometry?: SurfaceGeometry;
211
212
  };
212
213
  } | {
213
214
  event: 'session.candidate';
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
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 the cue gets no pointer or click feedback —
276
- the engine places the pointer itself, so a stream fraction is not the window's
277
- desktop point (see Input and clipboard); keys still show. On bare X11 it is an override-redirect, click-through window that follows the
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. It starts at the requested ceiling capped at
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. Both coordinates must be within its bounds. The
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.7"
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.7"
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
- if(o.output_manager) {
230
- for(int i=0;i<o.output_count;i++) {
231
- struct Output *out=&o.outputs[i];
232
- out->logical=wl_proxy_marshal_flags(o.output_manager,1,&xdg_output_interface,wl_proxy_get_version(o.output_manager),0,NULL,out->handle);
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
- desklink_wayland_geometry(o.source_w,o.source_h,o.width,o.height,px,py,&x,&y);
293
- snprintf(label,sizeof(label),"%s",pending+offset);deadline=now()+timeout/1000.0;active=1;dirty=1;visible=1;
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
- if(desklink_wayland_geometry(o.source_w,o.source_h,o.width,o.height,px,py,&tx,&ty)
300
- && !positioned){x=tx;y=ty;positioned=1;cue_started=now();}
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,0,0,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) {
@@ -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
- pub fn place(&self, x: i64, y: i64) -> Result<(), String> {
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
- self.warp((px.floor() as i64, py.floor() as i64))
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()?));
@@ -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(width: usize, height: usize) -> Result<Self> {
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
- Self::spawn(
224
- Command::new(executable)
225
- .arg("agent-overlay-wayland")
226
- .arg(width.to_string())
227
- .arg(height.to_string()),
228
- 1.0,
229
- 1.0,
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
- drained.extend(feed.drain().into_iter().map(|cue| cue.x));
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
  }
@@ -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(source_w: i32, source_h: i32) -> i32;
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(w: i32, h: i32, known: i32, x: i32, y: i32) -> i32;
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() != 5 || values[0] <= 0 || values[1] <= 0 {
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], values[1], values[2], values[3], values[4],
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
- unsafe { desklink_agent_overlay_wayland(width, height) }
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: params
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 {