@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.
- package/dist/constants/common.d.ts +1 -1
- package/dist/constants/common.ts +1 -1
- package/dist/engine/PeerProducer.d.ts +3 -0
- package/dist/engine/handlers/ChannelStateSyncEventHandler/ChannelStateConsistencyChecker.d.ts +3 -1
- package/dist/engine/media/streamEffects/audio/AudioTrackProcessor.d.ts +1 -0
- package/dist/engine/media/streamEffects/audio/asdk/ASDKTrackProcessor.d.ts +1 -0
- package/dist/engine/media/streamEffects/audio/noiseSuppression/RNNoiseTrackProcessor.d.ts +1 -0
- package/dist/index.es.js +2 -2
- package/dist/index.js +2 -2
- package/dist/types/channelStateSyncronizer.d.ts +6 -0
- package/package.json +1 -1
- package/src/constants/common.ts +1 -1
- package/src/engine/ChannelStateSynchronizer/ChannelStateSynchronizer.ts +1 -1
- package/src/engine/PeerProducer.ts +12 -0
- package/src/engine/handlers/ChannelStateSyncEventHandler/ChannelStateConsistencyChecker.ts +31 -14
- package/src/engine/handlers/ChannelStateSyncEventHandler/index.ts +1 -0
- package/src/engine/handlers/MediaEventHandler.ts +2 -2
- package/src/engine/index.ts +4 -4
- package/src/engine/media/streamEffects/ProcessorsCache.ts +1 -0
- package/src/engine/media/streamEffects/audio/AudioTrackProcessor.ts +1 -0
- package/src/engine/media/streamEffects/audio/asdk/ASDKTrackProcessor.ts +5 -0
- package/src/engine/media/streamEffects/audio/noiseSuppression/RNNoiseTrackProcessor.ts +4 -0
- package/src/engine/network/index.ts +20 -20
- package/src/helpers/randomString.ts +1 -1
- 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
package/src/constants/common.ts
CHANGED
|
@@ -361,7 +361,7 @@ class ChannelStateSynchronizer {
|
|
|
361
361
|
const { paused } = clusterPeerProducer;
|
|
362
362
|
|
|
363
363
|
if (localProducer.paused !== paused) {
|
|
364
|
-
localProducer.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 {
|
|
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:
|
|
14
|
+
localState: LocalChannelState;
|
|
11
15
|
remoteState: ChannelStateShort;
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
class ChannelStateConsistencyChecker {
|
|
15
|
-
private readonly localState:
|
|
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 (
|
|
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):
|
|
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:
|
|
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;
|
|
@@ -131,7 +131,7 @@ class MediaEventHandler {
|
|
|
131
131
|
return;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
producer.
|
|
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.
|
|
155
|
+
producer.setPaused(false);
|
|
156
156
|
peer.observer.safeEmit(PEER_EVENTS.publisherResumed, {
|
|
157
157
|
producerId: producer.id,
|
|
158
158
|
kind: producer.kind,
|
package/src/engine/index.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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 =
|
|
892
|
-
const REQUIRED_SUCCESSFUL_CHECKS =
|
|
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 () => {
|
|
@@ -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
|
|
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: '
|
|
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
|
-
|
|
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
|
|
812
|
+
if (this.#iceIntervalTimeouts.has(transport.id)) {
|
|
822
813
|
this.#logger.debug('Stop receiveTransport.restartIce() retries', { recvTransportId: transport.id });
|
|
823
|
-
clearInterval(this.#iceIntervalTimeouts
|
|
824
|
-
this.#iceIntervalTimeouts
|
|
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
|
|
844
|
+
if (this.#iceIntervalTimeouts.has(transport.id)) {
|
|
854
845
|
return;
|
|
855
846
|
}
|
|
856
847
|
|
|
857
848
|
if (state === 'failed') {
|
|
858
|
-
this.#logger.debug(`${ transport.
|
|
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
|
|
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.
|
|
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 =
|
|
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
|
|