Roderic Day 5 anni fa
parent
commit
a24942b7e1
2 ha cambiato i file con 108 aggiunte e 111 eliminazioni
  1. +107
    -111
      apps/streams.js
  2. +1
    -0
      pico.js

+ 107
- 111
apps/streams.js Vedi File

@@ -10,124 +10,114 @@ const VideoConfig = Object.seal({
},
toggle: (property) => () => {
VideoConfig[property] = !VideoConfig[property]
VideoSelf.update()
updateSelfVideo()
}
})
const VideoSelf = {
async update() {
const video = document.querySelector('video.self')
video.srcObject.getTracks().forEach(track => {
const updateSelfVideo = async () => {
const video = document.querySelector('video.self')

video.srcObject.getTracks().forEach(track => {
track.stop()
video.srcObject.removeTrack(track)
delete track
})

if(VideoConfig.videoOn || VideoConfig.audioOn) {
await navigator.mediaDevices
.getUserMedia(VideoConfig)
.then(s => s.getTracks().forEach(t => video.srcObject.addTrack(t)))
.catch(e => console.error(e))
}
video.srcObject = video.srcObject // safari

wire({kind: 'peerInfo', value: {type: 'request'}})
}
const updateOtherVideo = (target, dom) => {
dom.srcObject = new MediaStream()
let rpc = null

const rpcConfig = {iceServers: [{urls: 'stun:stun.sipgate.net:3478'}]}

const stopRpc = () => {
rpc && rpc.close()
dom.srcObject.getTracks().forEach(track => {
track.stop()
video.srcObject.removeTrack(track)
dom.srcObject.removeTrack(track)
delete track
})
stream = new MediaStream()
if(VideoConfig.videoOn || VideoConfig.audioOn) {
await navigator.mediaDevices
.getUserMedia(VideoConfig)
.then(s => s.getTracks().forEach(t => stream.addTrack(t)))
.catch(e => console.error(e))
}

const resetRpc = () => {
stopRpc()
rpc = new RTCPeerConnection(rpcConfig)
document.querySelector('video.self').srcObject.getTracks()
.forEach(t => rpc.addTrack(t))

rpc.onicecandidate = ({candidate}) => {
if(candidate && candidate.candidate) {
const value = {type: 'candidate', candidate}
wire({kind: 'peerInfo', value, target})
}
}
video.srcObject = stream
wire({kind: 'peerInfo', value: {type: 'request'}})
},
setUp: ({dom}) => {
dom.playsinline = true
dom.autoplay = true
dom.muted = true
dom.srcObject = new MediaStream()
VideoSelf.update()
},
view({attrs: {username}}) {
const styleOuter = {
position: 'relative',
display: 'block',
backgroundColor: 'black',
color: 'white',
overflow: 'hidden',
rpc.ontrack = ({track}) => {
dom.srcObject.addTrack(track)
dom.srcObject = dom.srcObject
}
const styleInner = {
objectFit: 'cover',
width: '100%',
height: '100%',
transform: 'scaleX(-1)',
}

dom.listener = async ({detail: {source, value}}) => {
if(source !== target) {
return
}
return m('.video-container', {style: styleOuter},
m('.video-info', {style: {position: 'absolute', zIndex: 999}},
m('span', {style: {padding: '5px'}}, username),
),
m('video.self', {style: styleInner, oncreate: this.setUp}),
)
},
console.log(source, value.type)
if(value.type === 'request') {
resetRpc()
const localOffer = await rpc.createOffer()
await rpc.setLocalDescription(localOffer)
wire({kind: 'peerInfo', value: localOffer, target})
}
else if(value.type === 'offer') {
resetRpc()
const remoteOffer = new RTCSessionDescription(value)
await rpc.setRemoteDescription(remoteOffer)
const localAnswer = await rpc.createAnswer()
await rpc.setLocalDescription(localAnswer)
wire({kind: 'peerInfo', value: localAnswer, target})
}
else if(value.type === 'answer') {
const remoteAnswer = new RTCSessionDescription(value)
await rpc.setRemoteDescription(remoteAnswer)
}
else if(value.type === 'candidate') {
const candidate = new RTCIceCandidate(value.candidate)
await rpc.addIceCandidate(candidate)
}
else if(value.type === 'stop') {
stopRpc()
}
}
addEventListener('peerInfo', dom.listener)
}
const VideoOther = {
const Video = {
setUp: (username) => ({dom}) => {
dom.playsinline = true
dom.autoplay = true
dom.srcObject = new MediaStream()
let rpc = null

const rpcConfig = {iceServers: [{urls: 'stun:stun.sipgate.net:3478'}]}

const stopRpc = () => {
rpc && rpc.close()
dom.srcObject.getTracks().forEach(track => {
track.stop()
dom.srcObject.removeTrack(track)
delete track
})
if(username === State.username) {
dom.classList.add('self')
dom.muted = true
updateSelfVideo()
}

const resetRpc = () => {
stopRpc()
rpc = new RTCPeerConnection(rpcConfig)
dom.srcObject = new MediaStream()
document.querySelector('video.self').srcObject.getTracks()
.forEach(t => rpc.addTrack(t))

rpc.onicecandidate = ({candidate}) => {
if(candidate && candidate.candidate) {
wire({kind: 'peerInfo', value: {type: 'candidate', candidate}, target: username})
}
}
rpc.ontrack = ({track}) => {
dom.srcObject.addTrack(track)
}
}

const onPeerInfo = async ({detail: {source, value}}) => {
if(source !== username) {
return
}
console.log(source, value.type)
if(value.type === 'request') {
resetRpc()
const localOffer = await rpc.createOffer()
await rpc.setLocalDescription(localOffer)
wire({kind: 'peerInfo', value: localOffer, target: username})
}
else if(value.type === 'offer') {
resetRpc()
const remoteOffer = new RTCSessionDescription(value)
await rpc.setRemoteDescription(remoteOffer)
const localAnswer = await rpc.createAnswer()
await rpc.setLocalDescription(localAnswer)
wire({kind: 'peerInfo', value: localAnswer, target: username})
}
else if(value.type === 'answer') {
const remoteAnswer = new RTCSessionDescription(value)
await rpc.setRemoteDescription(remoteAnswer)
}
else if(value.type === 'candidate') {
const candidate = new RTCIceCandidate(value.candidate)
await rpc.addIceCandidate(candidate)
}
else if(value.type === 'stop') {
stopRpc()
}
else {
updateOtherVideo(username, dom)
}
},
tearDown: (username) => ({dom}) => {
removeEventListener('peerInfo', dom.listener)

addEventListener('peerInfo', onPeerInfo)
dom.srcObject.getTracks().forEach(track => {
track.stop()
dom.srcObject.removeTrack(track)
delete track
})
},
view({attrs: {username}}) {
const styleOuter = {
@@ -143,11 +133,15 @@ const VideoOther = {
height: '100%',
transform: 'scaleX(-1)',
}
return m('.video-container', {style: styleOuter},
return m('.video-container', {key: username, style: styleOuter},
m('.video-info', {style: {position: 'absolute', zIndex: 999}},
m('span', {style: {padding: '5px'}}, username),
),
m('video', {style: styleInner, oncreate: this.setUp(username)}),
m('video[playsinline][autoplay]', {
style: styleInner,
oncreate: this.setUp(username),
onremove: this.tearDown(username),
}),
)
},
}
@@ -166,13 +160,15 @@ const StreamContainer = {
return '1fr'
},
view() {
const dims = [StreamContainer.getRows(), StreamContainer.getColumns()]
if(screen.height > screen.width) dims.reverse()
const style = {
display: 'grid',
padding: '3px',
gridGap: '3px',
height: '80vh',
gridTemplateColumns: StreamContainer.getColumns(),
gridTemplateRows: StreamContainer.getRows(),
height: '70vh',
gridTemplateRows: dims[0],
gridTemplateColumns: dims[1],
}
return m('div',
m('.video-controls',
@@ -180,9 +176,9 @@ const StreamContainer = {
m('button', {onclick: VideoConfig.toggle('audioOn')}, 'audio'),
),
m('.videos', {style},
m(VideoSelf, {username: State.username}),
m(Video, {username: State.username}),
State.online.filter(username => username != State.username)
.map(username => m(VideoOther, {username}))
.map(username => m(Video, {username}))
),
)
},

+ 1
- 0
pico.js Vedi File

@@ -89,6 +89,7 @@ const Base = {
m('form.logout' + (State.isConnected ? '' : '.hidden'),
{onsubmit: Base.sendLogout},
m('button', 'Logout'),
m('input[readonly]', {value: location}),
),
m('.error', State.info),
),

Loading…
Annulla
Salva