CliffbreakMeet/webapp/src/js/app.js
2020-04-23 14:24:36 +02:00

282 lines
No EOL
9.8 KiB
JavaScript

import io from 'socket.io-client';
import kurentoUtils from 'kurento-utils';
import { EventEmitter } from 'events';
(async () => {
// RTCPeerConnection
let pc;
// Send permission dialog to client
const openMediaDevices = async (constraints) => {
return await navigator.mediaDevices.getUserMedia(constraints);
}
try {
const stream = await openMediaDevices({ 'video': true, 'audio': true });
console.log('Got MediaStream:', stream);
function updateList(elements, type) {
const listElement = document.querySelector(type == 'video' ? 'select#availableCameras' : 'select#availableMicrophones');
listElement.innerHTML = '';
elements.forEach(camera => {
const cameraOption = document.createElement('option');
cameraOption.label = camera.label;
cameraOption.value = camera.deviceId;
listElement.add(cameraOption);
});
}
// Fetch an array of devices of a certain type
async function getConnectedDevices(type) {
const devices = await navigator.mediaDevices.enumerateDevices();
return devices.filter(device => device.kind === type)
}
// Listen for changes to media devices and update the list accordingly
navigator.mediaDevices.addEventListener('devicechange', async _ => {
updateList(await getConnectedDevices('videoinput'), 'video');
updateList(await getConnectedDevices('audioinput'), 'audio');
});
updateList(await getConnectedDevices('videoinput'), 'video');
updateList(await getConnectedDevices('audioinput'), 'audio');
async function playVideoFromCamera() {
try {
const videoSelect = document.querySelector('select#availableCameras');
const stream = await navigator.mediaDevices.getUserMedia({
video: {
deviceId: videoSelect.options[videoSelect.selectedIndex].value,
// width: 1920,
// height: 1080,
frameRate: 30,
}
});
const videoElement = document.querySelector('video#localVideo');
videoElement.srcObject = stream;
} catch (error) {
console.error('Error opening video camera.', error);
}
}
// document.querySelector('button#startVideo').addEventListener('click', () => playVideoFromCamera());
} catch (error) {
console.error('Error accessing media devices.', error);
}
// console.log('Make Call');
const socket = io();
socket.on('connect', function () {
socket.on('startResponse', startResponse);
});
// socket.emit('events', { test: 'test' });
// socket.emit('start', {});
// });
// socket.on('exception', function (data) { // Not working?
// console.log('event', data);
// });
// socket.on('disconnect', function () {
// console.log('Disconnected');
// socket.close(); // Good idea?
// });
var webRtcPeer;
document.querySelector('button#startCall').addEventListener('click', () => start());
document.querySelector('button#stopCall').addEventListener('click', () => stop());
async function start() {
console.log('Starting video call ...')
console.log('Creating WebRtcPeer and generating local sdp offer ...');
pc = new RTCPeerConnection({
iceServers: [
{
urls: 'stun:stun.cliffbreak.de',
credential: '8dd2a7643a840ff4bb10e82069b6feceaf6d344a19a590ffc062fa10ea34687b',
},
]
});
const dataChannel = pc.createDataChannel('test'); //Unneeded?
let videoStream;
try {
const videoSelect = document.querySelector('select#availableCameras');
const stream = await navigator.mediaDevices.getUserMedia({
video: {
deviceId: videoSelect.options[videoSelect.selectedIndex].value,
// width: 1920,
// height: 1080,
frameRate: 30,
}
});
const videoElement = document.querySelector('video#localVideo');
console.log(stream);
videoElement.srcObject = stream;
videoStream = stream;
} catch (error) {
console.error('Error opening video camera.', error);
}
let candidategatheringdone = false;
const candidatesQueueOut = [];
pc.onicecandidate = (event) => {
const candidate = event.candidate;
if (EventEmitter.listenerCount('icecandidate') || EventEmitter
.listenerCount('candidategatheringdone')) {
candidategatheringdone = false;
} else if (!candidategatheringdone) {
candidatesQueueOut.push(candidate);
if (!candidate) {
candidategatheringdone = true;
console.log(candidatesQueueOut);
while (candidatesQueueOut.length) {
const candidate = candidatesQueueOut.shift();
if (!!candidate)
onIceCandidate(candidate);
}
for (const track of videoStream.getVideoTracks()) {
pc.addTrack(track, videoStream);
}
// pc.addStream(videoStream);
}
}
};
pc.createOffer().then((offer) => {
console.log('Created SDP offer');
console.log(offer);
const newOffer = new RTCSessionDescription({
type: offer.type,
sdp: removeFIDFromOffer(offer.sdp) + getSimulcastInfo(videoStream),
});
return pc.setLocalDescription(newOffer);
}).then(() => {
const localDescription = pc.localDescription;
console.log('Local description set: ' + localDescription.sdp);
onOffer(null, localDescription.sdp);
}).catch(onOffer);
function removeFIDFromOffer(sdp) {
var n = sdp.indexOf("a=ssrc-group:FID");
if (n > 0) {
return sdp.slice(0, n);
} else {
return sdp;
}
}
function getSimulcastInfo(videoStream) {
var videoTracks = videoStream.getVideoTracks();
if (!videoTracks.length) {
logger.warn('No video tracks available in the video stream')
return ''
}
var lines = [
'a=x-google-flag:conference',
'a=ssrc-group:SIM 1 2 3',
'a=ssrc:1 cname:localVideo',
'a=ssrc:1 msid:' + videoStream.id + ' ' + videoTracks[0].id,
'a=ssrc:1 mslabel:' + videoStream.id,
'a=ssrc:1 label:' + videoTracks[0].id,
'a=ssrc:2 cname:localVideo',
'a=ssrc:2 msid:' + videoStream.id + ' ' + videoTracks[0].id,
'a=ssrc:2 mslabel:' + videoStream.id,
'a=ssrc:2 label:' + videoTracks[0].id,
'a=ssrc:3 cname:localVideo',
'a=ssrc:3 msid:' + videoStream.id + ' ' + videoTracks[0].id,
'a=ssrc:3 mslabel:' + videoStream.id,
'a=ssrc:3 label:' + videoTracks[0].id
];
lines.push('');
return lines.join('\n');
}
// var options = {
// localVideo: document.querySelector('video#localVideo'),
// remoteVideo: document.querySelector('video#remoteVideo'),
// onicecandidate: onIceCandidate
// }
// webRtcPeer = kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv(options, function (error) {
// if (error) return onError(error);
// this.generateOffer(onOffer);
// });
}
function onIceCandidate(candidate) {
console.log('Local candidate' + JSON.stringify(candidate));
socket.emit('onIceCandidate', JSON.stringify({ candidate }));
}
function onOffer(error, offerSdp) {
if (error) return onError(error);
console.info('Invoking SDP offer callback function ' + location.host);
socket.emit('start', JSON.stringify({ sdpOffer: offerSdp }));
}
function onError(error) {
console.error(error);
}
function startResponse(message) {
console.log('SDP answer received from server. Processing ...');
const sdpAnswer = JSON.parse(message).sdpAnswer;
// webRtcPeer.processAnswer(sdpAnswer);
let answer = new RTCSessionDescription({
type: 'answer',
sdp: sdpAnswer,
});
pc.setRemoteDescription(answer, () => {
const remoteVideo = document.querySelector('video#remoteVideo');
// remoteVideo.pause();
// pc.getRemoteStreams = function () {
// var stream = new MediaStream();
// pc.getReceivers().forEach(function (sender) {
// stream.addTrack(sender.track);
// });
// return [stream];
// };
// console.table(pc.getRemoteStreams());
// const stream = pc.getRemoteStreams()[0];
// console.log(stream);
pc.ontrack = function (event) {
console.log('ontrack');
console.log(event);
remoteVideo.srcObject = event.streams[0];
}
// remoteVideo.load();
});
}
function stop() {
console.log('Stopping video call ...');
socket.emit('stop');
// TODO:::
if (webRtcPeer) {
webRtcPeer.dispose();
webRtcPeer = null;
}
}
})();