💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] ## RTCPeerConnection RTCPeerConnection 接口代表一个由本地计算机到远端的WebRTC连接。该接口提供了创建,保持,监控,关闭连接的方法的实现。 ### sample 1. 添加流 ``` var pc = new RTCPeerConnection(); // 设置添加流事件 pc.onaddstream = function(obj) { var vid = document.createElement("video"); document.appendChild(vid); vid.srcObject = obj.stream; } // 帮助函数 function endCall() { var videos = document.getElementsByTagName("video"); for (var i = 0; i < videos.length; i++) { videos[i].pause(); } pc.close(); } function error(err) { endCall(); } ``` 2. 呼叫初始化 ``` navigator.getUserMedia({video: true}, function(stream) { pc.onaddstream({stream: stream}); // Adding a local stream won't trigger the onaddstream callback pc.addStream(stream); pc.createOffer(function(offer) { pc.setLocalDescription(new RTCSessionDescription(offer), function() { // send the offer to a server to be forwarded to the friend you're calling. }, error); }, error); }) ``` 3. 呼叫回答 ``` var offer = getOfferFromFriend(); navigator.getUserMedia({video: true}, function(stream) { pc.onaddstream({stream: stream}); pc.addStream(stream); pc.setRemoteDescription(new RTCSessionDescription(offer), function() { pc.createAnswer(function(answer) { pc.setLocalDescription(new RTCSessionDescription(answer), function() { // send the answer to a server to be forwarded back to the caller (you) }, error); }, error); }, error); }) ``` 4. 处理应答 ``` // pc was set up earlier when we made the original offer var offer = getResponseFromFriend(); pc.setRemoteDescription(new RTCSessionDescription(offer), function() { }, error); ``` ## 事件 ### onaddstream 是收到`[addstream](https://developer.mozilla.org/zh-CN/docs/Web/Reference/Events/addstream "/zh-CN/docs/Web/Reference/Events/addstream")`事件时调用的事件处理器。 Such an event is 当[`MediaStream`](https://developer.mozilla.org/zh-CN/docs/Web/API/MediaStream)被远端机器添加到这条连接时,该事件会被触发。 当调用[`RTCPeerConnection.setRemoteDescription()`](https://developer.mozilla.org/zh-CN/docs/Web/API/RTCPeerConnection/setRemoteDescription)方法时,这个事件就会被立即触发,它不会等待SDP协商的结果 ### ondatachannel 是收到datachannel 事件时调用的事件处理器。 当一个 RTCDataChannel 被添加到连接时,这个事件被触发。 ``` pc.ondatachannel = function(ev) { console.log('Data channel is created!'); ev.channel.onopen = function() { console.log('Data channel is open and ready to be used.'); }; }; ``` ### onicecandidate 只要本地代理ICE 需要通过信令服务器传递信息给其他对等端时就会触发。 ``` pc.onicecandidate = function(event) { if (event.candidate) { // Send the candidate to the remote peer } else { // All ICE candidates have been sent } } ``` ### oniceconnectionstatechange 是收到iceconnectionstatechange事件时调用的事件处理器 。 当iceConnectionState 改变时,这个事件被触发。 ``` pc.oniceconnectionstatechange = function(event) { if (pc.iceConnectionState === "failed" || pc.iceConnectionState === "disconnected" || pc.iceConnectionState === "closed") { // Handle the failure } }; ``` ### onnegotiationneeded 发生需要会话协商的更改时,将触发此事件 ## 方法 ### createOffer() 生成一个offer,它是一个带有特定的配置信息寻找远端匹配机器(peer)的请求。 ``` myPeerConnection.createOffer().then(function(offer) { return myPeerConnection.setLocalDescription(offer); }) .then(function() { // 自定义函数 sendToServer({ name: myUsername, target: targetUsername, type: "video-offer", sdp: myPeerConnection.localDescription }); }) .catch(function(reason) { // An error occurred, so handle the failure to connect }); ``` ### createAnswer() 在协调一条连接中的两端offer/answers时,根据从远端发来的offer生成一个answer ``` pc.createAnswer().then(function(answer) { return pc.setLocalDescription(answer); }) .then(function() { // Send the answer to the remote peer through the signaling server. }) .catch(handleGetUserMediaError); ``` ### setLocalDescription() 改变与连接相关的本地描述。这个描述定义了连接的属性,例如:连接的编码方式。连接会受到它的改变的影响 实例1: ``` myPeerConnection.createOffer().then(function(offer) { return myPeerConnection.setLocalDescription(offer); }); // 等价于 myPeerConnection.createOffer().then(function(offer) { return myPeerConnection.setLocalDescription(new RTCSessionDescription(offer)); }); ``` 实例2: **隐式描述** 无参数形式的优点之一 setLocalDescription() 是,它使您可以大大简化协商代码 ``` pc.addEventListener("negotiationneeded", async (event) => { await pc.setLocalDescription(); signalRemotePeer({ description: pc.localDescription }); }); ``` **显示** ``` async function handleNegotiationNeededEvent() { try { const offer = await pc.createOffer(); pc.setLocalDescription(offer); signalRemotePeer({ description: pc.localDescription }); } catch(err) { reportError(err); } } ``` ### setRemoteDescription() - 改变与连接相关的远端描述。这个描述定义了连接的属性,例如:连接的编码方式。连接会受到它的改变的影响 - 连接的offer通常来自于负责匹配的服务器所发送的数据。执行者应调用此方法设置远程描述,然后生成发送到对端计算机的answer ``` var pc = new PeerConnection(); pc.setRemoteDescription( new RTCSessionDescription( offer ), function() { pc.createAnswer( function( answer ) { pc.setLocalDescription( answer, function() { // send the answer to the remote connection }) }) }); ``` ### addIceCandidate() - 这是一个实验中的功能 - 当本机当前页面的 RTCPeerConnection 接收到一个从远端页面通过信号通道发来的新的 ICE 候选地址信息,本机可以通过调用RTCPeerConnection.addIceCandidate() 来添加一个 ICE 代理 ``` let candidate = new RTCIceCandidate(receivedSDP); pc.addIceCandidate(candidate).then(_=>{ // Do stuff when the candidate is successfully passed to the ICE agent }).catch(e=>{ console.log("Error: Failure during addIceCandidate()"); }); ``` ### getConfiguration() RTCPeerConnection上调用该方法的当前配置 ``` let configuration = myPeerConnection.getConfiguration(); if ((configuration.certificates != undefined) && (!configuration.certificates.length)) { RTCPeerConnection.generateCertificate({ name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256', modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]) }).then(function(cert) { configuration.certificates = [cert]; myPeerConnection.setConfiguration(configuration); }); } ``` ### getSenders (原 getLocalStreams ) - 返回一个RTCRtpSender对象数组 ,每个对象代表负责传输一个轨道的数据的RTP发送方 实例:静音 ``` function setMuting(pc, muting) { let senderList = pc.getSenders(); senderList.forEach(sender) { sender.track.enabled = !muting; } } ``` ### getReceivers (原 getReceivers) 返回一个RTCRtpReceiver对象数组,每个对象代表一个RTP接收器 ### removeStream 移除媒体流 ``` var pc, videoStream; navigator.getUserMedia({video: true}, function(stream) { pc = new RTCPeerConnection(); videoStream = stream; pc.addStream(stream); } document.getElementById("closeButton").addEventListener("click", function(event) { pc.removeStream(videoStream); pc.close(); }, false); ``` ### close 关闭当前对等连接 ``` var pc = new RTCPeerConnection(); var dc = pc.createDataChannel("my channel"); dc.onmessage = function (event) { console.log("received: " + event.data); pc.close(); // We decided to close after the first received message }; dc.onopen = function () { console.log("datachannel open"); }; dc.onclose = function () { console.log("datachannel close"); }; ``` ### createDataChannel 创建一个可以发送任意数据的数据通道(data channel)。常用于后台传输内容, 例如: 图像, 文件传输, 聊天文字, 游戏数据更新包, 等等 实例1: ``` // 邀约方 var pc = new RTCPeerConnection(options); var channel = pc.createDataChannel("chat"); channel.onopen = function(event) { channel.send('Hi you!'); } channel.onmessage = function(event) { console.log(event.data); } // 应答方 var pc = new RTCPeerConnection(options); pc.ondatachannel = function(event) { var channel = event.channel;  channel.onopen = function(event) { channel.send('Hi back!'); } channel.onmessage = function(event) { console.log(event.data); } } ``` 实例2:使用约定的id ``` var pc = new RTCPeerConnection(options); var channel = pc.createDataChannel("chat", {negotiated: true, id: 0}); channel.onopen = function(event) { channel.send('Hi!'); } channel.onmessage = function(event) { console.log(event.data); } ``` ### getStats 关整体连接或指定的统计信息的数据进行解析 ``` window.setInterval(function() { myPeerConnection.getStats(null).then(stats => { let statsOutput = ""; stats.forEach(report => { statsOutput += `<h2>Report: ${report.type}</h2>\n<strong>ID:</strong> ${report.id}<br>\n` + `<strong>Timestamp:</strong> ${report.timestamp}<br>\n`; // Now the statistics for this report; we intentially drop the ones we // sorted to the top above Object.keys(report).forEach(statName => { if (statName !== "id" && statName !== "timestamp" && statName !== "type") { statsOutput += `<strong>${statName}:</strong> ${report[statName]}<br>\n`; } }); }); document.querySelector(".stats-box").innerHTML = statsOutput; }); }, 1000); ``` ### getStreamById (弃用) ``` var stream = pc.getStreamById(myTrackId); if (stream) { console.log("Found stream: " + stream.id); } ``` ### addStream (弃用,推荐用 addTrack) ``` navigator.mediaDevices.getUserMedia({video:true, audio:true}, function(stream) { var pc = new RTCPeerConnection(); pc.addStream(stream); }); ```