上一篇webRTC通话的实现(上)说到了一些基础,接下来做个实践
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>demo</title>
</head>
<body>
<div class="controlbox">
<button id="connectButton" name="connectButton" class="buttonleft">
连接
</button>
<button id="disconnectButton" name="disconnectButton" class="buttonright" disabled>
取消连接
</button>
</div>
<div class="messagebox">
<label for="message">发送一条消息:
<input type="text" name="message" id="message" placeholder="Message text"
inputmode="latin" size=60 maxlength=120 disabled>
</label>
<button id="sendButton" name="sendButton" class="buttonright" disabled>
发送
</button>
</div>
<div class="messagebox" id="receivebox">
<p>消息接收:</p>
</div>
<script>
// https://developer.mozilla.org/zh-CN/docs/Web/API/WebRTC_API/Simple_RTCDataChannel_sample
var connectButton = null;
var disconnectButton = null;
var sendButton = null;
var messageInputBox = null;
var receiveBox = null;
var localConnection = null; // RTCPeerConnection for our "local" connection
var remoteConnection = null; // RTCPeerConnection for the "remote"
var sendChannel = null; // RTCDataChannel for the local (sender)
var receiveChannel = null; // RTCDataChannel for the remote (receiver)
function startup() {
// 获取按钮
connectButton = document.getElementById("connectButton");
disconnectButton = document.getElementById("disconnectButton");
sendButton = document.getElementById("sendButton");
messageInputBox = document.getElementById("message");
receiveBox = document.getElementById("receivebox");
// Set event listeners for user interface widgets
// 为按钮设置事件
connectButton.addEventListener("click", connectPeers, false);
disconnectButton.addEventListener("click", disconnectPeers, false);
sendButton.addEventListener("click", sendMessage, false);
}
// 创建本地连接并监听
function connectPeers() {
// Create the local connection and its event listeners
// 创建本地连接及其事件侦听器
localConnection = new RTCPeerConnection();
console.log(localConnection,"localConnection");
// Create the data channel and establish its event listeners
// 创建数据通道并建立其事件侦听器
sendChannel = localConnection.createDataChannel("sendChannel");
// 打开或关闭信道
sendChannel.onopen = handleSendChannelStatusChange;
sendChannel.onclose = handleSendChannelStatusChange;
// Create the remote connection and its event listeners
// 创建远程连接
remoteConnection = new RTCPeerConnection();
// 接收信道的返回
remoteConnection.ondatachannel = receiveChannelCallback;
// Set up the ICE candidates for the two peers
// 建立ICE候选人
localConnection.onicecandidate = e => !e.candidate
|| remoteConnection.addIceCandidate(e.candidate)
.catch(handleAddCandidateError);
remoteConnection.onicecandidate = e => !e.candidate
|| localConnection.addIceCandidate(e.candidate)
.catch(handleAddCandidateError);
// Now create an offer to connect; this starts the process
// 创建一个offer连接
// 开始步骤
// 调用.createOffer()方法创建 SDP (Session Description Protocol) 字节块用于描述我们期待建立的连接;
// offer创建成功后,将字节块传递给local连接setLocalDescription(),配置local连接;
// 调用setRemoteDescription()方法将 local 节点连接到到远程;remote 节点回应调用 createAnswer()方法给予回应
// 应答建立之后,通过调用RTCPeerConnection.setLocalDescription() (en-US)传入 remoteConnection,从而完成了 remote 端连接的建立
// 过调用 localConnection 的RTCPeerConnection.setRemoteDescription()方法,本地连接的远端描述被设置为指向 remote 节点。
// catch() 用于处理异常的逻辑
localConnection.createOffer()
.then(offer => localConnection.setLocalDescription(offer))
.then(() => remoteConnection.setRemoteDescription(localConnection.localDescription))
.then(() => remoteConnection.createAnswer())
.then(answer => remoteConnection.setLocalDescription(answer))
.then(() => localConnection.setRemoteDescription(remoteConnection.localDescription))
.catch(handleCreateDescriptionError);
}
// 处理创建连接错误的逻辑
function handleCreateDescriptionError(error) {
console.log("Unable to create an offer: " + error.toString());
}
// 本地添加候选人成功的处理
function handleLocalAddCandidateSuccess() {
connectButton.disabled = true;
}
// 远端添加候选人成功的处理
function handleRemoteAddCandidateSuccess() {
disconnectButton.disabled = false;
}
// 添加ice候选人错误的处理方法
function handleAddCandidateError() {
console.log("Oh noes! addICECandidate failed!");
}
// 发送消息
function sendMessage() {
// 获取输入框的信息
var message = messageInputBox.value;
// 通过信道发送输入框的消息
sendChannel.send(message);
// Clear the input box and re-focus it, so that we're
// ready for the next message.
// 清空输入框内容
messageInputBox.value = "";
// 对输入框设置焦点
messageInputBox.focus();
}
function handleSendChannelStatusChange(event) {
console.log(event,sendChannel,"event>>>");
if (sendChannel) {
var state = sendChannel.readyState;
// 根据信道是否打开判断输入框,发送按钮以及连接按钮,取消按钮是否可以点击
if (state === "open") {
messageInputBox.disabled = false;
messageInputBox.focus();
sendButton.disabled = false;
disconnectButton.disabled = false;
connectButton.disabled = true;
} else {
messageInputBox.disabled = true;
sendButton.disabled = true;
connectButton.disabled = false;
disconnectButton.disabled = true;
}
}
}
// 获取信道的返回
function receiveChannelCallback(event) {
console.log(event,"receiveChannelCallback");
receiveChannel = event.channel;
receiveChannel.onmessage = handleReceiveMessage;
receiveChannel.onopen = handleReceiveChannelStatusChange;
receiveChannel.onclose = handleReceiveChannelStatusChange;
}
// 处理发送过来的信息
function handleReceiveMessage(event) {
var el = document.createElement("p");
var txtNode = document.createTextNode(event.data);
el.appendChild(txtNode);
receiveBox.appendChild(el);
}
// 处理信道的状态
function handleReceiveChannelStatusChange(event) {
if (receiveChannel) {
console.log("Receive channel's status has changed to " + receiveChannel.readyState);
}
// Here you would do stuff that needs to be done
// when the channel's status changes.
}
// 取消连接
function disconnectPeers() {
// Close the RTCDataChannels if they're open.
sendChannel.close();
receiveChannel.close();
// Close the RTCPeerConnections
localConnection.close();
remoteConnection.close();
sendChannel = null;
receiveChannel = null;
localConnection = null;
remoteConnection = null;
// Update user interface elements
connectButton.disabled = false;
disconnectButton.disabled = true;
sendButton.disabled = true;
messageInputBox.value = "";
messageInputBox.disabled = true;
}
// 对Window添加监听器
// 注册一个加载事件处理程序
window.addEventListener('load', startup, false);
</script>
<style>
body {
font-family: "Lucida Grande", "Arial", sans-serif;
font-size: 16px;
}
.messagebox {
border: 1px solid black;
padding: 5px;
width: 500px;
}
.buttonright {
float: right;
}
.buttonleft {
float: left;
}
.controlbox {
padding: 5px;
width: 450px;
height: 28px;
}
</style>
</body>
</html>
实现一个简单的双方通信的效果