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.
Files changed (145) hide show
  1. package/dist/livekit-client.e2ee.worker.js +1 -1
  2. package/dist/livekit-client.e2ee.worker.js.map +1 -1
  3. package/dist/livekit-client.e2ee.worker.mjs +8 -7
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +8026 -5883
  6. package/dist/livekit-client.esm.mjs.map +1 -1
  7. package/dist/livekit-client.umd.js +1 -1
  8. package/dist/livekit-client.umd.js.map +1 -1
  9. package/dist/src/api/SignalClient.d.ts +12 -4
  10. package/dist/src/api/SignalClient.d.ts.map +1 -1
  11. package/dist/src/connectionHelper/ConnectionCheck.d.ts +1 -1
  12. package/dist/src/connectionHelper/ConnectionCheck.d.ts.map +1 -1
  13. package/dist/src/e2ee/constants.d.ts.map +1 -1
  14. package/dist/src/e2ee/types.d.ts +6 -0
  15. package/dist/src/e2ee/types.d.ts.map +1 -1
  16. package/dist/src/e2ee/utils.d.ts +2 -1
  17. package/dist/src/e2ee/utils.d.ts.map +1 -1
  18. package/dist/src/e2ee/worker/DataCryptor.d.ts.map +1 -1
  19. package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  20. package/dist/src/index.d.ts +6 -4
  21. package/dist/src/index.d.ts.map +1 -1
  22. package/dist/src/room/PCTransport.d.ts +5 -0
  23. package/dist/src/room/PCTransport.d.ts.map +1 -1
  24. package/dist/src/room/PCTransportManager.d.ts +1 -1
  25. package/dist/src/room/PCTransportManager.d.ts.map +1 -1
  26. package/dist/src/room/RTCEngine.d.ts +28 -11
  27. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  28. package/dist/src/room/Room.d.ts +14 -3
  29. package/dist/src/room/Room.d.ts.map +1 -1
  30. package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts +5 -1
  31. package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts.map +1 -1
  32. package/dist/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts.map +1 -1
  33. package/dist/src/room/data-track/LocalDataTrack.d.ts +28 -5
  34. package/dist/src/room/data-track/LocalDataTrack.d.ts.map +1 -1
  35. package/dist/src/room/data-track/RemoteDataTrack.d.ts +5 -5
  36. package/dist/src/room/data-track/RemoteDataTrack.d.ts.map +1 -1
  37. package/dist/src/room/data-track/depacketizer.d.ts +4 -4
  38. package/dist/src/room/data-track/depacketizer.d.ts.map +1 -1
  39. package/dist/src/room/data-track/frame.d.ts +14 -0
  40. package/dist/src/room/data-track/frame.d.ts.map +1 -1
  41. package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts +19 -11
  42. package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts.map +1 -1
  43. package/dist/src/room/data-track/incoming/pipeline.d.ts +6 -5
  44. package/dist/src/room/data-track/incoming/pipeline.d.ts.map +1 -1
  45. package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +57 -23
  46. package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts.map +1 -1
  47. package/dist/src/room/data-track/outgoing/errors.d.ts +16 -6
  48. package/dist/src/room/data-track/outgoing/errors.d.ts.map +1 -1
  49. package/dist/src/room/data-track/outgoing/pipeline.d.ts +7 -6
  50. package/dist/src/room/data-track/outgoing/pipeline.d.ts.map +1 -1
  51. package/dist/src/room/data-track/outgoing/types.d.ts +14 -4
  52. package/dist/src/room/data-track/outgoing/types.d.ts.map +1 -1
  53. package/dist/src/room/data-track/packet/extensions.d.ts.map +1 -1
  54. package/dist/src/room/data-track/packetizer.d.ts +4 -4
  55. package/dist/src/room/data-track/packetizer.d.ts.map +1 -1
  56. package/dist/src/room/data-track/track-interfaces.d.ts +1 -1
  57. package/dist/src/room/data-track/track-interfaces.d.ts.map +1 -1
  58. package/dist/src/room/data-track/types.d.ts +6 -1
  59. package/dist/src/room/data-track/types.d.ts.map +1 -1
  60. package/dist/src/room/events.d.ts +24 -3
  61. package/dist/src/room/events.d.ts.map +1 -1
  62. package/dist/src/room/participant/LocalParticipant.d.ts +12 -1
  63. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  64. package/dist/src/room/participant/RemoteParticipant.d.ts +13 -0
  65. package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
  66. package/dist/src/room/utils.d.ts +1 -0
  67. package/dist/src/room/utils.d.ts.map +1 -1
  68. package/dist/src/utils/deferrable-map.d.ts +32 -0
  69. package/dist/src/utils/deferrable-map.d.ts.map +1 -0
  70. package/dist/src/utils/serializer.d.ts +48 -0
  71. package/dist/src/utils/serializer.d.ts.map +1 -0
  72. package/dist/ts4.2/api/SignalClient.d.ts +12 -4
  73. package/dist/ts4.2/connectionHelper/ConnectionCheck.d.ts +2 -1
  74. package/dist/ts4.2/e2ee/types.d.ts +6 -0
  75. package/dist/ts4.2/e2ee/utils.d.ts +2 -1
  76. package/dist/ts4.2/index.d.ts +7 -4
  77. package/dist/ts4.2/room/PCTransport.d.ts +5 -0
  78. package/dist/ts4.2/room/PCTransportManager.d.ts +1 -1
  79. package/dist/ts4.2/room/RTCEngine.d.ts +28 -11
  80. package/dist/ts4.2/room/Room.d.ts +14 -3
  81. package/dist/ts4.2/room/data-stream/incoming/IncomingDataStreamManager.d.ts +5 -1
  82. package/dist/ts4.2/room/data-track/LocalDataTrack.d.ts +27 -4
  83. package/dist/ts4.2/room/data-track/RemoteDataTrack.d.ts +4 -4
  84. package/dist/ts4.2/room/data-track/depacketizer.d.ts +4 -4
  85. package/dist/ts4.2/room/data-track/frame.d.ts +14 -0
  86. package/dist/ts4.2/room/data-track/incoming/IncomingDataTrackManager.d.ts +21 -10
  87. package/dist/ts4.2/room/data-track/incoming/pipeline.d.ts +6 -5
  88. package/dist/ts4.2/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +57 -23
  89. package/dist/ts4.2/room/data-track/outgoing/errors.d.ts +16 -6
  90. package/dist/ts4.2/room/data-track/outgoing/pipeline.d.ts +7 -6
  91. package/dist/ts4.2/room/data-track/outgoing/types.d.ts +14 -4
  92. package/dist/ts4.2/room/data-track/packetizer.d.ts +4 -4
  93. package/dist/ts4.2/room/data-track/track-interfaces.d.ts +1 -1
  94. package/dist/ts4.2/room/data-track/types.d.ts +6 -1
  95. package/dist/ts4.2/room/events.d.ts +24 -3
  96. package/dist/ts4.2/room/participant/LocalParticipant.d.ts +12 -1
  97. package/dist/ts4.2/room/participant/RemoteParticipant.d.ts +13 -0
  98. package/dist/ts4.2/room/utils.d.ts +1 -0
  99. package/dist/ts4.2/utils/deferrable-map.d.ts +32 -0
  100. package/dist/ts4.2/utils/serializer.d.ts +48 -0
  101. package/package.json +1 -1
  102. package/src/api/SignalClient.test.ts +9 -4
  103. package/src/api/SignalClient.ts +116 -9
  104. package/src/connectionHelper/ConnectionCheck.ts +1 -1
  105. package/src/e2ee/constants.ts +1 -0
  106. package/src/e2ee/types.ts +6 -0
  107. package/src/e2ee/utils.ts +4 -3
  108. package/src/e2ee/worker/DataCryptor.ts +1 -4
  109. package/src/e2ee/worker/FrameCryptor.ts +1 -4
  110. package/src/e2ee/worker/ParticipantKeyHandler.ts +1 -1
  111. package/src/index.ts +13 -4
  112. package/src/room/PCTransport.ts +41 -1
  113. package/src/room/PCTransportManager.ts +1 -1
  114. package/src/room/RTCEngine.ts +312 -125
  115. package/src/room/Room.ts +168 -35
  116. package/src/room/data-stream/incoming/IncomingDataStreamManager.ts +26 -2
  117. package/src/room/data-stream/outgoing/OutgoingDataStreamManager.ts +7 -7
  118. package/src/room/data-track/LocalDataTrack.ts +83 -10
  119. package/src/room/data-track/RemoteDataTrack.ts +7 -9
  120. package/src/room/data-track/depacketizer.ts +21 -12
  121. package/src/room/data-track/frame.ts +28 -2
  122. package/src/room/data-track/incoming/IncomingDataTrackManager.test.ts +58 -73
  123. package/src/room/data-track/incoming/IncomingDataTrackManager.ts +139 -80
  124. package/src/room/data-track/incoming/pipeline.ts +29 -24
  125. package/src/room/data-track/outgoing/OutgoingDataTrackManager.test.ts +225 -32
  126. package/src/room/data-track/outgoing/OutgoingDataTrackManager.ts +150 -75
  127. package/src/room/data-track/outgoing/errors.ts +36 -7
  128. package/src/room/data-track/outgoing/pipeline.ts +23 -17
  129. package/src/room/data-track/outgoing/types.ts +12 -3
  130. package/src/room/data-track/packet/extensions.ts +17 -22
  131. package/src/room/data-track/packet/index.test.ts +22 -33
  132. package/src/room/data-track/packetizer.test.ts +2 -2
  133. package/src/room/data-track/packetizer.ts +4 -4
  134. package/src/room/data-track/track-interfaces.ts +1 -1
  135. package/src/room/data-track/types.ts +21 -1
  136. package/src/room/events.ts +26 -1
  137. package/src/room/participant/LocalParticipant.ts +74 -8
  138. package/src/room/participant/RemoteParticipant.ts +25 -0
  139. package/src/room/utils.ts +4 -0
  140. package/src/utils/deferrable-map.ts +109 -0
  141. package/src/utils/serializer.ts +72 -0
  142. package/dist/src/room/data-track/e2ee.d.ts +0 -12
  143. package/dist/src/room/data-track/e2ee.d.ts.map +0 -1
  144. package/dist/ts4.2/room/data-track/e2ee.d.ts +0 -12
  145. package/src/room/data-track/e2ee.ts +0 -15
@@ -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
- [DataPacket_Kind.LOSSY, true],
243
- [DataPacket_Kind.RELIABLE, true],
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
- const joinResponse = await this.client.join(url, token, opts, abortSignal, useV0Path);
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 (!this.pcManager) {
293
- await this.configure(joinResponse, !useV0Path);
294
- }
295
-
296
- // create offer
297
- if (!this.subscriberPrimary || joinResponse.fastPublish) {
298
- this.negotiate().catch((err) => {
299
- log.error(err, this.logContext);
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
- return joinResponse;
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: JoinResponse, useSinglePeerConnection: boolean) {
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
- this.participantSid = joinResponse.participant?.sid;
462
-
463
- const rtcConfig = this.makeRTCConfiguration(joinResponse);
464
-
465
- this.pcManager = new PCTransportManager(
466
- rtcConfig,
467
- useSinglePeerConnection
468
- ? 'publisher-only'
469
- : joinResponse.subscriberPrimary
470
- ? 'subscriber-primary'
471
- : 'publisher-primary',
472
- this.loggerOptions,
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, joinResponse);
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
- const transceiverInit: RTCRtpTransceiverInit = { direction: 'recvonly' };
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(serverResponse: JoinResponse | ReconnectResponse): RTCConfiguration {
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 = this.handleBufferedAmountLow;
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(DataPacket_Kind.LOSSY);
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 = this.handleDataMessage;
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 = (event: Event) => {
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 = await this.join(
1111
- regionUrl ?? this.url,
1112
- this.token,
1113
- this.signalOpts,
1114
- undefined,
1115
- !this.options.singlePeerConnection,
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, DataPacket_Kind.RELIABLE);
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, DataPacket_Kind.RELIABLE);
1430
+ await this.sendDataPacket(packet, DataChannelKind.RELIABLE);
1307
1431
  }
1308
1432
 
1309
1433
  /* @internal */
1310
- async sendDataPacket(packet: DataPacket, kind: 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 === DataPacket_Kind.RELIABLE) {
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 === DataPacket_Kind.RELIABLE) {
1339
- await this.waitForBufferStatusLow(kind);
1340
- this.reliableMessageBuffer.push({ data: msg, sequence: packet.sequence });
1341
- } else {
1342
- // lossy channel, drop messages to reduce latency
1343
- if (!this.isBufferStatusLow(kind)) {
1344
- this.lossyDataDropCount += 1;
1345
- if (this.lossyDataDropCount % 100 === 0) {
1346
- this.log.warn(
1347
- `dropping lossy data channel messages, total dropped: ${this.lossyDataDropCount}`,
1348
- this.logContext,
1349
- );
1350
- }
1351
- return;
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(msg);
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(DataPacket_Kind.RELIABLE);
1368
- const dc = this.dataChannelForKind(DataPacket_Kind.RELIABLE);
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(DataPacket_Kind.RELIABLE);
1535
+ this.updateAndEmitDCBufferStatus(DataChannelKind.RELIABLE);
1376
1536
  }
1377
1537
 
1378
- private updateAndEmitDCBufferStatus = (kind: DataPacket_Kind) => {
1379
- if (kind === DataPacket_Kind.RELIABLE) {
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: DataPacket_Kind): boolean | undefined => {
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: DataPacket_Kind): TypedPromise<void, UnexpectedConnectionState> {
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
- while (!this.dcBufferStatus.get(kind)) {
1408
- await sleep(10);
1570
+ const dc = this.dataChannelForKind(kind);
1571
+ if (!dc) {
1572
+ reject(new UnexpectedConnectionState(`DataChannel not found, kind: ${kind}`));
1573
+ return;
1409
1574
  }
1410
- this.off(EngineEvent.Closing, onClosing);
1411
- resolve();
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: DataPacket_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: DataPacket_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: DataPacket_Kind, sub?: boolean): RTCDataChannel | undefined {
1577
- if (!sub) {
1578
- if (kind === DataPacket_Kind.LOSSY) {
1579
- return this.lossyDC;
1580
- }
1581
- if (kind === DataPacket_Kind.RELIABLE) {
1582
- return this.reliableDC;
1583
- }
1584
- } else {
1585
- if (kind === DataPacket_Kind.LOSSY) {
1586
- return this.lossyDCSub;
1587
- }
1588
- if (kind === DataPacket_Kind.RELIABLE) {
1589
- return this.reliableDCSub;
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(remoteTracks: RemoteTrackPublication[], localTracks: LocalTrackPublication[]) {
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(DataPacket_Kind.LOSSY), SignalTarget.PUBLISHER);
1691
- getInfo(this.dataChannelForKind(DataPacket_Kind.RELIABLE), SignalTarget.PUBLISHER);
1692
- getInfo(this.dataChannelForKind(DataPacket_Kind.LOSSY, true), SignalTarget.SUBSCRIBER);
1693
- getInfo(this.dataChannelForKind(DataPacket_Kind.RELIABLE, true), SignalTarget.SUBSCRIBER);
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: DataPacket_Kind) => void;
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