Refactor WebRTC class (#13736)

* improved event emitter

* more changes

* Update WebRTCClass.js

* fix review

* Update index.js

* Update WebRTCClass.js

* Update WebRTCClass.js

* Revert webrtc api paths
pull/13807/head^2
Guilherme Gazzo 7 years ago committed by Rodrigo Nascimento
parent 309335e865
commit e89b450da7
  1. 4
      app/notifications/server/lib/Notifications.js
  2. 159
      app/webrtc/client/WebRTCClass.js
  3. 5
      app/webrtc/client/index.js
  4. 8
      app/webrtc/index.js

@ -1,6 +1,7 @@
import { Meteor } from 'meteor/meteor';
import { DDPCommon } from 'meteor/ddp-common';
import { WEB_RTC_EVENTS } from '../../../webrtc';
import { Subscriptions, Rooms } from '../../../models';
import { settings } from '../../../settings';
@ -176,9 +177,10 @@ const notifications = new Notifications();
notifications.streamRoom.allowWrite(function(eventName, username, typing, extraData) {
const [roomId, e] = eventName.split('/');
if (e === 'webrtc') {
if (isNaN(e) ? e === WEB_RTC_EVENTS.WEB_RTC : parseFloat(e) === WEB_RTC_EVENTS.WEB_RTC) {
return true;
}
if (e === 'typing') {
const key = settings.get('UI_Use_Real_Name') ? 'name' : 'username';
// typing from livechat widget

@ -1,3 +1,4 @@
import EventEmitter from 'wolfy87-eventemitter';
import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker';
import { ReactiveVar } from 'meteor/reactive-var';
@ -11,26 +12,22 @@ import { settings } from '../../settings';
import { modal } from '../../ui-utils';
import { ChatSubscription } from '../../models';
class WebRTCTransportClass {
import { WEB_RTC_EVENTS } from '..';
class WebRTCTransportClass extends EventEmitter {
constructor(webrtcInstance) {
super();
this.debug = false;
this.webrtcInstance = webrtcInstance;
this.callbacks = {};
Notifications.onRoom(this.webrtcInstance.room, 'webrtc', (type, data) => {
const { onRemoteStatus } = this.callbacks;
Notifications.onRoom(this.webrtcInstance.room, WEB_RTC_EVENTS.WEB_RTC, (type, data) => {
this.log('WebRTCTransportClass - onRoom', type, data);
switch (type) {
case 'status':
if (onRemoteStatus && onRemoteStatus.length) {
onRemoteStatus.forEach((fn) => fn(data));
}
}
this.emit(type, data);
});
}
log(...args) {
if (this.debug === true) {
console.log.apply(console, args);
console.log(...args);
}
}
@ -38,35 +35,14 @@ class WebRTCTransportClass {
if (data.room !== this.webrtcInstance.room) {
return;
}
this.log('WebRTCTransportClass - onUser', type, data);
const { onRemoteCall, onRemoteJoin, onRemoteCandidate, onRemoteDescription } = this.callbacks;
switch (type) {
case 'call':
if (onRemoteCall && onRemoteCall.length) {
onRemoteCall.forEach((fn) => fn(data));
}
break;
case 'join':
if (onRemoteJoin && onRemoteJoin.length) {
onRemoteJoin.forEach((fn) => fn(data));
}
break;
case 'candidate':
if (onRemoteCandidate && onRemoteCandidate.length) {
onRemoteCandidate.forEach((fn) => fn(data));
}
break;
case 'description':
if (onRemoteDescription && onRemoteDescription.length) {
onRemoteDescription.forEach((fn) => fn(data));
}
}
this.log('WebRTCTransportClass - onUser', type, data);
this.emit(type, data);
}
startCall(data) {
this.log('WebRTCTransportClass - startCall', this.webrtcInstance.room, this.webrtcInstance.selfId);
Notifications.notifyUsersOfRoom(this.webrtcInstance.room, 'webrtc', 'call', {
Notifications.notifyUsersOfRoom(this.webrtcInstance.room, WEB_RTC_EVENTS.WEB_RTC, WEB_RTC_EVENTS.CALL, {
from: this.webrtcInstance.selfId,
room: this.webrtcInstance.room,
media: data.media,
@ -77,14 +53,14 @@ class WebRTCTransportClass {
joinCall(data) {
this.log('WebRTCTransportClass - joinCall', this.webrtcInstance.room, this.webrtcInstance.selfId);
if (data.monitor === true) {
Notifications.notifyUser(data.to, 'webrtc', 'join', {
Notifications.notifyUser(data.to, WEB_RTC_EVENTS.WEB_RTC, WEB_RTC_EVENTS.JOIN, {
from: this.webrtcInstance.selfId,
room: this.webrtcInstance.room,
media: data.media,
monitor: data.monitor,
});
} else {
Notifications.notifyUsersOfRoom(this.webrtcInstance.room, 'webrtc', 'join', {
Notifications.notifyUsersOfRoom(this.webrtcInstance.room, WEB_RTC_EVENTS.WEB_RTC, WEB_RTC_EVENTS.JOIN, {
from: this.webrtcInstance.selfId,
room: this.webrtcInstance.room,
media: data.media,
@ -97,60 +73,40 @@ class WebRTCTransportClass {
data.from = this.webrtcInstance.selfId;
data.room = this.webrtcInstance.room;
this.log('WebRTCTransportClass - sendCandidate', data);
Notifications.notifyUser(data.to, 'webrtc', 'candidate', data);
Notifications.notifyUser(data.to, WEB_RTC_EVENTS.WEB_RTC, WEB_RTC_EVENTS.CANDIDATE, data);
}
sendDescription(data) {
data.from = this.webrtcInstance.selfId;
data.room = this.webrtcInstance.room;
this.log('WebRTCTransportClass - sendDescription', data);
Notifications.notifyUser(data.to, 'webrtc', 'description', data);
Notifications.notifyUser(data.to, WEB_RTC_EVENTS.WEB_RTC, WEB_RTC_EVENTS.DESCRIPTION, data);
}
sendStatus(data) {
this.log('WebRTCTransportClass - sendStatus', data, this.webrtcInstance.room);
data.from = this.webrtcInstance.selfId;
Notifications.notifyRoom(this.webrtcInstance.room, 'webrtc', 'status', data);
Notifications.notifyRoom(this.webrtcInstance.room, WEB_RTC_EVENTS.WEB_RTC, WEB_RTC_EVENTS.STATUS, data);
}
onRemoteCall(fn) {
const { callbacks } = this;
if (callbacks.onRemoteCall == null) {
callbacks.onRemoteCall = [];
}
callbacks.onRemoteCall.push(fn);
return this.on(WEB_RTC_EVENTS.CALL, fn);
}
onRemoteJoin(fn) {
const { callbacks } = this;
if (callbacks.onRemoteJoin == null) {
callbacks.onRemoteJoin = [];
}
callbacks.onRemoteJoin.push(fn);
return this.on(WEB_RTC_EVENTS.JOIN, fn);
}
onRemoteCandidate(fn) {
const { callbacks } = this;
if (callbacks.onRemoteCandidate == null) {
callbacks.onRemoteCandidate = [];
}
callbacks.onRemoteCandidate.push(fn);
return this.on(WEB_RTC_EVENTS.CANDIDATE, fn);
}
onRemoteDescription(fn) {
const { callbacks } = this;
if (callbacks.onRemoteDescription == null) {
callbacks.onRemoteDescription = [];
}
callbacks.onRemoteDescription.push(fn);
return this.on(WEB_RTC_EVENTS.DESCRIPTION, fn);
}
onRemoteStatus(fn) {
const { callbacks } = this;
if (callbacks.onRemoteStatus == null) {
callbacks.onRemoteStatus = [];
}
callbacks.onRemoteStatus.push(fn);
return this.on(WEB_RTC_EVENTS.STATUS, fn);
}
}
@ -211,8 +167,8 @@ class WebRTCClass {
} else if (userAgent.indexOf('safari') !== -1) {
this.navigator = 'safari';
}
const nav = this.navigator;
this.screenShareAvailable = nav === 'chrome' || nav === 'firefox' || nav === 'electron';
this.screenShareAvailable = ['chrome', 'firefox', 'electron'].includes(this.navigator);
this.media = {
video: false,
audio: true,
@ -223,11 +179,17 @@ class WebRTCClass {
this.transport.onRemoteCandidate(this.onRemoteCandidate.bind(this));
this.transport.onRemoteDescription(this.onRemoteDescription.bind(this));
this.transport.onRemoteStatus(this.onRemoteStatus.bind(this));
Meteor.setInterval(this.checkPeerConnections.bind(this), 1000);
// Meteor.setInterval(this.broadcastStatus.bind(@), 1000);
}
onUserStream(...args) {
return this.transport.onUserStream(...args);
}
log(...args) {
if (this.debug === true) {
console.log.apply(console, args);
@ -240,11 +202,13 @@ class WebRTCClass {
checkPeerConnections() {
const { peerConnections } = this;
Object.keys(peerConnections).forEach((id) => {
const peerConnection = peerConnections[id];
if (peerConnection.iceConnectionState !== 'connected' && peerConnection.iceConnectionState !== 'completed' && peerConnection.createdAt + 5000 < Date.now()) {
const date = Date.now();
Object.entries(peerConnections).some(([id, peerConnection]) => {
if (!['connected', 'completed'].includes(peerConnection.iceConnectionState) && peerConnection.createdAt + 5000 < date) {
this.stopPeerConnection(id);
return true;
}
return false;
});
}
@ -253,9 +217,7 @@ class WebRTCClass {
const itemsById = {};
const { peerConnections } = this;
Object.keys(peerConnections).forEach((id) => {
const peerConnection = peerConnections[id];
Object.entries(peerConnections).forEach(([id, peerConnection]) => {
peerConnection.getRemoteStreams().forEach((remoteStream) => {
const item = {
id,
@ -288,7 +250,7 @@ class WebRTCClass {
this.remoteItemsById.set(itemsById);
}
resetCallInProgress() {
resetCallInProgress = () => {
this.callInProgress.set(false);
}
@ -298,11 +260,10 @@ class WebRTCClass {
}
const remoteConnections = [];
const { peerConnections } = this;
Object.keys(peerConnections).forEach((id) => {
const peerConnection = peerConnections[id];
Object.keys(peerConnections).entries(([id, { remoteMedia: media }]) => {
remoteConnections.push({
id,
media: peerConnection.remoteMedia,
media,
});
});
@ -326,7 +287,7 @@ class WebRTCClass {
// this.log(onRemoteStatus, arguments);
this.callInProgress.set(true);
Meteor.clearTimeout(this.callInProgressTimeout);
this.callInProgressTimeout = Meteor.setTimeout(this.resetCallInProgress.bind(this), 2000);
this.callInProgressTimeout = Meteor.setTimeout(this.resetCallInProgress, 2000);
if (this.active !== true) {
return;
}
@ -419,6 +380,10 @@ class WebRTCClass {
}
onSuccess(stream);
};
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
return navigator.mediaDevices.getUserMedia(media).then(onSuccessLocal).catch(onError);
}
navigator.getUserMedia(media, onSuccessLocal, onError);
}
@ -538,10 +503,7 @@ class WebRTCClass {
this.videoEnabled.set(this.media.video === true);
this.audioEnabled.set(this.media.audio === true);
const { peerConnections } = this;
Object.keys(peerConnections).forEach((id) => {
const peerConnection = peerConnections[id];
peerConnection.addStream(stream);
});
Object.entries(peerConnections).forEach(([, peerConnection]) => peerConnection.addStream(stream));
callback(null, this.localStream);
};
const onError = (error) => {
@ -556,7 +518,7 @@ class WebRTCClass {
@param id {String}
*/
stopPeerConnection(id) {
stopPeerConnection = (id) => {
const peerConnection = this.peerConnections[id];
if (peerConnection == null) {
return;
@ -569,9 +531,7 @@ class WebRTCClass {
stopAllPeerConnections() {
const { peerConnections } = this;
Object.keys(peerConnections).forEach((id) => {
this.stopPeerConnection(id);
});
Object.keys(peerConnections).forEach(this.stopPeerConnection);
window.audioContext && window.audioContext.close();
}
@ -754,16 +714,13 @@ class WebRTCClass {
}, (isConfirm) => {
if (isConfirm) {
FlowRouter.goToRoomById(data.room);
Meteor.defer(() => {
this.joinCall({
to: data.from,
monitor: data.monitor,
media: data.media,
});
return this.joinCall({
to: data.from,
monitor: data.monitor,
media: data.media,
});
} else {
this.stop();
}
this.stop();
});
}
@ -960,8 +917,8 @@ const WebRTC = new class {
this.instancesByRoomId = {};
}
getInstanceByRoomId(roomId) {
const subscription = ChatSubscription.findOne({ rid: roomId });
getInstanceByRoomId(rid) {
const subscription = ChatSubscription.findOne({ rid });
if (!subscription) {
return;
}
@ -979,22 +936,22 @@ const WebRTC = new class {
if (enabled === false) {
return;
}
if (this.instancesByRoomId[roomId] == null) {
this.instancesByRoomId[roomId] = new WebRTCClass(Meteor.userId(), roomId);
if (this.instancesByRoomId[rid] == null) {
this.instancesByRoomId[rid] = new WebRTCClass(Meteor.userId(), rid);
}
return this.instancesByRoomId[roomId];
return this.instancesByRoomId[rid];
}
}();
Meteor.startup(function() {
Tracker.autorun(function() {
if (Meteor.userId()) {
Notifications.onUser('webrtc', (type, data) => {
Notifications.onUser(WEB_RTC_EVENTS.WEB_RTC, (type, data) => {
if (data.room == null) {
return;
}
const webrtc = WebRTC.getInstanceByRoomId(data.room);
webrtc.transport.onUserStream(type, data);
webrtc.onUserStream(type, data);
});
}
});

@ -1,6 +1,3 @@
import './adapter';
import { WebRTC } from './WebRTCClass';
export {
WebRTC,
};
export * from './WebRTCClass';

@ -0,0 +1,8 @@
export const WEB_RTC_EVENTS = {
WEB_RTC: 'webrtc',
STATUS: 'status',
CALL: 'call',
JOIN: 'join',
CANDIDATE: 'candidate',
DESCRIPTION: 'description',
};
Loading…
Cancel
Save