livekit-client 2.20.0 → 2.20.1

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 (116) 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 -4
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +156 -16
  6. package/dist/livekit-client.esm.mjs.map +1 -1
  7. package/dist/livekit-client.fm.worker.js +1 -1
  8. package/dist/livekit-client.fm.worker.js.map +1 -1
  9. package/dist/livekit-client.fm.worker.mjs +8 -0
  10. package/dist/livekit-client.fm.worker.mjs.map +1 -1
  11. package/dist/livekit-client.umd.js +1 -1
  12. package/dist/livekit-client.umd.js.map +1 -1
  13. package/dist/src/api/SignalClient.d.ts.map +1 -1
  14. package/dist/src/e2ee/E2eeManager.d.ts +1 -0
  15. package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
  16. package/dist/src/e2ee/types.d.ts +1 -0
  17. package/dist/src/e2ee/types.d.ts.map +1 -1
  18. package/dist/src/e2ee/utils.d.ts +1 -0
  19. package/dist/src/e2ee/utils.d.ts.map +1 -1
  20. package/dist/src/e2ee/worker/DataCryptor.d.ts +1 -0
  21. package/dist/src/e2ee/worker/DataCryptor.d.ts.map +1 -1
  22. package/dist/src/e2ee/worker/FrameCryptor.d.ts +1 -0
  23. package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  24. package/dist/src/e2ee/worker/naluUtils.d.ts +1 -0
  25. package/dist/src/e2ee/worker/naluUtils.d.ts.map +1 -1
  26. package/dist/src/e2ee/worker/sifPayload.d.ts +1 -0
  27. package/dist/src/e2ee/worker/sifPayload.d.ts.map +1 -1
  28. package/dist/src/frameMetadata/frameMetadata.d.ts +1 -0
  29. package/dist/src/frameMetadata/frameMetadata.d.ts.map +1 -1
  30. package/dist/src/frameMetadata/types.d.ts +1 -0
  31. package/dist/src/frameMetadata/types.d.ts.map +1 -1
  32. package/dist/src/room/PCTransport.d.ts +40 -1
  33. package/dist/src/room/PCTransport.d.ts.map +1 -1
  34. package/dist/src/room/RTCEngine.d.ts +1 -0
  35. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  36. package/dist/src/room/Room.d.ts +1 -0
  37. package/dist/src/room/Room.d.ts.map +1 -1
  38. package/dist/src/room/data-track/depacketizer.d.ts.map +1 -1
  39. package/dist/src/room/data-track/frame.d.ts +1 -0
  40. package/dist/src/room/data-track/frame.d.ts.map +1 -1
  41. package/dist/src/room/data-track/outgoing/types.d.ts +1 -0
  42. package/dist/src/room/data-track/outgoing/types.d.ts.map +1 -1
  43. package/dist/src/room/data-track/packet/extensions.d.ts +1 -0
  44. package/dist/src/room/data-track/packet/extensions.d.ts.map +1 -1
  45. package/dist/src/room/data-track/packet/index.d.ts +1 -0
  46. package/dist/src/room/data-track/packet/index.d.ts.map +1 -1
  47. package/dist/src/room/data-track/packet/serializable.d.ts +1 -0
  48. package/dist/src/room/data-track/packet/serializable.d.ts.map +1 -1
  49. package/dist/src/room/participant/LocalParticipant.d.ts +1 -0
  50. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  51. package/dist/src/room/participant/Participant.d.ts +1 -0
  52. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  53. package/dist/src/room/track/Track.d.ts +1 -0
  54. package/dist/src/room/track/Track.d.ts.map +1 -1
  55. package/dist/src/room/track/record.d.ts.map +1 -1
  56. package/dist/src/room/utils.d.ts +1 -0
  57. package/dist/src/room/utils.d.ts.map +1 -1
  58. package/dist/src/type-polyfills/non-shared-typed-arrays.d.ts +2 -0
  59. package/dist/src/type-polyfills/non-shared-typed-arrays.d.ts.map +1 -0
  60. package/dist/src/utils/dataPacketBuffer.d.ts +1 -0
  61. package/dist/src/utils/dataPacketBuffer.d.ts.map +1 -1
  62. package/dist/ts4.2/e2ee/E2eeManager.d.ts +1 -0
  63. package/dist/ts4.2/e2ee/types.d.ts +1 -0
  64. package/dist/ts4.2/e2ee/utils.d.ts +1 -0
  65. package/dist/ts4.2/e2ee/worker/DataCryptor.d.ts +1 -0
  66. package/dist/ts4.2/e2ee/worker/FrameCryptor.d.ts +1 -0
  67. package/dist/ts4.2/e2ee/worker/naluUtils.d.ts +1 -0
  68. package/dist/ts4.2/e2ee/worker/sifPayload.d.ts +1 -0
  69. package/dist/ts4.2/frameMetadata/frameMetadata.d.ts +1 -0
  70. package/dist/ts4.2/frameMetadata/types.d.ts +1 -0
  71. package/dist/ts4.2/room/PCTransport.d.ts +40 -1
  72. package/dist/ts4.2/room/RTCEngine.d.ts +1 -0
  73. package/dist/ts4.2/room/Room.d.ts +1 -0
  74. package/dist/ts4.2/room/data-track/frame.d.ts +1 -0
  75. package/dist/ts4.2/room/data-track/outgoing/types.d.ts +1 -0
  76. package/dist/ts4.2/room/data-track/packet/extensions.d.ts +1 -0
  77. package/dist/ts4.2/room/data-track/packet/index.d.ts +1 -0
  78. package/dist/ts4.2/room/data-track/packet/serializable.d.ts +1 -0
  79. package/dist/ts4.2/room/participant/LocalParticipant.d.ts +1 -0
  80. package/dist/ts4.2/room/participant/Participant.d.ts +1 -0
  81. package/dist/ts4.2/room/track/Track.d.ts +1 -0
  82. package/dist/ts4.2/room/utils.d.ts +1 -0
  83. package/dist/ts4.2/type-polyfills/non-shared-typed-arrays.d.ts +2 -0
  84. package/dist/ts4.2/utils/dataPacketBuffer.d.ts +1 -0
  85. package/package.json +2 -2
  86. package/src/api/SignalClient.ts +1 -0
  87. package/src/e2ee/E2eeManager.ts +3 -1
  88. package/src/e2ee/types.ts +1 -0
  89. package/src/e2ee/utils.ts +1 -0
  90. package/src/e2ee/worker/DataCryptor.ts +1 -0
  91. package/src/e2ee/worker/FrameCryptor.test.ts +1 -0
  92. package/src/e2ee/worker/FrameCryptor.ts +1 -0
  93. package/src/e2ee/worker/ParticipantKeyHandler.test.ts +1 -0
  94. package/src/e2ee/worker/e2ee.worker.ts +1 -0
  95. package/src/e2ee/worker/naluUtils.ts +1 -0
  96. package/src/e2ee/worker/sifPayload.ts +1 -0
  97. package/src/frameMetadata/frameMetadata.test.ts +83 -0
  98. package/src/frameMetadata/frameMetadata.ts +8 -0
  99. package/src/frameMetadata/types.ts +1 -0
  100. package/src/room/PCTransport.test.ts +150 -0
  101. package/src/room/PCTransport.ts +113 -0
  102. package/src/room/RTCEngine.ts +1 -0
  103. package/src/room/Room.ts +1 -0
  104. package/src/room/data-track/depacketizer.ts +1 -0
  105. package/src/room/data-track/frame.ts +1 -0
  106. package/src/room/data-track/outgoing/types.ts +1 -0
  107. package/src/room/data-track/packet/extensions.ts +1 -0
  108. package/src/room/data-track/packet/index.ts +1 -0
  109. package/src/room/data-track/packet/serializable.ts +1 -0
  110. package/src/room/participant/LocalParticipant.ts +1 -0
  111. package/src/room/participant/Participant.ts +1 -0
  112. package/src/room/track/Track.ts +1 -0
  113. package/src/room/track/record.ts +1 -0
  114. package/src/room/utils.ts +1 -0
  115. package/src/type-polyfills/{non-shared-typed-arrays.d.ts → non-shared-typed-arrays.ts} +6 -1
  116. package/src/utils/dataPacketBuffer.ts +2 -0
@@ -0,0 +1,150 @@
1
+ import { type MediaDescription, parse } from 'sdp-transform';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { conformBundledCodecFmtp, placeholderMidsFromTransceivers } from './PCTransport';
4
+
5
+ /** Parse the `key[=value]` pairs of an fmtp config into a comparable set. */
6
+ const paramSet = (config: string) => new Set(config.split(';').filter(Boolean));
7
+
8
+ const fmtpOf = (media: MediaDescription[], mid: string, payload: number) => {
9
+ const m = media.find((section) => `${section.mid}` === mid)!;
10
+ return m.fmtp.find((f) => f.payload === payload)?.config;
11
+ };
12
+
13
+ /** Predicate for conformBundledCodecFmtp based on an explicit set of mids. */
14
+ const placeholders = (mids: string[]) => {
15
+ const set = new Set(mids);
16
+ return (m: MediaDescription) => set.has(`${m.mid}`);
17
+ };
18
+
19
+ // One publisher bundle: a published mic + camera (real sends, with msid/ssrc)
20
+ // and their pre-populated recvonly placeholders.
21
+ const PUBLISHER_SDP = `v=0
22
+ o=- 0 0 IN IP4 127.0.0.1
23
+ s=-
24
+ t=0 0
25
+ a=group:BUNDLE 0 1 2 3
26
+ m=audio 9 UDP/TLS/RTP/SAVPF 111
27
+ c=IN IP4 0.0.0.0
28
+ a=mid:0
29
+ a=sendonly
30
+ a=msid:s mic
31
+ a=ssrc:1111 cname:a
32
+ a=rtpmap:111 opus/48000/2
33
+ a=fmtp:111 minptime=10;useinbandfec=1;usedtx=1
34
+ m=audio 9 UDP/TLS/RTP/SAVPF 111
35
+ c=IN IP4 0.0.0.0
36
+ a=mid:1
37
+ a=recvonly
38
+ a=rtpmap:111 opus/48000/2
39
+ a=fmtp:111 minptime=10;useinbandfec=1
40
+ m=video 9 UDP/TLS/RTP/SAVPF 49
41
+ c=IN IP4 0.0.0.0
42
+ a=mid:2
43
+ a=sendonly
44
+ a=msid:s cam
45
+ a=ssrc:2222 cname:b
46
+ a=rtpmap:49 H265/90000
47
+ a=fmtp:49 level-id=186;profile-id=1;tier-flag=0;tx-mode=SRST
48
+ m=video 9 UDP/TLS/RTP/SAVPF 49
49
+ c=IN IP4 0.0.0.0
50
+ a=mid:3
51
+ a=recvonly
52
+ a=rtpmap:49 H265/90000
53
+ a=fmtp:49 level-id=180;profile-id=1;tier-flag=0;tx-mode=SRST`;
54
+
55
+ describe('placeholderMidsFromTransceivers', () => {
56
+ const tr = (mid: string | null, track: unknown) =>
57
+ ({ mid, sender: { track } }) as unknown as RTCRtpTransceiver;
58
+
59
+ it('includes transceivers with a mid and no outgoing track', () => {
60
+ const mids = placeholderMidsFromTransceivers([
61
+ tr('0', {}), // real send
62
+ tr('1', null), // pre-populated placeholder
63
+ tr('2', null), // reverted after unpublish (msid may linger in SDP, but no track)
64
+ tr(null, null), // not yet negotiated — no mid, excluded
65
+ ]);
66
+ expect(mids).toEqual(new Set(['1', '2']));
67
+ });
68
+ });
69
+
70
+ describe('conformBundledCodecFmtp', () => {
71
+ it('copies opus and H.265 fmtp from real sections onto placeholders', () => {
72
+ const { media } = parse(PUBLISHER_SDP);
73
+
74
+ conformBundledCodecFmtp(media, placeholders(['1', '3']));
75
+
76
+ expect(fmtpOf(media, '1', 111)).toBe(fmtpOf(media, '0', 111));
77
+ expect(paramSet(fmtpOf(media, '1', 111)!)).toContain('usedtx=1');
78
+ expect(fmtpOf(media, '3', 49)).toBe(fmtpOf(media, '2', 49));
79
+ expect(paramSet(fmtpOf(media, '3', 49)!)).toContain('level-id=186');
80
+ });
81
+
82
+ it('never rewrites the real (non-placeholder) sections', () => {
83
+ const { media } = parse(PUBLISHER_SDP);
84
+
85
+ conformBundledCodecFmtp(media, placeholders(['1', '3']));
86
+
87
+ expect(fmtpOf(media, '0', 111)).toBe('minptime=10;useinbandfec=1;usedtx=1');
88
+ expect(paramSet(fmtpOf(media, '2', 49)!)).toContain('level-id=186');
89
+ });
90
+
91
+ it('converges divergent placeholders even when no real section declares the payload', () => {
92
+ // Two placeholders that disagree (a reverted one kept level 186, a fresh one
93
+ // has 180) with no active send present.
94
+ const { media } = parse(`v=0
95
+ o=- 0 0 IN IP4 127.0.0.1
96
+ s=-
97
+ t=0 0
98
+ a=group:BUNDLE 10 11
99
+ m=video 9 UDP/TLS/RTP/SAVPF 49
100
+ a=mid:10
101
+ a=rtpmap:49 H265/90000
102
+ a=fmtp:49 level-id=186;profile-id=1;tier-flag=0;tx-mode=SRST
103
+ m=video 9 UDP/TLS/RTP/SAVPF 49
104
+ a=mid:11
105
+ a=rtpmap:49 H265/90000
106
+ a=fmtp:49 level-id=180;profile-id=1;tier-flag=0;tx-mode=SRST`);
107
+
108
+ conformBundledCodecFmtp(media, placeholders(['10', '11']));
109
+
110
+ expect(fmtpOf(media, '10', 49)).toBe(fmtpOf(media, '11', 49));
111
+ });
112
+
113
+ it('conforms a reverted section that kept its msid (second-publish case)', () => {
114
+ // The real second publish: a live camera send (level 186), plus the section
115
+ // left over from the first (unpublished) track. Chrome keeps that section's
116
+ // `a=msid`/`a=ssrc` even though it no longer sends, so it must be identified
117
+ // as a placeholder by its transceiver (no track), not by SDP.
118
+ const { media } = parse(`v=0
119
+ o=- 0 0 IN IP4 127.0.0.1
120
+ s=-
121
+ t=0 0
122
+ a=group:BUNDLE 3 4 5
123
+ m=video 9 UDP/TLS/RTP/SAVPF 49
124
+ a=mid:3
125
+ a=sendonly
126
+ a=msid:s cam
127
+ a=ssrc:9 cname:c
128
+ a=rtpmap:49 H265/90000
129
+ a=fmtp:49 level-id=186;profile-id=1;tier-flag=0;tx-mode=SRST
130
+ m=video 9 UDP/TLS/RTP/SAVPF 49
131
+ a=mid:4
132
+ a=sendonly
133
+ a=msid:s stale
134
+ a=ssrc:8 cname:d
135
+ a=rtpmap:49 H265/90000
136
+ a=fmtp:49 level-id=180;profile-id=1;tier-flag=0;tx-mode=SRST
137
+ m=video 9 UDP/TLS/RTP/SAVPF 49
138
+ a=mid:5
139
+ a=recvonly
140
+ a=rtpmap:49 H265/90000
141
+ a=fmtp:49 level-id=180;profile-id=1;tier-flag=0;tx-mode=SRST`);
142
+
143
+ // mid 4 still has msid/ssrc in the SDP, but its transceiver has no track.
144
+ conformBundledCodecFmtp(media, placeholders(['4', '5']));
145
+
146
+ expect(paramSet(fmtpOf(media, '3', 49)!)).toContain('level-id=186'); // real send untouched
147
+ expect(fmtpOf(media, '4', 49)).toBe(fmtpOf(media, '3', 49)); // stale conformed
148
+ expect(fmtpOf(media, '5', 49)).toBe(fmtpOf(media, '3', 49)); // placeholder conformed
149
+ });
150
+ });
@@ -234,6 +234,17 @@ export default class PCTransport extends (EventEmitter as new () => TypedEmitter
234
234
  });
235
235
  }
236
236
  });
237
+ // The server's answer sets per-track codec params (e.g. opus `usedtx`) on
238
+ // the sections mapped to a published track, but leaves the pre-populated
239
+ // recvonly placeholder sections with defaults. Conform the placeholders so
240
+ // each shared payload type is consistent across the bundle, otherwise
241
+ // libwebrtc flags a "bundled payload type collision".
242
+ const placeholderMids = this.getPlaceholderMids();
243
+ if (placeholderMids.size > 0) {
244
+ conformBundledCodecFmtp(sdpParsed.media, (media) =>
245
+ placeholderMids.has(getMidString(media.mid!)),
246
+ );
247
+ }
237
248
  mungedSDP = write(sdpParsed);
238
249
  }
239
250
  await this.setMungedSDP(sd, mungedSDP, true);
@@ -400,6 +411,17 @@ export default class PCTransport extends (EventEmitter as new () => TypedEmitter
400
411
  });
401
412
  }
402
413
  });
414
+ // Conform the placeholder sections (pre-populated, or reverted after an
415
+ // unpublish) so every shared payload type carries identical fmtp across the
416
+ // bundle, otherwise libwebrtc flags a "bundled payload type collision".
417
+ // Detection is by transceiver (mids are stable across renegotiations) since
418
+ // an unpublished section keeps its `a=msid`.
419
+ const placeholderMids = this.getPlaceholderMids();
420
+ if (placeholderMids.size > 0) {
421
+ conformBundledCodecFmtp(sdpParsed.media, (media) =>
422
+ placeholderMids.has(getMidString(media.mid!)),
423
+ );
424
+ }
403
425
  if (this.latestOfferId > offerId) {
404
426
  this.log.warn('latestOfferId mismatch', {
405
427
  ...this.logContext,
@@ -428,6 +450,17 @@ export default class PCTransport extends (EventEmitter as new () => TypedEmitter
428
450
  return answer;
429
451
  }
430
452
 
453
+ /**
454
+ * Returns the mids of transceivers that carry no outgoing track on this
455
+ * (publisher) connection: the pre-populated placeholders added by
456
+ * `RTCEngine.applyInitialPublisherLayout`, plus any transceiver that was used
457
+ * for a track and reverted on unpublish. Their codec fmtp is conformed to the
458
+ * published tracks so a shared payload type stays consistent across the bundle.
459
+ */
460
+ private getPlaceholderMids(): Set<string> {
461
+ return placeholderMidsFromTransceivers(this._pc?.getTransceivers() ?? []);
462
+ }
463
+
431
464
  createDataChannel(label: string, dataChannelDict: RTCDataChannelInit) {
432
465
  return this.pc.createDataChannel(label, dataChannelDict);
433
466
  }
@@ -703,6 +736,86 @@ function ensureAudioNackAndStereo(
703
736
  }
704
737
  }
705
738
 
739
+ /**
740
+ * Returns the mids of transceivers that carry no outgoing track: the
741
+ * pre-populated placeholders added by `RTCEngine.applyInitialPublisherLayout`,
742
+ * plus any transceiver that was used for a track and reverted on unpublish. The
743
+ * `sender.track` check is the reliable signal — an unpublished section keeps its
744
+ * `a=msid` (and its stale send-derived fmtp), so it can't be told apart from a
745
+ * real send by SDP alone. Transceiver mids are stable across renegotiations, so
746
+ * this works for every offer/answer after the first.
747
+ * @internal
748
+ */
749
+ export function placeholderMidsFromTransceivers(
750
+ transceivers: readonly RTCRtpTransceiver[],
751
+ ): Set<string> {
752
+ const mids = new Set<string>();
753
+ for (const transceiver of transceivers) {
754
+ if (transceiver.mid && !transceiver.sender.track) {
755
+ mids.add(transceiver.mid);
756
+ }
757
+ }
758
+ return mids;
759
+ }
760
+
761
+ /**
762
+ * Within a BUNDLE group a payload type must map to identical codec parameters
763
+ * across every m-line. When the same payload type carries different fmtp between
764
+ * sections — e.g. opus `usedtx=1` on the published microphone but not on the
765
+ * pre-populated recvonly placeholders, or H.265 with different `level-id` between
766
+ * a published video track and a placeholder — libwebrtc flags a "bundled payload
767
+ * type collision".
768
+ *
769
+ * Rewrite the placeholder sections so every shared payload type carries the
770
+ * same fmtp. Real (non-placeholder) sections always win the canonical value, so
771
+ * a published track's encoder parameters are never altered. When no real
772
+ * section declares a payload type — e.g. a placeholder that was reused for a
773
+ * track and then reverted to recvonly keeps its send-derived `level-id` while
774
+ * fresh placeholders use the default — the placeholders still converge on the
775
+ * first value seen, so two placeholders can't disagree either. Only placeholder
776
+ * sections are ever rewritten, and it is codec-agnostic (opus, H.265, ...).
777
+ * `isPlaceholder` identifies the sections to conform.
778
+ * @internal
779
+ */
780
+ export function conformBundledCodecFmtp(
781
+ media: MediaDescription[],
782
+ isPlaceholder: (media: MediaDescription) => boolean,
783
+ ) {
784
+ // Canonical fmtp per payload type. Payload types are unique within a BUNDLE
785
+ // group, so keying by payload alone (across audio and video) is safe. A real
786
+ // section's value always takes precedence; otherwise the first placeholder
787
+ // value seen is used so divergent placeholders still converge.
788
+ const canonicalByPayload = new Map<number, string>();
789
+ const fromRealSection = new Set<number>();
790
+ for (const m of media) {
791
+ const placeholder = isPlaceholder(m);
792
+ for (const fmtp of m.fmtp ?? []) {
793
+ if (!placeholder) {
794
+ canonicalByPayload.set(fmtp.payload, fmtp.config);
795
+ fromRealSection.add(fmtp.payload);
796
+ } else if (!canonicalByPayload.has(fmtp.payload)) {
797
+ canonicalByPayload.set(fmtp.payload, fmtp.config);
798
+ }
799
+ }
800
+ }
801
+ if (canonicalByPayload.size === 0) {
802
+ return;
803
+ }
804
+
805
+ // Conform placeholder sections to the canonical fmtp for each shared payload.
806
+ for (const m of media) {
807
+ if (!isPlaceholder(m)) {
808
+ continue;
809
+ }
810
+ for (const fmtp of m.fmtp ?? []) {
811
+ const config = canonicalByPayload.get(fmtp.payload);
812
+ if (config !== undefined && fmtp.config !== config) {
813
+ fmtp.config = config;
814
+ }
815
+ }
816
+ }
817
+ }
818
+
706
819
  function extractStereoAndNackAudioFromOffer(offer: RTCSessionDescriptionInit): {
707
820
  stereoMids: string[];
708
821
  nackMids: string[];
@@ -61,6 +61,7 @@ import {
61
61
  } from '../frameMetadata/utils';
62
62
  import log, { LoggerNames, getLogger } from '../logger';
63
63
  import type { InternalRoomOptions } from '../options';
64
+ import type { NonSharedUint8Array } from '../type-polyfills/non-shared-typed-arrays';
64
65
  import TypedPromise from '../utils/TypedPromise';
65
66
  import { DataPacketBuffer } from '../utils/dataPacketBuffer';
66
67
  import { TTLMap } from '../utils/ttlmap';
package/src/room/Room.ts CHANGED
@@ -46,6 +46,7 @@ import type {
46
46
  RoomConnectOptions,
47
47
  RoomOptions,
48
48
  } from '../options';
49
+ import type { NonSharedUint8Array } from '../type-polyfills/non-shared-typed-arrays';
49
50
  import TypedPromise from '../utils/TypedPromise';
50
51
  import { getBrowser } from '../utils/browserParser';
51
52
  import { CLIENT_PROTOCOL_DEFAULT } from '../version';
@@ -1,5 +1,6 @@
1
1
  import { type Throws } from '@livekit/throws-transformer/throws';
2
2
  import { LoggerNames, getLogger } from '../../logger';
3
+ import type { NonSharedUint8Array } from '../../type-polyfills/non-shared-typed-arrays';
3
4
  import { LivekitReasonedError } from '../errors';
4
5
  import { type DataTrackFrameInternal } from './frame';
5
6
  import { DataTrackPacket, FrameMarker } from './packet';
@@ -1,3 +1,4 @@
1
+ import type { NonSharedUint8Array } from '../../type-polyfills/non-shared-typed-arrays';
1
2
  import { DataTrackExtensions, DataTrackUserTimestampExtension } from './packet/extensions';
2
3
 
3
4
  /** A pair of payload bytes and packet extensions which can be fed into a {@link DataTrackPacketizer}. */
@@ -1,3 +1,4 @@
1
+ import type { NonSharedUint8Array } from '../../../type-polyfills/non-shared-typed-arrays';
1
2
  import type LocalDataTrack from '../LocalDataTrack';
2
3
  import { type DataTrackHandle } from '../handle';
3
4
  import { type DataTrackInfo, type DataTrackSid } from '../types';
@@ -1,4 +1,5 @@
1
1
  import { type Throws } from '@livekit/throws-transformer/throws';
2
+ import type { NonSharedUint8Array } from '../../../type-polyfills/non-shared-typed-arrays';
2
3
  import { coerceToDataView } from '../utils';
3
4
  import { EXT_TAG_PADDING, U8_LENGTH_BYTES, U64_LENGTH_BYTES } from './constants';
4
5
  import { DataTrackDeserializeError, DataTrackDeserializeErrorReason } from './errors';
@@ -1,4 +1,5 @@
1
1
  import { type Throws } from '@livekit/throws-transformer/throws';
2
+ import type { NonSharedUint8Array } from '../../../type-polyfills/non-shared-typed-arrays';
2
3
  import { DataTrackHandle, DataTrackHandleError, DataTrackHandleErrorReason } from '../handle';
3
4
  import {
4
5
  DataTrackTimestamp,
@@ -1,4 +1,5 @@
1
1
  import { type Throws } from '@livekit/throws-transformer/throws';
2
+ import type { NonSharedUint8Array } from '../../../type-polyfills/non-shared-typed-arrays';
2
3
  import { DataTrackSerializeError } from './errors';
3
4
 
4
5
  /** An abstract class implementing common behavior related to data track binary serialization. */
@@ -29,6 +29,7 @@ import {
29
29
  isFrameMetadataSupported,
30
30
  } from '../../frameMetadata/utils';
31
31
  import type { InternalRoomOptions } from '../../options';
32
+ import type { NonSharedUint8Array } from '../../type-polyfills/non-shared-typed-arrays';
32
33
  import TypedPromise from '../../utils/TypedPromise';
33
34
  import { PCTransportState } from '../PCTransportManager';
34
35
  import type RTCEngine from '../RTCEngine';
@@ -12,6 +12,7 @@ import {
12
12
  import { EventEmitter } from 'events';
13
13
  import type TypedEmitter from 'typed-emitter';
14
14
  import log, { LoggerNames, type StructuredLogger, getLogger } from '../../logger';
15
+ import type { NonSharedUint8Array } from '../../type-polyfills/non-shared-typed-arrays';
15
16
  import { ParticipantEvent, TrackEvent } from '../events';
16
17
  import type LocalTrackPublication from '../track/LocalTrackPublication';
17
18
  import type LocalVideoTrack from '../track/LocalVideoTrack';
@@ -9,6 +9,7 @@ import { EventEmitter } from 'events';
9
9
  import type TypedEventEmitter from 'typed-emitter';
10
10
  import type { SignalClient } from '../../api/SignalClient';
11
11
  import log, { LoggerNames, type StructuredLogger, getLogger } from '../../logger';
12
+ import type { NonSharedUint8Array } from '../../type-polyfills/non-shared-typed-arrays';
12
13
  import { TrackEvent } from '../events';
13
14
  import type { LoggerOptions } from '../types';
14
15
  import { isFireFox, isSafari, isWeb } from '../utils';
@@ -1,3 +1,4 @@
1
+ import type { NonSharedUint8Array } from '../../type-polyfills/non-shared-typed-arrays';
1
2
  import type LocalTrack from './LocalTrack';
2
3
 
3
4
  // Check if MediaRecorder is available
package/src/room/utils.ts CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  Transcription as TranscriptionModel,
8
8
  } from '@livekit/protocol';
9
9
  import { type Throws } from '@livekit/throws-transformer/throws';
10
+ import type { NonSharedUint8Array } from '../type-polyfills/non-shared-typed-arrays';
10
11
  import TypedPromise from '../utils/TypedPromise';
11
12
  import { getBrowser } from '../utils/browserParser';
12
13
  import type { BrowserDetails } from '../utils/browserParser';
@@ -3,4 +3,9 @@
3
3
  // only accept the non-shared variant `Uint8Array<ArrayBuffer>`. Using `ReturnType<typeof Uint8Array.from>`
4
4
  // resolves to that non-shared variant on TS versions that support the generic, while remaining
5
5
  // equivalent to plain `Uint8Array` on older versions — so this alias works across the range we support.
6
- type NonSharedUint8Array = ReturnType<typeof Uint8Array.from>;
6
+ //
7
+ // Exported as a normal type (rather than an ambient global) so it is emitted into the published `dist`
8
+ // types and imported explicitly wherever it is used. An earlier ambient `.d.ts` declaration was resolved
9
+ // during our own build but never shipped, so consumers' type-checkers (and tools like API Extractor)
10
+ // failed with "Cannot find name 'NonSharedUint8Array'" on our emitted `.d.ts` files.
11
+ export type NonSharedUint8Array = ReturnType<typeof Uint8Array.from>;
@@ -1,3 +1,5 @@
1
+ import type { NonSharedUint8Array } from '../type-polyfills/non-shared-typed-arrays';
2
+
1
3
  export interface DataPacketItem {
2
4
  data: NonSharedUint8Array;
3
5
  sequence: number;