Webrtc穿透转发通讯1-网页
来源:互联网 发布:unity3d制作复杂模型 编辑:程序博客网 时间:2024/06/11 19:07
Webrtc穿透转发通讯1-网页
- Webrtc穿透转发通讯2-windows
Webrtc应用模式
本文记录一个最基本webrtc网页类服务端对多个客户端模式通讯。基本作用就是实现以一个浏览器网页作为服务端,其它作为客户端交互由服务端网页提供的视频以及数据,由于浏览器种类众多,这里只以chrome和360最新版本浏览器为例,在这里将演示浏览器的使用方法。
组成部分:
需要注意的地方:
信令服务器
这里以websocket作为信令通信方式,浏览器服务端需要连接保持,以保证客户浏览器随时可以加入。
客户端通过信令服务器接收从服务端返回的应答后退出信令服务。
简易流程图
流程图(客户端) 流程图(服务端)
代码:
服务端代码
index_server.html
<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>webrtc 服务端</title></head><body> <div class="select"> <label for="audioSource">Audio input source: </label><select id="audioSource"></select> </div> <div class="select"> <label for="audioOutput">Audio output destination: </label><select id="audioOutput"></select> </div> <div class="select"> <label for="videoSource">Video source: </label><select id="videoSource"></select> </div> <input id="Button1" type="button" value="连接" onclick="connect()" /> <div id="labe2"></div> <br /><br /> <video id="vidLocal" autoplay controls muted style="display: none"></video> <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script> <script src="rtc_server.js"></script> <script> var t = null; function connect() { if (document.getElementById('Button1').value == "连接") { wsconnect(); //测试 if(t == null) { var sendNum = 0; t = setInterval(function () { var connNum = 0; for (var socketId in dataChannels) { connNum++; } for (var socketId in dataChannels) { var sdata = {}; sdata["content"] = "Hello RTC Server," + sendNum++ + ",server peerconn.num:" + connNum; rtc_send(sdata, socketId); } }, 1000); } } else { delAllPeerConn(); document.getElementById('Button1').value = "连接"; } } connect(); </script></body></html>
rtc_server.js
/** * 简单的基于webrtc的网页服务端 * Simple based on webrtc web service side * * zhaiye * tgmaa@163.com * * 本例子实现一个网页客户端与网页服务端交互的简单程序。 * * This example a web client, a simple example of interacting with the server. * *///信令服务var host = "tgmaa.cn";var UserID = "test";var Password = "a9f696454710384bf228047acba4d5ef";var nativePeerConnection = window.RTCPeerConnection;var nativeRTCSessionDescription = window.RTCSessionDescription;var nativeRTCIceCandidate = (window.RTCIceCandidate);var rtc_ws = null;var dataChannels = {};var ClientPeerConnList = {};var localMediaStream = null;var pcConstraints = { 'optional': []};//stun/turnvar servers = { iceServers: [ { "url": "stun:stun.l.google.com:19302" }, { "url": "stun:stun.xten.com" }, ]};//数据通道发送测试var sendTryCount = 0;function rtc_send(msg, socketId) { if (dataChannels[socketId] && dataChannels[socketId].readyState == "open") { dataChannels[socketId].send(JSON.stringify(msg)); console.log("Message sending success!"); } else { if (sendTryCount++ == 10) { sendTryCount = 0; delSinglePeerConn(socketId); } console.log("Message sending failed!"); }}var testNum = 0;function setDataChannel(dc) { dc.onerror = function (error) { console.log("DataChannel Error:", error); }; dc.onmessage = function (event) { labe2.innerHTML = event.data; }; dc.onopen = function () { console.log("DataChannel open"); }; dc.onclose = function () { console.log("DataChannel is Closed"); for (var socketId in dataChannels) { if (dataChannels[socketId] == dc) { delSinglePeerConn(socketId); } } };}function delSinglePeerConn(socketId){ labe2.innerHTML = "DataChannel is Closed remove:" + socketId; dataChannels[socketId].close(); delete dataChannels[socketId]; ClientPeerConnList[socketId].close(); delete ClientPeerConnList[socketId];}function delAllPeerConn() { for (var socketId in dataChannels) { delSinglePeerConn(socketId); } if (rtc_ws) { rtc_ws.close(); rtc_ws = null; } labe2.innerHTML = "已关闭"; document.getElementById('Button1').value = "连接";}//创建peer连接function createPeerConnection(socketId, sdp) { var pc = new nativePeerConnection(servers, pcConstraints); ClientPeerConnList[socketId] = pc; if (localMediaStream) { pc.addStream(localMediaStream); } dataChannels[socketId] = pc.createDataChannel("sendDataChannel", null); setDataChannel(dataChannels[socketId]); pc.onaddstream = function (e) { console.log("pc.onaddstream"); }; pc.onicecandidate = function (event) { if (event.candidate != null) { console.log("pc.onicecandidate:" + JSON.stringify(event.candidate)); var sdata = {}; sdata["command"] = "__OnIceCandidate"; sdata["socketId"] = socketId; sdata["sdp_mid"] = event.candidate.sdpMid; sdata["sdp_mline_index"] = event.candidate.sdpMLineIndex; sdata["sdp"] = event.candidate.candidate; ws_Send(sdata); } }; pc.ondatachannel = function (e) { console.log("pc.ondatachannel"); }; pc.createOffer = function (e) { console.log("pc.createOffer"); }; pc.setRemoteDescription(new nativeRTCSessionDescription({ type: "offer", sdp: sdp }), function () { pc.createAnswer(function (session_desc) { pc.setLocalDescription(session_desc); var sdata = {}; sdata["command"] = "__OnSuccessAnswer"; sdata["socketId"] = socketId; sdata["sdp"] = session_desc.sdp; ws_Send(sdata); }, function (errorInformation) { console.log(errorInformation); }); }, function (errorInformation) { console.log('setRemoteDescription error: ' + errorInformation); });}//信令服务function ws_Send(data) { try { rtc_ws.send(JSON.stringify(data)); } catch (ex) { console.log("Message sending failed!"); }}function wsconnect() { rtc_ws = new WebSocket("ws://" + host + ":9000"); rtc_ws.onopen = function () { var sdata = {}; sdata["command"] = "__UserCreate"; var udata = {}; udata["UserID"] = UserID; udata["Password"] = Password; sdata["udata"] = udata; ws_Send(sdata); console.log("Socket connected!"); labe2.innerHTML = "Socket connected!"; ////与信令服务器保持连接,允许新加入客户端 //setInterval(function () { // ws_Send(0); //}, 1000 * 20); document.getElementById('Button1').value = "断开"; }; rtc_ws.onclose = function () { console.log("webSocket connection has been disconnected!"); delAllPeerConn(); }; rtc_ws.onerror = function (err) { labe2.innerHTML = "Socket error :" + err.message; }; rtc_ws.onmessage = function (Message) { var obj = JSON.parse(Message.data); var command = obj.command; switch (command) { case "__OnLoginSuccessful": { if (!localMediaStream) getLocalStream(); } break; case "__OnError": { labe2.innerHTML = obj.info; } break; case "__Offer": { createPeerConnection(obj.socketId, obj.desc.sdp); } break; } };}//获取相关音视频设备navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);var videoElement = document.getElementById('vidLocal');var audioInputSelect = document.querySelector('select#audioSource');var audioOutputSelect = document.querySelector('select#audioOutput');var videoSelect = document.querySelector('select#videoSource');var selectors = [audioInputSelect, audioOutputSelect, videoSelect];audioInputSelect.onchange = getLocalStream;videoSelect.onchange = getLocalStream;function handleError(error) { console.log('navigator.getUserMedia error: ', error);}function gotDevices(deviceInfos) { // Handles being called several times to update labels. Preserve values. var values = selectors.map(function (select) { return select.value; }); selectors.forEach(function (select) { while (select.firstChild) { select.removeChild(select.firstChild); } }); for (var i = 0; i !== deviceInfos.length; ++i) { var deviceInfo = deviceInfos[i]; var option = document.createElement('option'); option.value = deviceInfo.deviceId; if (deviceInfo.kind === 'audioinput') { option.text = deviceInfo.label || 'microphone ' + (audioInputSelect.length + 1); audioInputSelect.appendChild(option); } else if (deviceInfo.kind === 'audiooutput') { option.text = deviceInfo.label || 'speaker ' + (audioOutputSelect.length + 1); audioOutputSelect.appendChild(option); } else if (deviceInfo.kind === 'videoinput') { option.text = deviceInfo.label || 'camera ' + (videoSelect.length + 1); videoSelect.appendChild(option); } else { console.log('Some other kind of source/device: ', deviceInfo); } } selectors.forEach(function (select, selectorIndex) { if (Array.prototype.slice.call(select.childNodes).some(function (n) { return n.value === values[selectorIndex]; })) { select.value = values[selectorIndex]; } });}function gotStream(stream) { window.stream = stream; // make stream available to console //videoElement.srcObject = stream; //videoElement.onloadedmetadata = function (e) { // videoElement.play(); //}; localMediaStream = stream; console.log("localMediaStream chang."); // Refresh button list in case labels have become available return navigator.mediaDevices.enumerateDevices();}function getLocalStream() { if (window.stream) { window.stream.getTracks().forEach(function (track) { track.stop(); }); } //获取选择的设备 var audioSource = audioInputSelect.value; var videoSource = videoSelect.value; //过滤设备 var constraints = { audio: { deviceId: audioSource ? { exact: audioSource } : undefined }, video: { deviceId: videoSource ? { exact: videoSource } : undefined, "width": { "max": "640" }, "height": { "max": "480" }, "frameRate": { "max": "25" } } }; navigator.mediaDevices.getUserMedia(constraints).then(gotStream).then(gotDevices).catch(handleError);}
客户端代码
index_client.html
<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>webrtc 客户端</title></head><body> <input id="Button1" type="button" value="连接" onclick="connect()" /> <div id="labe2"></div> <br /><br /> <video id="vid2" autoplay controls ></video> <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script> <script src="rtc_client.js"></script> <script> window.onbeforeunload = function () { delPeerConn(); } var t = null; function connect() { if (document.getElementById('Button1').value == "连接") { wsconnect(); if (t == null) { //测试 var testNum = 0; t = setInterval(function () { var sdata = {}; sdata["socketId"] = cursocketId; sdata["content"] = "Hello RTC Client," + testNum++; if (document.getElementById('Button1').value == "断开") rtc_send(sdata); }, 1000); } } else { delPeerConn(); } } connect(); </script></body></html>
rtc_client.js
/** * 简单的基于webrtc的网页客户端 * Simple based on webrtc web client * * zhaiye * tgmaa@163.com * * 本例子实现一个网页客户端与网页服务端交互的简单程序。 * * This example a web client, a simple example of interacting with the server. * *///信令服务var host = "tgmaa.cn";var UserID = "test";var Password = "a9f696454710384bf228047acba4d5ef";var nativePeerConnection = window.RTCPeerConnection;var nativeRTCSessionDescription = window.RTCSessionDescription;var nativeRTCIceCandidate = (window.RTCIceCandidate);var rtc_ws = null;var ServerPeerConn = null;var dataChannel = null;var cursocketId;var pcConstraints = { 'optional': []};//stun/turnvar servers = { iceServers: [ { "url": "stun:stun.l.google.com:19302" }, { "url": "stun:stun.xten.com" }, ]};function rtc_send(msg) { console.log("rtc_send"); if (dataChannel && dataChannel.readyState == "open") { dataChannel.send(JSON.stringify(msg)); } else { delPeerConn(); }}function setDataChannel(dc) { dc.onerror = function (error) { console.log("DataChannel Error:", error); }; dc.onmessage = function (event) { labe2.innerHTML = event.data; }; dc.onopen = function () { console.log("DataChannel is onopen"); document.getElementById('Button1').value = "断开"; }; dc.onclose = function () { console.log("DataChannel is Closed"); delPeerConn(); document.getElementById('Button1').value = "连接"; labe2.innerHTML = "已关闭"; };}function delPeerConn() { if (dataChannel) { dataChannel.close(); ServerPeerConn.close(); dataChannel = ServerPeerConn = null; } if (rtc_ws) { rtc_ws.close(); rtc_ws = null; }}function createPeerConnection() { console.log("createPeerConnection..."); ServerPeerConn = new nativePeerConnection(servers, pcConstraints); // optional data channel dataChannel = ServerPeerConn.createDataChannel("sendDataChannel", null); setDataChannel(dataChannel); ServerPeerConn.onaddstream = function (e) { try { console.log("remote media connection success!"); var vid2 = document.getElementById('vid2'); vid2.srcObject = e.stream; vid2.onloadedmetadata = function (e) { vid2.play(); }; } catch (ex) { console.log("Failed to connect to remote media!", ex); } }; ServerPeerConn.onicecandidate = function (event) { console.log("ServerPeerConn!"); }; ServerPeerConn.ondatachannel = function (event) { dataChannel = event.channel; setDataChannel(dataChannel); } var offerOptions = { // New spec states offerToReceiveAudio/Video are of type long (due to // having to tell how many "m" lines to generate). // http://w3c.github.io/webrtc-pc/#idl-def-RTCOfferAnswerOptions. offerToReceiveAudio: 1, offerToReceiveVideo: 1, iceRestart: 0, voiceActivityDetection: 0 }; //ServerPeerConn.createOffer(function (desc) { ServerPeerConn.createOffer(offerOptions).then(function (desc) { console.log('createOffer: ' + desc.sdp); ServerPeerConn.setLocalDescription(desc, function () { var sdata = {}; sdata["command"] = "__Offer"; sdata["desc"] = desc; ws_Send(sdata); }, function (errorInformation) { console.log('setLocalDescription error: ' + errorInformation); }); }, function (error) { console.log(error); }, offerOptions);}//信令服务function ws_Send(data) { try { rtc_ws.send(JSON.stringify(data)); } catch (ex) { console.log("Message sending failed!"); }}function wsconnect() { rtc_ws = new WebSocket("ws://" + host + ":9000"); rtc_ws.onopen = function () { var sdata = {}; sdata["command"] = "__UserJoin"; var udata = {}; udata["UserID"] = UserID; udata["Password"] = Password; sdata["udata"] = udata; ws_Send(sdata); console.log("Socket connected!"); labe2.innerHTML = "Socket connected!"; }; rtc_ws.onclose = function () { console.log("webSocket connection has been disconnected!"); rtc_ws = null; }; rtc_ws.onmessage = function (Message) { var obj = JSON.parse(Message.data); var command = obj.command; switch (command) { case "__OnLoginSuccessful": { createPeerConnection(); cursocketId = obj.socketId; } break; case "__OnError": { labe2.innerHTML = obj.info; } break; case "__OnSuccessAnswer": { if (ServerPeerConn) { console.log("OnSuccessAnswer[remote]: " + obj.sdp); ServerPeerConn.setRemoteDescription( new nativeRTCSessionDescription({ type: "answer", sdp: obj.sdp }), function () { }, function (errorInformation) { console.log('setRemoteDescription error: ' + errorInformation); }); } } break; case "__OnIceCandidate": { if (ServerPeerConn) { console.log("OnIceCandidate[remote]: " + obj.sdp); var c = new nativeRTCIceCandidate({ sdpMLineIndex: obj.sdp_mline_index, candidate: obj.sdp }); ServerPeerConn.addIceCandidate(c); } } break; default: { console.log(Message.data); } } };}
效果:
服务端:
客户端:
阅读全文
0 0
- Webrtc穿透转发通讯1-网页
- Webrtc穿透转发通讯2-windows
- WEBRTC核心技术穿透
- socat端口转发-穿透网络
- rfc5766-turn-server webrtc穿透服务器配置
- WebRTC穿透服务器防火墙配置问题
- WebRTC peer之间通讯过程
- webrtc网页视频demo
- SSH端口转发与内网穿透
- P2P穿透及TURN转发简要说明
- 利用SSH端口转发作内网穿透
- 强制WebRTC使用转发(relay)模式
- 网页转发代码(2)
- 网页上如何使用WebRTC
- 网页上如何使用WebRTC
- 基于webrtc的一对多音视频通讯
- 基于webrtc的一对多音视频通讯
- WebRTC-web实时通讯(转)
- tensorflow--模型持久化
- drawerlayout_demo
- 实例笔记(一)
- C++IO类&文件输入输出
- KNN算法(一)
- Webrtc穿透转发通讯1-网页
- 某二进制位置0或置1
- 程序 进程 线程
- Java学习(十)
- 快速部署开源的 Java 博客系统 Tale
- cd test2
- 线段树入门 南阳oj 119
- android 7.0系统解决拍照的问题
- JVM调优浅谈