Added ux to vanilla client, rebuild server side

This commit is contained in:
gltron
2020-03-31 20:32:50 +02:00
parent c7466e6e51
commit 60ff817711
46 changed files with 284 additions and 13660 deletions

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<link rel="stylesheet" href="style.css" />
<title>Lil'Streamy</title>
</head>
<body>
<div id="loginDiv">
<input class="input" id="loginInput" placeholder="username" type="text"/>
<button class="button" id="loginBt" >Login</button>
</div>
<div id="connectDiv">
<input id="callInput" placeholder="user to call" type="text"/>
<button id="callBt" >Connect</button>
<hr>
<input id="videoInput" type="file" accept="video/*"/>
</div>
<div id="videoDiv">
<h2 id="videoTitle"></h2>
<video autoplay controls id="video"></video>
<hr>
<button id="disconnectBt">Disconnect</button>
</div>
<div id="loadDiv">
<div class="loader" style="display:block"></div>
</div>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src = "scripts/script.js"></script>
<script src = "scripts/rtc.js"></script>
<script src = "scripts/signal.js"></script>
</body>
</html>

View File

@@ -1,200 +0,0 @@
var name
var connections = new Map()
const configuration = {
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
}
const offerOptions = {
offerToReceiveAudio: 1,
offerToReceiveVideo: 1
}
function handleLogin(success) {
if (success === false) {
alert('try a different username')
} else {
loginDiv.style.display = 'none'
connectDiv.style.display = 'block'
}
}
async function createPeerConnection(target) {
console.log('CREATED PEER CONNECTION')
var connection = new RTCPeerConnection(configuration)
connections[target] = connection
connection.onicecandidate = function(event) {
if (event.candidate) {
send({
type: 'candidate',
name: name,
target: target,
candidate: event.candidate
})
}
}
connection.onnegotiationneeded = function() { handleNegotiationNeededEvent(target) }
connection.ontrack = function(event) { handleTrackEvent(event) }
connection.onsignalingstatechange = function() { handleSignalingStateChangeEvent(connection) }
connection.oniceconnectionstatechange = function() { handleICEConnectionStateChangeEvent(connection) }
connection.onicegatheringstatechange = function() { handleICEGatheringStateChangeEvent(connection) }
// window.setInterval(getConnectionStats, 1000)
}
function handleICEConnectionStateChangeEvent(connection) {
console.log('ICE CONNECTION CHANGE ' + connection.iceConnectionState)
}
function handleICEGatheringStateChangeEvent(connection) {
console.log('ICE GATHERING CHANGE ' + connection.iceGatheringState)
}
async function makeOffer(target) {
createPeerConnection(target)
var connection = connections[target]
var offer = await connection.createOffer()
send({
type: 'offer',
name: name,
target: target,
offer: offer
})
await connection.setLocalDescription(offer)
}
async function handleOffer(offer, target) {
console.log('GOT OFFER FROM ' + target)
await createPeerConnection(target)
var connection = connections[target]
await connection.setRemoteDescription(new RTCSessionDescription(offer))
if (stream) {
console.log('STREAM DETECTED')
stream.getTracks().forEach((track) => {
console.log('ADDED TRACK')
connection.addTrack(track, stream)
})
}
var answer = await connection.createAnswer()
await connection.setLocalDescription(answer)
send({
type: 'answer',
name: name,
target: target,
answer: answer
})
videoTitle.innerHTML = name + ' | ' + connections.size + ' users connected'
}
async function handleAnswer(answer, target) {
console.log('GOT ANSWER FROM ' + target)
var connection = connections[target]
await connection.setRemoteDescription(new RTCSessionDescription(answer))
}
async function handleCandidate(candidate, target) {
console.log('GOT CANDIDATE FROM ' + target)
var connection = connections[target]
await connection.addIceCandidate(new RTCIceCandidate(candidate))
}
async function handleNegotiationNeededEvent(target) {
console.log('NEGOTIATION NEEDED FROM ' + target)
var connection = connections[target]
var offer = await connection.createOffer(offerOptions)
await connection.setLocalDescription(offer)
send({
type: 'video-offer',
name: name,
target: target,
sdp: connection.localDescription
})
}
function handleLeave() {
connections.forEach((connection) => {
connection.close()
connection = null
})
connections = new Map()
remoteVideo.pause()
remoteVideo.src = null
}
function handleUserlist(list) {
console.log('GOT USER LIST')
}
async function handleVideoOffer(sdp, target) {
console.log('GOT VIDEO OFFER FROM ' + target)
await createPeerConnection(target)
var connection = connections[target]
await connection.setRemoteDescription(new RTCSessionDescription(sdp))
if (stream) {
console.log('STREAM DETECTED')
stream.getTracks().forEach((track) => {
console.log('ADDED TRACK')
connection.addTrack(track, stream)
})
}
var answer = await connection.createAnswer()
await connection.setLocalDescription(answer)
send({
type: 'video-answer',
name: name,
target: target,
sdp: answer
})
//var keys = connections.keys().next().value
videoTitle.innerHTML = name + ' | connected to '
}
async function handleVideoAnswer(sdp, target) {
console.log('GOT VIDEO ANSWER FROM ' + target)
var connection = connections[target]
await connection.setRemoteDescription(new RTCSessionDescription(sdp))
}
async function handleSignalingStateChangeEvent(connection) {
console.log('STATE CHANGED TO : ' + connection.signalingState)
switch(connection.signalingState) {
case 'closed':
await connection.close()
break
}
}
function handleTrackEvent(event) {
console.log('GOT TRACK')
remoteVideo.srcObject = event.streams[0]
videoDiv.style.display = 'block'
loadDiv.style.display = 'none'
}
function getConnectionStats() {
connections.forEach((connection, target) => {
console.log('[' + target + '] ' + connection.connectionState)
})
}

View File

@@ -1,64 +0,0 @@
const loginDiv = document.querySelector('#loginDiv')
const loginInput = document.querySelector('#loginInput')
const loginBt = document.querySelector('#loginBt')
const connectDiv = document.querySelector('#connectDiv')
const callInput = document.querySelector('#callInput')
const callBt = document.querySelector('#callBt')
const videoInput = document.querySelector('#videoInput')
const videoDiv = document.querySelector('#videoDiv')
const videoTitle = document.querySelector('#videoTitle')
const remoteVideo = document.querySelector('#video')
const disconnectBt = document.querySelector('#disconnectBt')
const loadDiv = document.querySelector('#loadDiv')
var stream
loginDiv.style.display = 'block'
loginBt.addEventListener('click', function (event) {
name = loginInput.value
if (name.length > 0) {
send({
type: 'login',
name: name
})
}
})
callBt.addEventListener('click', function () {
var callToUsername = callInput.value;
if (callToUsername.length > 0) {
makeOffer(callToUsername)
loadDiv.style.display = 'block'
connectDiv.style.display = 'none'
}
})
disconnectBt.addEventListener('click', function () {
send({
type: 'leave',
name: name
})
handleLeave()
videoDiv.style.display = 'none'
loginDiv.style.display = 'block'
})
videoInput.addEventListener('change', function (event) {
remoteVideo.src = URL.createObjectURL(this.files[0])
videoDiv.style.display = 'block'
connectDiv.style.display = 'none'
videoTitle.innerHTML = name + ' | ' + connections.size + ' user connected'
})
remoteVideo.onplay = function () {
console.log('ADD STREAM')
if(remoteVideo.mozCaptureStream()) stream = remoteVideo.mozCaptureStream()
else stream = remoteVideo.captureStream()
}

View File

@@ -1,57 +0,0 @@
const conn = new WebSocket('wss://gltronic.ovh/lilstreamy/')
conn.onopen = function () {
console.log('Connected to the signaling server')
}
conn.onmessage = function (msg) {
console.log('Got message', msg.data);
var data = JSON.parse(msg.data);
switch (data.type) {
case 'login':
handleLogin(data.success)
break
case 'offer':
handleOffer(data.offer, data.name)
break
case 'answer':
handleAnswer(data.answer, data.name)
break
case 'candidate':
handleCandidate(data.candidate, data.name)
break
case 'userlist':
handleUserlist(data)
break
case 'leave':
handleLeave()
break
case 'video-offer':
handleVideoOffer(data.sdp, data.name)
break
case 'video-answer':
handleVideoAnswer(data.sdp, data.name)
break
default:
break
}
};
conn.onerror = function (err) {
console.log('Got error', err)
}
function send(message) {
console.log('Sended message', message)
conn.send(JSON.stringify(message))
}

View File

@@ -1,49 +0,0 @@
body {
color: #ffffff;
background-color: #23232e;
font: 14px normal Arial, Helvetica, sans-serif;
z-index: -4;
margin: auto;
}
div {
display: none;
margin: auto;
padding: 20px;
text-align: center;
}
video {
width: 50%;
}
#loadDiv {
display: none;
position: fixed;
z-index: 1;
padding-top: 100px;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.4);
}
.loader {
margin: auto;
padding: 20px;
border: 16px solid #f3f3f3;
border-top: 16px solid #3498db;
border-bottom: 16px solid violet;
border-radius: 50%;
width: 120px;
height: 120px;
animation: spin 0.5s ease-in-out infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

View File

@@ -3,6 +3,7 @@ const fs = require('fs')
const bodyParser = require('body-parser')
const cors = require('cors')
const config = require('../config.json')
const signal = require('./signal')
const https = require('https')
const WebSocketServer = require('ws').Server
@@ -18,109 +19,17 @@ app.use(cors())
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(express.static('./client'))
app.use(express.static('../../client'))
server.listen(port, () => {
console.log(`Launching Lil'Streamy on ${port}`)
})
var users = {}
wss.on('connection', function(connection) {
console.log('User connected')
connection.on('message', (message) => onMessage(connection, message))
connection.on('message', (message) => signal.onMessage(connection, message))
connection.on('close', () => onClose(connection))
connection.on('close', () => signal.onClose(connection))
})
function sendTo(connection, message) {
connection.send(JSON.stringify(message))
}
function onClose(connection) {
if(connection.name) {
delete users[connection.name]
if(connection.otherName) {
console.log('Disconnecting from ', connection.otherName)
var conn = users[connection.otherName]
conn.otherName = null
if(conn != null) {
sendTo(conn, {
type: 'leave'
})
}
}
}
}
function onMessage(connection, message) {
var data
try {
data = JSON.parse(message);
} catch (e) {
console.log('Invalid JSON')
data = {}
}
switch (data.type) {
case 'login' :
console.log('User logged', data.name);
if(users[data.name]) {
sendTo(connection, {
type: 'login',
success: false
})
} else {
users[data.name] = connection
connection.name = data.name
sendTo(connection, {
type: 'login',
success: true
})
}
break
case 'leave' :
console.log('Disconnecting from', data.name)
var conn = users[data.name]
conn.otherName = null
//notify the other user so he can disconnect his peer connection
/*
if(conn != null) {
sendTo(conn, {
type: 'leave'
});
}*/
break;
case 'userlist' :
console.log('Send list to', data.name)
sendTo(connection, {
type: 'userlist',
list: users
});
break
default:
if (data.target){
var targetConnection = users[data.target];
if(targetConnection){
console.log('Forward message from ' + data.name + ' to ' + data.target + ' (' + data.type + ')')
sendTo(targetConnection, data)
}
} else {
sendTo(connection, {
type: 'error',
message: 'Command not found: ' + data.type
});
}
}
}

View File

@@ -1,19 +1,23 @@
const WebSocketServer = require('ws').Server
var wss = new WebSocketServer({port: 9090})
var users = {}
wss.on('connection', function(connection) {
console.log('User connected')
connection.on('message', (message) => onMessage(connection, message))
connection.on('close', () => onClose(connection))
})
var users = new Map()
function sendTo(connection, message) {
connection.send(JSON.stringify(message))
connection.send(JSON.stringify(message))
}
function broadcast(message) {
console.log('Broadcast '+message)
var jsonMessage = JSON.stringify(message)
Object.keys(users).forEach(function(key) {
users[key].send(jsonMessage)
})
}
function getUserlist(){
var usersArray = []
Object.keys(users).forEach(function(key) {
usersArray.push(key)
})
return usersArray
}
function onClose(connection) {
@@ -60,43 +64,67 @@ function onMessage(connection, message) {
type: 'login',
success: true
})
broadcast({
type: 'userlist',
users: getUserlist()
})
}
break
case 'leave' :
console.log('Disconnecting from', data.name)
var conn = users[data.name]
conn.otherName = null
users[data.name] = null
//notify the other user so he can disconnect his peer connection
//notify the other
/*
if(conn != null) {
sendTo(conn, {
type: 'leave'
broadcast({
type: 'leave',
name: data.name
});
}*/
break;
break
case 'userlist' :
console.log('Send list to', data.name)
sendTo(connection, {
type: 'userlist',
list: users
});
users: getUserlist()
})
break
default:
if (data.target){
var targetConnection = users[data.target];
if(targetConnection){
if (data.target) {
if (data.target == data.name) {
sendTo(connection, {
type: 'error',
message: 'No loopback'
})
break
}
var targetConnection = users[data.target]
if (targetConnection) {
console.log('Forward message from ' + data.name + ' to ' + data.target + ' (' + data.type + ')')
sendTo(targetConnection, data)
} else {
sendTo(connection, {
type: 'error',
message: 'Peer not found'
})
}
} else {
sendTo(connection, {
type: 'error',
message: 'Command not found: ' + data.type
});
})
}
}
}
module.exports = {
sendTo,
broadcast,
onClose,
onMessage
}