最近有一个功能需要在网页web端实现对另一个设备的控制,参考了网上的教程是用webrtc实现,梳理了整体的实现过程
最终效果
整体逻辑
主要分为三部分:web端(控制端)
、中继服务端
、被控端
,各部分的工作内容如下
web端
- 建立
Websocket
与服务端
通信 - 建立
Webrct
通道与被控端
通信 - 远程桌面
视频流的渲染
- 反向控制(
键、鼠
:按比例将数据下发)
被控端
- 建立
Websocket
与服务端
通信 - 建立
Webrct
通道与控制端
通信 - 设备屏幕截图、截屏压缩处理、将截取的图片转成流推送【屏幕截图、截屏压缩处理耗时处理】
- 解析和响应控制(键、鼠:按比例将数据解析后模拟鼠标事件)
中继服务端
它是在建立连接之前交换信息的任何一种通信渠道,
turn服务
的搭建- 开发websocket服务、账号管理、消息转发
流程
整体功能流程
实现过程
主要梳理的是web前端部分的实现过程,分为4部分:
- 建立
Websocket
与服务端
通信 - 建立
Webrct
通道与被控端
通信 - 远程桌面
视频流的渲染
- 反向控制(
键、鼠
:按比例将数据下发)
Websocket 与服务端通信
websocket
的连接是为了后续建立p2p连接
做的前置工作。websocket
的通信比较简单,soket连接直接使用new WebSocket(地址)
可以实例化sokcet对象
,sokcet对象
的回调函数有onopen
/onerror
/onclose
/onmessage
等,可以在对应的回调里执行相关操作
this.socket = new WebSocket(this.socketUrl)
this.socket.onopen = () => {}
this.socket.onerror = (error) => {}
this.socket.onclose = (error) => {}
this.socket.onmessage = (Message) => {}
Webrct 通道建立
Webrct
通道建立也就是我们常提到的p2p连接
,第一步控制端
和被控端
都与中继服务
建立了websoket
连接后,可以借用中继服务交换Offer
和 Answer
,成功建立p2p连接
。对应的是流程图中的这部分
websocket
连接成功后,中继服务器转发给控制端connected
指令,控制端onmessage
接收到指令connected
后,控制端要做的事情有:
-
- 执行
初始化peer
的操作
- 执行
-
创建数据通道
-
- 给中继服务
发送ready
消息
- 给中继服务
this.socket.onmessage = (Message) => {
const obj = JSON.parse(Message.data)
const command = obj.command
let data = null
switch (command) {
case 'connected': // 链接成功
// 1. 初始化 peer
const PeerConnection =
window.RTCPeerConnection ||
window.mozRTCPeerConnection ||
window.webkitRTCPeerConnection
this.peer = new PeerConnection(SERVERS, PC_OPTIONS)
// 2. 创建数据通道
this.channel = this.peer.createDataChannel('msgdatachannel')
// 3. 发送ready消息
data = JSON.stringify({
'command': 'ready'
})
this.send(data)
break
default: {
console.log(Message.data)
}
}
}
中继服务
收到ready
后转发
给被控端,被控端也进行初始化peerB
的操作,初始化完成同样发送ready
给中继服务
,中继再转发
给控制端,控制端就能在onmessage
回调里接收到ready指令后,就能进行offer创建的
操作,创建offer
后,再把offer发送给中继服务
this.socket.onmessage = (Message) => {
const obj = JSON.parse(Message.data)
const command = obj.command
switch (command) {
case 'ready':
// 创建offer
this.peer.createOffer(
(desc) => {
this.peer.setLocalDescription(desc, () => {
const obj = JSON.stringify({
'command': 'offer',
'desc': desc
})
// 发送offer给中继服务
this.send(obj)
}
}
)
break
default: {
console.log(Message.data)
}
}
}
中继服务收到offer
后转发给被控端,被控端创建answer
,同样再通过中继服务转发给控制端,此时连接完成,会自动调用peer
和peerB
的onopen事件
,后续就可以进行指令
的发送和视频流
的接收了。
远程桌面视频流的渲染
在peer.onaddstream
可以监听到视频流,然后通过标签play
即可
this.peer.onaddstream = (e) => {
try {
const vid2 = document.getElementById('remote-control')
vid2.srcObject = e.stream
vid2.onloadedmetadata = function() {
vid2.play()
}
} catch (ex) {
this.socket.close()
}
}
鼠标/键盘指令的发送
已经建立了p2p
连接,并且在前面已经创建了数据通道
,指令可以通过channel.send
发送,常用指令定义参考如下
完整代码
参考文章
developer.mozilla.org/en-US/docs/…
原创文章,记录成长,也希望对你有帮助!喜欢请点赞哦~
作者:前端小小梦
主页:了解更多,点击个人主页