@100mslive/hms-video-store
Version:
@100mslive Core SDK which abstracts the complexities of webRTC while providing a reactive store for data management with a unidirectional data flow
204 lines (184 loc) • 8.76 kB
text/typescript
import { ActiveSpeakerManager } from './managers/ActiveSpeakerManager';
import { BroadcastManager } from './managers/BroadcastManager';
import { ConnectionQualityManager } from './managers/ConnectionQualityManager';
import { OnDemandTrackManager } from './managers/onDemandTrackManager';
import { PeerListManager } from './managers/PeerListManager';
import { PeerManager } from './managers/PeerManager';
import { PolicyChangeManager } from './managers/PolicyChangeManager';
import { PollsManager } from './managers/PollsManager';
import { RequestManager } from './managers/RequestManager';
import { RoomUpdateManager } from './managers/RoomUpdateManager';
import { SessionMetadataManager } from './managers/SessionMetadataManager';
import { TrackManager } from './managers/TrackManager';
import { WhiteboardManager } from './managers/WhiteboardManager';
import { HMSNotificationMethod } from './HMSNotificationMethod';
import {
ConnectionQualityList,
NodeInfo,
OnTrackLayerUpdateNotification,
PolicyParams,
SpeakerList,
TrackStateNotification,
} from './HMSNotifications';
import { EventBus } from '../events/EventBus';
import { HMSAudioListener, HMSConnectionQualityListener, HMSUpdateListener } from '../interfaces';
import { HMSRemoteTrack } from '../media/tracks';
import { Store } from '../sdk/store';
import { InitFlags } from '../signal/init/models';
import HMSTransport from '../transport';
import HMSLogger from '../utils/logger';
export class NotificationManager {
private readonly TAG = '[HMSNotificationManager]';
private trackManager: TrackManager;
private peerManager: PeerManager;
private peerListManager: PeerListManager;
private activeSpeakerManager: ActiveSpeakerManager;
private connectionQualityManager: ConnectionQualityManager;
private broadcastManager: BroadcastManager;
private policyChangeManager: PolicyChangeManager;
private requestManager: RequestManager;
private roomUpdateManager: RoomUpdateManager;
private sessionMetadataManager: SessionMetadataManager;
private pollsManager: PollsManager;
private whiteboardManager: WhiteboardManager;
/**
* room state can be sent before join in preview stage as well but that is outdated, based on
* eventual consistency and doesn't have all data. If we get at least one consistent room update
* from that point onwards we can rely on live server updates and ignore periodic room state messages
*/
private hasConsistentRoomStateArrived = false;
constructor(
private store: Store,
eventBus: EventBus,
private transport: HMSTransport,
private listener?: HMSUpdateListener,
private audioListener?: HMSAudioListener,
private connectionQualityListener?: HMSConnectionQualityListener,
) {
const isOnDemandTracksEnabled = this.transport.isFlagEnabled(InitFlags.FLAG_ON_DEMAND_TRACKS);
this.trackManager = isOnDemandTracksEnabled
? new OnDemandTrackManager(this.store, eventBus, this.transport, this.listener)
: new TrackManager(this.store, eventBus, this.listener);
this.peerManager = new PeerManager(this.store, this.trackManager, this.listener);
this.peerListManager = new PeerListManager(this.store, this.peerManager, this.trackManager, this.listener);
this.broadcastManager = new BroadcastManager(this.listener);
this.policyChangeManager = new PolicyChangeManager(this.store, eventBus);
this.requestManager = new RequestManager(this.store, this.listener);
this.activeSpeakerManager = new ActiveSpeakerManager(this.store, this.listener, this.audioListener);
this.connectionQualityManager = new ConnectionQualityManager(this.store, this.connectionQualityListener);
this.roomUpdateManager = new RoomUpdateManager(this.store, this.listener);
this.sessionMetadataManager = new SessionMetadataManager(this.store, this.listener);
this.pollsManager = new PollsManager(this.store, this.transport, this.listener);
this.whiteboardManager = new WhiteboardManager(this.store, this.transport, this.listener);
}
setListener(listener?: HMSUpdateListener) {
this.listener = listener;
this.trackManager.listener = listener;
this.peerManager.listener = listener;
this.peerListManager.listener = listener;
this.broadcastManager.listener = listener;
this.requestManager.listener = listener;
this.activeSpeakerManager.listener = listener;
this.roomUpdateManager.listener = listener;
this.sessionMetadataManager.listener = listener;
this.pollsManager.listener = listener;
this.whiteboardManager.listener = listener;
}
setAudioListener(audioListener?: HMSAudioListener) {
this.audioListener = audioListener;
this.activeSpeakerManager.audioListener = audioListener;
}
setConnectionQualityListener(qualityListener?: HMSConnectionQualityListener) {
this.connectionQualityListener = qualityListener;
this.connectionQualityManager.listener = qualityListener;
}
handleNotification(message: { method: string; params: any }, isReconnecting = false) {
const method = message.method as HMSNotificationMethod;
const notification = message.params;
if (
![
HMSNotificationMethod.ACTIVE_SPEAKERS,
HMSNotificationMethod.SFU_STATS,
HMSNotificationMethod.CONNECTION_QUALITY,
undefined, // this is is to ignore notifications without any method
].includes(method)
) {
HMSLogger.d(this.TAG, `Received notification - ${method}`, { notification });
}
if (method === HMSNotificationMethod.SFU_STATS) {
if (window.HMS?.ON_SFU_STATS && typeof window.HMS?.ON_SFU_STATS === 'function') {
window.HMS.ON_SFU_STATS(message.params);
}
}
if (this.ignoreNotification(method)) {
return;
}
this.roomUpdateManager.handleNotification(method, notification);
this.peerManager.handleNotification(method, notification);
this.requestManager.handleNotification(method, notification);
this.peerListManager.handleNotification(method, notification, isReconnecting);
this.broadcastManager.handleNotification(method, notification);
this.sessionMetadataManager.handleNotification(method, notification);
this.pollsManager.handleNotification(method, notification);
this.whiteboardManager.handleNotification(method, notification);
this.handleIsolatedMethods(method, notification);
}
// eslint-disable-next-line complexity
handleIsolatedMethods(method: string, notification: any) {
switch (method) {
case HMSNotificationMethod.TRACK_METADATA_ADD: {
this.trackManager.handleTrackMetadataAdd(notification as TrackStateNotification);
break;
}
case HMSNotificationMethod.TRACK_UPDATE: {
this.trackManager.handleTrackUpdate(notification as TrackStateNotification);
break;
}
case HMSNotificationMethod.TRACK_REMOVE: {
if (!notification.peer) {
HMSLogger.d(this.TAG, `Ignoring sfu notification - ${method}`, { notification });
return;
}
this.trackManager.handleTrackRemovedPermanently(notification as TrackStateNotification);
break;
}
case HMSNotificationMethod.ON_SFU_TRACK_LAYER_UPDATE: {
this.trackManager.handleTrackLayerUpdate(notification as OnTrackLayerUpdateNotification);
break;
}
case HMSNotificationMethod.ACTIVE_SPEAKERS:
this.activeSpeakerManager.handleActiveSpeakers(notification as SpeakerList);
break;
case HMSNotificationMethod.CONNECTION_QUALITY:
this.connectionQualityManager.handleQualityUpdate(notification as ConnectionQualityList);
break;
case HMSNotificationMethod.POLICY_CHANGE:
this.policyChangeManager.handlePolicyChange(notification as PolicyParams);
break;
case HMSNotificationMethod.NODE_INFO:
this.transport.setSFUNodeId((notification as NodeInfo).sfu_node_id);
break;
default:
break;
}
}
ignoreNotification = (method: string): boolean => {
if (method === HMSNotificationMethod.PEER_LIST) {
this.hasConsistentRoomStateArrived = true;
} else if (method === HMSNotificationMethod.ROOM_STATE) {
// ignore periodic inconsistent room state if consistent one has arrived at least once
return this.hasConsistentRoomStateArrived;
}
return false;
};
handleTrackAdd = (track: HMSRemoteTrack) => {
this.trackManager.handleTrackAdd(track);
};
handleTrackRemove = (track: HMSRemoteTrack) => {
this.trackManager.handleTrackRemove(track);
};
updateLocalPeer = ({ name, metadata }: { name?: string; metadata?: string }) => {
const peer = this.store.getLocalPeer();
this.peerManager.handlePeerInfoUpdate({ peer, name, data: metadata });
};
}