diff --git a/examples/prebuilt-react-integration/index.html b/examples/prebuilt-react-integration/index.html index 895cbcd8ce..aee5d151bb 100644 --- a/examples/prebuilt-react-integration/index.html +++ b/examples/prebuilt-react-integration/index.html @@ -1,4 +1,4 @@ - + diff --git a/packages/hms-video-store/src/analytics/AnalyticsEventFactory.ts b/packages/hms-video-store/src/analytics/AnalyticsEventFactory.ts index e387fa4991..d7f4200922 100644 --- a/packages/hms-video-store/src/analytics/AnalyticsEventFactory.ts +++ b/packages/hms-video-store/src/analytics/AnalyticsEventFactory.ts @@ -256,6 +256,18 @@ export default class AnalyticsEventFactory { level: AnalyticsEventLevel.INFO, }); } + + static interruption(started: boolean, type: string, deviceInfo: Partial) { + return new AnalyticsEvent({ + name: `${started ? 'interruption.start' : 'interruption.stop'}`, + level: AnalyticsEventLevel.INFO, + properties: { + type, + ...deviceInfo, + }, + }); + } + private static eventNameFor(name: string, ok: boolean) { const suffix = ok ? 'success' : 'failed'; return `${name}.${suffix}`; diff --git a/packages/hms-video-store/src/media/tracks/HMSLocalAudioTrack.ts b/packages/hms-video-store/src/media/tracks/HMSLocalAudioTrack.ts index 2e3883660c..c0e6a99fc6 100644 --- a/packages/hms-video-store/src/media/tracks/HMSLocalAudioTrack.ts +++ b/packages/hms-video-store/src/media/tracks/HMSLocalAudioTrack.ts @@ -9,7 +9,6 @@ import { HMSAudioPlugin, HMSPluginSupportResult } from '../../plugins'; import { HMSAudioPluginsManager } from '../../plugins/audio'; import Room from '../../sdk/models/HMSRoom'; import HMSLogger from '../../utils/logger'; -import { isBrowser, isIOS } from '../../utils/support'; import { getAudioTrack, isEmptyTrack } from '../../utils/track'; import { TrackAudioLevelMonitor } from '../../utils/track-audio-level-monitor'; import { HMSAudioTrackSettings, HMSAudioTrackSettingsBuilder } from '../settings'; @@ -60,7 +59,7 @@ export class HMSLocalAudioTrack extends HMSAudioTrack { } this.pluginsManager = new HMSAudioPluginsManager(this, eventBus, room); this.setFirstTrackId(track.id); - if (isIOS() && isBrowser) { + if (source === 'regular') { document.addEventListener('visibilitychange', this.handleVisibilityChange); } } @@ -73,9 +72,30 @@ export class HMSLocalAudioTrack extends HMSAudioTrack { this.manuallySelectedDeviceId = undefined; } + private isTrackNotPublishing = () => { + return this.nativeTrack.readyState === 'ended' || this.nativeTrack.muted; + }; + private handleVisibilityChange = async () => { - if (document.visibilityState === 'visible') { + // track state is fine do nothing + if (!this.isTrackNotPublishing()) { + HMSLogger.d(this.TAG, `visibiltiy: ${document.visibilityState}`, `${this}`); + return; + } + if (document.visibilityState === 'hidden') { + this.eventBus.analytics.publish( + this.sendInterruptionEvent({ + started: true, + }), + ); + } else { + HMSLogger.d(this.TAG, 'On visibile replacing track as it is not publishing'); await this.replaceTrackWith(this.settings); + this.eventBus.analytics.publish( + this.sendInterruptionEvent({ + started: false, + }), + ); } }; @@ -230,9 +250,7 @@ export class HMSLocalAudioTrack extends HMSAudioTrack { this.processedTrack?.stop(); this.isPublished = false; this.destroyAudioLevelMonitor(); - if (isIOS() && isBrowser) { - document.removeEventListener('visibilitychange', this.handleVisibilityChange); - } + document.removeEventListener('visibilitychange', this.handleVisibilityChange); } /** diff --git a/packages/hms-video-store/src/media/tracks/HMSLocalVideoTrack.ts b/packages/hms-video-store/src/media/tracks/HMSLocalVideoTrack.ts index 0a19048514..758881a3d0 100644 --- a/packages/hms-video-store/src/media/tracks/HMSLocalVideoTrack.ts +++ b/packages/hms-video-store/src/media/tracks/HMSLocalVideoTrack.ts @@ -84,7 +84,7 @@ export class HMSLocalVideoTrack extends HMSVideoTrack { this.pluginsManager = new HMSVideoPluginsManager(this, eventBus); this.mediaStreamPluginsManager = new HMSMediaStreamPluginsManager(eventBus, room); this.setFirstTrackId(this.trackId); - if (isBrowser && isMobile()) { + if (isBrowser && source === 'regular') { document.addEventListener('visibilitychange', this.handleVisibilityChange); } } @@ -495,13 +495,34 @@ export class HMSLocalVideoTrack extends HMSVideoTrack { }; private handleVisibilityChange = async () => { - if (document.visibilityState === 'hidden' && this.source === 'regular') { - this.enabledStateBeforeBackground = this.enabled; - this.nativeTrack.enabled = false; - this.replaceSenderTrack(this.nativeTrack); + if (document.visibilityState === 'hidden') { + if (isMobile()) { + this.enabledStateBeforeBackground = this.enabled; + this.nativeTrack.enabled = false; + HMSLogger.d(this.TAG, 'visibility hidden muting track'); + this.replaceSenderTrack(this.nativeTrack); + // started interruption event + this.eventBus.analytics.publish( + this.sendInterruptionEvent({ + started: true, + }), + ); + } } else { - this.nativeTrack.enabled = this.enabledStateBeforeBackground; - this.replaceSenderTrack(this.processedTrack || this.nativeTrack); + if (this.nativeTrack.muted || this.nativeTrack.readyState === 'ended') { + HMSLogger.d(this.TAG, 'visibility visible, restarting track', `${this}`); + const track = await this.replaceTrackWith(this.settings); + this.nativeTrack?.stop(); + this.nativeTrack = track; + } + if (isMobile()) { + this.nativeTrack.enabled = this.enabledStateBeforeBackground; + await this.replaceSender(this.nativeTrack, this.enabledStateBeforeBackground); + } else { + await this.replaceSender(this.nativeTrack, this.enabled); + } + await this.processPlugins(); + this.videoHandler.updateSinks(); } this.eventBus.localVideoEnabled.publish({ enabled: this.nativeTrack.enabled, track: this }); }; diff --git a/packages/hms-video-store/src/media/tracks/HMSTrack.ts b/packages/hms-video-store/src/media/tracks/HMSTrack.ts index b3c5574bb1..470a3eae88 100644 --- a/packages/hms-video-store/src/media/tracks/HMSTrack.ts +++ b/packages/hms-video-store/src/media/tracks/HMSTrack.ts @@ -1,4 +1,5 @@ import { HMSTrackType } from './HMSTrackType'; +import AnalyticsEventFactory from '../../analytics/AnalyticsEventFactory'; import { stringifyMediaStreamTrack } from '../../utils/json'; import HMSLogger from '../../utils/logger'; import { HMSMediaStream } from '../streams'; @@ -84,7 +85,16 @@ export abstract class HMSTrack { protected setFirstTrackId(trackId: string) { this.firstTrackId = trackId; } - + /** + * @internal + * It will send event to analytics when interruption start/stop + */ + sendInterruptionEvent({ started, isRemoteAudio = false }: { started: boolean; isRemoteAudio?: boolean }) { + return AnalyticsEventFactory.interruption(started, isRemoteAudio ? 'remote.audio' : this.type, { + deviceId: this.nativeTrack.getSettings().deviceId, + groupId: this.nativeTrack.getSettings().groupId, + }); + } /** * @internal * take care of -