;(function(){ var GUN = (typeof window !== "undefined")? window.Gun : require('../gun'); GUN.on('opt', function(root){ this.to.next(root); var opt = root.opt; if(root.once){ return } if(!GUN.Mesh){ return } if(false === opt.RTCPeerConnection){ return } var env; if(typeof window !== "undefined"){ env = window } if(typeof global !== "undefined"){ env = global } env = env || {}; var rtcpc = opt.RTCPeerConnection || env.RTCPeerConnection || env.webkitRTCPeerConnection || env.mozRTCPeerConnection; var rtcsd = opt.RTCSessionDescription || env.RTCSessionDescription || env.webkitRTCSessionDescription || env.mozRTCSessionDescription; var rtcic = opt.RTCIceCandidate || env.RTCIceCandidate || env.webkitRTCIceCandidate || env.mozRTCIceCandidate; if(!rtcpc || !rtcsd || !rtcic){ return } opt.RTCPeerConnection = rtcpc; opt.RTCSessionDescription = rtcsd; opt.RTCIceCandidate = rtcic; opt.rtc = opt.rtc || {'iceServers': [ {urls: 'stun:stun.l.google.com:19302'}, {urls: 'stun:stun.cloudflare.com:3478'}/*, {urls: "stun:stun.sipgate.net:3478"}, {urls: "stun:stun.stunprotocol.org"}, {urls: "stun:stun.sipgate.net:10000"}, {urls: "stun:217.10.68.152:10000"}, {urls: 'stun:stun.services.mozilla.com'}*/ ]}; // TODO: Select the most appropriate stuns. // FIXME: Find the wire throwing ICE Failed // The above change corrects at least firefox RTC Peer handler where it **throws** on over 6 ice servers, and updates url: to urls: removing deprecation warning opt.rtc.dataChannel = opt.rtc.dataChannel || {ordered: false, maxRetransmits: 2}; opt.rtc.sdp = opt.rtc.sdp || {mandatory: {OfferToReceiveAudio: false, OfferToReceiveVideo: false}}; opt.rtc.max = opt.rtc.max || 55; // is this a magic number? // For Future WebRTC notes: Chrome 500 max limit, however 256 likely - FF "none", webtorrent does 55 per torrent. opt.rtc.room = opt.rtc.room || GUN.window && (location.hash.slice(1) || location.pathname.slice(1)); opt.announce = function(to){ opt.rtc.start = +new Date; // handle room logic: root.$.get('/RTC/'+opt.rtc.room+' msg.put['>']){ return } plan({'#': ''+msg['#'], ok: {rtc: {id: last}}}); }); }; var mesh = opt.mesh = opt.mesh || GUN.Mesh(root), wired = mesh.wire; mesh.hear['rtc'] = plan; mesh.wire = function(media){ try{ wired && wired(media); if(!(media instanceof MediaStream)){ return } (open.media = open.media||{})[media.id] = media; for(var p in opt.peers){ p = opt.peers[p]||''; p.addTrack && media.getTracks().forEach(track => { p.addTrack(track, media); }); p.createOffer && p.createOffer(function(offer){ p.setLocalDescription(offer); mesh.say({'#': root.ask(plan), dam: 'rtc', ok: {rtc: {offer: offer, id: opt.pid}}}, p); }, function(){}, opt.rtc.sdp); } } catch(e){console.log(e)} } root.on('create', function(at){ this.to.next(at); setTimeout(opt.announce, 1); }); function plan(msg){ if(!msg.ok){ return } var rtc = msg.ok.rtc, peer, tmp; if(!rtc || !rtc.id || rtc.id === opt.pid){ return } peer = open(msg, rtc); if(tmp = rtc.candidate){ return peer.addIceCandidate(new opt.RTCIceCandidate(tmp)); } if(tmp = rtc.answer){ tmp.sdp = tmp.sdp.replace(/\\r\\n/g, '\r\n'); return peer.setRemoteDescription(peer.remoteSet = new opt.RTCSessionDescription(tmp)); } if(tmp = rtc.offer){ rtc.offer.sdp = rtc.offer.sdp.replace(/\\r\\n/g, '\r\n'); peer.setRemoteDescription(new opt.RTCSessionDescription(tmp)); return peer.createAnswer(function(answer){ peer.setLocalDescription(answer); root.on('out', {'@': msg['#'], ok: {rtc: {answer: answer, id: opt.pid}}}); }, function(){}, opt.rtc.sdp); } } function open(msg, rtc, peer){ if(peer = opt.peers[rtc.id] || open[rtc.id]){ return peer } (peer = new opt.RTCPeerConnection(opt.rtc)).id = rtc.id; var wire = peer.wire = peer.createDataChannel('dc', opt.rtc.dataChannel); function rtceve(eve){ eve.peer = peer; gun.on('rtc', eve) } peer.$ = gun; open[rtc.id] = peer; peer.ontrack = rtceve; peer.onremovetrack = rtceve; peer.onconnectionstatechange = rtceve; wire.to = setTimeout(function(){delete open[rtc.id]},1000*60); wire.onclose = function(){ mesh.bye(peer) }; wire.onerror = function(err){ }; wire.onopen = function(e){ delete open[rtc.id]; mesh.hi(peer); } wire.onmessage = function(msg){ if(!msg){ return } mesh.hear(msg.data || msg, peer); }; peer.onicecandidate = function(e){ rtceve(e); if(!e.candidate){ return } root.on('out', {'@': (msg||'')['#'], '#': root.ask(plan), ok: {rtc: {candidate: e.candidate, id: opt.pid}}}); } peer.ondatachannel = function(e){ rtceve(e); var rc = e.channel; rc.onmessage = wire.onmessage; rc.onopen = wire.onopen; rc.onclose = wire.onclose; } if(rtc.offer){ return peer } for(var m in open.media){ m = open.media[m]; m.getTracks().forEach(track => { peer.addTrack(track, m); }); } peer.createOffer(function(offer){ peer.setLocalDescription(offer); root.on('out', {'@': (msg||'')['#'], '#': root.ask(plan), ok: {rtc: {offer: offer, id: opt.pid}}}); }, function(){}, opt.rtc.sdp); return peer; } }); }());