@livedigital/client 3.48.0 → 3.49.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/encodings.d.ts +3 -3
- package/dist/constants/encodings.ts +3 -3
- package/dist/engine/handlers/ChannelAudioObserverEventHandler.d.ts +3 -1
- package/dist/engine/handlers/ChannelAudioObserverMissingProducerRestorer.d.ts +10 -0
- package/dist/engine/handlers/MediaEventHandler.d.ts +0 -1
- package/dist/engine/index.d.ts +7 -4
- package/dist/engine/network/DatachannelHeartbeater.d.ts +2 -2
- package/dist/engine/network/NetworkTransportPolicyManager.d.ts +22 -0
- package/dist/engine/network/index.d.ts +10 -8
- package/dist/index.d.ts +2 -0
- package/dist/index.es.js +2 -2
- package/dist/index.js +2 -2
- package/dist/inversify.tokens.d.ts +3 -1
- package/dist/types/network.d.ts +6 -6
- package/package.json +2 -3
- package/src/ClientMetaProvider.ts +0 -41
- package/src/EnhancedEventEmitter.ts +0 -75
- package/src/config/ConfigService.ts +0 -66
- package/src/constants/common.ts +0 -85
- package/src/constants/encodings.ts +0 -26
- package/src/constants/events.ts +0 -126
- package/src/constants/mutex.ts +0 -6
- package/src/constants/stats.ts +0 -1
- package/src/constants/videoConstrains.ts +0 -21
- package/src/engine/CallState.ts +0 -19
- package/src/engine/ChannelStateSynchronizer/ChannelStateSynchronizer.ts +0 -448
- package/src/engine/ChannelStateSynchronizer/types.ts +0 -22
- package/src/engine/EventsQueue.ts +0 -255
- package/src/engine/IntegrationsService.ts +0 -163
- package/src/engine/LocalMutex.ts +0 -45
- package/src/engine/Logger.ts +0 -234
- package/src/engine/MyPeer.ts +0 -25
- package/src/engine/Peer.ts +0 -602
- package/src/engine/PeerConsumer.ts +0 -276
- package/src/engine/PeerProducer.ts +0 -50
- package/src/engine/Peers.ts +0 -150
- package/src/engine/PeersStorage.ts +0 -45
- package/src/engine/RemotePeerTracks.ts +0 -73
- package/src/engine/WIDHandler.ts +0 -166
- package/src/engine/WebRTCStats/ConnectionStatsManager.ts +0 -31
- package/src/engine/WebRTCStats/InboundTrackStatsManager.ts +0 -51
- package/src/engine/WebRTCStats/OutboudTrackStatsManager.ts +0 -51
- package/src/engine/WebRTCStats/StatsHandler.ts +0 -80
- package/src/engine/WebRTCStats/TransportsStatsProvider.ts +0 -123
- package/src/engine/WebRTCStats/types.ts +0 -20
- package/src/engine/analyticsApiClient/LogApi.ts +0 -24
- package/src/engine/analyticsApiClient/MetricsApi.ts +0 -30
- package/src/engine/analyticsApiClient/helper.ts +0 -88
- package/src/engine/analyticsApiClient/index.ts +0 -42
- package/src/engine/analyticsApiClient/types.ts +0 -33
- package/src/engine/handlers/ChannelAudioObserverEventHandler.ts +0 -177
- package/src/engine/handlers/ChannelEventHandler.ts +0 -268
- package/src/engine/handlers/ChannelStateSyncEventHandler/ChannelStateConsistencyCheckResult.ts +0 -31
- package/src/engine/handlers/ChannelStateSyncEventHandler/ChannelStateConsistencyChecker.ts +0 -146
- package/src/engine/handlers/ChannelStateSyncEventHandler/consts.ts +0 -7
- package/src/engine/handlers/ChannelStateSyncEventHandler/index.ts +0 -342
- package/src/engine/handlers/ChannelStateSyncEventHandler/types.ts +0 -21
- package/src/engine/handlers/MediaEventHandler.ts +0 -273
- package/src/engine/index.ts +0 -793
- package/src/engine/media/index.ts +0 -574
- package/src/engine/media/producer/PendingClosureProducerStorage.ts +0 -37
- package/src/engine/media/producer/ProducerCloseManager.ts +0 -115
- package/src/engine/media/streamEffects/ProcessorsCache.ts +0 -41
- package/src/engine/media/streamEffects/audio/AudioTrackProcessor.ts +0 -7
- package/src/engine/media/streamEffects/audio/asdk/ASDKTrackProcessor.ts +0 -275
- package/src/engine/media/streamEffects/audio/asdk/atsrb.d.ts +0 -36
- package/src/engine/media/streamEffects/audio/asdk/errorBus.d.ts +0 -47
- package/src/engine/media/streamEffects/audio/noiseSuppression/NoiseSuppressionAudioWorkletNode.ts +0 -35
- package/src/engine/media/streamEffects/audio/noiseSuppression/NoiseSuppressionNodeProvider.ts +0 -44
- package/src/engine/media/streamEffects/audio/noiseSuppression/NoiseSuppressionScriptProcessorNode.ts +0 -69
- package/src/engine/media/streamEffects/audio/noiseSuppression/RNNoiseTrackProcessor.ts +0 -134
- package/src/engine/media/streamEffects/audio/noiseSuppression/WasmModuleCompiler.ts +0 -9
- package/src/engine/media/streamEffects/video/esdk/TrackProcessor.ts +0 -386
- package/src/engine/media/streamEffects/video/esdk/components/component.d.ts +0 -35
- package/src/engine/media/streamEffects/video/esdk/components/countdown/countdown.d.ts +0 -27
- package/src/engine/media/streamEffects/video/esdk/components/lower-third/collection/doubleSlideRect.d.ts +0 -33
- package/src/engine/media/streamEffects/video/esdk/components/lower-third/collection/horizontalMirror.d.ts +0 -29
- package/src/engine/media/streamEffects/video/esdk/components/lower-third/collection/leftTextbox.d.ts +0 -31
- package/src/engine/media/streamEffects/video/esdk/components/lower-third/collection/slideBold.d.ts +0 -41
- package/src/engine/media/streamEffects/video/esdk/components/lower-third/collection/twoSideRects/animatedBox.d.ts +0 -59
- package/src/engine/media/streamEffects/video/esdk/components/lower-third/collection/twoSideRects/twoSlideRects.d.ts +0 -27
- package/src/engine/media/streamEffects/video/esdk/components/lower-third/lowerThird.d.ts +0 -83
- package/src/engine/media/streamEffects/video/esdk/components/overlay-screen/overlayScreen.d.ts +0 -40
- package/src/engine/media/streamEffects/video/esdk/components/overlay-screen/overlaySprite.d.ts +0 -10
- package/src/engine/media/streamEffects/video/esdk/components/stickers/stickerSprite.d.ts +0 -51
- package/src/engine/media/streamEffects/video/esdk/components/stickers/stickers.d.ts +0 -54
- package/src/engine/media/streamEffects/video/esdk/components/utils/positionHelper.d.ts +0 -14
- package/src/engine/media/streamEffects/video/esdk/components/waterMark/waterMark.d.ts +0 -20
- package/src/engine/media/streamEffects/video/esdk/tsvb.d.ts +0 -187
- package/src/engine/media/streamEffects/video/esdk/utils/errorBus.d.ts +0 -42
- package/src/engine/media/tracks/DefaultAudioTrack.ts +0 -178
- package/src/engine/media/tracks/DefaultBaseTrack.ts +0 -592
- package/src/engine/media/tracks/DefaultVideoTrack.ts +0 -301
- package/src/engine/media/tracks/MediaStreamTrackManager.ts +0 -50
- package/src/engine/media/tracks/PeerTrack.ts +0 -558
- package/src/engine/network/DataChannelsManager.ts +0 -164
- package/src/engine/network/DatachannelHeartbeater.ts +0 -122
- package/src/engine/network/SignalingHeartbeater.ts +0 -55
- package/src/engine/network/index.ts +0 -961
- package/src/engine/signalingApiClient/SignalingApiClient.ts +0 -95
- package/src/engine/signalingApiClient/api.ts +0 -2289
- package/src/engine/system/index.ts +0 -221
- package/src/errors/AlreadyConnectedError.ts +0 -11
- package/src/errors/AlreadyCreatedError.ts +0 -11
- package/src/errors/ForbiddenError.ts +0 -11
- package/src/errors/InvalidPayloadError.ts +0 -11
- package/src/errors/InvalidRequestError.ts +0 -11
- package/src/errors/LivedigitalSDKError.ts +0 -15
- package/src/errors/NeedJoinFirstError.ts +0 -11
- package/src/errors/NotFoundError.ts +0 -11
- package/src/errors/OperationError.ts +0 -47
- package/src/errors/RequestError.ts +0 -11
- package/src/errors/TimeoutError.ts +0 -11
- package/src/errors/TooManyRequestsError.ts +0 -11
- package/src/errors/UnauthorizedError.ts +0 -11
- package/src/errors/UnsupportedError.ts +0 -15
- package/src/errors/signalingApiErrorMapper.ts +0 -143
- package/src/helpers/appDataValidator.ts +0 -21
- package/src/helpers/browser.ts +0 -37
- package/src/helpers/channelMessageConverter.ts +0 -124
- package/src/helpers/common.ts +0 -96
- package/src/helpers/datetime.ts +0 -11
- package/src/helpers/errors.ts +0 -25
- package/src/helpers/filterStatsCodecs.ts +0 -3
- package/src/helpers/loader.ts +0 -59
- package/src/helpers/media.ts +0 -57
- package/src/helpers/peer.ts +0 -19
- package/src/helpers/randomString.ts +0 -18
- package/src/helpers/retry.ts +0 -74
- package/src/index.ts +0 -171
- package/src/inversify.config.ts +0 -333
- package/src/inversify.factories.ts +0 -191
- package/src/inversify.tokens.ts +0 -42
- package/src/proto/.gitkeep +0 -0
- package/src/proto/generated/channel/channel_activity_confirmation_time.ts +0 -110
- package/src/proto/generated/channel/channel_management_event.ts +0 -213
- package/src/proto/generated/channel/channel_produce_permissions.ts +0 -171
- package/src/proto/generated/channel/channel_state.ts +0 -94
- package/src/proto/generated/channel/channel_state_short.ts +0 -282
- package/src/proto/generated/channel_message/channel_event.ts +0 -401
- package/src/proto/generated/channel_message/channel_message.ts +0 -139
- package/src/proto/generated/channel_message/media_event.ts +0 -290
- package/src/proto/generated/consumer/consumer.ts +0 -167
- package/src/proto/generated/google/protobuf/struct.ts +0 -588
- package/src/proto/generated/google/protobuf/timestamp.ts +0 -229
- package/src/proto/generated/peer/peer.ts +0 -430
- package/src/proto/generated/peer/peer_group.ts +0 -48
- package/src/proto/generated/peer/peer_role.ts +0 -48
- package/src/proto/generated/producer/producer.ts +0 -204
- package/src/proto/generated/producer/producer_kind.ts +0 -48
- package/src/proto/generated/producer/producer_label.ts +0 -78
- package/src/proto/generated/producer/producer_spatial_layer_request.ts +0 -116
- package/src/proto/generated/transport/transport_connection_timeout.ts +0 -156
- package/src/proto/generated/transport/transport_connection_timeout_reason.ts +0 -48
- package/src/proto/generated/transport/transport_direction.ts +0 -48
- package/src/types/channelAudioObserver.ts +0 -34
- package/src/types/channelStateSyncronizer.ts +0 -22
- package/src/types/client.ts +0 -27
- package/src/types/common.ts +0 -399
- package/src/types/container.ts +0 -31
- package/src/types/engine.ts +0 -97
- package/src/types/media.ts +0 -146
- package/src/types/mediasoup.ts +0 -10
- package/src/types/network.ts +0 -10
- package/src/types/streamEffects.ts +0 -23
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
import { inject, injectable } from 'inversify';
|
|
2
|
-
import { DataConsumer } from 'mediasoup-client/lib/DataConsumer';
|
|
3
|
-
import { serializeError } from 'serialize-error';
|
|
4
|
-
import { Logger } from '../types/common';
|
|
5
|
-
import { TOKEN } from '../inversify.tokens';
|
|
6
|
-
import { ChannelMessage } from '../proto/generated/channel_message/channel_message';
|
|
7
|
-
import { ChannelEvent, channelEventTypeToJSON } from '../proto/generated/channel_message/channel_event';
|
|
8
|
-
import { MediaEvent, mediaEventTypeToJSON } from '../proto/generated/channel_message/media_event';
|
|
9
|
-
|
|
10
|
-
interface PendingMessage {
|
|
11
|
-
total: number;
|
|
12
|
-
received: Uint8Array[];
|
|
13
|
-
msgId: number;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const CHUNK_HEADER_SIZE = 12;
|
|
17
|
-
const CHUNK_HEADER_MSG_ID_OFFSET = 0;
|
|
18
|
-
const CHUNK_HEADER_INDEX_OFFSET = 4;
|
|
19
|
-
const CHUNK_HEADER_TOTAL_OFFSET = 8;
|
|
20
|
-
|
|
21
|
-
@injectable()
|
|
22
|
-
export default class EventsQueue {
|
|
23
|
-
readonly #queue: ChannelMessage[] = [];
|
|
24
|
-
|
|
25
|
-
#paused = false;
|
|
26
|
-
|
|
27
|
-
#processing = false;
|
|
28
|
-
|
|
29
|
-
#mediaEventHandler?: (event: MediaEvent) => void | Promise<void>;
|
|
30
|
-
|
|
31
|
-
#channelEventHandler?: (event: ChannelEvent) => void | Promise<void>;
|
|
32
|
-
|
|
33
|
-
readonly #pendingMessagesBuffer = new Map<number, PendingMessage>();
|
|
34
|
-
readonly #logger: Logger;
|
|
35
|
-
|
|
36
|
-
#processedMessageIds: Set<number> = new Set<number>();
|
|
37
|
-
|
|
38
|
-
constructor(@inject(TOKEN.LoggerFactory) loggerFactory: (namespace: string) => Logger) {
|
|
39
|
-
this.#logger = loggerFactory('EventsQueue');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
setMediaEventHandler(handler: (event: MediaEvent) => void | Promise<void>): void {
|
|
43
|
-
this.#mediaEventHandler = handler;
|
|
44
|
-
this.#logger.info('Media event handler set', {
|
|
45
|
-
case: 'EventsQueue',
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
setChannelEventHandler(handler: (event: ChannelEvent) => void | Promise<void>): void {
|
|
50
|
-
this.#channelEventHandler = handler;
|
|
51
|
-
this.#logger.info('Channel event handler set', {
|
|
52
|
-
case: 'EventsQueue',
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
subscribe(dataChannel: DataConsumer): void {
|
|
57
|
-
this.#processedMessageIds = new Set<number>();
|
|
58
|
-
let lastReceivedMsgId = 0;
|
|
59
|
-
|
|
60
|
-
const onMessage = (raw: ArrayBuffer): void => {
|
|
61
|
-
try {
|
|
62
|
-
const pendingMessage = this.processMessageChunk(raw);
|
|
63
|
-
|
|
64
|
-
if (!pendingMessage || !this.isPendingMessageFullyReceived(pendingMessage)) {
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const fullBytes = this.finalizeMessageBytes(pendingMessage);
|
|
69
|
-
const message = ChannelMessage.decode(fullBytes);
|
|
70
|
-
|
|
71
|
-
if (message.id) {
|
|
72
|
-
if (this.#processedMessageIds.has(message.id)) {
|
|
73
|
-
this.#logger.warn('Received duplicate message', {
|
|
74
|
-
case: 'EventsQueue',
|
|
75
|
-
lastReceivedMsgId,
|
|
76
|
-
currentReceivedMsgId: message.id,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (message.id > lastReceivedMsgId + 1) {
|
|
81
|
-
this.#logger.warn('Received out of order message', {
|
|
82
|
-
case: 'EventsQueue',
|
|
83
|
-
lastReceivedMsgId,
|
|
84
|
-
currentReceivedMsgId: message.id,
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
this.#processedMessageIds.add(message.id);
|
|
90
|
-
lastReceivedMsgId = message.id;
|
|
91
|
-
this.push(message);
|
|
92
|
-
} catch (e) {
|
|
93
|
-
this.#logger.error('Failed to parse channel message', {
|
|
94
|
-
error: serializeError(e),
|
|
95
|
-
case: 'EventsQueue',
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const onClose = (): void => {
|
|
101
|
-
dataChannel.removeListener('message', onMessage);
|
|
102
|
-
dataChannel.removeListener('close', onClose);
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
dataChannel.on('close', onClose);
|
|
106
|
-
dataChannel.on('message', onMessage);
|
|
107
|
-
|
|
108
|
-
this.#logger.info('Subscribed to data channel', {
|
|
109
|
-
case: 'EventsQueue',
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
private push(message: ChannelMessage): void {
|
|
114
|
-
this.#queue.push(message);
|
|
115
|
-
void this.process();
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
private async process(): Promise<void> {
|
|
119
|
-
if (this.#paused || this.#processing) {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
this.#processing = true;
|
|
124
|
-
|
|
125
|
-
while (!this.#paused && this.#queue.length > 0) {
|
|
126
|
-
const message = this.#queue.shift();
|
|
127
|
-
|
|
128
|
-
if (!message) {
|
|
129
|
-
continue;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
if (message.channelEvent && this.#channelEventHandler) {
|
|
134
|
-
this.#logger.debug('Handle channel event', {
|
|
135
|
-
case: 'EventsQueue',
|
|
136
|
-
id: message.id,
|
|
137
|
-
type: channelEventTypeToJSON(message.channelEvent.eventType),
|
|
138
|
-
event: message.channelEvent,
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
await this.#channelEventHandler(message.channelEvent);
|
|
142
|
-
continue;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (message.mediaEvent && this.#mediaEventHandler) {
|
|
146
|
-
this.#logger.debug('Handle media event', {
|
|
147
|
-
case: 'EventsQueue',
|
|
148
|
-
id: message.id,
|
|
149
|
-
type: mediaEventTypeToJSON(message.mediaEvent.eventType),
|
|
150
|
-
event: message.mediaEvent,
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
await this.#mediaEventHandler(message.mediaEvent);
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
this.#logger.warn('Received unknown message', { message, case: 'EventsQueue' });
|
|
158
|
-
} catch (error) {
|
|
159
|
-
this.#logger.error('Failed to handle event', {
|
|
160
|
-
case: 'EventsQueue',
|
|
161
|
-
id: message.id,
|
|
162
|
-
error: serializeError(error),
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
this.#processing = false;
|
|
168
|
-
|
|
169
|
-
// If new events were pushed during processing, process again
|
|
170
|
-
if (!this.#paused && this.#queue.length > 0) {
|
|
171
|
-
queueMicrotask(() => void this.process());
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
private processMessageChunk(data: ArrayBuffer): PendingMessage | undefined {
|
|
176
|
-
const bytes = new Uint8Array(data);
|
|
177
|
-
|
|
178
|
-
if (bytes.length < CHUNK_HEADER_SIZE) {
|
|
179
|
-
this.#logger.warn('Chunk too small', {
|
|
180
|
-
case: 'EventsQueue',
|
|
181
|
-
bytesLength: bytes.length,
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const { msgId, index, total } = this.parseMessageChunkHeader(bytes);
|
|
188
|
-
const dataPart = bytes.slice(CHUNK_HEADER_SIZE);
|
|
189
|
-
|
|
190
|
-
if (!this.#pendingMessagesBuffer.has(msgId)) {
|
|
191
|
-
this.#pendingMessagesBuffer.set(msgId, { msgId, total, received: [] });
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const entry: PendingMessage | undefined = this.#pendingMessagesBuffer.get(msgId);
|
|
195
|
-
|
|
196
|
-
if (!entry) {
|
|
197
|
-
this.#logger.warn('Chunk buffer entry not found for msgId', {
|
|
198
|
-
msgId,
|
|
199
|
-
case: 'EventsQueue',
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
entry.received[index] = dataPart;
|
|
206
|
-
entry.msgId = msgId;
|
|
207
|
-
|
|
208
|
-
return entry;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
private parseMessageChunkHeader(bytes: Uint8Array): { msgId: number; index: number; total: number } {
|
|
212
|
-
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
213
|
-
|
|
214
|
-
return {
|
|
215
|
-
msgId: view.getUint32(CHUNK_HEADER_MSG_ID_OFFSET),
|
|
216
|
-
index: view.getUint32(CHUNK_HEADER_INDEX_OFFSET),
|
|
217
|
-
total: view.getUint32(CHUNK_HEADER_TOTAL_OFFSET),
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
private isPendingMessageFullyReceived(pendingMessage: PendingMessage): boolean {
|
|
222
|
-
return pendingMessage.received.filter(Boolean).length === pendingMessage.total;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
private finalizeMessageBytes(entry: PendingMessage): Uint8Array {
|
|
226
|
-
const fullBytes = new Uint8Array(entry.received.reduce((sum, arr) => sum + arr.length, 0));
|
|
227
|
-
let offset = 0;
|
|
228
|
-
|
|
229
|
-
for (const chunk of entry.received) {
|
|
230
|
-
fullBytes.set(chunk, offset);
|
|
231
|
-
offset += chunk.length;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
this.#pendingMessagesBuffer.delete(entry.msgId);
|
|
235
|
-
|
|
236
|
-
return fullBytes;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
pause(): void {
|
|
240
|
-
this.#paused = true;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
size(): number {
|
|
244
|
-
return this.#queue.length;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
resume(): void {
|
|
248
|
-
this.#paused = false;
|
|
249
|
-
void this.process();
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
isMessageReceived(messageId: number): boolean {
|
|
253
|
-
return this.#processedMessageIds.has(messageId);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import { inject, injectable } from 'inversify';
|
|
2
|
-
import { URL } from 'url';
|
|
3
|
-
import ConfigService from '../config/ConfigService';
|
|
4
|
-
import { loadScriptWithFallback } from '../helpers/loader';
|
|
5
|
-
import { TOKEN } from '../inversify.tokens';
|
|
6
|
-
import { TrackLabel } from '../types/common';
|
|
7
|
-
import type { AudioTrackProcessorFactory, LoggerFactory } from '../types/container';
|
|
8
|
-
import Logger from './Logger';
|
|
9
|
-
import { ASDKTrackProcessor } from './media/streamEffects/audio/asdk/ASDKTrackProcessor';
|
|
10
|
-
import { compileWASMModule } from './media/streamEffects/audio/noiseSuppression/WasmModuleCompiler';
|
|
11
|
-
import { ProcessorsCache } from './media/streamEffects/ProcessorsCache';
|
|
12
|
-
|
|
13
|
-
export type Integrations = 'asdk' | 'rnnoise'; // later 'esdk' should be added
|
|
14
|
-
export interface IntegrationContext {
|
|
15
|
-
integrated: boolean;
|
|
16
|
-
initPromise: Promise<void>;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface Integration {
|
|
20
|
-
type: Integrations;
|
|
21
|
-
enabled: boolean; // flag to show that integration is requested/enabled through ClientParams
|
|
22
|
-
isInitialized: boolean;
|
|
23
|
-
waitForInitialization: Promise<void>;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
@injectable()
|
|
27
|
-
export class IntegrationsService {
|
|
28
|
-
readonly #integrationsStorage = new Map<Integrations, IntegrationContext>();
|
|
29
|
-
|
|
30
|
-
readonly #logger: Logger;
|
|
31
|
-
|
|
32
|
-
constructor(
|
|
33
|
-
@inject(TOKEN.Config) private readonly config: ConfigService,
|
|
34
|
-
@inject(TOKEN.ProcessorsCache) private readonly processorsCache: ProcessorsCache,
|
|
35
|
-
@inject(TOKEN.AudioTrackProcessorFactory) private readonly audioTrackProcessorFactory: AudioTrackProcessorFactory,
|
|
36
|
-
@inject(TOKEN.LoggerFactory) loggerFactory: LoggerFactory,
|
|
37
|
-
) {
|
|
38
|
-
this.#logger = loggerFactory('IntegrationsService');
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
init(): void { // must not be async
|
|
42
|
-
const denoiser = this.config.get('denoiser');
|
|
43
|
-
|
|
44
|
-
if (denoiser === 'asdk') {
|
|
45
|
-
this.#logger.info('Start integration of ASDK', {
|
|
46
|
-
denoiser,
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
const context: IntegrationContext = {
|
|
50
|
-
integrated: false,
|
|
51
|
-
initPromise: this.integrateASDK(),
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
this.#integrationsStorage.set('asdk', context);
|
|
55
|
-
} else {
|
|
56
|
-
this.#logger.info('Start integration of RNNoise', {
|
|
57
|
-
denoiser,
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
const context: IntegrationContext = {
|
|
61
|
-
integrated: false,
|
|
62
|
-
initPromise: this.integrateRNNoise(),
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
this.#integrationsStorage.set('rnnoise', context);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
private async integrateASDK(): Promise<void> {
|
|
70
|
-
const asdkParams = this.config.get('asdk');
|
|
71
|
-
const staticFilesPath = this.config.get('staticFilesPath');
|
|
72
|
-
|
|
73
|
-
if (!window.atsvb) {
|
|
74
|
-
const remoteUrl = `https://effectssdk.ai/sdk/audio/dev/${ asdkParams.version }/atsvb-web.js`;
|
|
75
|
-
let localUrl = remoteUrl;
|
|
76
|
-
|
|
77
|
-
if (asdkParams.localDir) {
|
|
78
|
-
const localPath = `${ asdkParams.localDir }/${ asdkParams.version }/atsvb-web.js`;
|
|
79
|
-
const url = new URL(localPath, staticFilesPath);
|
|
80
|
-
localUrl = url.href;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
await loadScriptWithFallback(localUrl, remoteUrl);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (!window.atsvb) {
|
|
87
|
-
this.#logger.info('Audio Effects SDK is not loaded, skipping initialization', { case: 'initAudioSDK' });
|
|
88
|
-
|
|
89
|
-
throw new Error('windows.atsvb is still missing');
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const processor = this.audioTrackProcessorFactory({
|
|
93
|
-
trackLabel: TrackLabel.Microphone,
|
|
94
|
-
}) as ASDKTrackProcessor;
|
|
95
|
-
|
|
96
|
-
await processor.init();
|
|
97
|
-
|
|
98
|
-
this.processorsCache.add('asdk', TrackLabel.Microphone, processor);
|
|
99
|
-
|
|
100
|
-
const context = this.#integrationsStorage.get('asdk');
|
|
101
|
-
|
|
102
|
-
if (!context) {
|
|
103
|
-
throw Error('IntegrationContext is missing for ASDK');
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
context.integrated = true;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
get audio(): Integration {
|
|
110
|
-
const denoiser = this.config.get('denoiser');
|
|
111
|
-
|
|
112
|
-
if (denoiser === 'asdk') {
|
|
113
|
-
return this.getASDKState();
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return this.getRNNoiseState();
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
private getASDKState(): Integration {
|
|
120
|
-
const asdk = this.#integrationsStorage.get('asdk');
|
|
121
|
-
|
|
122
|
-
return {
|
|
123
|
-
type: 'asdk',
|
|
124
|
-
enabled: Boolean(asdk),
|
|
125
|
-
isInitialized: asdk?.integrated ?? false,
|
|
126
|
-
waitForInitialization: asdk?.initPromise ?? Promise.resolve(),
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
private getRNNoiseState(): Integration {
|
|
131
|
-
const rnnoise = this.#integrationsStorage.get('rnnoise');
|
|
132
|
-
|
|
133
|
-
return {
|
|
134
|
-
type: 'rnnoise',
|
|
135
|
-
enabled: Boolean(rnnoise),
|
|
136
|
-
isInitialized: rnnoise?.integrated ?? false,
|
|
137
|
-
waitForInitialization: rnnoise?.initPromise ?? Promise.resolve(),
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
private async integrateRNNoise(): Promise<void> {
|
|
142
|
-
const noiseSuppressor = await compileWASMModule(this.config.get('staticFilesPath'));
|
|
143
|
-
|
|
144
|
-
const processor = this.audioTrackProcessorFactory({
|
|
145
|
-
trackLabel: TrackLabel.Microphone,
|
|
146
|
-
noiseSuppressor,
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
this.processorsCache.add('rnnoise', TrackLabel.Microphone, processor);
|
|
150
|
-
|
|
151
|
-
const context = this.#integrationsStorage.get('rnnoise');
|
|
152
|
-
|
|
153
|
-
if (!context) {
|
|
154
|
-
throw Error('IntegrationContext is missing for RNNoise');
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
context.integrated = true;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
reset(): void {
|
|
161
|
-
this.#integrationsStorage.clear();
|
|
162
|
-
}
|
|
163
|
-
}
|
package/src/engine/LocalMutex.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Mutex } from 'async-mutex';
|
|
2
|
-
import { injectable } from 'inversify';
|
|
3
|
-
import { MutexKey } from '../constants/mutex';
|
|
4
|
-
|
|
5
|
-
@injectable()
|
|
6
|
-
export default class LocalMutex {
|
|
7
|
-
readonly #mutexMap = new Map<MutexKey, Mutex>();
|
|
8
|
-
|
|
9
|
-
async lock(key: MutexKey): Promise<() => void> {
|
|
10
|
-
let mutex = this.#mutexMap.get(key);
|
|
11
|
-
|
|
12
|
-
if (!mutex) {
|
|
13
|
-
mutex = new Mutex();
|
|
14
|
-
this.#mutexMap.set(key, mutex);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (mutex.isLocked()) {
|
|
18
|
-
await mutex.waitForUnlock();
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return await mutex.acquire();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
isLocked(key: MutexKey): boolean {
|
|
25
|
-
const mutex = this.#mutexMap.get(key);
|
|
26
|
-
|
|
27
|
-
if (mutex) {
|
|
28
|
-
return mutex.isLocked();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async waitForUnlock(key: MutexKey): Promise<void> {
|
|
35
|
-
const mutex = this.#mutexMap.get(key);
|
|
36
|
-
|
|
37
|
-
if (mutex?.isLocked()) {
|
|
38
|
-
await mutex.waitForUnlock();
|
|
39
|
-
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
await Promise.resolve();
|
|
44
|
-
}
|
|
45
|
-
}
|
package/src/engine/Logger.ts
DELETED
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
import debug from 'debug';
|
|
2
|
-
import { MessageBatcher } from 'message-batcher';
|
|
3
|
-
import { serializeError } from 'serialize-error';
|
|
4
|
-
import clientMetaProvider from '../ClientMetaProvider';
|
|
5
|
-
import { HALF_SECOND_IN_MS, LogLevels, SECOND_IN_MS } from '../constants/common';
|
|
6
|
-
import { isObject } from '../helpers/common';
|
|
7
|
-
import type { LogLevel, LogLevelStr, LogMessageHandler } from '../types/common';
|
|
8
|
-
import AnalyticsApiClient from './analyticsApiClient';
|
|
9
|
-
import { getClientUniqueId } from './analyticsApiClient/helper';
|
|
10
|
-
|
|
11
|
-
const APP_NAME = 'LiveDigital';
|
|
12
|
-
const BATCH_SIZE = 50;
|
|
13
|
-
|
|
14
|
-
export interface RecordMeta {
|
|
15
|
-
error?: unknown;
|
|
16
|
-
clientTimestamp: string;
|
|
17
|
-
from_sdk: boolean;
|
|
18
|
-
case?: string;
|
|
19
|
-
channelId?: string;
|
|
20
|
-
applicationId?: string;
|
|
21
|
-
peerId?: string;
|
|
22
|
-
[key: string]: unknown;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface ClientMeta {
|
|
26
|
-
clUId: string;
|
|
27
|
-
peerId?: string;
|
|
28
|
-
channelId?: string;
|
|
29
|
-
appId?: string;
|
|
30
|
-
[key: string]: unknown;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface LoggerParams {
|
|
34
|
-
logLevel: LogLevel;
|
|
35
|
-
onLogMessage?: LogMessageHandler;
|
|
36
|
-
sendAnalytics: boolean;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface LoggerConstructorParams {
|
|
40
|
-
namespace: string;
|
|
41
|
-
logLevel: LogLevel;
|
|
42
|
-
onLogMessage?: LogMessageHandler;
|
|
43
|
-
sendAnalytics: boolean;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export type LogRecordMeta = Record<string, unknown> & {
|
|
47
|
-
error?: unknown;
|
|
48
|
-
case?: string;
|
|
49
|
-
channelId?: string;
|
|
50
|
-
applicationId?: string;
|
|
51
|
-
peerId?: string;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export interface LogToRemotePayload {
|
|
55
|
-
level: LogLevel;
|
|
56
|
-
message: string;
|
|
57
|
-
meta?: LogRecordMeta;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
class Logger {
|
|
61
|
-
private readonly _debug: debug.Debugger;
|
|
62
|
-
|
|
63
|
-
private readonly _info: debug.Debugger;
|
|
64
|
-
|
|
65
|
-
private readonly _warn: debug.Debugger;
|
|
66
|
-
|
|
67
|
-
private readonly _error: debug.Debugger;
|
|
68
|
-
|
|
69
|
-
readonly #namespace: string;
|
|
70
|
-
|
|
71
|
-
readonly #logLevel: LogLevel;
|
|
72
|
-
|
|
73
|
-
readonly onLogMessage?: LogMessageHandler;
|
|
74
|
-
|
|
75
|
-
readonly #logToRemoteBatcher: MessageBatcher;
|
|
76
|
-
|
|
77
|
-
readonly #analyticsApi: AnalyticsApiClient;
|
|
78
|
-
|
|
79
|
-
readonly #sendAnalytics: boolean;
|
|
80
|
-
|
|
81
|
-
constructor(params: LoggerConstructorParams) {
|
|
82
|
-
const { logLevel, namespace, onLogMessage } = params;
|
|
83
|
-
this.#namespace = namespace;
|
|
84
|
-
this.#logLevel = logLevel;
|
|
85
|
-
this.onLogMessage = onLogMessage;
|
|
86
|
-
this.#analyticsApi = new AnalyticsApiClient();
|
|
87
|
-
this.#logToRemoteBatcher = new MessageBatcher({
|
|
88
|
-
MaxBatchSize: BATCH_SIZE,
|
|
89
|
-
MaxDelay: SECOND_IN_MS,
|
|
90
|
-
MinDelay: HALF_SECOND_IN_MS,
|
|
91
|
-
});
|
|
92
|
-
this.#sendAnalytics = params.sendAnalytics;
|
|
93
|
-
|
|
94
|
-
this.#logToRemoteBatcher.on('batch', (logs: LogToRemotePayload[]) => {
|
|
95
|
-
this.logToApi(logs).catch((error: unknown) => {
|
|
96
|
-
this.error('Failed to log to api', {
|
|
97
|
-
case: 'Logger',
|
|
98
|
-
error: serializeError(error),
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
this._debug = debug(APP_NAME).extend('debug').extend(this.#namespace);
|
|
104
|
-
this._info = debug(APP_NAME).extend('info').extend(this.#namespace);
|
|
105
|
-
this._warn = debug(APP_NAME).extend('warn').extend(this.#namespace);
|
|
106
|
-
this._error = debug(APP_NAME).extend('error').extend(this.#namespace);
|
|
107
|
-
|
|
108
|
-
// eslint-disable-next-line no-console
|
|
109
|
-
this._debug.log = console.info.bind(console);
|
|
110
|
-
// eslint-disable-next-line no-console
|
|
111
|
-
this._info.log = console.info.bind(console);
|
|
112
|
-
this._warn.log = console.warn.bind(console);
|
|
113
|
-
this._error.log = console.error.bind(console);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
debug(message: string, meta: Record<string, unknown>): void {
|
|
117
|
-
this._debug(message, meta);
|
|
118
|
-
|
|
119
|
-
if (this.#sendAnalytics) {
|
|
120
|
-
this.#logToRemoteBatcher.Queue({ level: 'debug', message, meta });
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (this.#logLevel >= LogLevels.Debug) {
|
|
124
|
-
this.#log('debug', message, meta);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
info(message: string, meta: Record<string, unknown>): void {
|
|
129
|
-
this._info(message, meta);
|
|
130
|
-
|
|
131
|
-
if (this.#sendAnalytics) {
|
|
132
|
-
this.#logToRemoteBatcher.Queue({ level: 'info', message, meta });
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (this.#logLevel >= LogLevels.Info) {
|
|
136
|
-
this.#log('info', message, meta);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
warn(message: string, meta: Record<string, unknown>): void {
|
|
141
|
-
this._warn(message, meta);
|
|
142
|
-
|
|
143
|
-
if (this.#sendAnalytics) {
|
|
144
|
-
this.#logToRemoteBatcher.Queue({ level: 'warn', message, meta });
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (this.#logLevel >= LogLevels.Warn) {
|
|
148
|
-
this.#log('warn', message, meta);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
error(message: string, meta: Record<string, unknown>): void {
|
|
153
|
-
this._error(message, meta);
|
|
154
|
-
|
|
155
|
-
if (this.#sendAnalytics) {
|
|
156
|
-
this.#logToRemoteBatcher.Queue({ level: 'error', message, meta });
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (this.#logLevel >= LogLevels.Error) {
|
|
160
|
-
this.#log('error', message, meta);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
#log(level: LogLevelStr, message: string, ...args: readonly unknown[]): void {
|
|
165
|
-
if (typeof this.onLogMessage === 'function') {
|
|
166
|
-
this.onLogMessage(message, ...this.#decirculate(args), level);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
#decirculate<Input>(object: Input): Input {
|
|
171
|
-
const seenObjects = new WeakMap<Record<string, unknown>, readonly string[]>();
|
|
172
|
-
|
|
173
|
-
function internalDecirculate<T>(value: T, path: readonly string[] = []): T {
|
|
174
|
-
if (!isObject(value)) {
|
|
175
|
-
return value;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const existingPath = seenObjects.get(value);
|
|
179
|
-
|
|
180
|
-
if (existingPath) {
|
|
181
|
-
return `[Circular *${ existingPath.join('.') }]` as unknown as T;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
seenObjects.set(value, path);
|
|
185
|
-
|
|
186
|
-
const newValue = (Array.isArray(value) ? [] : {}) as T;
|
|
187
|
-
|
|
188
|
-
Object.entries(value).forEach(([key, propValue]) => {
|
|
189
|
-
newValue[key as keyof T] = internalDecirculate(propValue, [...path, key]) as T[keyof T];
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
seenObjects.delete(value);
|
|
193
|
-
|
|
194
|
-
return newValue;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return internalDecirculate(object);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
private async logToApi(logs: LogToRemotePayload[]): Promise<void> {
|
|
201
|
-
try {
|
|
202
|
-
await this.#analyticsApi.log.batch({
|
|
203
|
-
logs: logs.map((log) => this.#decirculate({
|
|
204
|
-
...log,
|
|
205
|
-
meta: this.prepareRecordMeta(log.meta),
|
|
206
|
-
})),
|
|
207
|
-
clientMeta: this.getClientMeta(),
|
|
208
|
-
});
|
|
209
|
-
} catch (error) {
|
|
210
|
-
this._debug('Log request was not successful', { error });
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
private getClientMeta(): ClientMeta {
|
|
215
|
-
return {
|
|
216
|
-
...clientMetaProvider.meta,
|
|
217
|
-
clUId: getClientUniqueId(),
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
private prepareRecordMeta(metaData?: LogRecordMeta): RecordMeta {
|
|
222
|
-
const meta = metaData ?? {};
|
|
223
|
-
const { error } = meta;
|
|
224
|
-
|
|
225
|
-
return {
|
|
226
|
-
...meta,
|
|
227
|
-
clientTimestamp: new Date().toISOString(),
|
|
228
|
-
from_sdk: true,
|
|
229
|
-
...(error && typeof error === 'object' ? { error: serializeError(error) } : {}),
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
export default Logger;
|