@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.
- package/README.md +19 -44
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js +2 -1
- package/dist/bridge.js.map +1 -1
- package/dist/engineProcess.d.ts.map +1 -1
- package/dist/engineProcess.js +1 -0
- package/dist/engineProcess.js.map +1 -1
- package/dist/protocol.d.ts +58 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js.map +1 -1
- package/docs/PROTOCOL.md +56 -0
- package/engine/Cargo.lock +2 -1
- package/engine/Cargo.toml +3 -1
- package/engine/native/agent_overlay_mac.m +19 -12
- package/engine/native/agent_overlay_wayland.c +15 -12
- package/engine/native/agent_overlay_x11.c +66 -17
- package/engine/src/input_mac.rs +433 -0
- package/engine/src/keymap_mac.rs +257 -0
- package/engine/src/mac.rs +8 -0
- package/engine/src/main.rs +12 -1
- package/engine/src/observe.rs +94 -0
- package/engine/src/portal.rs +83 -1
- package/engine/src/protocol.rs +30 -1
- package/engine/src/session.rs +59 -0
- package/package.json +3 -3
package/engine/src/session.rs
CHANGED
|
@@ -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.
|
|
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.
|
|
42
|
-
"@desklink/host-darwin-arm64": "0.5.
|
|
41
|
+
"@desklink/host-linux-x64-gnu": "0.5.11",
|
|
42
|
+
"@desklink/host-darwin-arm64": "0.5.11"
|
|
43
43
|
}
|
|
44
44
|
}
|