fix: accept low-latency desktop move channel
This commit is contained in:
parent
4859396051
commit
3dd2359ca3
@ -471,12 +471,14 @@ WebRTC RTP stats: packets=... packetDelta=1100 byteDelta=950000 writeErrors=0
|
|||||||
- `mouse_move` / hover 约 16ms 最多发送一次
|
- `mouse_move` / hover 约 16ms 最多发送一次
|
||||||
- 同一归一化坐标重复移动不发送
|
- 同一归一化坐标重复移动不发送
|
||||||
- `mouse_down` 前强制发送最新坐标,保证点击命中
|
- `mouse_down` 前强制发送最新坐标,保证点击命中
|
||||||
- data channel `bufferedAmount` 过高时只丢弃 `mouse_move`
|
- `mouse_move` 走独立 `input-move` data channel,配置为 unordered + 短 packet lifetime
|
||||||
|
- 点击、键盘、滚轮走可靠有序 `input` data channel
|
||||||
|
- `input-move` channel `bufferedAmount` 过高时只丢弃 `mouse_move`
|
||||||
- `mouse_down`、`mouse_up`、`key_down`、`key_up`、`scroll` 不因背压丢弃
|
- `mouse_down`、`mouse_up`、`key_down`、`key_up`、`scroll` 不因背压丢弃
|
||||||
|
|
||||||
判读:
|
判读:
|
||||||
|
|
||||||
- 鼠标轨迹延迟但点击最终准确,通常是旧 `mouse_move` 事件排队。
|
- 鼠标轨迹延迟但点击最终准确,通常是 `input-move` 背压或 Bridge 侧 mouse move coalescing 积压。
|
||||||
- 点击也延迟或丢失,要查 data channel 状态、Bridge input injector、xdotool 写入。
|
- 点击也延迟或丢失,要查 data channel 状态、Bridge input injector、xdotool 写入。
|
||||||
|
|
||||||
### 3. 再看 Bridge input injector
|
### 3. 再看 Bridge input injector
|
||||||
@ -484,13 +486,14 @@ WebRTC RTP stats: packets=... packetDelta=1100 byteDelta=950000 writeErrors=0
|
|||||||
Bridge 侧输入链路是:
|
Bridge 侧输入链路是:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
APP Pointer/Key event -> WebRTC data channel -> Bridge OnDataChannel -> XdotoolInjector.Inject -> persistent xdotool stdin -> X11
|
APP Pointer/Key event -> WebRTC input/input-move data channel -> Bridge OnDataChannel -> XdotoolInjector.Inject -> persistent xdotool stdin -> X11
|
||||||
```
|
```
|
||||||
|
|
||||||
重点日志:
|
重点日志:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Data channel 'input'-'...' opened
|
Data channel 'input'-'...' opened
|
||||||
|
Data channel 'input-move'-'...' opened
|
||||||
xdotool write error: ...
|
xdotool write error: ...
|
||||||
xdotool mousemove write error: ...
|
xdotool mousemove write error: ...
|
||||||
```
|
```
|
||||||
|
|||||||
@ -13,6 +13,11 @@ import (
|
|||||||
"github.com/pion/webrtc/v4"
|
"github.com/pion/webrtc/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
desktopReliableInputChannelLabel = "input"
|
||||||
|
desktopMoveInputChannelLabel = "input-move"
|
||||||
|
)
|
||||||
|
|
||||||
type WebRTCServer struct {
|
type WebRTCServer struct {
|
||||||
peerConnection *webrtc.PeerConnection
|
peerConnection *webrtc.PeerConnection
|
||||||
videoTrack *webrtc.TrackLocalStaticRTP
|
videoTrack *webrtc.TrackLocalStaticRTP
|
||||||
@ -88,18 +93,24 @@ func (w *WebRTCServer) InitPeerConnection(iceServers []string) error {
|
|||||||
// Handle Data Channel for inputs
|
// Handle Data Channel for inputs
|
||||||
pc.OnDataChannel(func(d *webrtc.DataChannel) {
|
pc.OnDataChannel(func(d *webrtc.DataChannel) {
|
||||||
log.Printf("Data channel '%s'-'%d' opened", d.Label(), d.ID())
|
log.Printf("Data channel '%s'-'%d' opened", d.Label(), d.ID())
|
||||||
if d.Label() == "input" {
|
label := d.Label()
|
||||||
d.OnMessage(func(msg webrtc.DataChannelMessage) {
|
if !isDesktopInputDataChannelLabel(label) {
|
||||||
var event InputEvent
|
return
|
||||||
if err := json.Unmarshal(msg.Data, &event); err != nil {
|
|
||||||
log.Printf("Failed to unmarshal input event: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := w.inputInjector.Inject(event); err != nil {
|
|
||||||
log.Printf("Failed to inject input event: %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
d.OnMessage(func(msg webrtc.DataChannelMessage) {
|
||||||
|
var event InputEvent
|
||||||
|
if err := json.Unmarshal(msg.Data, &event); err != nil {
|
||||||
|
log.Printf("Failed to unmarshal input event: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if label == desktopMoveInputChannelLabel && event.Type != "mouse_move" {
|
||||||
|
log.Printf("Ignoring non-mouse_move input event on %s channel: %s", label, event.Type)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := w.inputInjector.Inject(event); err != nil {
|
||||||
|
log.Printf("Failed to inject input event: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
w.peerConnection = pc
|
w.peerConnection = pc
|
||||||
@ -108,6 +119,10 @@ func (w *WebRTCServer) InitPeerConnection(iceServers []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isDesktopInputDataChannelLabel(label string) bool {
|
||||||
|
return label == desktopReliableInputChannelLabel || label == desktopMoveInputChannelLabel
|
||||||
|
}
|
||||||
|
|
||||||
// StartRTPReceiver listens on local UDP port for GStreamer RTP stream and forwards to WebRTC video track
|
// StartRTPReceiver listens on local UDP port for GStreamer RTP stream and forwards to WebRTC video track
|
||||||
func (w *WebRTCServer) StartRTPReceiver(port int) error {
|
func (w *WebRTCServer) StartRTPReceiver(port int) error {
|
||||||
addr := fmt.Sprintf("127.0.0.1:%d", port)
|
addr := fmt.Sprintf("127.0.0.1:%d", port)
|
||||||
|
|||||||
15
internal/desktop/webrtc_test.go
Normal file
15
internal/desktop/webrtc_test.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package desktop
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestIsDesktopInputDataChannelLabelAllowsReliableAndMoveChannels(t *testing.T) {
|
||||||
|
if !isDesktopInputDataChannelLabel(desktopReliableInputChannelLabel) {
|
||||||
|
t.Fatalf("expected reliable input channel label to be accepted")
|
||||||
|
}
|
||||||
|
if !isDesktopInputDataChannelLabel(desktopMoveInputChannelLabel) {
|
||||||
|
t.Fatalf("expected mouse move input channel label to be accepted")
|
||||||
|
}
|
||||||
|
if isDesktopInputDataChannelLabel("debug") {
|
||||||
|
t.Fatalf("expected unrelated data channel label to be ignored")
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user