@desklink/host 0.5.9 → 0.5.11

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.
@@ -714,6 +714,8 @@ pub struct OpenRequest {
714
714
  pub local_frames: bool,
715
715
  /// Capture the desktop's own system audio for `session.audio`.
716
716
  pub audio: bool,
717
+ /// Listen to the desktop's own pointer buttons, cursor and keys.
718
+ pub observe_input: bool,
717
719
  }
718
720
 
719
721
  /// Events a session raises for its consumer.
@@ -755,6 +757,11 @@ pub enum SessionEvent {
755
757
  Input {
756
758
  input: serde_json::Value,
757
759
  },
760
+ /// A pointer button or key the person pressed, observed rather than applied.
761
+ Observed {
762
+ timestamp_us: u64,
763
+ input: crate::protocol::ObservedInput,
764
+ },
758
765
  /// The far end needs a fresh reference frame and only the consumer can make
759
766
  /// one: the encoder for this track is on its side. Raised by an RTCP PLI or
760
767
  /// FIR, and once when the transport connects, because everything sent before
@@ -854,6 +861,9 @@ struct Inner {
854
861
  #[cfg(target_os = "linux")]
855
862
  audio: Mutex<Option<crate::audio::AudioCapture>>,
856
863
  cursor_info: serde_json::Value,
864
+ /// `session.open`'s `inputObservation` member, fixed when the session opened.
865
+ observation: serde_json::Value,
866
+ observer: Mutex<Option<crate::observe::Tap>>,
857
867
  }
858
868
 
859
869
  /// A source whose video arrives already encoded.
@@ -978,6 +988,7 @@ pub fn capabilities() -> serde_json::Value {
978
988
  }),
979
989
  ),
980
990
  };
991
+ let observe = crate::input::observe_probe();
981
992
  serde_json::json!({
982
993
  "protocol": crate::protocol::PROTOCOL_VERSION,
983
994
  "engine": format!("desklink-host/{}", env!("CARGO_PKG_VERSION")),
@@ -1009,6 +1020,11 @@ pub fn capabilities() -> serde_json::Value {
1009
1020
  "layout": keymap::LayoutNames::from_environment().identity(),
1010
1021
  "unavailable_reason": unavailable,
1011
1022
  "grant": input_grant,
1023
+ "observe": {
1024
+ "mechanism": "cgeventtap",
1025
+ "grant": if observe.is_ok() { "granted" } else { "missing-input-monitoring" },
1026
+ "unavailable_reason": observe.as_ref().err().map(|e| serde_json::json!({"reason": e.reason, "remedy": e.remedy})),
1027
+ },
1012
1028
  },
1013
1029
  "clipboard": { "read": true, "write": true, "mime": ["text/plain;charset=utf-8"],
1014
1030
  "maxBytes": clipboard::MAX_CLIPBOARD_BYTES },
@@ -1480,6 +1496,29 @@ impl Session {
1480
1496
  "origin": { "x": source.origin_x, "y": source.origin_y },
1481
1497
  });
1482
1498
 
1499
+ // Observation is an addition to the stream, never a condition of it: a
1500
+ // desktop that cannot be observed still streams, and the reply says why.
1501
+ let observed = request.observe_input.then(|| {
1502
+ let sink: crate::observe::Sink = {
1503
+ let events = events.clone();
1504
+ let id = id.clone();
1505
+ Arc::new(move |observation| {
1506
+ let event = match observation {
1507
+ crate::observe::Observation::Input { timestamp_us, input } => {
1508
+ SessionEvent::Observed { timestamp_us, input }
1509
+ }
1510
+ crate::observe::Observation::Cursor(position) => SessionEvent::Cursor { position },
1511
+ };
1512
+ let _ = events.send(Notice { session_id: id.clone(), event });
1513
+ })
1514
+ };
1515
+ crate::observe::start(source.node_id, (source_w, source_h), sink)
1516
+ });
1517
+ if let Some(Err(error)) = &observed {
1518
+ log::warn!("input observation unavailable: {} ({})", error.reason, error.code);
1519
+ }
1520
+ let observation = crate::observe::status(observed.as_ref());
1521
+
1483
1522
  let pipeline = Arc::new(AtomicBool::new(true));
1484
1523
  let inner = Arc::new(Inner {
1485
1524
  id,
@@ -1526,6 +1565,8 @@ impl Session {
1526
1565
  encoded: Mutex::new(None),
1527
1566
  local_frames: request.local_frames,
1528
1567
  cursor_info,
1568
+ observation,
1569
+ observer: Mutex::new(observed.and_then(Result::ok)),
1529
1570
  });
1530
1571
 
1531
1572
  inner.notify(SessionEvent::Description {
@@ -1641,6 +1682,13 @@ impl Session {
1641
1682
  })),
1642
1683
  local_frames: false,
1643
1684
  cursor_info: serde_json::json!({"mode":"unavailable", "positions":false}),
1685
+ observation: serde_json::json!({
1686
+ "observing": false,
1687
+ "code": "unsupported-source",
1688
+ "reason": "consumer-encoded video has no desktop of its own to observe",
1689
+ "remedy": "observe the device where its pixels come from",
1690
+ }),
1691
+ observer: Mutex::new(None),
1644
1692
  });
1645
1693
  inner.notify(SessionEvent::State {
1646
1694
  capture: "consented",
@@ -1706,6 +1754,10 @@ impl Session {
1706
1754
  &self.inner.cursor_info
1707
1755
  }
1708
1756
 
1757
+ pub fn observation_info(&self) -> &serde_json::Value {
1758
+ &self.inner.observation
1759
+ }
1760
+
1709
1761
  pub fn geometry(&self) -> &serde_json::Value {
1710
1762
  &self.inner.geometry
1711
1763
  }
@@ -2176,6 +2228,8 @@ impl Inner {
2176
2228
  // handlers, and `shutdown` exits right after this. The encode thread
2177
2229
  // finds it gone and stops.
2178
2230
  drop(lock(&self.encoder).take());
2231
+ // Stop listening to the person's keys the moment the session ends.
2232
+ drop(lock(&self.observer).take());
2179
2233
  if let Ok(mut indicator) = self.indicator.lock() {
2180
2234
  indicator.take();
2181
2235
  }
@@ -3829,6 +3883,8 @@ mod tests {
3829
3883
  })),
3830
3884
  local_frames: false,
3831
3885
  cursor_info: serde_json::json!({"mode":"unavailable", "positions":false}),
3886
+ observation: serde_json::json!({"observing": false}),
3887
+ observer: Mutex::new(None),
3832
3888
  });
3833
3889
  spawn_peer_events(&inner, peer_events_rx);
3834
3890
  spawn_encoded(&inner, feed_rx);
@@ -4084,6 +4140,8 @@ mod tests {
4084
4140
  encoded: Mutex::new(None),
4085
4141
  local_frames: true,
4086
4142
  cursor_info: serde_json::json!({"mode":"embedded", "positions":false}),
4143
+ observation: serde_json::json!({"observing": false}),
4144
+ observer: Mutex::new(None),
4087
4145
  });
4088
4146
  (inner, recorded)
4089
4147
  }
@@ -4484,6 +4542,7 @@ mod tests {
4484
4542
  agent_indicator: false,
4485
4543
  local_frames: true,
4486
4544
  audio: false,
4545
+ observe_input: false,
4487
4546
  }
4488
4547
  }
4489
4548
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@desklink/host",
3
- "version": "0.5.9",
3
+ "version": "0.5.11",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -38,7 +38,7 @@
38
38
  "ws": "8.21.3"
39
39
  },
40
40
  "optionalDependencies": {
41
- "@desklink/host-linux-x64-gnu": "0.5.9",
42
- "@desklink/host-darwin-arm64": "0.5.9"
41
+ "@desklink/host-linux-x64-gnu": "0.5.11",
42
+ "@desklink/host-darwin-arm64": "0.5.11"
43
43
  }
44
44
  }