Skip to content

Commit

Permalink
Unify events and output single TypeScript declaration (#2407)
Browse files Browse the repository at this point in the history
* fix(events): unify events to a single EventManager type, add support for single typescript declaration

* fix(lint): fix lint

* fix(events): fix incorrect instatiation

* fix(events): clean up redundant methods

* fix(events): keep EventEmitter name, alias NodeEventEmitter

* fix(events): fix loose reference

* fix(EventEmitter): remove on/off alias as redundant

* fix(RTCUtils): bring event handlers under class to use same event emitter

* fix(RTCUtils): fix lint
  • Loading branch information
DanielMcAssey authored Dec 15, 2023
1 parent 7e34520 commit 0e9a4e2
Show file tree
Hide file tree
Showing 21 changed files with 135 additions and 148 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ npm-*.log
stats.json
.vscode
dist
index.d.ts
types/auto
types/types-comparer/auto.json
types/types-comparer/hand-crafted.json
Expand Down
2 changes: 1 addition & 1 deletion JitsiConference.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { getLogger } from '@jitsi/logger';
import EventEmitter from 'events';
import $ from 'jquery';
import isEqual from 'lodash.isequal';
import { Strophe } from 'strophe.js';
Expand Down Expand Up @@ -38,6 +37,7 @@ import AvgRTPStatsReporter from './modules/statistics/AvgRTPStatsReporter';
import LocalStatsCollector from './modules/statistics/LocalStatsCollector';
import SpeakerStatsCollector from './modules/statistics/SpeakerStatsCollector';
import Statistics from './modules/statistics/statistics';
import EventEmitter from './modules/util/EventEmitter';
import { safeSubtract } from './modules/util/MathUtil';
import RandomUtil from './modules/util/RandomUtil';
import ComponentsVersions from './modules/version/ComponentsVersions';
Expand Down
37 changes: 5 additions & 32 deletions JitsiMediaDevices.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import EventEmitter from 'events';

import * as JitsiMediaDevicesEvents from './JitsiMediaDevicesEvents';
import RTC from './modules/RTC/RTC';
import browser from './modules/browser';
import Listenable from './modules/util/Listenable';
import { MediaType } from './service/RTC/MediaType';
import RTCEvents from './service/RTC/RTCEvents';

Expand All @@ -13,19 +12,19 @@ const VIDEO_PERMISSION_NAME = 'camera';
/**
* Media devices utilities for Jitsi.
*/
class JitsiMediaDevices {
class JitsiMediaDevices extends Listenable {
/**
* Initializes a {@code JitsiMediaDevices} object. There will be a single
* instance of this class.
*/
constructor() {
this._eventEmitter = new EventEmitter();
super();
this._permissions = {};

RTC.addListener(
RTCEvents.DEVICE_LIST_CHANGED,
devices =>
this._eventEmitter.emit(
this.eventEmitter.emit(
JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED,
devices));

Expand Down Expand Up @@ -128,7 +127,7 @@ class JitsiMediaDevices {
...this._permissions,
...permissions
};
this._eventEmitter.emit(JitsiMediaDevicesEvents.PERMISSIONS_CHANGED, this._permissions);
this.eventEmitter.emit(JitsiMediaDevicesEvents.PERMISSIONS_CHANGED, this._permissions);

if (this._permissions[MediaType.AUDIO] || this._permissions[MediaType.VIDEO]) {
// Triggering device list update when the permissiions are granted in order to update
Expand Down Expand Up @@ -265,32 +264,6 @@ class JitsiMediaDevices {
setAudioOutputDevice(deviceId) {
return RTC.setAudioOutputDevice(deviceId);
}

/**
* Adds an event handler.
* @param {string} event - event name
* @param {function} handler - event handler
*/
addEventListener(event, handler) {
this._eventEmitter.addListener(event, handler);
}

/**
* Removes event handler.
* @param {string} event - event name
* @param {function} handler - event handler
*/
removeEventListener(event, handler) {
this._eventEmitter.removeListener(event, handler);
}

/**
* Emits an event.
* @param {string} event - event name
*/
emitEvent(event, ...args) {
this._eventEmitter.emit(event, ...args);
}
}

export default new JitsiMediaDevices();
4 changes: 2 additions & 2 deletions JitsiMeetJS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,11 +318,11 @@ export default {

if (firePermissionPrompt && !RTC.arePermissionsGrantedForAvailableDevices()) {
// @ts-ignore
JitsiMediaDevices.emitEvent(JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN, browser.getName());
JitsiMediaDevices.emit(JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN, browser.getName());
} else if (fireSlowPromiseEvent) {
window.setTimeout(() => {
if (!promiseFulfilled) {
JitsiMediaDevices.emitEvent(JitsiMediaDevicesEvents.SLOW_GET_USER_MEDIA);
JitsiMediaDevices.emit(JitsiMediaDevicesEvents.SLOW_GET_USER_MEDIA);
}
}, USER_MEDIA_SLOW_PROMISE_TIMEOUT);
}
Expand Down
3 changes: 0 additions & 3 deletions modules/RTC/CodecSelection.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import EventEmitter from 'events';

import * as JitsiConferenceEvents from '../../JitsiConferenceEvents.ts';
import Listenable from '../util/Listenable.js';
import JingleSessionPC from '../xmpp/JingleSessionPC.js';
Expand Down Expand Up @@ -42,7 +40,6 @@ class MockConference extends Listenable {
};

this.activeMediaSession = undefined;
this.eventEmitter = new EventEmitter();
this.mediaSessions = [];
this.participants = [];
this._signalingLayer = new MockSignalingLayerImpl();
Expand Down
6 changes: 1 addition & 5 deletions modules/RTC/JitsiTrack.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { getLogger } from '@jitsi/logger';
import EventEmitter from 'events';

import * as JitsiTrackEvents from '../../JitsiTrackEvents';
import { MediaType } from '../../service/RTC/MediaType';
import browser from '../browser';
import EventEmitter from '../util/EventEmitter';

import RTCUtils from './RTCUtils';

Expand Down Expand Up @@ -44,10 +44,6 @@ export default class JitsiTrack extends EventEmitter {
videoType) {
super();

// aliases for addListener/removeListener
this.addEventListener = this.addListener;
this.removeEventListener = this.off = this.removeListener;

/**
* Array with the HTML elements that are displaying the streams.
* @type {Array}
Expand Down
139 changes: 65 additions & 74 deletions modules/RTC/RTCUtils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { getLogger } from '@jitsi/logger';
import EventEmitter from 'events';
import clonedeep from 'lodash.clonedeep';
import 'webrtc-adapter';

Expand All @@ -18,8 +17,6 @@ import screenObtainer from './ScreenObtainer';

const logger = getLogger(__filename);

const eventEmitter = new EventEmitter();

const AVAILABLE_DEVICES_POLL_INTERVAL_TIME = 3000; // ms

/**
Expand Down Expand Up @@ -157,29 +154,6 @@ function getConstraints(um = [], options = {}) {
return constraints;
}

/**
* Updates the granted permissions based on the options we requested and the
* streams we received.
* @param um the options we requested to getUserMedia.
* @param stream the stream we received from calling getUserMedia.
*/
function updateGrantedPermissions(um, stream) {
const audioTracksReceived
= Boolean(stream) && stream.getAudioTracks().length > 0;
const videoTracksReceived
= Boolean(stream) && stream.getVideoTracks().length > 0;
const grantedPermissions = {};

if (um.indexOf('video') !== -1) {
grantedPermissions.video = videoTracksReceived;
}
if (um.indexOf('audio') !== -1) {
grantedPermissions.audio = audioTracksReceived;
}

eventEmitter.emit(RTCEvents.PERMISSIONS_CHANGED, grantedPermissions);
}

/**
* Checks if new list of available media devices differs from previous one.
* @param {MediaDeviceInfo[]} newDevices - list of new devices.
Expand Down Expand Up @@ -247,52 +221,10 @@ function sendDeviceListToAnalytics(deviceList) {
});
}


/**
* Update known devices.
*
* @param {Array<Object>} pds - The new devices.
* @returns {void}
*
* NOTE: Use this function as a shared callback to handle both the devicechange event and the polling implementations.
* This prevents duplication and works around a chrome bug (verified to occur on 68) where devicechange fires twice in
* a row, which can cause async post devicechange processing to collide.
*/
function updateKnownDevices(pds) {
if (compareAvailableMediaDevices(pds)) {
onMediaDevicesListChanged(pds);
}
}

/**
* Event handler for the 'devicechange' event.
*
* @param {MediaDeviceInfo[]} devices - list of media devices.
* @emits RTCEvents.DEVICE_LIST_CHANGED
*/
function onMediaDevicesListChanged(devicesReceived) {
availableDevices = devicesReceived.slice(0);
logger.info('list of media devices has changed:', availableDevices);

sendDeviceListToAnalytics(availableDevices);

// Used by tracks to update the real device id before the consumer of lib-jitsi-meet receives the new device list.
eventEmitter.emit(RTCEvents.DEVICE_LIST_WILL_CHANGE, availableDevices);

eventEmitter.emit(RTCEvents.DEVICE_LIST_CHANGED, availableDevices);
}

/**
*
*/
class RTCUtils extends Listenable {
/**
*
*/
constructor() {
super(eventEmitter);
}

/**
* Depending on the browser, sets difference instance methods for
* interacting with user media and adds methods to native WebRTC-related
Expand Down Expand Up @@ -347,7 +279,7 @@ class RTCUtils extends Listenable {
logger.debug('Available devices: ', availableDevices);
sendDeviceListToAnalytics(availableDevices);

eventEmitter.emit(
this.eventEmitter.emit(
RTCEvents.DEVICE_LIST_AVAILABLE,
availableDevices);

Expand All @@ -373,12 +305,12 @@ class RTCUtils extends Listenable {
enumerateDevices(callback) {
navigator.mediaDevices.enumerateDevices()
.then(devices => {
updateKnownDevices(devices);
this._updateKnownDevices(devices);
callback(devices);
})
.catch(error => {
logger.warn(`Failed to enumerate devices. ${error}`);
updateKnownDevices([]);
this._updateKnownDevices([]);
callback([]);
});
}
Expand Down Expand Up @@ -407,7 +339,7 @@ class RTCUtils extends Listenable {
navigator.mediaDevices.getUserMedia(constraints)
.then(stream => {
logger.log('onUserMediaSuccess');
updateGrantedPermissions(umDevices, stream);
this._updateGrantedPermissions(umDevices, stream);
if (!timeoutExpired) {
if (typeof gumTimeout !== 'undefined') {
clearTimeout(gumTimeout);
Expand All @@ -427,7 +359,7 @@ class RTCUtils extends Listenable {
}

if (jitsiError.name === JitsiTrackErrors.PERMISSION_DENIED) {
updateGrantedPermissions(umDevices, undefined);
this._updateGrantedPermissions(umDevices, undefined);
}

// else {
Expand Down Expand Up @@ -497,6 +429,65 @@ class RTCUtils extends Listenable {
return missingDevices;
}

/**
* Event handler for the 'devicechange' event.
*
* @param {MediaDeviceInfo[]} devices - list of media devices.
* @emits RTCEvents.DEVICE_LIST_CHANGED
*/
_onMediaDevicesListChanged(devicesReceived) {
availableDevices = devicesReceived.slice(0);
logger.info('list of media devices has changed:', availableDevices);

sendDeviceListToAnalytics(availableDevices);

// Used by tracks to update the real device id before the consumer of lib-jitsi-meet receives the
// new device list.
this.eventEmitter.emit(RTCEvents.DEVICE_LIST_WILL_CHANGE, availableDevices);

this.eventEmitter.emit(RTCEvents.DEVICE_LIST_CHANGED, availableDevices);
}

/**
* Update known devices.
*
* @param {Array<Object>} pds - The new devices.
* @returns {void}
*
* NOTE: Use this function as a shared callback to handle both the devicechange event and the
* polling implementations.
* This prevents duplication and works around a chrome bug (verified to occur on 68) where devicechange
* fires twice in a row, which can cause async post devicechange processing to collide.
*/
_updateKnownDevices(pds) {
if (compareAvailableMediaDevices(pds)) {
this._onMediaDevicesListChanged(pds);
}
}

/**
* Updates the granted permissions based on the options we requested and the
* streams we received.
* @param um the options we requested to getUserMedia.
* @param stream the stream we received from calling getUserMedia.
*/
_updateGrantedPermissions(um, stream) {
const audioTracksReceived
= Boolean(stream) && stream.getAudioTracks().length > 0;
const videoTracksReceived
= Boolean(stream) && stream.getVideoTracks().length > 0;
const grantedPermissions = {};

if (um.indexOf('video') !== -1) {
grantedPermissions.video = videoTracksReceived;
}
if (um.indexOf('audio') !== -1) {
grantedPermissions.audio = audioTracksReceived;
}

this.eventEmitter.emit(RTCEvents.PERMISSIONS_CHANGED, grantedPermissions);
}

/**
* Gets streams from specified device types. This function intentionally
* ignores errors for upstream to catch and handle instead.
Expand Down Expand Up @@ -792,7 +783,7 @@ class RTCUtils extends Listenable {

logger.log(`Audio output device set to ${deviceId}`);

eventEmitter.emit(RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED,
this.eventEmitter.emit(RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED,
deviceId);
});
}
Expand Down
2 changes: 1 addition & 1 deletion modules/RTCStats/RTCStats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { getLogger } from '@jitsi/logger';

import rtcstatsInit from '@jitsi/rtcstats/rtcstats';
import traceInit from '@jitsi/rtcstats/trace-ws';
import EventEmitter from 'events';

import {
CONFERENCE_JOINED,
Expand All @@ -12,6 +11,7 @@ import {
import JitsiConference from '../../JitsiConference';
import { IRTCStatsConfiguration } from './interfaces';
import { RTC_STATS_PC_EVENT, RTC_STATS_WC_DISCONNECTED } from './RTCStatsEvents';
import EventEmitter from '../util/EventEmitter';

const logger = getLogger(__filename);

Expand Down
3 changes: 1 addition & 2 deletions modules/detection/NoAudioSignalDetection.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import EventEmitter from 'events';

import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';
import * as JitsiTrackEvents from '../../JitsiTrackEvents';
import EventEmitter from '../util/EventEmitter';

import * as DetectionEvents from './DetectionEvents';

Expand Down
3 changes: 1 addition & 2 deletions modules/detection/TrackVADEmitter.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import EventEmitter from 'events';

import RTC from '../RTC/RTC';
import EventEmitter from '../util/EventEmitter';
import { createAudioContext } from '../webaudio/WebAudioUtils';

import { VAD_SCORE_PUBLISHED } from './DetectionEvents';
Expand Down
Loading

0 comments on commit 0e9a4e2

Please sign in to comment.