소스 검색

RPC file

master
Roderic Day 4 년 전
부모
커밋
bafe0da0c8
5개의 변경된 파일121개의 추가작업 그리고 78개의 파일을 삭제
  1. +76
    -0
      apps/rpc.js
  2. +39
    -16
      apps/screen.js
  3. +0
    -56
      apps/streams.js
  4. +5
    -4
      pico.html
  5. +1
    -2
      pico.js

+ 76
- 0
apps/rpc.js 파일 보기

@@ -0,0 +1,76 @@
const connections = {}
const datachannels = {}

function createConnection(target) {
const rpc = new RTCPeerConnection(rpcConfig)

rpc.onicecandidate = ({candidate}) => {
if(candidate && candidate.candidate) {
const value = {type: 'candidate', candidate}
wire({kind: 'rpc', value, target})
}
}
rpc.ontrack = ({track}) => {
console.log(track)
}
rpc.onconnectionstatechange = () => {
if(rpc.connectionState === 'failed') {
console.log(target, 'failed, retry!')
wire({kind: 'rpc', value: {type: 'request'}, target})
}
}
rpc.ondatachannel = ({channel}) => {
datachannels[target] = channel
datachannels[target].onmessage = ({data}) => console.log(data)

// for testing purposes
const msg = `rpc established from ${target} to ${State.username}`
datachannels[target].send(msg)
console.log(msg)
}

connections[target] = rpc
if(State.username > target) {
datachannels[target] = rpc.createDataChannel('test')
datachannels[target].onmessage = ({data}) => console.log(data)
signal({kind: 'rpc', value: {type: 'request'}, source: target})
}
}

async function handlePeerInfo({source: target, value}) {
const rpc = connections[target]
if(!rpc) {
return
}
if(value.type === 'request') {
const localOffer = await rpc.createOffer()
await rpc.setLocalDescription(localOffer)
wire({kind: 'rpc', value: localOffer, target})
}
else if(value.type === 'offer') {
const remoteOffer = new RTCSessionDescription(value)
await rpc.setRemoteDescription(remoteOffer)
const localAnswer = await rpc.createAnswer()
await rpc.setLocalDescription(localAnswer)
wire({kind: 'rpc', 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)
}
}

function removeConnection(user) {
const rpc = connections[user]
if(rpc) {
delete connections[user]
}
}

addEventListener('rpc', (e) => handlePeerInfo(e.detail))
addEventListener('join', (e) => createConnection(e.detail.value))
addEventListener('load', () => doNotLog.add('rpc'))

+ 39
- 16
apps/screen.js 파일 보기

@@ -1,7 +1,15 @@
const ScreenShareConfig = {
toggle() {
if(ScreenShare.isOn && ScreenShare.isStreaming) {
wire({kind: 'screen-sharing-stop'})
}
else {
ScreenShare.requestScreen()
}
},
view() {
const checked = ScreenShare.isOn
const onclick = ScreenShare.toggle
const onclick = ScreenShareConfig.toggle
return m('label.styled',
m('input[type=checkbox]', {checked, onclick}),
'screen-share',
@@ -9,31 +17,46 @@ const ScreenShareConfig = {
}
}
const ScreenShare = {
isOn: false,
start() {
const screen = document.querySelector('video.screen')
if(screen) {
navigator.mediaDevices.getDisplayMedia()
.then(s => {screen.srcObject = s})
.catch(e => console.error(e))
}
streamer: null,
stream: null,
get isStreaming() {
return ScreenShare.streamer === State.username
},
toggle() {
ScreenShare.isOn = !ScreenShare.isOn
if(ScreenShare.isOn) {
// setTimeout(ScreenShare.start, 100)
}
get isOn() {
return !! ScreenShare.streamer
},
async requestScreen() {
// ScreenShare.stream = await navigator.mediaDevices.getDisplayMedia()
// ScreenShare.streamer = State.username
// wire({kind: 'screen-sharing-start'})
},
view() {
const style = {
overflow: 'scroll',
backgroundColor: 'black',
color: 'white',
fontFamily: 'monospace',
}
return ScreenShare.isOn && m('div', {style},
m('video.screen[playsinline][autoplay]'),
return ScreenShare.isOn && m('.screen-share', {style},
m('.streamer', `${ScreenShare.streamer}'s stream`),
m('video.screen[playsinline][autoplay]', {srcObject: ScreenShare.stream}),
)
},
}
addEventListener('screen-sharing-start', ({detail}) => {
ScreenShare.streamer = detail.source
})
addEventListener('screen-sharing-stop', ({detail}) => {
if(ScreenShare.stream) {
ScreenShare.stream.getTracks().forEach(track => track.stop())
ScreenShare.stream = null
}
ScreenShare.streamer = null
})
addEventListener('load', () => {
doNotLog.add('screen-share-start')
doNotLog.add('screen-share-stop')
Headers.push([ScreenShareConfig])
Apps.push([ScreenShare, {key: 'screen-share-container'}])
})
setTimeout(ScreenShare.requestScreen, 200)

+ 0
- 56
apps/streams.js 파일 보기

@@ -52,12 +52,6 @@ const updateOtherVideo = (target, dom) => {
dom.srcObject = new MediaStream()
let rpc = null

const rpcConfig = {iceServers: [{
urls: ['stun:stun.pico.chat:5349', 'turn:turn.pico.chat:5349'],
username: 'roderic',
credential: 'tomodachi',
}]}

const stopRpc = () => {
rpc && rpc.close()
dom.srcObject.getTracks().forEach(track => {
@@ -72,57 +66,7 @@ const updateOtherVideo = (target, dom) => {
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})
}
}
rpc.ontrack = ({track}) => {
dom.srcObject.addTrack(track)
dom.srcObject = dom.srcObject
}
rpc.onconnectionstatechange = () => {
if(rpc.connectionState === 'failed') {
console.log(target, 'failed, retry!')
wire({kind: 'peerInfo', value: {type: 'request'}, target})
}
}
}

dom.listener = async ({detail: {source, value}}) => {
if(source !== target) {
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})
}
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 Video = {
setUp: (username) => ({dom}) => {

+ 5
- 4
pico.html 파일 보기

@@ -6,11 +6,12 @@
<link rel="stylesheet" href="/apps/chat.css"/>
<script src="/libs/mithril.min.js"></script>
<script src="/libs/marked.min.js"></script>
<script src="/libs/purify.min.js"></script>
<!-- <script src="/libs/purify.min.js"></script> -->
<script src="/pico.js" defer></script>
<script src="/apps/streams.js"></script>
<script src="/apps/screen.js"></script>
<script src="/apps/chat.js"></script>
<script src="/apps/rpc.js"></script>
<!-- <script src="/apps/streams.js"></script> -->
<!-- <script src="/apps/screen.js"></script> -->
<!-- <script src="/apps/chat.js"></script> -->
<!-- <script src="/apps/volume.js"></script> -->
<!-- <script src="/apps/screen.js"></script> -->
</head>

+ 1
- 2
pico.js 파일 보기

@@ -37,7 +37,7 @@ listen('state', ({detail}) => {
delete detail.kind
Object.assign(State, detail)
})
const doNotLog = new Set(['login', 'state', 'post', 'peerInfo', 'volumeMapMove'])
const doNotLog = new Set(['state'])
/*
*
* UTILS
@@ -86,7 +86,6 @@ const connect = (username) => {
}

State.websocket.onclose = (e) => {
State.online.forEach(signalPeerStop)
if(!e.wasClean) {
setTimeout(connect, 1000, username)
}

Loading…
취소
저장