UNPKG

@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
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 }); }; }