Pārlūkot izejas kodu

Concentrate state

master
Roderic Day pirms 5 gadiem
vecāks
revīzija
63b3368b11
1 mainītis faili ar 34 papildinājumiem un 32 dzēšanām
  1. +34
    -32
      pico.js

+ 34
- 32
pico.js Parādīt failu

@@ -1,9 +1,10 @@
const State = {
username: null,
websocket: null,
online: [],
posts: [],
media: null,
username: null,
rpcs: {},
media: {},
}

/*
@@ -13,43 +14,44 @@ const State = {
*/
const wire = (message) => State.websocket.send(JSON.stringify(message))
const signal = (message) => dispatchEvent(new CustomEvent(message.kind, {detail: message}))
const signalPeerStop = (username) => signal({kind: 'peerInfo', value: {type: 'stop'}, source: username})
const listen = (kind, handler) => addEventListener(kind, handler)
listen('login', ({detail}) => State.username = detail.value)
listen('post', ({detail}) => State.posts.push(detail))
listen('peerInfo', (e) => onPeerInfo(e))
const doNotLog = new Set(['login', 'post', 'peerInfo'])


/*
*
* WEBRTC
*
*/
const rpcs = {}
const streams = {}
const getOrCreateRpc = (username) => {
if(!rpcs[username] && State.media) {
if(State.username === username) {
return
}
const myStream = State.media[State.username]
if(!State.rpcs[username] && myStream) {
const rpc = new RTCPeerConnection({iceServers: [{urls: 'stun:stun.sipgate.net:3478'}]})
State.media.getTracks().forEach(track => rpc.addTrack(track, State.media))
myStream.getTracks().forEach(track => rpc.addTrack(track, myStream))
rpc.onicecandidate = ({candidate}) => {
if(candidate) {
wire({kind: 'peerInfo', value: {type: 'candidate', candidate}})
}
}
rpc.ontrack = (e) => {
streams[username] = e.streams[0]
State.media[username] = e.streams[0]
m.redraw()
}
rpc.onclose = (e) => {
console.log(username, e)
}
rpcs[username] = rpc
State.rpcs[username] = rpc
}
return rpcs[username]
return State.rpcs[username]
}
const onPeerInfo = async ({detail: message}) => {
if(State.username === message.source) {
return
}
const rpc = getOrCreateRpc(message.source)
if(rpc && message.value.type === 'request') {
const localOffer = await rpc.createOffer()
@@ -72,16 +74,16 @@ const onPeerInfo = async ({detail: message}) => {
rpc.addIceCandidate(candidate)
}
else if(message.value.type === 'stop') {
if(streams[message.source]) {
streams[message.source].getTracks().map(track => track.stop())
delete streams[message.source]
if(State.media[message.source]) {
State.media[message.source].getTracks().map(track => track.stop())
delete State.media[message.source]
}
if(rpcs[message.source]) {
rpcs[message.source].close()
delete rpcs[message.source]
if(State.rpcs[message.source]) {
State.rpcs[message.source].close()
delete State.rpcs[message.source]
}
}
else {
else if(rpc) {
console.log('uncaught', message)
}
}
@@ -101,34 +103,34 @@ const prettyTime = (ts) => {
return ts.slice(11, 19)
}
const Video = {
appendStream: (stream) => ({dom}) => {
appendStream: ({username, stream}) => ({dom}) => {
dom.autoplay = true
dom.muted = true
dom.muted = (username === State.username)
dom.srcObject = stream
},
view({attrs}) {
const rpc = State.rpcs[attrs.username] || {iceConnectionState: m.trust(' ')}
return m('.video-container',
m('.video-source', attrs.username),
m('video', {playsinline: true, oncreate: Video.appendStream(attrs.stream)}),
m('.video-state', rpc.iceConnectionState),
m('video', {playsinline: true, oncreate: Video.appendStream(attrs)}),
)
},
}
const Media = {
constraints: {audio: true, video: {width: {ideal: 320}, facingMode: 'user'}},
turnOn: async () => {
State.media = await navigator.mediaDevices.getUserMedia(Media.constraints)
const media = await navigator.mediaDevices.getUserMedia(Media.constraints)
State.media[State.username] = media
wire({kind: 'peerInfo', value: {type: 'request'}})
m.redraw()
},
turnOff: () => {
wire({kind: 'peerInfo', value: {type: 'stop'}})
// signal internally
Object.keys(rpcs).forEach(source => signal({kind: 'peerInfo', value: {type: 'stop'}, source}))
State.media.getTracks().map(track => track.stop())
delete State.media
State.online.forEach(signalPeerStop)
},
view() {
if(!State.media) {
if(!State.media[State.username]) {
return m('.media',
m('button', {onclick: Media.turnOn}, 'turn media on'),
)
@@ -137,8 +139,7 @@ const Media = {
return m('.media',
m('button', {onclick: Media.turnOff}, 'turn media off'),
m('.videos',
m(Video, {username: State.username, stream: State.media}),
Object.entries(streams).map(([username, stream]) =>
Object.entries(State.media).map(([username, stream]) =>
m(Video, {username, stream})
),
),
@@ -154,7 +155,7 @@ const Login = {
connect(username)
},
sendLogout: (e) => {
State.media && Media.turnOff()
Media.turnOff()
wire({kind: 'logout'})
State.posts = []
},
@@ -170,7 +171,7 @@ const Login = {
m('input', attrs),
m('button', 'Login'),
),
State.kind === 'error' && m('.error', State.info),
m('.error', State.info),
)
},
}
@@ -251,3 +252,4 @@ const connect = (username) => {
if(localStorage.username) {
connect(localStorage.username)
}
addEventListener('pagehide', Media.turnOff)

Notiek ielāde…
Atcelt
Saglabāt