diff --git a/README.md b/README.md index 7f6795c..571e1d6 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # oozik 2 -Webapp edition \ No newline at end of file +Webapp edition + +socket messages types: serverInfos, login, leave, userList, createRoom, connectRoom, offer, answer, candidate diff --git a/client/src/App.vue b/client/src/App.vue index 3943904..c077d53 100644 --- a/client/src/App.vue +++ b/client/src/App.vue @@ -1,9 +1,5 @@ @@ -19,14 +15,5 @@ #nav { padding: 30px; - - a { - font-weight: bold; - color: #2c3e50; - - &.router-link-exact-active { - color: #42b983; - } - } } diff --git a/client/src/components/HelloWorld.vue b/client/src/components/HelloWorld.vue deleted file mode 100644 index 5673c54..0000000 --- a/client/src/components/HelloWorld.vue +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - diff --git a/client/src/main.js b/client/src/main.js index d12df39..6d3fe40 100644 --- a/client/src/main.js +++ b/client/src/main.js @@ -3,7 +3,12 @@ import App from './App.vue' import './registerServiceWorker' import router from './router' import store from './store' +import Buefy from 'buefy' +import 'buefy/dist/buefy.css' + +// import './assets/style.scss' +Vue.use(Buefy) Vue.config.productionTip = false new Vue({ diff --git a/client/src/router/index.js b/client/src/router/index.js index e44cdcd..325d91b 100644 --- a/client/src/router/index.js +++ b/client/src/router/index.js @@ -11,12 +11,9 @@ const routes = [ component: Home }, { - path: '/about', - name: 'About', - // route level code-splitting - // this generates a separate chunk (about.[hash].js) for this route - // which is lazy-loaded when the route is visited. - component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') + path: '/room', + name: 'Room', + component: () => import('../views/Room.vue') } ] diff --git a/client/src/rtc.js b/client/src/rtc.js new file mode 100644 index 0000000..93894fd --- /dev/null +++ b/client/src/rtc.js @@ -0,0 +1,205 @@ +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 + }) + + for (let user of connections.keys()) { + console.log(user) + } + + console.log('CONNECTION SIZE ' + connections.size) + + 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 +} + +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 ' + target +} + +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) + }) +} + +export const rtc = { + send +} diff --git a/client/src/script.js b/client/src/script.js new file mode 100644 index 0000000..9b9bd4e --- /dev/null +++ b/client/src/script.js @@ -0,0 +1,92 @@ +/* +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 callDatalist = document.querySelector('#callDatalist') +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') +const titleDiv = document.querySelector('#titleDiv') + +var stream +var users + +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' + titleDiv.style.display = 'none' + connectDiv.style.display = 'none' + } +}) + +disconnectBt.addEventListener('click', function () { + send({ + type: 'leave', + name: name + }) + handleLeave() + videoDiv.style.display = 'none' + loginDiv.style.display = 'block' + titleDiv.style.display = 'block' +}) + +videoInput.addEventListener('change', function (event) { + remoteVideo.src = URL.createObjectURL(this.files[0]) + + videoDiv.style.display = 'block' + connectDiv.style.display = 'none' + titleDiv.style.display = 'none' + videoTitle.innerHTML = name + ' | ' + connections.size + ' users connected' +}) + +remoteVideo.onplay = function () { + console.log('ADD STREAM') + if (remoteVideo.mozCaptureStream()) stream = remoteVideo.mozCaptureStream() + else stream = remoteVideo.captureStream() +} + +function handleUserlist(list) { + console.log('GOT USER LIST '+list) + users = Array.from(list) + console.log(' users '+users) + console.log(typeof users) + console.log(' users '+users) + callDatalist.innerHTML = '' + users.forEach(user => { + if(user != name) callDatalist.innerHTML += '