livekit-client 2.18.0 → 2.18.2
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/livekit-client.e2ee.worker.js +1 -1
- package/dist/livekit-client.e2ee.worker.js.map +1 -1
- package/dist/livekit-client.e2ee.worker.mjs +8 -7
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +8026 -5883
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/api/SignalClient.d.ts +12 -4
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/connectionHelper/ConnectionCheck.d.ts +1 -1
- package/dist/src/connectionHelper/ConnectionCheck.d.ts.map +1 -1
- package/dist/src/e2ee/constants.d.ts.map +1 -1
- package/dist/src/e2ee/types.d.ts +6 -0
- package/dist/src/e2ee/types.d.ts.map +1 -1
- package/dist/src/e2ee/utils.d.ts +2 -1
- package/dist/src/e2ee/utils.d.ts.map +1 -1
- package/dist/src/e2ee/worker/DataCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/index.d.ts +6 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +5 -0
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/PCTransportManager.d.ts +1 -1
- package/dist/src/room/PCTransportManager.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +28 -11
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +14 -3
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts +5 -1
- package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts.map +1 -1
- package/dist/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts.map +1 -1
- package/dist/src/room/data-track/LocalDataTrack.d.ts +28 -5
- package/dist/src/room/data-track/LocalDataTrack.d.ts.map +1 -1
- package/dist/src/room/data-track/RemoteDataTrack.d.ts +5 -5
- package/dist/src/room/data-track/RemoteDataTrack.d.ts.map +1 -1
- package/dist/src/room/data-track/depacketizer.d.ts +4 -4
- package/dist/src/room/data-track/depacketizer.d.ts.map +1 -1
- package/dist/src/room/data-track/frame.d.ts +14 -0
- package/dist/src/room/data-track/frame.d.ts.map +1 -1
- package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts +19 -11
- package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts.map +1 -1
- package/dist/src/room/data-track/incoming/pipeline.d.ts +6 -5
- package/dist/src/room/data-track/incoming/pipeline.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +57 -23
- package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/errors.d.ts +16 -6
- package/dist/src/room/data-track/outgoing/errors.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/pipeline.d.ts +7 -6
- package/dist/src/room/data-track/outgoing/pipeline.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/types.d.ts +14 -4
- package/dist/src/room/data-track/outgoing/types.d.ts.map +1 -1
- package/dist/src/room/data-track/packet/extensions.d.ts.map +1 -1
- package/dist/src/room/data-track/packetizer.d.ts +4 -4
- package/dist/src/room/data-track/packetizer.d.ts.map +1 -1
- package/dist/src/room/data-track/track-interfaces.d.ts +1 -1
- package/dist/src/room/data-track/track-interfaces.d.ts.map +1 -1
- package/dist/src/room/data-track/types.d.ts +6 -1
- package/dist/src/room/data-track/types.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +24 -3
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +12 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts +13 -0
- package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +1 -0
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/src/utils/deferrable-map.d.ts +32 -0
- package/dist/src/utils/deferrable-map.d.ts.map +1 -0
- package/dist/src/utils/serializer.d.ts +48 -0
- package/dist/src/utils/serializer.d.ts.map +1 -0
- package/dist/ts4.2/api/SignalClient.d.ts +12 -4
- package/dist/ts4.2/connectionHelper/ConnectionCheck.d.ts +2 -1
- package/dist/ts4.2/e2ee/types.d.ts +6 -0
- package/dist/ts4.2/e2ee/utils.d.ts +2 -1
- package/dist/ts4.2/index.d.ts +7 -4
- package/dist/ts4.2/room/PCTransport.d.ts +5 -0
- package/dist/ts4.2/room/PCTransportManager.d.ts +1 -1
- package/dist/ts4.2/room/RTCEngine.d.ts +28 -11
- package/dist/ts4.2/room/Room.d.ts +14 -3
- package/dist/ts4.2/room/data-stream/incoming/IncomingDataStreamManager.d.ts +5 -1
- package/dist/ts4.2/room/data-track/LocalDataTrack.d.ts +27 -4
- package/dist/ts4.2/room/data-track/RemoteDataTrack.d.ts +4 -4
- package/dist/ts4.2/room/data-track/depacketizer.d.ts +4 -4
- package/dist/ts4.2/room/data-track/frame.d.ts +14 -0
- package/dist/ts4.2/room/data-track/incoming/IncomingDataTrackManager.d.ts +21 -10
- package/dist/ts4.2/room/data-track/incoming/pipeline.d.ts +6 -5
- package/dist/ts4.2/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +57 -23
- package/dist/ts4.2/room/data-track/outgoing/errors.d.ts +16 -6
- package/dist/ts4.2/room/data-track/outgoing/pipeline.d.ts +7 -6
- package/dist/ts4.2/room/data-track/outgoing/types.d.ts +14 -4
- package/dist/ts4.2/room/data-track/packetizer.d.ts +4 -4
- package/dist/ts4.2/room/data-track/track-interfaces.d.ts +1 -1
- package/dist/ts4.2/room/data-track/types.d.ts +6 -1
- package/dist/ts4.2/room/events.d.ts +24 -3
- package/dist/ts4.2/room/participant/LocalParticipant.d.ts +12 -1
- package/dist/ts4.2/room/participant/RemoteParticipant.d.ts +13 -0
- package/dist/ts4.2/room/utils.d.ts +1 -0
- package/dist/ts4.2/utils/deferrable-map.d.ts +32 -0
- package/dist/ts4.2/utils/serializer.d.ts +48 -0
- package/package.json +1 -1
- package/src/api/SignalClient.test.ts +9 -4
- package/src/api/SignalClient.ts +116 -9
- package/src/connectionHelper/ConnectionCheck.ts +1 -1
- package/src/e2ee/constants.ts +1 -0
- package/src/e2ee/types.ts +6 -0
- package/src/e2ee/utils.ts +4 -3
- package/src/e2ee/worker/DataCryptor.ts +1 -4
- package/src/e2ee/worker/FrameCryptor.ts +1 -4
- package/src/e2ee/worker/ParticipantKeyHandler.ts +1 -1
- package/src/index.ts +13 -4
- package/src/room/PCTransport.ts +41 -1
- package/src/room/PCTransportManager.ts +1 -1
- package/src/room/RTCEngine.ts +312 -125
- package/src/room/Room.ts +168 -35
- package/src/room/data-stream/incoming/IncomingDataStreamManager.ts +26 -2
- package/src/room/data-stream/outgoing/OutgoingDataStreamManager.ts +7 -7
- package/src/room/data-track/LocalDataTrack.ts +83 -10
- package/src/room/data-track/RemoteDataTrack.ts +7 -9
- package/src/room/data-track/depacketizer.ts +21 -12
- package/src/room/data-track/frame.ts +28 -2
- package/src/room/data-track/incoming/IncomingDataTrackManager.test.ts +58 -73
- package/src/room/data-track/incoming/IncomingDataTrackManager.ts +139 -80
- package/src/room/data-track/incoming/pipeline.ts +29 -24
- package/src/room/data-track/outgoing/OutgoingDataTrackManager.test.ts +225 -32
- package/src/room/data-track/outgoing/OutgoingDataTrackManager.ts +150 -75
- package/src/room/data-track/outgoing/errors.ts +36 -7
- package/src/room/data-track/outgoing/pipeline.ts +23 -17
- package/src/room/data-track/outgoing/types.ts +12 -3
- package/src/room/data-track/packet/extensions.ts +17 -22
- package/src/room/data-track/packet/index.test.ts +22 -33
- package/src/room/data-track/packetizer.test.ts +2 -2
- package/src/room/data-track/packetizer.ts +4 -4
- package/src/room/data-track/track-interfaces.ts +1 -1
- package/src/room/data-track/types.ts +21 -1
- package/src/room/events.ts +26 -1
- package/src/room/participant/LocalParticipant.ts +74 -8
- package/src/room/participant/RemoteParticipant.ts +25 -0
- package/src/room/utils.ts +4 -0
- package/src/utils/deferrable-map.ts +109 -0
- package/src/utils/serializer.ts +72 -0
- package/dist/src/room/data-track/e2ee.d.ts +0 -12
- package/dist/src/room/data-track/e2ee.d.ts.map +0 -1
- package/dist/ts4.2/room/data-track/e2ee.d.ts +0 -12
- package/src/room/data-track/e2ee.ts +0 -15
package/src/room/RTCEngine.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
DataChannelReceiveState,
|
|
9
9
|
DataPacket,
|
|
10
10
|
DataPacket_Kind,
|
|
11
|
+
DataTrackSubscriberHandles,
|
|
11
12
|
DisconnectReason,
|
|
12
13
|
EncryptedPacket,
|
|
13
14
|
EncryptedPacketPayload,
|
|
@@ -17,6 +18,7 @@ import {
|
|
|
17
18
|
LeaveRequest_Action,
|
|
18
19
|
MediaSectionsRequirement,
|
|
19
20
|
ParticipantInfo,
|
|
21
|
+
PublishDataTrackResponse,
|
|
20
22
|
ReconnectReason,
|
|
21
23
|
type ReconnectResponse,
|
|
22
24
|
RequestResponse,
|
|
@@ -24,6 +26,8 @@ import {
|
|
|
24
26
|
RoomMovedResponse,
|
|
25
27
|
RpcAck,
|
|
26
28
|
RpcResponse,
|
|
29
|
+
ServerInfo,
|
|
30
|
+
SessionDescription,
|
|
27
31
|
SignalTarget,
|
|
28
32
|
SpeakerInfo,
|
|
29
33
|
type StreamStateUpdate,
|
|
@@ -35,6 +39,7 @@ import {
|
|
|
35
39
|
type TrackPublishedResponse,
|
|
36
40
|
TrackUnpublishedResponse,
|
|
37
41
|
Transcription,
|
|
42
|
+
UnpublishDataTrackResponse,
|
|
38
43
|
UpdateSubscription,
|
|
39
44
|
type UserPacket,
|
|
40
45
|
} from '@livekit/protocol';
|
|
@@ -58,6 +63,7 @@ import PCTransport, { PCEvents } from './PCTransport';
|
|
|
58
63
|
import { PCTransportManager, PCTransportState } from './PCTransportManager';
|
|
59
64
|
import type { ReconnectContext, ReconnectPolicy } from './ReconnectPolicy';
|
|
60
65
|
import { DEFAULT_MAX_AGE_MS, type RegionUrlProvider } from './RegionUrlProvider';
|
|
66
|
+
import { DataTrackInfo } from './data-track/types';
|
|
61
67
|
import { roomConnectOptionDefaults } from './defaults';
|
|
62
68
|
import {
|
|
63
69
|
ConnectionError,
|
|
@@ -80,6 +86,7 @@ import type { TrackPublishOptions, VideoCodec } from './track/options';
|
|
|
80
86
|
import { getTrackPublicationInfo } from './track/utils';
|
|
81
87
|
import type { LoggerOptions } from './types';
|
|
82
88
|
import {
|
|
89
|
+
isCompressionStreamSupported,
|
|
83
90
|
isVideoCodec,
|
|
84
91
|
isVideoTrack,
|
|
85
92
|
isWeb,
|
|
@@ -91,11 +98,14 @@ import {
|
|
|
91
98
|
|
|
92
99
|
const lossyDataChannel = '_lossy';
|
|
93
100
|
const reliableDataChannel = '_reliable';
|
|
101
|
+
const dataTrackDataChannel = '_data_track';
|
|
94
102
|
const minReconnectWait = 2 * 1000;
|
|
95
103
|
const leaveReconnect = 'leave-reconnect';
|
|
96
104
|
const reliabeReceiveStateTTL = 30_000;
|
|
97
105
|
const lossyDataChannelBufferThresholdMin = 8 * 1024;
|
|
98
106
|
const lossyDataChannelBufferThresholdMax = 256 * 1024;
|
|
107
|
+
const initialMediaSectionsAudio = 3;
|
|
108
|
+
const initialMediaSectionsVideo = 3;
|
|
99
109
|
|
|
100
110
|
enum PCState {
|
|
101
111
|
New,
|
|
@@ -105,6 +115,12 @@ enum PCState {
|
|
|
105
115
|
Closed,
|
|
106
116
|
}
|
|
107
117
|
|
|
118
|
+
export enum DataChannelKind {
|
|
119
|
+
RELIABLE = DataPacket_Kind.RELIABLE,
|
|
120
|
+
LOSSY = DataPacket_Kind.LOSSY,
|
|
121
|
+
DATA_TRACK_LOSSY,
|
|
122
|
+
}
|
|
123
|
+
|
|
108
124
|
/** @internal */
|
|
109
125
|
export default class RTCEngine extends (EventEmitter as new () => TypedEventEmitter<EngineEventCallbacks>) {
|
|
110
126
|
client: SignalClient;
|
|
@@ -149,11 +165,16 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
149
165
|
|
|
150
166
|
private reliableDC?: RTCDataChannel;
|
|
151
167
|
|
|
152
|
-
private dcBufferStatus: Map<DataPacket_Kind, boolean>;
|
|
153
|
-
|
|
154
168
|
// @ts-ignore noUnusedLocals
|
|
155
169
|
private reliableDCSub?: RTCDataChannel;
|
|
156
170
|
|
|
171
|
+
private dataTrackDC?: RTCDataChannel;
|
|
172
|
+
|
|
173
|
+
// @ts-ignore noUnusedLocals
|
|
174
|
+
private dataTrackDCSub?: RTCDataChannel;
|
|
175
|
+
|
|
176
|
+
private dcBufferStatus: Map<DataChannelKind, boolean>;
|
|
177
|
+
|
|
157
178
|
private subscriberPrimary: boolean = false;
|
|
158
179
|
|
|
159
180
|
private pcState: PCState = PCState.New;
|
|
@@ -239,8 +260,9 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
239
260
|
this.closingLock = new Mutex();
|
|
240
261
|
this.dataProcessLock = new Mutex();
|
|
241
262
|
this.dcBufferStatus = new Map([
|
|
242
|
-
[
|
|
243
|
-
[
|
|
263
|
+
[DataChannelKind.RELIABLE, true],
|
|
264
|
+
[DataChannelKind.LOSSY, true],
|
|
265
|
+
[DataChannelKind.DATA_TRACK_LOSSY, true],
|
|
244
266
|
]);
|
|
245
267
|
|
|
246
268
|
this.client.onParticipantUpdate = (updates) =>
|
|
@@ -255,6 +277,9 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
255
277
|
this.client.onStreamStateUpdate = (update) => this.emit(EngineEvent.StreamStateChanged, update);
|
|
256
278
|
this.client.onRequestResponse = (response) =>
|
|
257
279
|
this.emit(EngineEvent.SignalRequestResponse, response);
|
|
280
|
+
this.client.onParticipantUpdate = (updates) =>
|
|
281
|
+
this.emit(EngineEvent.ParticipantUpdate, updates);
|
|
282
|
+
this.client.onJoined = (joinResponse) => this.emit(EngineEvent.Joined, joinResponse);
|
|
258
283
|
}
|
|
259
284
|
|
|
260
285
|
/** @internal */
|
|
@@ -274,7 +299,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
274
299
|
abortSignal?: AbortSignal,
|
|
275
300
|
/** setting this to true results in dual peer connection mode being used */
|
|
276
301
|
useV0Path: boolean = false,
|
|
277
|
-
): Promise<JoinResponse> {
|
|
302
|
+
): Promise<{ joinResponse: JoinResponse; serverInfo: Partial<ServerInfo> }> {
|
|
278
303
|
this._isNewlyCreated = false;
|
|
279
304
|
this.url = url;
|
|
280
305
|
this.token = token;
|
|
@@ -284,26 +309,68 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
284
309
|
this.joinAttempts += 1;
|
|
285
310
|
|
|
286
311
|
this.setupSignalClientCallbacks();
|
|
287
|
-
|
|
312
|
+
let offerProto: SessionDescription | undefined;
|
|
313
|
+
if (!useV0Path && isCompressionStreamSupported()) {
|
|
314
|
+
if (!this.pcManager) {
|
|
315
|
+
await this.configure();
|
|
316
|
+
this.createDataChannels();
|
|
317
|
+
this.addMediaSections(initialMediaSectionsAudio, initialMediaSectionsVideo);
|
|
318
|
+
}
|
|
319
|
+
const offer = await this.pcManager?.publisher.createInitialOffer();
|
|
320
|
+
if (offer) {
|
|
321
|
+
offerProto = toProtoSessionDescription(offer.offer, offer.offerId);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (abortSignal?.aborted) {
|
|
325
|
+
throw ConnectionError.cancelled('Connection aborted');
|
|
326
|
+
}
|
|
327
|
+
const joinResponse = await this.client.join(
|
|
328
|
+
url,
|
|
329
|
+
token,
|
|
330
|
+
opts,
|
|
331
|
+
abortSignal,
|
|
332
|
+
useV0Path,
|
|
333
|
+
offerProto,
|
|
334
|
+
);
|
|
288
335
|
this._isClosed = false;
|
|
289
336
|
this.latestJoinResponse = joinResponse;
|
|
337
|
+
this.participantSid = joinResponse.participant?.sid;
|
|
290
338
|
|
|
291
339
|
this.subscriberPrimary = joinResponse.subscriberPrimary;
|
|
292
|
-
if (!
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
340
|
+
if (!useV0Path && isCompressionStreamSupported()) {
|
|
341
|
+
this.pcManager?.updateConfiguration(this.makeRTCConfiguration(joinResponse));
|
|
342
|
+
} else {
|
|
343
|
+
if (!this.pcManager) {
|
|
344
|
+
await this.configure(joinResponse, !useV0Path);
|
|
345
|
+
}
|
|
346
|
+
// create offer
|
|
347
|
+
if (!this.subscriberPrimary || joinResponse.fastPublish) {
|
|
348
|
+
this.negotiate().catch((err) => {
|
|
349
|
+
log.error(err, this.logContext);
|
|
350
|
+
});
|
|
351
|
+
}
|
|
301
352
|
}
|
|
302
353
|
|
|
303
354
|
this.registerOnLineListener();
|
|
304
355
|
this.clientConfiguration = joinResponse.clientConfiguration;
|
|
305
356
|
this.emit(EngineEvent.SignalConnected, joinResponse);
|
|
306
|
-
|
|
357
|
+
|
|
358
|
+
let serverInfo: Partial<ServerInfo> | undefined = joinResponse.serverInfo;
|
|
359
|
+
if (!serverInfo) {
|
|
360
|
+
serverInfo = { version: joinResponse.serverVersion, region: joinResponse.serverRegion };
|
|
361
|
+
}
|
|
362
|
+
this.log.debug(
|
|
363
|
+
`connected to Livekit Server ${Object.entries(serverInfo)
|
|
364
|
+
.map(([key, value]) => `${key}: ${value}`)
|
|
365
|
+
.join(', ')}`,
|
|
366
|
+
{
|
|
367
|
+
room: joinResponse.room?.name,
|
|
368
|
+
roomSid: joinResponse.room?.sid,
|
|
369
|
+
identity: joinResponse.participant?.identity,
|
|
370
|
+
},
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
return { joinResponse, serverInfo };
|
|
307
374
|
} catch (e) {
|
|
308
375
|
if (e instanceof ConnectionError) {
|
|
309
376
|
if (e.reason === ConnectionErrorReason.ServerUnreachable) {
|
|
@@ -362,11 +429,15 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
362
429
|
dcCleanup(this.lossyDCSub);
|
|
363
430
|
dcCleanup(this.reliableDC);
|
|
364
431
|
dcCleanup(this.reliableDCSub);
|
|
432
|
+
dcCleanup(this.dataTrackDC);
|
|
433
|
+
dcCleanup(this.dataTrackDCSub);
|
|
365
434
|
|
|
366
435
|
this.lossyDC = undefined;
|
|
367
436
|
this.lossyDCSub = undefined;
|
|
368
437
|
this.reliableDC = undefined;
|
|
369
438
|
this.reliableDCSub = undefined;
|
|
439
|
+
this.dataTrackDC = undefined;
|
|
440
|
+
this.dataTrackDCSub = undefined;
|
|
370
441
|
this.reliableMessageBuffer = new DataPacketBuffer();
|
|
371
442
|
this.reliableDataSequence = 1;
|
|
372
443
|
this.reliableReceivedState.clear();
|
|
@@ -452,25 +523,28 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
452
523
|
this.regionUrlProvider = provider;
|
|
453
524
|
}
|
|
454
525
|
|
|
455
|
-
private async configure(joinResponse
|
|
526
|
+
private async configure(joinResponse?: JoinResponse, useSinglePeerConnection?: boolean) {
|
|
456
527
|
// already configured
|
|
457
528
|
if (this.pcManager && this.pcManager.currentState !== PCTransportState.NEW) {
|
|
458
529
|
return;
|
|
459
530
|
}
|
|
460
531
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
rtcConfig
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
532
|
+
if (!joinResponse) {
|
|
533
|
+
const rtcConfig = this.makeRTCConfiguration();
|
|
534
|
+
this.pcManager = new PCTransportManager('publisher-only', this.loggerOptions, rtcConfig);
|
|
535
|
+
} else {
|
|
536
|
+
this.participantSid = joinResponse.participant?.sid;
|
|
537
|
+
const rtcConfig = this.makeRTCConfiguration(joinResponse);
|
|
538
|
+
this.pcManager = new PCTransportManager(
|
|
539
|
+
useSinglePeerConnection
|
|
540
|
+
? 'publisher-only'
|
|
541
|
+
: joinResponse.subscriberPrimary
|
|
542
|
+
? 'subscriber-primary'
|
|
543
|
+
: 'publisher-primary',
|
|
544
|
+
this.loggerOptions,
|
|
545
|
+
rtcConfig,
|
|
546
|
+
);
|
|
547
|
+
}
|
|
474
548
|
|
|
475
549
|
this.emit(EngineEvent.TransportsCreated, this.pcManager.publisher, this.pcManager.subscriber);
|
|
476
550
|
|
|
@@ -494,7 +568,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
494
568
|
const shouldEmit = this.pcState === PCState.New;
|
|
495
569
|
this.pcState = PCState.Connected;
|
|
496
570
|
if (shouldEmit) {
|
|
497
|
-
this.emit(EngineEvent.Connected,
|
|
571
|
+
this.emit(EngineEvent.Connected, this.latestJoinResponse!);
|
|
498
572
|
}
|
|
499
573
|
} else if (connectionState === PCTransportState.FAILED) {
|
|
500
574
|
// on Safari, PeerConnection will switch to 'disconnected' during renegotiation
|
|
@@ -529,10 +603,6 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
529
603
|
if (ev.streams.length === 0) return;
|
|
530
604
|
this.emit(EngineEvent.MediaTrackAdded, ev.track, ev.streams[0], ev.receiver);
|
|
531
605
|
};
|
|
532
|
-
|
|
533
|
-
if (!supportOptionalDatachannel(joinResponse.serverInfo?.protocol)) {
|
|
534
|
-
this.createDataChannels();
|
|
535
|
-
}
|
|
536
606
|
}
|
|
537
607
|
|
|
538
608
|
private setupSignalClientCallbacks() {
|
|
@@ -621,17 +691,22 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
621
691
|
};
|
|
622
692
|
|
|
623
693
|
this.client.onMediaSectionsRequirement = (requirement: MediaSectionsRequirement) => {
|
|
624
|
-
|
|
625
|
-
for (let i: number = 0; i < requirement.numAudios; i++) {
|
|
626
|
-
this.pcManager?.addPublisherTransceiverOfKind('audio', transceiverInit);
|
|
627
|
-
}
|
|
628
|
-
for (let i: number = 0; i < requirement.numVideos; i++) {
|
|
629
|
-
this.pcManager?.addPublisherTransceiverOfKind('video', transceiverInit);
|
|
630
|
-
}
|
|
631
|
-
|
|
694
|
+
this.addMediaSections(requirement.numAudios, requirement.numVideos);
|
|
632
695
|
this.negotiate();
|
|
633
696
|
};
|
|
634
697
|
|
|
698
|
+
this.client.onPublishDataTrackResponse = (event: PublishDataTrackResponse) => {
|
|
699
|
+
this.emit(EngineEvent.PublishDataTrackResponse, event);
|
|
700
|
+
};
|
|
701
|
+
|
|
702
|
+
this.client.onUnPublishDataTrackResponse = (event: UnpublishDataTrackResponse) => {
|
|
703
|
+
this.emit(EngineEvent.UnPublishDataTrackResponse, event);
|
|
704
|
+
};
|
|
705
|
+
|
|
706
|
+
this.client.onDataTrackSubscriberHandles = (event: DataTrackSubscriberHandles) => {
|
|
707
|
+
this.emit(EngineEvent.DataTrackSubscriberHandles, event);
|
|
708
|
+
};
|
|
709
|
+
|
|
635
710
|
this.client.onClose = () => {
|
|
636
711
|
this.handleDisconnect('signal', ReconnectReason.RR_SIGNAL_DISCONNECTED);
|
|
637
712
|
};
|
|
@@ -665,7 +740,9 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
665
740
|
};
|
|
666
741
|
}
|
|
667
742
|
|
|
668
|
-
private makeRTCConfiguration(
|
|
743
|
+
private makeRTCConfiguration(
|
|
744
|
+
serverResponse?: JoinResponse | ReconnectResponse,
|
|
745
|
+
): RTCConfiguration {
|
|
669
746
|
const rtcConfig = { ...this.rtcConfig };
|
|
670
747
|
|
|
671
748
|
if (this.signalOpts?.e2eeEnabled) {
|
|
@@ -675,6 +752,15 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
675
752
|
rtcConfig.encodedInsertableStreams = true;
|
|
676
753
|
}
|
|
677
754
|
|
|
755
|
+
// @ts-ignore
|
|
756
|
+
rtcConfig.sdpSemantics = 'unified-plan';
|
|
757
|
+
// @ts-ignore
|
|
758
|
+
rtcConfig.continualGatheringPolicy = 'gather_continually';
|
|
759
|
+
|
|
760
|
+
if (!serverResponse) {
|
|
761
|
+
return rtcConfig;
|
|
762
|
+
}
|
|
763
|
+
|
|
678
764
|
// update ICE servers before creating PeerConnection
|
|
679
765
|
if (serverResponse.iceServers && !rtcConfig.iceServers) {
|
|
680
766
|
const rtcIceServers: RTCIceServer[] = [];
|
|
@@ -698,14 +784,19 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
698
784
|
rtcConfig.iceTransportPolicy = 'relay';
|
|
699
785
|
}
|
|
700
786
|
|
|
701
|
-
// @ts-ignore
|
|
702
|
-
rtcConfig.sdpSemantics = 'unified-plan';
|
|
703
|
-
// @ts-ignore
|
|
704
|
-
rtcConfig.continualGatheringPolicy = 'gather_continually';
|
|
705
|
-
|
|
706
787
|
return rtcConfig;
|
|
707
788
|
}
|
|
708
789
|
|
|
790
|
+
private addMediaSections(numAudios: number, numVideos: number) {
|
|
791
|
+
const transceiverInit: RTCRtpTransceiverInit = { direction: 'recvonly' };
|
|
792
|
+
for (let i: number = 0; i < numAudios; i++) {
|
|
793
|
+
this.pcManager?.addPublisherTransceiverOfKind('audio', transceiverInit);
|
|
794
|
+
}
|
|
795
|
+
for (let i: number = 0; i < numVideos; i++) {
|
|
796
|
+
this.pcManager?.addPublisherTransceiverOfKind('video', transceiverInit);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
709
800
|
private createDataChannels() {
|
|
710
801
|
if (!this.pcManager) {
|
|
711
802
|
return;
|
|
@@ -720,6 +811,10 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
720
811
|
this.reliableDC.onmessage = null;
|
|
721
812
|
this.reliableDC.onerror = null;
|
|
722
813
|
}
|
|
814
|
+
if (this.dataTrackDC) {
|
|
815
|
+
this.dataTrackDC.onmessage = null;
|
|
816
|
+
this.dataTrackDC.onerror = null;
|
|
817
|
+
}
|
|
723
818
|
|
|
724
819
|
// create data channels
|
|
725
820
|
this.lossyDC = this.pcManager.createPublisherDataChannel(lossyDataChannel, {
|
|
@@ -729,29 +824,39 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
729
824
|
this.reliableDC = this.pcManager.createPublisherDataChannel(reliableDataChannel, {
|
|
730
825
|
ordered: true,
|
|
731
826
|
});
|
|
827
|
+
this.dataTrackDC = this.pcManager.createPublisherDataChannel(dataTrackDataChannel, {
|
|
828
|
+
ordered: false,
|
|
829
|
+
maxRetransmits: 0,
|
|
830
|
+
});
|
|
732
831
|
|
|
733
832
|
// also handle messages over the pub channel, for backwards compatibility
|
|
734
833
|
this.lossyDC.onmessage = this.handleDataMessage;
|
|
735
834
|
this.reliableDC.onmessage = this.handleDataMessage;
|
|
835
|
+
this.dataTrackDC.onmessage = this.handleDataTrackMessage;
|
|
736
836
|
|
|
737
837
|
// handle datachannel errors
|
|
738
838
|
this.lossyDC.onerror = this.handleDataError;
|
|
739
839
|
this.reliableDC.onerror = this.handleDataError;
|
|
840
|
+
this.dataTrackDC.onerror = this.handleDataError;
|
|
740
841
|
|
|
741
842
|
// set up dc buffer threshold, set to 64kB (otherwise 0 by default)
|
|
742
843
|
this.lossyDC.bufferedAmountLowThreshold = 65535;
|
|
743
844
|
this.reliableDC.bufferedAmountLowThreshold = 65535;
|
|
845
|
+
this.dataTrackDC.bufferedAmountLowThreshold = 65535;
|
|
744
846
|
|
|
745
847
|
// handle buffer amount low events
|
|
746
|
-
this.lossyDC.onbufferedamountlow = this.handleBufferedAmountLow;
|
|
747
|
-
this.reliableDC.onbufferedamountlow =
|
|
848
|
+
this.lossyDC.onbufferedamountlow = () => this.handleBufferedAmountLow(DataChannelKind.LOSSY);
|
|
849
|
+
this.reliableDC.onbufferedamountlow = () =>
|
|
850
|
+
this.handleBufferedAmountLow(DataChannelKind.RELIABLE);
|
|
851
|
+
this.dataTrackDC.onbufferedamountlow = () =>
|
|
852
|
+
this.handleBufferedAmountLow(DataChannelKind.DATA_TRACK_LOSSY);
|
|
748
853
|
|
|
749
854
|
this.cleanupLossyDataStats();
|
|
750
855
|
this.lossyDataStatInterval = setInterval(() => {
|
|
751
856
|
this.lossyDataStatByterate = this.lossyDataStatCurrentBytes;
|
|
752
857
|
this.lossyDataStatCurrentBytes = 0;
|
|
753
858
|
|
|
754
|
-
const dc = this.dataChannelForKind(
|
|
859
|
+
const dc = this.dataChannelForKind(DataChannelKind.LOSSY);
|
|
755
860
|
if (dc) {
|
|
756
861
|
// control buffered latency to ~100ms
|
|
757
862
|
const threshold = this.lossyDataStatByterate / 10;
|
|
@@ -767,15 +872,21 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
767
872
|
if (!channel) {
|
|
768
873
|
return;
|
|
769
874
|
}
|
|
875
|
+
let handler;
|
|
770
876
|
if (channel.label === reliableDataChannel) {
|
|
771
877
|
this.reliableDCSub = channel;
|
|
878
|
+
handler = this.handleDataMessage;
|
|
772
879
|
} else if (channel.label === lossyDataChannel) {
|
|
773
880
|
this.lossyDCSub = channel;
|
|
881
|
+
handler = this.handleDataMessage;
|
|
882
|
+
} else if (channel.label === dataTrackDataChannel) {
|
|
883
|
+
this.dataTrackDCSub = channel;
|
|
884
|
+
handler = this.handleDataTrackMessage;
|
|
774
885
|
} else {
|
|
775
886
|
return;
|
|
776
887
|
}
|
|
777
888
|
this.log.debug(`on data channel ${channel.id}, ${channel.label}`, this.logContext);
|
|
778
|
-
channel.onmessage =
|
|
889
|
+
channel.onmessage = handler;
|
|
779
890
|
};
|
|
780
891
|
|
|
781
892
|
private handleDataMessage = async (message: MessageEvent) => {
|
|
@@ -840,6 +951,21 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
840
951
|
}
|
|
841
952
|
};
|
|
842
953
|
|
|
954
|
+
private handleDataTrackMessage = async (message: MessageEvent) => {
|
|
955
|
+
// Decode / normalize into a common format
|
|
956
|
+
let buffer: ArrayBuffer | undefined;
|
|
957
|
+
if (message.data instanceof ArrayBuffer) {
|
|
958
|
+
buffer = message.data;
|
|
959
|
+
} else if (message.data instanceof Blob) {
|
|
960
|
+
buffer = await message.data.arrayBuffer();
|
|
961
|
+
} else {
|
|
962
|
+
this.log.error('unsupported data type', { ...this.logContext, data: message.data });
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
this.emit('dataTrackPacketReceived', new Uint8Array(buffer));
|
|
967
|
+
};
|
|
968
|
+
|
|
843
969
|
private handleDataError = (event: Event) => {
|
|
844
970
|
const channel = event.currentTarget as RTCDataChannel;
|
|
845
971
|
const channelKind = channel.maxRetransmits === 0 ? 'lossy' : 'reliable';
|
|
@@ -855,11 +981,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
855
981
|
}
|
|
856
982
|
};
|
|
857
983
|
|
|
858
|
-
private handleBufferedAmountLow = (
|
|
859
|
-
const channel = event.currentTarget as RTCDataChannel;
|
|
860
|
-
const channelKind =
|
|
861
|
-
channel.maxRetransmits === 0 ? DataPacket_Kind.LOSSY : DataPacket_Kind.RELIABLE;
|
|
862
|
-
|
|
984
|
+
private handleBufferedAmountLow = (channelKind: DataChannelKind) => {
|
|
863
985
|
this.updateAndEmitDCBufferStatus(channelKind);
|
|
864
986
|
};
|
|
865
987
|
|
|
@@ -1107,13 +1229,15 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1107
1229
|
throw new SignalReconnectError();
|
|
1108
1230
|
}
|
|
1109
1231
|
// in case a regionUrl is passed, the region URL takes precedence
|
|
1110
|
-
joinResponse =
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1232
|
+
joinResponse = (
|
|
1233
|
+
await this.join(
|
|
1234
|
+
regionUrl ?? this.url,
|
|
1235
|
+
this.token,
|
|
1236
|
+
this.signalOpts,
|
|
1237
|
+
undefined,
|
|
1238
|
+
!this.options.singlePeerConnection,
|
|
1239
|
+
)
|
|
1240
|
+
).joinResponse;
|
|
1117
1241
|
} catch (e) {
|
|
1118
1242
|
if (e instanceof ConnectionError && e.reason === ConnectionErrorReason.NotAllowed) {
|
|
1119
1243
|
throw new UnexpectedConnectionState('could not reconnect, token might be expired');
|
|
@@ -1288,7 +1412,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1288
1412
|
},
|
|
1289
1413
|
});
|
|
1290
1414
|
|
|
1291
|
-
await this.sendDataPacket(packet,
|
|
1415
|
+
await this.sendDataPacket(packet, DataChannelKind.RELIABLE);
|
|
1292
1416
|
}
|
|
1293
1417
|
|
|
1294
1418
|
/** @internal */
|
|
@@ -1303,11 +1427,11 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1303
1427
|
}),
|
|
1304
1428
|
},
|
|
1305
1429
|
});
|
|
1306
|
-
await this.sendDataPacket(packet,
|
|
1430
|
+
await this.sendDataPacket(packet, DataChannelKind.RELIABLE);
|
|
1307
1431
|
}
|
|
1308
1432
|
|
|
1309
1433
|
/* @internal */
|
|
1310
|
-
async sendDataPacket(packet: DataPacket, kind:
|
|
1434
|
+
async sendDataPacket(packet: DataPacket, kind: DataChannelKind) {
|
|
1311
1435
|
// make sure we do have a data connection
|
|
1312
1436
|
await this.ensurePublisherConnected(kind);
|
|
1313
1437
|
|
|
@@ -1326,57 +1450,93 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1326
1450
|
}
|
|
1327
1451
|
}
|
|
1328
1452
|
|
|
1329
|
-
if (kind ===
|
|
1453
|
+
if (kind === DataChannelKind.RELIABLE) {
|
|
1330
1454
|
packet.sequence = this.reliableDataSequence;
|
|
1331
1455
|
this.reliableDataSequence += 1;
|
|
1332
1456
|
}
|
|
1333
1457
|
|
|
1334
1458
|
const msg = packet.toBinary();
|
|
1335
1459
|
|
|
1460
|
+
switch (kind) {
|
|
1461
|
+
case DataChannelKind.LOSSY:
|
|
1462
|
+
case DataChannelKind.DATA_TRACK_LOSSY:
|
|
1463
|
+
return this.sendLossyBytes(msg, kind);
|
|
1464
|
+
|
|
1465
|
+
case DataChannelKind.RELIABLE:
|
|
1466
|
+
const dc = this.dataChannelForKind(kind);
|
|
1467
|
+
if (dc) {
|
|
1468
|
+
await this.waitForBufferStatusLow(kind);
|
|
1469
|
+
this.reliableMessageBuffer.push({ data: msg, sequence: packet.sequence });
|
|
1470
|
+
|
|
1471
|
+
if (this.attemptingReconnect) {
|
|
1472
|
+
return;
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
dc.send(msg);
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
this.updateAndEmitDCBufferStatus(kind);
|
|
1479
|
+
break;
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
/* @internal */
|
|
1484
|
+
async sendLossyBytes(
|
|
1485
|
+
bytes: Uint8Array,
|
|
1486
|
+
kind: Exclude<DataChannelKind, DataChannelKind.RELIABLE>,
|
|
1487
|
+
bufferStatusLowBehavior: 'drop' | 'wait' = 'drop',
|
|
1488
|
+
) {
|
|
1489
|
+
// make sure we do have a data connection
|
|
1490
|
+
await this.ensurePublisherConnected(kind);
|
|
1491
|
+
|
|
1336
1492
|
const dc = this.dataChannelForKind(kind);
|
|
1337
1493
|
if (dc) {
|
|
1338
|
-
if (kind
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
this.log.warn(
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
)
|
|
1350
|
-
|
|
1351
|
-
|
|
1494
|
+
if (!this.isBufferStatusLow(kind)) {
|
|
1495
|
+
// Depending on the exact circumstance that data is being sent, either drop or wait for the
|
|
1496
|
+
// buffer status to not be low before continuing.
|
|
1497
|
+
switch (bufferStatusLowBehavior) {
|
|
1498
|
+
case 'wait':
|
|
1499
|
+
await this.waitForBufferStatusLow(kind);
|
|
1500
|
+
break;
|
|
1501
|
+
case 'drop':
|
|
1502
|
+
// this.log.warn(`dropping lossy data channel message`, this.logContext);
|
|
1503
|
+
// Drop messages to reduce latency
|
|
1504
|
+
this.lossyDataDropCount += 1;
|
|
1505
|
+
if (this.lossyDataDropCount % 100 === 0) {
|
|
1506
|
+
this.log.warn(
|
|
1507
|
+
`dropping lossy data channel messages, total dropped: ${this.lossyDataDropCount}`,
|
|
1508
|
+
this.logContext,
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1511
|
+
return;
|
|
1352
1512
|
}
|
|
1353
|
-
this.lossyDataStatCurrentBytes += msg.byteLength;
|
|
1354
1513
|
}
|
|
1514
|
+
this.lossyDataStatCurrentBytes += bytes.byteLength;
|
|
1355
1515
|
|
|
1356
1516
|
if (this.attemptingReconnect) {
|
|
1357
1517
|
return;
|
|
1358
1518
|
}
|
|
1359
1519
|
|
|
1360
|
-
dc.send(
|
|
1520
|
+
dc.send(bytes);
|
|
1361
1521
|
}
|
|
1362
1522
|
|
|
1363
1523
|
this.updateAndEmitDCBufferStatus(kind);
|
|
1364
1524
|
}
|
|
1365
1525
|
|
|
1366
1526
|
private async resendReliableMessagesForResume(lastMessageSeq: number) {
|
|
1367
|
-
await this.ensurePublisherConnected(
|
|
1368
|
-
const dc = this.dataChannelForKind(
|
|
1527
|
+
await this.ensurePublisherConnected(DataChannelKind.RELIABLE);
|
|
1528
|
+
const dc = this.dataChannelForKind(DataChannelKind.RELIABLE);
|
|
1369
1529
|
if (dc) {
|
|
1370
1530
|
this.reliableMessageBuffer.popToSequence(lastMessageSeq);
|
|
1371
1531
|
this.reliableMessageBuffer.getAll().forEach((msg) => {
|
|
1372
1532
|
dc.send(msg.data);
|
|
1373
1533
|
});
|
|
1374
1534
|
}
|
|
1375
|
-
this.updateAndEmitDCBufferStatus(
|
|
1535
|
+
this.updateAndEmitDCBufferStatus(DataChannelKind.RELIABLE);
|
|
1376
1536
|
}
|
|
1377
1537
|
|
|
1378
|
-
private updateAndEmitDCBufferStatus = (kind:
|
|
1379
|
-
if (kind ===
|
|
1538
|
+
private updateAndEmitDCBufferStatus = (kind: DataChannelKind) => {
|
|
1539
|
+
if (kind === DataChannelKind.RELIABLE) {
|
|
1380
1540
|
const dc = this.dataChannelForKind(kind);
|
|
1381
1541
|
if (dc) {
|
|
1382
1542
|
this.reliableMessageBuffer.alignBufferedAmount(dc.bufferedAmount);
|
|
@@ -1390,25 +1550,38 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1390
1550
|
}
|
|
1391
1551
|
};
|
|
1392
1552
|
|
|
1393
|
-
private isBufferStatusLow = (kind:
|
|
1553
|
+
private isBufferStatusLow = (kind: DataChannelKind): boolean | undefined => {
|
|
1394
1554
|
const dc = this.dataChannelForKind(kind);
|
|
1395
1555
|
if (dc) {
|
|
1396
1556
|
return dc.bufferedAmount <= dc.bufferedAmountLowThreshold;
|
|
1397
1557
|
}
|
|
1398
1558
|
};
|
|
1399
1559
|
|
|
1400
|
-
waitForBufferStatusLow(kind:
|
|
1401
|
-
return new TypedPromise(async (resolve, reject) => {
|
|
1560
|
+
async waitForBufferStatusLow(kind: DataChannelKind) {
|
|
1561
|
+
return new TypedPromise<void, UnexpectedConnectionState>(async (resolve, reject) => {
|
|
1562
|
+
if (this.isClosed) {
|
|
1563
|
+
reject(new UnexpectedConnectionState('engine closed'));
|
|
1564
|
+
}
|
|
1402
1565
|
if (this.isBufferStatusLow(kind)) {
|
|
1403
1566
|
resolve();
|
|
1404
1567
|
} else {
|
|
1405
1568
|
const onClosing = () => reject(new UnexpectedConnectionState('engine closed'));
|
|
1406
1569
|
this.once(EngineEvent.Closing, onClosing);
|
|
1407
|
-
|
|
1408
|
-
|
|
1570
|
+
const dc = this.dataChannelForKind(kind);
|
|
1571
|
+
if (!dc) {
|
|
1572
|
+
reject(new UnexpectedConnectionState(`DataChannel not found, kind: ${kind}`));
|
|
1573
|
+
return;
|
|
1409
1574
|
}
|
|
1410
|
-
|
|
1411
|
-
|
|
1575
|
+
dc.addEventListener(
|
|
1576
|
+
'bufferedamountlow',
|
|
1577
|
+
() => {
|
|
1578
|
+
this.off(EngineEvent.Closing, onClosing);
|
|
1579
|
+
resolve();
|
|
1580
|
+
},
|
|
1581
|
+
{
|
|
1582
|
+
once: true,
|
|
1583
|
+
},
|
|
1584
|
+
);
|
|
1412
1585
|
}
|
|
1413
1586
|
});
|
|
1414
1587
|
}
|
|
@@ -1417,7 +1590,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1417
1590
|
* @internal
|
|
1418
1591
|
*/
|
|
1419
1592
|
async ensureDataTransportConnected(
|
|
1420
|
-
kind:
|
|
1593
|
+
kind: DataChannelKind,
|
|
1421
1594
|
subscriber: boolean = this.subscriberPrimary,
|
|
1422
1595
|
) {
|
|
1423
1596
|
if (!this.pcManager) {
|
|
@@ -1472,7 +1645,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1472
1645
|
);
|
|
1473
1646
|
}
|
|
1474
1647
|
|
|
1475
|
-
private async ensurePublisherConnected(kind:
|
|
1648
|
+
private async ensurePublisherConnected(kind: DataChannelKind) {
|
|
1476
1649
|
if (!this.publisherConnectionPromise) {
|
|
1477
1650
|
this.publisherConnectionPromise = this.ensureDataTransportConnected(kind, false);
|
|
1478
1651
|
}
|
|
@@ -1513,7 +1686,8 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1513
1686
|
if (
|
|
1514
1687
|
this.pcManager.publisher.getTransceivers().length == 0 &&
|
|
1515
1688
|
!this.lossyDC &&
|
|
1516
|
-
!this.reliableDC
|
|
1689
|
+
!this.reliableDC &&
|
|
1690
|
+
!this.dataTrackDC
|
|
1517
1691
|
) {
|
|
1518
1692
|
this.createDataChannels();
|
|
1519
1693
|
}
|
|
@@ -1573,26 +1747,35 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1573
1747
|
});
|
|
1574
1748
|
}
|
|
1575
1749
|
|
|
1576
|
-
dataChannelForKind(kind:
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1750
|
+
dataChannelForKind(kind: DataChannelKind, sub?: boolean): RTCDataChannel | undefined {
|
|
1751
|
+
switch (kind) {
|
|
1752
|
+
case DataChannelKind.RELIABLE:
|
|
1753
|
+
if (!sub) {
|
|
1754
|
+
return this.reliableDC;
|
|
1755
|
+
} else {
|
|
1756
|
+
return this.reliableDCSub;
|
|
1757
|
+
}
|
|
1758
|
+
case DataChannelKind.LOSSY:
|
|
1759
|
+
if (!sub) {
|
|
1760
|
+
return this.lossyDC;
|
|
1761
|
+
} else {
|
|
1762
|
+
return this.lossyDCSub;
|
|
1763
|
+
}
|
|
1764
|
+
case DataChannelKind.DATA_TRACK_LOSSY:
|
|
1765
|
+
if (!sub) {
|
|
1766
|
+
return this.dataTrackDC;
|
|
1767
|
+
} else {
|
|
1768
|
+
return this.dataTrackDCSub;
|
|
1769
|
+
}
|
|
1591
1770
|
}
|
|
1592
1771
|
}
|
|
1593
1772
|
|
|
1594
1773
|
/** @internal */
|
|
1595
|
-
sendSyncState(
|
|
1774
|
+
sendSyncState(
|
|
1775
|
+
remoteTracks: RemoteTrackPublication[],
|
|
1776
|
+
localTracks: LocalTrackPublication[],
|
|
1777
|
+
localDataTrackInfos: Array<DataTrackInfo>,
|
|
1778
|
+
) {
|
|
1596
1779
|
if (!this.pcManager) {
|
|
1597
1780
|
this.log.warn('sync state cannot be sent without peer connection setup', this.logContext);
|
|
1598
1781
|
return;
|
|
@@ -1664,6 +1847,9 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1664
1847
|
lastSeq: seq,
|
|
1665
1848
|
});
|
|
1666
1849
|
}),
|
|
1850
|
+
publishDataTracks: localDataTrackInfos.map((info) => {
|
|
1851
|
+
return new PublishDataTrackResponse({ info: DataTrackInfo.toProtobuf(info) });
|
|
1852
|
+
}),
|
|
1667
1853
|
}),
|
|
1668
1854
|
);
|
|
1669
1855
|
}
|
|
@@ -1687,10 +1873,10 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1687
1873
|
);
|
|
1688
1874
|
}
|
|
1689
1875
|
};
|
|
1690
|
-
getInfo(this.dataChannelForKind(
|
|
1691
|
-
getInfo(this.dataChannelForKind(
|
|
1692
|
-
getInfo(this.dataChannelForKind(
|
|
1693
|
-
getInfo(this.dataChannelForKind(
|
|
1876
|
+
getInfo(this.dataChannelForKind(DataChannelKind.LOSSY), SignalTarget.PUBLISHER);
|
|
1877
|
+
getInfo(this.dataChannelForKind(DataChannelKind.RELIABLE), SignalTarget.PUBLISHER);
|
|
1878
|
+
getInfo(this.dataChannelForKind(DataChannelKind.LOSSY, true), SignalTarget.SUBSCRIBER);
|
|
1879
|
+
getInfo(this.dataChannelForKind(DataChannelKind.RELIABLE, true), SignalTarget.SUBSCRIBER);
|
|
1694
1880
|
return infos;
|
|
1695
1881
|
}
|
|
1696
1882
|
|
|
@@ -1797,7 +1983,7 @@ export type EngineEventCallbacks = {
|
|
|
1797
1983
|
/** @internal */
|
|
1798
1984
|
trackSenderAdded: (track: Track, sender: RTCRtpSender) => void;
|
|
1799
1985
|
rtpVideoMapUpdate: (rtpMap: Map<number, VideoCodec>) => void;
|
|
1800
|
-
dcBufferStatusChanged: (isLow: boolean, kind:
|
|
1986
|
+
dcBufferStatusChanged: (isLow: boolean, kind: DataChannelKind) => void;
|
|
1801
1987
|
participantUpdate: (infos: ParticipantInfo[]) => void;
|
|
1802
1988
|
roomUpdate: (room: RoomModel) => void;
|
|
1803
1989
|
roomMoved: (room: RoomMovedResponse) => void;
|
|
@@ -1813,12 +1999,13 @@ export type EngineEventCallbacks = {
|
|
|
1813
1999
|
offline: () => void;
|
|
1814
2000
|
signalRequestResponse: (response: RequestResponse) => void;
|
|
1815
2001
|
signalConnected: (joinResp: JoinResponse) => void;
|
|
2002
|
+
publishDataTrackResponse: (event: PublishDataTrackResponse) => void;
|
|
2003
|
+
unPublishDataTrackResponse: (event: UnpublishDataTrackResponse) => void;
|
|
2004
|
+
dataTrackSubscriberHandles: (event: DataTrackSubscriberHandles) => void;
|
|
2005
|
+
dataTrackPacketReceived: (packet: Uint8Array) => void;
|
|
2006
|
+
joined: (joinResponse: JoinResponse) => void;
|
|
1816
2007
|
};
|
|
1817
2008
|
|
|
1818
|
-
function supportOptionalDatachannel(protocol: number | undefined): boolean {
|
|
1819
|
-
return protocol !== undefined && protocol > 13;
|
|
1820
|
-
}
|
|
1821
|
-
|
|
1822
2009
|
function applyUserDataCompat(newObj: DataPacket, oldObj: UserPacket) {
|
|
1823
2010
|
const participantIdentity = newObj.participantIdentity
|
|
1824
2011
|
? newObj.participantIdentity
|