Socket
Socket
Sign inDemoInstall

@100mslive/hms-video-store

Package Overview
Dependencies
Maintainers
0
Versions
708
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@100mslive/hms-video-store - npm Package Compare versions

Comparing version 0.12.20 to 0.12.21-alpha.0

2

dist/index.d.ts

@@ -7,3 +7,3 @@ export type { IStoreReadOnly, IHMSStore, IHMSStoreReadOnly as HMSStoreWrapper, IHMSStatsStore, IHMSStatsStoreReadOnly as HMSStatsStoreWrapper, } from './IHMSStore';

export * from './webrtc-stats';
export { HMSAudioMode, HMSLogLevel, HMSAudioPluginType, HMSVideoPluginType, HMSVideoPluginCanvasContextType, parsedUserAgent, simulcastMapping, DeviceType, HMSPeerType, } from './internal';
export { HMSAudioMode, HMSLogLevel, HMSAudioPluginType, HMSVideoPluginType, HMSVideoPluginCanvasContextType, parsedUserAgent, simulcastMapping, DeviceType, HMSPeerType, getAudioDeviceCategory, } from './internal';
export type { HMSConfig, HMSPreviewConfig, HMSConfigInitialSettings, HMSAudioTrackSettings, HMSVideoTrackSettings, RTMPRecordingConfig, HMSPeerStats, HMSTrackStats, HMSLocalTrackStats, HMSRemoteTrackStats, HLSConfig, HLSMeetingURLVariant, HMSScreenShareConfig, ScreenCaptureHandle, HMSPreferredSimulcastLayer, TokenRequest, TokenRequestOptions, RID, HMSPoll, HMSPollStates, HMSPollState, HMSPollCreateParams, HMSPollQuestionCreateParams, HMSPollQuestionAnswer, HMSPollQuestion, HMSPollQuestionType, HMSPollQuestionOptionCreateParams, HMSPollQuestionOption, HMSQuizLeaderboardResponse, HMSQuizLeaderboardSummary, HMSTranscriptionInfo, HMSICEServer, } from './internal';

@@ -10,0 +10,0 @@ export { EventBus } from './events/EventBus';

@@ -34,2 +34,3 @@ import { ServerError } from './internal';

isEffectsEnabled?: boolean;
disableNoneLayerRequest?: boolean;
isVBEnabled?: boolean;

@@ -36,0 +37,0 @@ effectsKey?: string;

@@ -12,3 +12,4 @@ import { HMSVideoTrack } from './HMSVideoTrack';

private bizTrackId;
constructor(stream: HMSRemoteStream, track: MediaStreamTrack, source?: string);
private disableNoneLayerRequest;
constructor(stream: HMSRemoteStream, track: MediaStreamTrack, source?: string, disableNoneLayerRequest?: boolean);
setTrackId(trackId: string): void;

@@ -15,0 +16,0 @@ get trackId(): string;

@@ -40,2 +40,3 @@ import { HMSPeerID } from './peer';

isEffectsEnabled?: boolean;
disableNoneLayerRequest?: boolean;
isVBEnabled?: boolean;

@@ -42,0 +43,0 @@ effectsKey?: string;

@@ -18,2 +18,3 @@ import { HMSHLS, HMSRecording, HMSRoom, HMSRTMP, HMSTranscriptionInfo } from '../../interfaces/room';

isEffectsEnabled?: boolean;
disableNoneLayerRequest?: boolean;
isVBEnabled?: boolean;

@@ -20,0 +21,0 @@ effectsKey?: string;

@@ -58,3 +58,4 @@ /**

FLAG_NOISE_CANCELLATION = "noiseCancellation",
FLAG_SCALE_SCREENSHARE_BASED_ON_PIXELS = "scaleScreenshareBasedOnPixels"
FLAG_SCALE_SCREENSHARE_BASED_ON_PIXELS = "scaleScreenshareBasedOnPixels",
FLAG_DISABLE_NONE_LAYER_REQUEST = "disableNoneLayerRequest"
}

@@ -21,3 +21,3 @@ import { TransportFailureCategory as TFC } from './models/TransportFailureCategory';

originalState: TransportState;
maxFailedRetries?: number;
maxRetryTime?: number;
changeState?: boolean;

@@ -32,7 +32,6 @@ }

constructor(onStateChange: (state: TransportState, error?: HMSException) => Promise<void>, sendEvent: (error: HMSException, category: TFC) => void);
schedule({ category, error, task, originalState, maxFailedRetries, changeState, }: ScheduleTaskParams): Promise<void>;
schedule({ category, error, task, originalState, maxRetryTime, changeState, }: ScheduleTaskParams): Promise<void>;
reset(): void;
isTaskInProgress(category: TFC): boolean;
private scheduleTask;
private getBaseDelayForTask;
private getDelayForRetryCount;

@@ -39,0 +38,0 @@ private setTimeoutPromise;

@@ -5,3 +5,3 @@ export declare const RENEGOTIATION_CALLBACK_ID = "renegotiation-callback-id";

/**
* Maximum number of retries that transport-layer will try
* Maximum time that transport-layer will try
* before giving up on the connection and returning a failure

@@ -11,4 +11,3 @@ *

*/
export declare const MAX_TRANSPORT_RETRIES = 5;
export declare const MAX_TRANSPORT_RETRY_DELAY = 60;
export declare const MAX_TRANSPORT_RETRY_TIME = 60000;
export declare const DEFAULT_SIGNAL_PING_TIMEOUT = 12000;

@@ -15,0 +14,0 @@ export declare const DEFAULT_SIGNAL_PING_INTERVAL = 3000;

@@ -15,2 +15,3 @@ export declare function getLocalStream(constraints: MediaStreamConstraints): Promise<MediaStream>;

export declare const HMSAudioContextHandler: HMSAudioContext;
export declare const getAudioDeviceCategory: (deviceLabel: string) => "bluetooth" | "speakerhone" | "wired" | "earpiece" | "speakerphone";
export {};
{
"version": "0.12.20",
"version": "0.12.21-alpha.0",
"license": "MIT",

@@ -76,3 +76,3 @@ "repository": {

],
"gitHead": "da50781c2357d6201da1c94dcfef574a0081e2dc"
"gitHead": "5b08acb39d9c077ca4c28c4bef65e0f7190a13d9"
}

@@ -101,4 +101,7 @@ import EventEmitter from 'eventemitter2';

const remote = this.remoteStreams.get(streamId)!;
const TrackCls = e.track.kind === 'audio' ? HMSRemoteAudioTrack : HMSRemoteVideoTrack;
const track = new TrackCls(remote, e.track);
const isAudioTrack = e.track.kind === 'audio';
const TrackCls = isAudioTrack ? HMSRemoteAudioTrack : HMSRemoteVideoTrack;
const track = isAudioTrack
? new TrackCls(remote, e.track)
: new TrackCls(remote, e.track, undefined, this.isFlagEnabled(InitFlags.FLAG_DISABLE_NONE_LAYER_REQUEST));
// reset the simulcast layer to none when new video tracks are added, UI will subscribe when required

@@ -105,0 +108,0 @@ if (e.track.kind === 'video') {

@@ -7,3 +7,3 @@ import { DeviceStorageManager } from './DeviceStorage';

import { DeviceMap, HMSDeviceChangeEvent, SelectedDevices } from '../interfaces';
import { isIOS } from '../internal';
import { getAudioDeviceCategory, isIOS } from '../internal';
import { HMSAudioTrackSettingsBuilder, HMSVideoTrackSettingsBuilder } from '../media/settings';

@@ -263,3 +263,3 @@ import { HMSLocalAudioTrack, HMSLocalTrack, HMSLocalVideoTrack } from '../media/tracks';

// false positives when device is removed, because the other available device
// get's the deviceId as default once this device is removed
// gets the deviceId as default once this device is removed
const nextDevice = this.audioInput.find(device => {

@@ -448,10 +448,10 @@ return device.deviceId !== 'default' && defaultDevice.label.includes(device.label);

for (const device of this.audioInput) {
const label = device.label.toLowerCase();
if (label.includes('speakerphone')) {
const deviceCategory = getAudioDeviceCategory(device.label);
if (deviceCategory === 'speakerphone') {
speakerPhone = device;
} else if (label.includes('wired')) {
} else if (deviceCategory === 'wired') {
wired = device;
} else if (/airpods|buds|wireless|bluetooth/gi.test(label)) {
} else if (deviceCategory === 'bluetooth') {
bluetoothDevice = device;
} else if (label.includes('earpiece')) {
} else if (deviceCategory === 'speakerhone') {
earpiece = device;

@@ -458,0 +458,0 @@ }

@@ -23,2 +23,3 @@ export type {

HMSPeerType,
getAudioDeviceCategory,
} from './internal';

@@ -25,0 +26,0 @@

@@ -37,2 +37,3 @@ import { ServerError } from './internal';

isEffectsEnabled?: boolean;
disableNoneLayerRequest?: boolean;
isVBEnabled?: boolean;

@@ -39,0 +40,0 @@ effectsKey?: string;

@@ -187,4 +187,4 @@ import isEqual from 'lodash.isequal';

// Replace silent empty track with an actual audio track, if enabled.
if (value && isEmptyTrack(this.nativeTrack)) {
// Replace silent empty track or muted track(happens when microphone is disabled from address bar in iOS) with an actual audio track, if enabled.
if (value && (isEmptyTrack(this.nativeTrack) || this.nativeTrack.muted)) {
await this.replaceTrackWith(this.settings);

@@ -191,0 +191,0 @@ }

@@ -569,8 +569,3 @@ import isEqual from 'lodash.isequal';

if (this.enabled) {
const track = await this.replaceTrackWithBlank();
await this.replaceSender(track, this.enabled);
this.nativeTrack?.stop();
this.nativeTrack = track;
} else {
await this.replaceSender(this.nativeTrack, false);
await this.setEnabled(false);
}

@@ -585,8 +580,5 @@ // started interruption event

} else {
HMSLogger.d(this.TAG, 'visibility visibile, restoring track state', this.enabledStateBeforeBackground);
HMSLogger.d(this.TAG, 'visibility visible, restoring track state', this.enabledStateBeforeBackground);
if (this.enabledStateBeforeBackground) {
await this.setEnabled(true);
} else {
this.nativeTrack.enabled = this.enabledStateBeforeBackground;
await this.replaceSender(this.nativeTrack, this.enabledStateBeforeBackground);
}

@@ -601,4 +593,3 @@ // ended interruption event

}
this.eventBus.localVideoEnabled.publish({ enabled: this.nativeTrack.enabled, track: this });
};
}

@@ -21,5 +21,7 @@ import { HMSVideoTrack } from './HMSVideoTrack';

private bizTrackId!: string;
private disableNoneLayerRequest = false;
constructor(stream: HMSRemoteStream, track: MediaStreamTrack, source?: string) {
constructor(stream: HMSRemoteStream, track: MediaStreamTrack, source?: string, disableNoneLayerRequest?: boolean) {
super(stream, track, source);
this.disableNoneLayerRequest = !!disableNoneLayerRequest;
this.setVideoHandler(new VideoElementManager(this));

@@ -174,3 +176,6 @@ }

private async updateLayer(source: string) {
const newLayer = this.degraded || !this.enabled || !this.hasSinks() ? HMSSimulcastLayer.NONE : this.preferredLayer;
const newLayer =
(this.degraded || !this.enabled || !this.hasSinks()) && !this.disableNoneLayerRequest
? HMSSimulcastLayer.NONE
: this.preferredLayer;
if (!this.shouldSendVideoLayer(newLayer, source)) {

@@ -177,0 +182,0 @@ return;

@@ -22,3 +22,3 @@ import { HMSRemoteVideoTrack } from './HMSRemoteVideoTrack';

nativeTrack = { id: trackId, kind: 'video', enabled: true } as MediaStreamTrack;
track = new HMSRemoteVideoTrack(stream, nativeTrack, 'regular');
track = new HMSRemoteVideoTrack(stream, nativeTrack, 'regular', false);
window.MediaStream = jest.fn().mockImplementation(() => ({

@@ -160,1 +160,61 @@ addTrack: jest.fn(),

});
describe('HMSRemoteVideoTrack with disableNoneLayerRequest', () => {
let stream: HMSRemoteStream;
let sendOverApiDataChannelWithResponse: jest.Mock;
let track: HMSRemoteVideoTrack;
let nativeTrack: MediaStreamTrack;
let videoElement: HTMLVideoElement;
const trackId = 'test-track-id';
beforeEach(() => {
videoElement = document.createElement('video');
sendOverApiDataChannelWithResponse = jest.fn();
const connection = { sendOverApiDataChannelWithResponse } as unknown as HMSSubscribeConnection;
const nativeStream = new MediaStream();
stream = new HMSRemoteStream(nativeStream, connection);
nativeTrack = { id: trackId, kind: 'video', enabled: true } as MediaStreamTrack;
track = new HMSRemoteVideoTrack(stream, nativeTrack, 'regular', true); // disableNoneLayerRequest flag is set
track.setTrackId(trackId);
window.MediaStream = jest.fn().mockImplementation(() => ({
addTrack: jest.fn(),
}));
});
const expectLayersSent = (layers: HMSSimulcastLayer[]) => {
const allCalls = sendOverApiDataChannelWithResponse.mock.calls;
expect(allCalls.length).toBe(layers.length);
for (let i = 0; i < allCalls.length; i++) {
const data = allCalls[i][0];
expect(data.params.max_spatial_layer).toBe(layers[i]);
}
};
const sfuDegrades = () => {
track.setLayerFromServer({
subscriber_degraded: true,
expected_layer: HMSSimulcastLayer.HIGH,
current_layer: HMSSimulcastLayer.NONE,
publisher_degraded: false,
track_id: trackId,
});
};
test('disableNoneLayerRequest - degradation', async () => {
await track.addSink(videoElement);
expectLayersSent([HMSSimulcastLayer.HIGH]);
sfuDegrades();
expectLayersSent([HMSSimulcastLayer.HIGH]);
});
test('disableNoneLayerRequest - mute and removeSink', async () => {
await track.addSink(videoElement);
track.setEnabled(false);
expectLayersSent([HMSSimulcastLayer.HIGH]);
await track.removeSink(videoElement);
expectLayersSent([HMSSimulcastLayer.HIGH]);
});
});

@@ -70,3 +70,8 @@ import { TrackManager } from './TrackManager';

emptyTrack.enabled = !trackInfo.mute;
const track = new HMSRemoteVideoTrack(remoteStream, emptyTrack, trackInfo.source);
const track = new HMSRemoteVideoTrack(
remoteStream,
emptyTrack,
trackInfo.source,
this.store.getRoom()?.disableNoneLayerRequest,
);
track.setTrackId(trackInfo.track_id);

@@ -73,0 +78,0 @@ track.peerId = hmsPeer.peerId;

@@ -162,2 +162,3 @@ import { areArraysEqual } from './sdkUtils/storeMergeUtils';

isEffectsEnabled: sdkRoom.isEffectsEnabled,
disableNoneLayerRequest: sdkRoom.disableNoneLayerRequest,
isVBEnabled: sdkRoom.isVBEnabled,

@@ -164,0 +165,0 @@ effectsKey: sdkRoom.effectsKey,

@@ -43,2 +43,3 @@ import { HMSPeerID } from './peer';

isEffectsEnabled?: boolean;
disableNoneLayerRequest?: boolean;
isVBEnabled?: boolean;

@@ -45,0 +46,0 @@ effectsKey?: string;

@@ -19,2 +19,3 @@ import { HMSHLS, HMSRecording, HMSRoom, HMSRTMP, HMSTranscriptionInfo } from '../../interfaces/room';

isEffectsEnabled?: boolean;
disableNoneLayerRequest?: boolean;
isVBEnabled?: boolean;

@@ -21,0 +22,0 @@ effectsKey?: string;

@@ -65,2 +65,3 @@ /**

FLAG_SCALE_SCREENSHARE_BASED_ON_PIXELS = 'scaleScreenshareBasedOnPixels',
FLAG_DISABLE_NONE_LAYER_REQUEST = 'disableNoneLayerRequest',
}

@@ -39,3 +39,2 @@ import { JoinParameters } from './models/JoinParameters';

ICE_DISCONNECTION_TIMEOUT,
MAX_TRANSPORT_RETRIES,
PROTOCOL_SPEC,

@@ -356,3 +355,2 @@ PROTOCOL_VERSION,

originalState: this.state,
maxFailedRetries: MAX_TRANSPORT_RETRIES,
changeState: false,

@@ -928,3 +926,2 @@ });

originalState: TransportState.Joined,
maxFailedRetries: 3,
changeState: false,

@@ -1093,3 +1090,2 @@ });

originalState: TransportState.Joined,
maxFailedRetries: 1,
});

@@ -1116,2 +1112,3 @@ }

room.isEffectsEnabled = this.isFlagEnabled(InitFlags.FLAG_EFFECTS_SDK_ENABLED);
room.disableNoneLayerRequest = this.isFlagEnabled(InitFlags.FLAG_DISABLE_NONE_LAYER_REQUEST);
room.isVBEnabled = this.isFlagEnabled(InitFlags.FLAG_VB_ENABLED);

@@ -1118,0 +1115,0 @@ room.isHipaaEnabled = this.isFlagEnabled(InitFlags.FLAG_HIPAA_ENABLED);

import { Dependencies as TFCDependencies, TransportFailureCategory as TFC } from './models/TransportFailureCategory';
import { TransportState } from './models/TransportState';
import { HMSException } from '../error/HMSException';
import { MAX_TRANSPORT_RETRIES, MAX_TRANSPORT_RETRY_DELAY } from '../utils/constants';
import { MAX_TRANSPORT_RETRY_TIME } from '../utils/constants';
import HMSLogger from '../utils/logger';

@@ -26,3 +26,3 @@ import { PromiseWithCallbacks } from '../utils/promise';

originalState: TransportState;
maxFailedRetries?: number;
maxRetryTime?: number;
changeState?: boolean;

@@ -46,6 +46,6 @@ }

originalState,
maxFailedRetries = MAX_TRANSPORT_RETRIES,
maxRetryTime = MAX_TRANSPORT_RETRY_TIME,
changeState = true,
}: ScheduleTaskParams) {
await this.scheduleTask({ category, error, changeState, task, originalState, maxFailedRetries });
await this.scheduleTask({ category, error, changeState, task, originalState, maxRetryTime, failedAt: Date.now() });
}

@@ -70,5 +70,6 @@

originalState,
maxFailedRetries = MAX_TRANSPORT_RETRIES,
failedAt,
maxRetryTime = MAX_TRANSPORT_RETRY_TIME,
failedRetryCount = 0,
}: ScheduleTaskParams & { failedRetryCount?: number }): Promise<void> {
}: ScheduleTaskParams & { failedAt: number; failedRetryCount?: number }): Promise<void> {
HMSLogger.d(this.TAG, 'schedule: ', { category: TFC[category], error });

@@ -119,4 +120,5 @@

if (failedRetryCount >= maxFailedRetries || hasFailedDependency) {
error.description += `. [${TFC[category]}] Could not recover after ${failedRetryCount} tries`;
const timeElapsedSinceError = Date.now() - failedAt;
if (timeElapsedSinceError >= maxRetryTime || hasFailedDependency) {
error.description += `. [${TFC[category]}] Could not recover after ${timeElapsedSinceError} milliseconds`;

@@ -151,3 +153,3 @@ if (hasFailedDependency) {

const delay = this.getDelayForRetryCount(category, failedRetryCount);
const delay = this.getDelayForRetryCount(category);

@@ -179,3 +181,6 @@ HMSLogger.d(

}
HMSLogger.d(this.TAG, `schedule: [${TFC[category]}] [failedRetryCount=${failedRetryCount}] Recovered ♻️`);
HMSLogger.d(
this.TAG,
`schedule: [${TFC[category]}] [failedRetryCount=${failedRetryCount}] Recovered ♻️ after ${timeElapsedSinceError}ms`,
);
} else {

@@ -188,3 +193,4 @@ await this.scheduleTask({

originalState,
maxFailedRetries,
maxRetryTime,
failedAt,
failedRetryCount: failedRetryCount + 1,

@@ -195,17 +201,14 @@ });

private getBaseDelayForTask(category: TFC, n: number) {
private getDelayForRetryCount(category: TFC) {
const jitter = category === TFC.JoinWSMessageFailed ? Math.random() * 2 : Math.random();
let delaySeconds = 0;
if (category === TFC.JoinWSMessageFailed) {
// linear backoff(2 + jitter for every retry)
return 2;
delaySeconds = 2 + jitter;
} else if (category === TFC.SignalDisconnect) {
delaySeconds = 1;
}
// exponential backoff
return Math.pow(2, n);
return delaySeconds * 1000;
}
private getDelayForRetryCount(category: TFC, n: number) {
const delay = this.getBaseDelayForTask(category, n);
const jitter = category === TFC.JoinWSMessageFailed ? Math.random() * 2 : Math.random();
return Math.round(Math.min(delay + jitter, MAX_TRANSPORT_RETRY_DELAY) * 1000);
}
private async setTimeoutPromise<T>(task: () => Promise<T>, delay: number): Promise<T> {

@@ -212,0 +215,0 @@ return new Promise((resolve, reject) => {

@@ -6,3 +6,3 @@ export const RENEGOTIATION_CALLBACK_ID = 'renegotiation-callback-id';

/**
* Maximum number of retries that transport-layer will try
* Maximum time that transport-layer will try
* before giving up on the connection and returning a failure

@@ -12,4 +12,3 @@ *

*/
export const MAX_TRANSPORT_RETRIES = 5;
export const MAX_TRANSPORT_RETRY_DELAY = 60;
export const MAX_TRANSPORT_RETRY_TIME = 60_000;

@@ -16,0 +15,0 @@ export const DEFAULT_SIGNAL_PING_TIMEOUT = 12_000;

@@ -66,1 +66,15 @@ import HMSLogger from './logger';

};
export const getAudioDeviceCategory = (deviceLabel: string) => {
const label = deviceLabel.toLowerCase();
if (label.includes('speakerphone')) {
return 'speakerhone';
} else if (label.includes('wired')) {
return 'wired';
} else if (/airpods|buds|wireless|bluetooth/gi.test(label)) {
return 'bluetooth';
} else if (label.includes('earpiece')) {
return 'earpiece';
}
return 'speakerphone';
};

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc