|
|
|
|
|
|
|
|
if(State.username === username) { |
|
|
if(State.username === username) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
const myStream = State.streams[State.username] |
|
|
|
|
|
if(!State.rpcs[username] && myStream) { |
|
|
|
|
|
|
|
|
if(!State.rpcs[username]) { |
|
|
const rpc = new RTCPeerConnection({iceServers: [{urls: 'stun:stun.sipgate.net:3478'}]}) |
|
|
const rpc = new RTCPeerConnection({iceServers: [{urls: 'stun:stun.sipgate.net:3478'}]}) |
|
|
myStream.getTracks().forEach(track => rpc.addTrack(track, myStream)) |
|
|
|
|
|
rpc.onicecandidate = ({candidate}) => { |
|
|
rpc.onicecandidate = ({candidate}) => { |
|
|
if(candidate) { |
|
|
if(candidate) { |
|
|
wire({kind: 'peerInfo', value: {type: 'candidate', candidate}}) |
|
|
wire({kind: 'peerInfo', value: {type: 'candidate', candidate}}) |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
return State.rpcs[username] |
|
|
return State.rpcs[username] |
|
|
} |
|
|
} |
|
|
const getSelectedMedia = async () => { |
|
|
|
|
|
const stream = new MediaStream() |
|
|
|
|
|
const addTrack = stream.addTrack.bind(stream) |
|
|
|
|
|
|
|
|
const setSelectedMedia = async () => { |
|
|
|
|
|
const localStream = State.streams[State.username] |
|
|
|
|
|
if(!localStream) { |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
localStream.getTracks().forEach(track => { |
|
|
|
|
|
track.stop() |
|
|
|
|
|
localStream.removeTrack(track) |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
const addTrack = localStream.addTrack.bind(localStream) |
|
|
|
|
|
|
|
|
const muted = document.querySelector('#mute-check').checked |
|
|
const muted = document.querySelector('#mute-check').checked |
|
|
if(!muted) { |
|
|
if(!muted) { |
|
|
|
|
|
|
|
|
.catch(e => console.error(e)) |
|
|
.catch(e => console.error(e)) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return stream |
|
|
|
|
|
|
|
|
document.querySelectorAll('video').forEach(video => video.srcObject = video.srcObject) |
|
|
|
|
|
wire({kind: 'peerInfo', value: {type: 'request'}}) |
|
|
} |
|
|
} |
|
|
const onPeerInfo = async ({detail: message}) => { |
|
|
const onPeerInfo = async ({detail: message}) => { |
|
|
const rpc = getOrCreateRpc(message.source) |
|
|
|
|
|
|
|
|
const localStream = State.streams[State.username] |
|
|
|
|
|
const rpc = localStream && getOrCreateRpc(message.source) |
|
|
|
|
|
const resetStreams = () => { |
|
|
|
|
|
rpc.getSenders().forEach(sender => rpc.removeTrack(sender)) |
|
|
|
|
|
localStream.getTracks().forEach(track => rpc.addTrack(track, localStream)) |
|
|
|
|
|
} |
|
|
if(rpc && message.value.type === 'request') { |
|
|
if(rpc && message.value.type === 'request') { |
|
|
|
|
|
resetStreams() |
|
|
const localOffer = await rpc.createOffer() |
|
|
const localOffer = await rpc.createOffer() |
|
|
await rpc.setLocalDescription(localOffer) |
|
|
await rpc.setLocalDescription(localOffer) |
|
|
wire({kind: 'peerInfo', value: localOffer, target: message.source}) |
|
|
wire({kind: 'peerInfo', value: localOffer, target: message.source}) |
|
|
} |
|
|
} |
|
|
else if(rpc && message.value.type === 'offer') { |
|
|
else if(rpc && message.value.type === 'offer') { |
|
|
|
|
|
resetStreams() |
|
|
const remoteOffer = new RTCSessionDescription(message.value) |
|
|
const remoteOffer = new RTCSessionDescription(message.value) |
|
|
await rpc.setRemoteDescription(remoteOffer) |
|
|
await rpc.setRemoteDescription(remoteOffer) |
|
|
const localAnswer = await rpc.createAnswer() |
|
|
const localAnswer = await rpc.createAnswer() |
|
|
|
|
|
|
|
|
echoCancellation: true, |
|
|
echoCancellation: true, |
|
|
}, |
|
|
}, |
|
|
turnOn: async () => { |
|
|
turnOn: async () => { |
|
|
const media = await getSelectedMedia() |
|
|
|
|
|
State.streams[State.username] = media |
|
|
|
|
|
wire({kind: 'peerInfo', value: {type: 'request'}}) |
|
|
|
|
|
|
|
|
State.streams[State.username] = new MediaStream() |
|
|
|
|
|
await setSelectedMedia() |
|
|
m.redraw() |
|
|
m.redraw() |
|
|
}, |
|
|
}, |
|
|
turnOff: () => { |
|
|
turnOff: () => { |
|
|
|
|
|
|
|
|
? m('button', {onclick: Media.turnOff}, 'turn off') |
|
|
? m('button', {onclick: Media.turnOff}, 'turn off') |
|
|
: m('button', {onclick: Media.turnOn}, 'turn on') |
|
|
: m('button', {onclick: Media.turnOn}, 'turn on') |
|
|
, |
|
|
, |
|
|
m('select#media-source', Media.videoSources.map(option => m('option', option))), |
|
|
|
|
|
m('label', m('input#mute-check', {type: 'checkbox'}), 'mute'), |
|
|
|
|
|
|
|
|
m('select#media-source', {onchange: setSelectedMedia}, |
|
|
|
|
|
Media.videoSources.map(option => m('option', option)) |
|
|
|
|
|
), |
|
|
|
|
|
m('label', |
|
|
|
|
|
m('input#mute-check', {onchange: setSelectedMedia, type: 'checkbox'}), |
|
|
|
|
|
'mute' |
|
|
|
|
|
), |
|
|
), |
|
|
), |
|
|
m('.videos', |
|
|
m('.videos', |
|
|
Object.keys(State.streams).map((username) => |
|
|
Object.keys(State.streams).map((username) => |