@livedigital/client 3.42.0-use-webapi-crypto.1 → 3.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/dist/constants/common.d.ts +1 -1
  2. package/dist/constants/common.ts +1 -1
  3. package/dist/engine/PeerProducer.d.ts +3 -0
  4. package/dist/engine/handlers/ChannelStateSyncEventHandler/ChannelStateConsistencyChecker.d.ts +3 -1
  5. package/dist/engine/media/streamEffects/audio/AudioTrackProcessor.d.ts +1 -0
  6. package/dist/engine/media/streamEffects/audio/asdk/ASDKTrackProcessor.d.ts +1 -0
  7. package/dist/engine/media/streamEffects/audio/noiseSuppression/RNNoiseTrackProcessor.d.ts +1 -0
  8. package/dist/index.es.js +2 -2
  9. package/dist/index.js +2 -2
  10. package/dist/types/channelStateSyncronizer.d.ts +6 -0
  11. package/package.json +1 -1
  12. package/src/constants/common.ts +1 -1
  13. package/src/engine/ChannelStateSynchronizer/ChannelStateSynchronizer.ts +1 -1
  14. package/src/engine/PeerProducer.ts +12 -0
  15. package/src/engine/handlers/ChannelStateSyncEventHandler/ChannelStateConsistencyChecker.ts +31 -14
  16. package/src/engine/handlers/ChannelStateSyncEventHandler/index.ts +1 -0
  17. package/src/engine/handlers/MediaEventHandler.ts +2 -2
  18. package/src/engine/index.ts +4 -4
  19. package/src/engine/media/streamEffects/ProcessorsCache.ts +1 -0
  20. package/src/engine/media/streamEffects/audio/AudioTrackProcessor.ts +1 -0
  21. package/src/engine/media/streamEffects/audio/asdk/ASDKTrackProcessor.ts +5 -0
  22. package/src/engine/media/streamEffects/audio/noiseSuppression/RNNoiseTrackProcessor.ts +4 -0
  23. package/src/engine/network/index.ts +20 -20
  24. package/src/helpers/randomString.ts +1 -1
  25. package/src/types/channelStateSyncronizer.ts +7 -0
@@ -1,10 +1,16 @@
1
1
  import type { ChannelStateShortPeer } from '../proto/generated/channel/channel_state_short';
2
+ export interface LocalChannelStatePeerProducer {
3
+ id: string;
4
+ paused: boolean;
5
+ stateChangedAt: number;
6
+ }
2
7
  export interface LocalChannelStatePeerConsumer {
3
8
  id: string;
4
9
  paused: boolean;
5
10
  producerId: string;
6
11
  }
7
12
  export interface LocalChannelStatePeer extends ChannelStateShortPeer {
13
+ producers: LocalChannelStatePeerProducer[];
8
14
  consumers?: LocalChannelStatePeerConsumer[];
9
15
  }
10
16
  export interface LocalChannelState {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@livedigital/client",
3
3
  "author": "vlprojects",
4
4
  "license": "MIT",
5
- "version": "3.42.0-use-webapi-crypto.1",
5
+ "version": "3.42.0",
6
6
  "private": false,
7
7
  "bugs": {
8
8
  "url": "https://github.com/vlprojects/livedigital-sdk/issues"
@@ -2,7 +2,7 @@
2
2
 
3
3
  import type { LogLevel } from '../types/common';
4
4
 
5
- export const SIGNALING_API_VERSION = 6;
5
+ export const SIGNALING_API_VERSION = 7;
6
6
 
7
7
  export const LOG_LEVEL_ERROR: LogLevel = 3;
8
8
  export const LOG_LEVEL_WARN: LogLevel = 4;
@@ -361,7 +361,7 @@ class ChannelStateSynchronizer {
361
361
  const { paused } = clusterPeerProducer;
362
362
 
363
363
  if (localProducer.paused !== paused) {
364
- localProducer.paused = paused;
364
+ localProducer.setPaused(paused);
365
365
  const producerStateEvent = localProducer.paused ? PEER_EVENTS.publisherPaused : PEER_EVENTS.publisherResumed;
366
366
  localPeer.observer.safeEmit(producerStateEvent, {
367
367
  producerId: localProducer.id,
@@ -19,6 +19,8 @@ class PeerProducer {
19
19
 
20
20
  readonly trackTransformParams?: TrackTransformParams;
21
21
 
22
+ #stateChangedAt: number;
23
+
22
24
  constructor(params: ProducerData) {
23
25
  const {
24
26
  id, kind, peerId, label, paused,
@@ -32,6 +34,16 @@ class PeerProducer {
32
34
  this.encodings = params.encodings;
33
35
  this.trackTransformParams = params.trackTransformParams;
34
36
  this.maxSpatialLayer = params.maxSpatialLayer;
37
+ this.#stateChangedAt = Date.now();
38
+ }
39
+
40
+ setPaused(paused: boolean): void {
41
+ this.paused = paused;
42
+ this.#stateChangedAt = Date.now();
43
+ }
44
+
45
+ getStateChangedAt(): number {
46
+ return this.#stateChangedAt;
35
47
  }
36
48
  }
37
49
 
@@ -1,18 +1,22 @@
1
+ import { FIVE_SECONDS_IN_MS } from '../../../constants/common';
1
2
  import type {
2
3
  ChannelStateShort,
3
- ChannelStateShortPeer,
4
- ChannelStateShortProducer,
5
4
  } from '../../../proto/generated/channel/channel_state_short';
6
- import type { LocalChannelStatePeer, LocalChannelStatePeerConsumer } from '../../../types/channelStateSyncronizer';
5
+ import type {
6
+ LocalChannelState,
7
+ LocalChannelStatePeer,
8
+ LocalChannelStatePeerConsumer,
9
+ LocalChannelStatePeerProducer,
10
+ } from '../../../types/channelStateSyncronizer';
7
11
  import ChannelStateConsistencyCheckResult from './ChannelStateConsistencyCheckResult';
8
12
 
9
13
  interface ChannelStateConsistencyCheckerParams {
10
- localState: ChannelStateShort;
14
+ localState: LocalChannelState;
11
15
  remoteState: ChannelStateShort;
12
16
  }
13
17
 
14
18
  class ChannelStateConsistencyChecker {
15
- private readonly localState: ChannelStateShort;
19
+ private readonly localState: LocalChannelState;
16
20
 
17
21
  private readonly remoteState: ChannelStateShort;
18
22
 
@@ -49,19 +53,15 @@ class ChannelStateConsistencyChecker {
49
53
  }
50
54
 
51
55
  remotePeer.producers.forEach((remoteProducer) => {
52
- const localConsumer = this.findLocalConsumerByProducerId(localPeer, remoteProducer.id);
53
-
54
- if (localConsumer && localConsumer.paused !== remoteProducer.paused) {
55
- this.consumersWithInconsistentState.push(localConsumer.id);
56
- }
57
-
58
56
  const localProducer = this.findLocalProducerById(localPeer, remoteProducer.id);
59
57
 
60
58
  if (!localProducer) {
61
59
  this.missingProducers.push(remoteProducer.id);
60
+
61
+ return;
62
62
  }
63
63
 
64
- if (!localProducer) {
64
+ if (this.isLocalProducerStateChangedRecently(localProducer)) {
65
65
  return;
66
66
  }
67
67
 
@@ -69,6 +69,19 @@ class ChannelStateConsistencyChecker {
69
69
 
70
70
  if (isInconsistentState) {
71
71
  this.producersWithInconsistentState.push(remoteProducer.id);
72
+
73
+ // don't check consumer state while producer state is inconsistent
74
+ return;
75
+ }
76
+
77
+ const localConsumer = this.findLocalConsumerByProducerId(localPeer, remoteProducer.id);
78
+
79
+ if (localConsumer && localConsumer.paused !== remoteProducer.paused) {
80
+ this.consumersWithInconsistentState.push(localConsumer.id);
81
+ }
82
+
83
+ if (!localProducer) {
84
+ this.missingProducers.push(remoteProducer.id);
72
85
  }
73
86
  });
74
87
  });
@@ -102,7 +115,7 @@ class ChannelStateConsistencyChecker {
102
115
  return this.peersWithInconsistentAppData;
103
116
  }
104
117
 
105
- private findLocalPeerById(id: string): ChannelStateShortPeer | undefined {
118
+ private findLocalPeerById(id: string): LocalChannelStatePeer | undefined {
106
119
  return this.localState.peers.find((item) => item.id === id);
107
120
  }
108
121
 
@@ -113,7 +126,7 @@ class ChannelStateConsistencyChecker {
113
126
  return peer.consumers?.find((item) => item.producerId === producerId);
114
127
  }
115
128
 
116
- private findLocalProducerById(peer: ChannelStateShortPeer, id: string): ChannelStateShortProducer | undefined {
129
+ private findLocalProducerById(peer: LocalChannelStatePeer, id: string): LocalChannelStatePeerProducer | undefined {
117
130
  return peer.producers.find((item) => item.id === id);
118
131
  }
119
132
 
@@ -124,6 +137,10 @@ class ChannelStateConsistencyChecker {
124
137
  this.producersWithInconsistentState = [];
125
138
  this.peersWithInconsistentAppData = [];
126
139
  }
140
+
141
+ private isLocalProducerStateChangedRecently(producer: LocalChannelStatePeerProducer): boolean {
142
+ return Date.now() - producer.stateChangedAt < FIVE_SECONDS_IN_MS;
143
+ }
127
144
  }
128
145
 
129
146
  export default ChannelStateConsistencyChecker;
@@ -274,6 +274,7 @@ class ChannelStateSyncEventHandler {
274
274
  producers: peer.getProducers().map((producer) => ({
275
275
  id: producer.id,
276
276
  paused: producer.paused,
277
+ stateChangedAt: producer.getStateChangedAt(),
277
278
  })),
278
279
  consumers: peer.getConsumersState(),
279
280
  })),
@@ -131,7 +131,7 @@ class MediaEventHandler {
131
131
  return;
132
132
  }
133
133
 
134
- producer.paused = true;
134
+ producer.setPaused(true);
135
135
  peer.observer.safeEmit(PEER_EVENTS.publisherPaused, {
136
136
  producerId: producer.id,
137
137
  kind: producer.kind,
@@ -152,7 +152,7 @@ class MediaEventHandler {
152
152
  return;
153
153
  }
154
154
 
155
- producer.paused = false;
155
+ producer.setPaused(false);
156
156
  peer.observer.safeEmit(PEER_EVENTS.publisherResumed, {
157
157
  producerId: producer.id,
158
158
  kind: producer.kind,
@@ -137,7 +137,7 @@ class Engine {
137
137
  this.network.createSendTransport(this.media.mediasoupDevice),
138
138
  this.network.createRecvTransport(this.media.mediasoupDevice),
139
139
  // @INFO: un-comment to enable signaling tcp transport connection
140
- // this.network.createSignalingTransport(this.media.mediasoupDevice),
140
+ this.network.createSignalingTransport(this.media.mediasoupDevice),
141
141
  ]);
142
142
 
143
143
  this.webRtcIssueDetector?.handleNewPeerConnection(sendTransport.handler._pc, sendTransport.id);
@@ -163,7 +163,7 @@ class Engine {
163
163
 
164
164
  // @INFO: un-comment to enable signaling tcp transport connection
165
165
  // @WARN: must be non-blocking, no await
166
- // this.network.createSignalingConsumer();
166
+ await this.network.createSignalingConsumer();
167
167
  } catch (error: unknown) {
168
168
  this.#logger.error('initialize()', { error });
169
169
 
@@ -888,8 +888,8 @@ class Engine {
888
888
  case: 'waitForReconnectOrTriggerRejoinEventIfAppropriate',
889
889
  });
890
890
 
891
- const CHECKS_INTERVAL = 3_000;
892
- const REQUIRED_SUCCESSFUL_CHECKS = 4;
891
+ const CHECKS_INTERVAL = 10_000;
892
+ const REQUIRED_SUCCESSFUL_CHECKS = 6;
893
893
  let continuousNumberOfLoadbalancerSuccessfulChecks = 0;
894
894
 
895
895
  const checkInterval = setInterval(async () => {
@@ -33,6 +33,7 @@ export class ProcessorsCache {
33
33
  reset(): void {
34
34
  for (const processor of this.#audioProcessorsCache.values()) {
35
35
  processor.stopProcessing();
36
+ processor.release();
36
37
  }
37
38
 
38
39
  this.#audioProcessorsCache.clear();
@@ -3,4 +3,5 @@ export interface AudioTrackProcessor {
3
3
  processTrack: (track: MediaStreamTrack) => Promise<MediaStreamTrack>;
4
4
  stopProcessing: () => void;
5
5
  get isProcessing(): boolean;
6
+ release: () => void;
6
7
  }
@@ -125,6 +125,11 @@ export class ASDKTrackProcessor implements AudioTrackProcessor {
125
125
  await this.#atsvb.preload();
126
126
  }
127
127
 
128
+ release(): void {
129
+ this.#atsvb.stop();
130
+ this.#atsvb.clear();
131
+ }
132
+
128
133
  get isProcessing(): boolean {
129
134
  return !!this.#track;
130
135
  }
@@ -38,6 +38,10 @@ export default class RNNoiseTrackProcessor implements AudioTrackProcessor {
38
38
  return !!this.#track;
39
39
  }
40
40
 
41
+ release(): void {
42
+ this.stopProcessing();
43
+ }
44
+
41
45
  async processTrack(track: MediaStreamTrack): Promise<MediaStreamTrack> {
42
46
  const context = getNewAudioContext();
43
47
 
@@ -41,11 +41,6 @@ import LivedigitalSDKError from '../../errors/LivedigitalSDKError';
41
41
  import { ClientObserverEvents } from '../../types/engine';
42
42
  import DataChannelsManager from './DataChannelsManager';
43
43
 
44
- interface IceIntervalTimeouts {
45
- send?: ReturnType<typeof setInterval>;
46
- recv?: ReturnType<typeof setInterval>;
47
- }
48
-
49
44
  const TRANSPORT_RESTART_ICE_INTERVAL = 5_000;
50
45
  const TRANSPORT_DETAILS_DELAY = 1500;
51
46
 
@@ -63,10 +58,7 @@ class Network {
63
58
 
64
59
  private preferRelay?: boolean;
65
60
 
66
- readonly #iceIntervalTimeouts: IceIntervalTimeouts = {
67
- send: undefined,
68
- recv: undefined,
69
- };
61
+ readonly #iceIntervalTimeouts = new Map<string, ReturnType<typeof setInterval>>();
70
62
 
71
63
  readonly #eventEmitter: EnhancedEventEmitter<NetworkObserverEvents>;
72
64
 
@@ -400,7 +392,7 @@ class Network {
400
392
  }
401
393
 
402
394
  this.signalingDataProducer = await transport.produceData({
403
- label: 'signaling-data-channel',
395
+ label: 'heart-beater',
404
396
  protocol: 'json',
405
397
  });
406
398
 
@@ -719,8 +711,7 @@ class Network {
719
711
  }
720
712
 
721
713
  private stopRestartIceAttempts(): void {
722
- clearInterval(this.#iceIntervalTimeouts.send);
723
- clearInterval(this.#iceIntervalTimeouts.recv);
714
+ Array.from(this.#iceIntervalTimeouts.values()).forEach((interval) => clearInterval(interval));
724
715
  }
725
716
 
726
717
  private subscribeCommonTransportEvents(transport: Transport): void {
@@ -818,10 +809,10 @@ class Network {
818
809
  direction: transport.direction,
819
810
  });
820
811
 
821
- if (this.#iceIntervalTimeouts[transport.direction]) {
812
+ if (this.#iceIntervalTimeouts.has(transport.id)) {
822
813
  this.#logger.debug('Stop receiveTransport.restartIce() retries', { recvTransportId: transport.id });
823
- clearInterval(this.#iceIntervalTimeouts[transport.direction]);
824
- this.#iceIntervalTimeouts[transport.direction] = undefined;
814
+ clearInterval(this.#iceIntervalTimeouts.get(transport.id));
815
+ this.#iceIntervalTimeouts.delete(transport.id);
825
816
 
826
817
  if (state === 'connected') {
827
818
  this.#eventEmitter.safeEmit(NETWORK_OBSERVER_EVENTS.transportState, {
@@ -850,29 +841,38 @@ class Network {
850
841
  });
851
842
 
852
843
  if (['disconnected', 'failed'].includes(state)) {
853
- if (this.#iceIntervalTimeouts[transport.direction]) {
844
+ if (this.#iceIntervalTimeouts.has(transport.id)) {
854
845
  return;
855
846
  }
856
847
 
857
848
  if (state === 'failed') {
858
- this.#logger.debug(`${ transport.direction }Transport.restartIce()`, { recvTransportId: transport.id });
849
+ this.#logger.debug(`${ transport.id } transport.restartIce()`, {
850
+ transportId: transport.id,
851
+ direction: transport.direction,
852
+ });
859
853
  this.restartIce(transport).catch((error: unknown) => {
860
854
  this.#logger.debug('Failed to execute restartIce', {
861
855
  error: serializeError(error),
856
+ transportId: transport.id,
857
+ direction: transport.direction,
862
858
  });
863
859
  });
864
860
  }
865
861
 
866
- this.#iceIntervalTimeouts[transport.direction] = setInterval(() => {
862
+ this.#iceIntervalTimeouts.set(transport.id, setInterval(() => {
867
863
  this.restartIce(transport).catch((error: unknown) => {
868
864
  this.#logger.debug('Failed to execute restartIce', {
869
865
  error: serializeError(error),
866
+ transportId: transport.id,
867
+ direction: transport.direction,
870
868
  });
871
869
  });
872
- this.#logger.debug(`${ transport.direction }Transport.restartIce() attempt`, {
870
+ this.#logger.debug(`${ transport.id } transport.restartIce() attempt`, {
873
871
  recvTransportId: transport.id,
872
+ transportId: transport.id,
873
+ direction: transport.direction,
874
874
  });
875
- }, TRANSPORT_RESTART_ICE_INTERVAL);
875
+ }, TRANSPORT_RESTART_ICE_INTERVAL));
876
876
  }
877
877
  });
878
878
 
@@ -1,7 +1,7 @@
1
1
  // eslint-disable-next-line
2
2
  const hexLUT: string[] = Array.from({ length: 256 }, (_, i) => (i + 256).toString(16).slice(1));
3
3
 
4
- const RANDOM_STR_LENGTH = 10;
4
+ const RANDOM_STR_LENGTH = 24;
5
5
 
6
6
  export function randomString(len: number = RANDOM_STR_LENGTH): string {
7
7
  const buf = new Uint8Array(len);
@@ -1,5 +1,11 @@
1
1
  import type { ChannelStateShortPeer } from '../proto/generated/channel/channel_state_short';
2
2
 
3
+ export interface LocalChannelStatePeerProducer {
4
+ id: string;
5
+ paused: boolean;
6
+ stateChangedAt: number;
7
+ }
8
+
3
9
  export interface LocalChannelStatePeerConsumer {
4
10
  id: string;
5
11
  paused: boolean;
@@ -7,6 +13,7 @@ export interface LocalChannelStatePeerConsumer {
7
13
  }
8
14
 
9
15
  export interface LocalChannelStatePeer extends ChannelStateShortPeer {
16
+ producers: LocalChannelStatePeerProducer[];
10
17
  consumers?: LocalChannelStatePeerConsumer[];
11
18
  };
12
19