diff --git a/examples/basic/meet.html b/examples/basic/meet.html new file mode 100644 index 00000000..e91f8f27 --- /dev/null +++ b/examples/basic/meet.html @@ -0,0 +1,38 @@ + + +
must press play or unmute on new videos to accept meeting
+
+ +
+
Stream
+ + + + + + + \ No newline at end of file diff --git a/gun.js b/gun.js index 810dda61..fc34f07b 100644 --- a/gun.js +++ b/gun.js @@ -220,6 +220,7 @@ } function set(word, is){ + // TODO: Perf on random write is decent, but short keys or seq seems significantly slower. var b = this, has = b.all[word]; if(has){ return b(word, is) } // updates to in-memory items will always match exactly. var page = b.page(word=''+word), tmp; // before we assume this is an insert tho, we need to check @@ -240,21 +241,22 @@ function split(p, b){ // TODO: use closest hash instead of half. //console.time(); + //var S = performance.now(); var L = sort(p), l = L.length, i = l/2 >> 0, j = i, half = L[j], tmp; //console.timeEnd(); var next = {first: half.substring(), size: 0, substring: sub, toString: to, book: b, get: b, read: list}, f = next.from = []; - //console.time(); while(tmp = L[i++]){ f.push(tmp); next.size += (tmp.is||'').length||1; tmp.page = next; } - //console.timeEnd(); console.time(); p.from = p.from.slice(0, j); p.size -= next.size; b.list.splice(spot(next.first, b.list)+1, 0, next); // TODO: BUG! Make sure next.first is decoded text. // TODO: BUG! spot may need parse too? //console.timeEnd(); if(b.split){ b.split(next, p) } + //console.log(S = (performance.now() - S), 'split'); + //console.BIG = console.BIG > S? console.BIG : S; } function slot(t){ return heal((t=t||'').substring(1, t.length-1).split(t[0]), t[0]) } B.slot = slot; // TODO: check first=last & pass `s`. @@ -1684,10 +1686,10 @@ if((tmp = msg['><']) && 'string' == typeof tmp){ tmp.slice(0,99).split(',').forEach(function(k){ this[k] = 1 }, (msg._).yo = {}) } // Peers already sent to, do not resend. // DAM ^ if(tmp = msg.dam){ + (dup_track(id)||{}).via = peer; if(tmp = mesh.hear[tmp]){ tmp(msg, peer, root); } - dup_track(id); return; } if(tmp = msg.ok){ msg._.near = tmp['/'] } @@ -1980,10 +1982,10 @@ var mesh = opt.mesh = opt.mesh || Gun.Mesh(root); - var wire = mesh.wire || opt.wire; + var wired = mesh.wire || opt.wire; mesh.wire = opt.wire = open; function open(peer){ try{ - if(!peer || !peer.url){ return wire && wire(peer) } + if(!peer || !peer.url){ return wired && wired(peer) } var url = peer.url.replace(/^http/, 'ws'); var wire = peer.wire = new opt.WebSocket(url); wire.onclose = function(){ diff --git a/lib/rfs.js b/lib/rfs.js index c43b14f8..8e37fe5a 100644 --- a/lib/rfs.js +++ b/lib/rfs.js @@ -83,7 +83,7 @@ Gun.on('create', function(root){ this.to.next(root); var opt = root.opt; if(opt.rfs === false){ return } - opt.store = opt.store || (!Gun.window || opt.rfs === true && Store(opt)); + opt.store = opt.store || ((!Gun.window || opt.rfs === true) && Store(opt)); }); module.exports = Store; \ No newline at end of file diff --git a/lib/store.js b/lib/store.js index f86634bf..8c567a54 100644 --- a/lib/store.js +++ b/lib/store.js @@ -66,7 +66,7 @@ Gun.on('create', function(root){ if((tmp = (root.next||'')[soul]) && tmp.put){ if(o.atom){ tmp = (tmp.next||'')[o.atom] ; - if(tmp && tmp.rad){ return } + if(tmp && tmp.root && tmp.root.graph && tmp.root.graph[soul] && tmp.root.graph[soul][o.atom]){ return } } else if(tmp && tmp.rad){ return } } diff --git a/lib/webrtc.js b/lib/webrtc.js index b746466e..60fe0e49 100644 --- a/lib/webrtc.js +++ b/lib/webrtc.js @@ -1,10 +1,10 @@ ;(function(){ - var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); - Gun.on('opt', function(root){ + 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(!GUN.Mesh){ return } if(false === opt.RTCPeerConnection){ return } var env; @@ -33,44 +33,69 @@ 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.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 } - open({'#': ''+msg['#'], ok: {rtc: {id: last}}}); + plan({'#': ''+msg['#'], ok: {rtc: {id: last}}}); }); }; - var mesh = opt.mesh = opt.mesh || Gun.Mesh(root); + 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 open(msg){ - if(this && this.off){ this.off() } // Ignore this, because of ask / ack. + function plan(msg){ if(!msg.ok){ return } var rtc = msg.ok.rtc, peer, tmp; if(!rtc || !rtc.id || rtc.id === opt.pid){ return } - //console.log("webrtc:", JSON.stringify(msg)); + peer = open(msg, rtc); + if(tmp = rtc.candidate){ + return peer.addIceCandidate(new opt.RTCIceCandidate(tmp)); + } if(tmp = rtc.answer){ - if(!(peer = opt.peers[rtc.id] || open[rtc.id]) || peer.remoteSet){ return } tmp.sdp = tmp.sdp.replace(/\\r\\n/g, '\r\n'); return peer.setRemoteDescription(peer.remoteSet = new opt.RTCSessionDescription(tmp)); } - if(tmp = rtc.candidate){ - peer = opt.peers[rtc.id] || open[rtc.id] || open({ok: {rtc: {id: rtc.id}}}); - return peer.addIceCandidate(new opt.RTCIceCandidate(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); } - //if(opt.peers[rtc.id]){ return } - if(open[rtc.id]){ return } + } + 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){ }; @@ -80,31 +105,27 @@ } wire.onmessage = function(msg){ if(!msg){ return } - //console.log('via rtc'); mesh.hear(msg.data || msg, peer); }; - peer.onicecandidate = function(e){ // source: EasyRTC! + peer.onicecandidate = function(e){ rtceve(e); if(!e.candidate){ return } - root.on('out', {'@': msg['#'], ok: {rtc: {candidate: e.candidate, id: opt.pid}}}); + root.on('out', {'@': (msg||'')['#'], '#': root.ask(plan), ok: {rtc: {candidate: e.candidate, id: opt.pid}}}); } - peer.ondatachannel = function(e){ + peer.ondatachannel = function(e){ rtceve(e); var rc = e.channel; rc.onmessage = wire.onmessage; rc.onopen = wire.onopen; rc.onclose = wire.onclose; } - if(tmp = rtc.offer){ - rtc.offer.sdp = rtc.offer.sdp.replace(/\\r\\n/g, '\r\n') - peer.setRemoteDescription(new opt.RTCSessionDescription(tmp)); - peer.createAnswer(function(answer){ - peer.setLocalDescription(answer); - root.on('out', {'@': msg['#'], ok: {rtc: {answer: answer, id: opt.pid}}}); - }, function(){}, opt.rtc.sdp); - return; + 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(open), ok: {rtc: {offer: offer, id: opt.pid}}}); + root.on('out', {'@': (msg||'')['#'], '#': root.ask(plan), ok: {rtc: {offer: offer, id: opt.pid}}}); }, function(){}, opt.rtc.sdp); return peer; }