livekit-client 2.10.0 → 2.11.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.
@@ -11027,6 +11027,7 @@ var EngineEvent;
11027
11027
  EngineEvent["LocalTrackSubscribed"] = "localTrackSubscribed";
11028
11028
  EngineEvent["Offline"] = "offline";
11029
11029
  EngineEvent["SignalRequestResponse"] = "signalRequestResponse";
11030
+ EngineEvent["SignalConnected"] = "signalConnected";
11030
11031
  })(EngineEvent || (EngineEvent = {}));
11031
11032
  var TrackEvent;
11032
11033
  (function (TrackEvent) {
@@ -11185,7 +11186,7 @@ function getOSVersion(ua) {
11185
11186
  return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
11186
11187
  }
11187
11188
 
11188
- var version$1 = "2.10.0";
11189
+ var version$1 = "2.11.1";
11189
11190
 
11190
11191
  const version = version$1;
11191
11192
  const protocolVersion = 15;
@@ -12201,14 +12202,18 @@ function mergeDefaultOptions(options, audioDefaults, videoDefaults) {
12201
12202
  // use defaults
12202
12203
  if (clonedOptions.audio) {
12203
12204
  mergeObjectWithoutOverwriting(clonedOptions.audio, audioDefaults);
12204
- (_b = (_d = clonedOptions.audio).deviceId) !== null && _b !== void 0 ? _b : _d.deviceId = 'default';
12205
+ (_b = (_d = clonedOptions.audio).deviceId) !== null && _b !== void 0 ? _b : _d.deviceId = {
12206
+ ideal: 'default'
12207
+ };
12205
12208
  if (audioProcessor || defaultAudioProcessor) {
12206
12209
  clonedOptions.audio.processor = audioProcessor !== null && audioProcessor !== void 0 ? audioProcessor : defaultAudioProcessor;
12207
12210
  }
12208
12211
  }
12209
12212
  if (clonedOptions.video) {
12210
12213
  mergeObjectWithoutOverwriting(clonedOptions.video, videoDefaults);
12211
- (_c = (_e = clonedOptions.video).deviceId) !== null && _c !== void 0 ? _c : _e.deviceId = 'default';
12214
+ (_c = (_e = clonedOptions.video).deviceId) !== null && _c !== void 0 ? _c : _e.deviceId = {
12215
+ ideal: 'default'
12216
+ };
12212
12217
  if (videoProcessor || defaultVideoProcessor) {
12213
12218
  clonedOptions.video.processor = videoProcessor !== null && videoProcessor !== void 0 ? videoProcessor : defaultVideoProcessor;
12214
12219
  }
@@ -12242,10 +12247,14 @@ function constraintsForOptions(options) {
12242
12247
  }
12243
12248
  });
12244
12249
  constraints.video = videoOptions;
12245
- (_a = (_c = constraints.video).deviceId) !== null && _a !== void 0 ? _a : _c.deviceId = 'default';
12250
+ (_a = (_c = constraints.video).deviceId) !== null && _a !== void 0 ? _a : _c.deviceId = {
12251
+ ideal: 'default'
12252
+ };
12246
12253
  } else {
12247
12254
  constraints.video = options.video ? {
12248
- deviceId: 'default'
12255
+ deviceId: {
12256
+ ideal: 'default'
12257
+ }
12249
12258
  } : false;
12250
12259
  }
12251
12260
  } else {
@@ -12254,10 +12263,14 @@ function constraintsForOptions(options) {
12254
12263
  if (options.audio) {
12255
12264
  if (typeof options.audio === 'object') {
12256
12265
  constraints.audio = options.audio;
12257
- (_b = (_d = constraints.audio).deviceId) !== null && _b !== void 0 ? _b : _d.deviceId = 'default';
12266
+ (_b = (_d = constraints.audio).deviceId) !== null && _b !== void 0 ? _b : _d.deviceId = {
12267
+ ideal: 'default'
12268
+ };
12258
12269
  } else {
12259
12270
  constraints.audio = {
12260
- deviceId: 'default'
12271
+ deviceId: {
12272
+ ideal: 'default'
12273
+ }
12261
12274
  };
12262
12275
  }
12263
12276
  } else {
@@ -12862,7 +12875,9 @@ class DeviceManager {
12862
12875
  const permissionsToAcquire = {
12863
12876
  video: kind !== 'audioinput' && kind !== 'audiooutput',
12864
12877
  audio: kind !== 'videoinput' && {
12865
- deviceId: 'default'
12878
+ deviceId: {
12879
+ ideal: 'default'
12880
+ }
12866
12881
  }
12867
12882
  };
12868
12883
  const stream = yield navigator.mediaDevices.getUserMedia(permissionsToAcquire);
@@ -12961,15 +12976,12 @@ function createValidateUrl(rtcWsUrl) {
12961
12976
  const urlObj = new URL(toHttpUrl(rtcWsUrl));
12962
12977
  return appendUrlPath(urlObj, 'validate');
12963
12978
  }
12964
- function ensureTrailingSlash(url) {
12965
- return url.endsWith('/') ? url : "".concat(url, "/");
12979
+ function ensureTrailingSlash(path) {
12980
+ return path.endsWith('/') ? path : "".concat(path, "/");
12966
12981
  }
12967
12982
  function appendUrlPath(urlObj, path) {
12968
- const result = "".concat(urlObj.protocol, "//").concat(urlObj.host).concat(ensureTrailingSlash(urlObj.pathname)).concat(path);
12969
- if (urlObj.searchParams.size > 0) {
12970
- return "".concat(result, "?").concat(urlObj.searchParams.toString());
12971
- }
12972
- return result;
12983
+ urlObj.pathname = "".concat(ensureTrailingSlash(urlObj.pathname)).concat(path);
12984
+ return urlObj.toString();
12973
12985
  }
12974
12986
 
12975
12987
  const passThroughQueueSignals = ['syncState', 'trickle', 'offer', 'answer', 'simulate', 'leave'];
@@ -14959,14 +14971,18 @@ const publishDefaults = {
14959
14971
  backupCodec: true
14960
14972
  };
14961
14973
  const audioDefaults = {
14962
- deviceId: 'default',
14974
+ deviceId: {
14975
+ ideal: 'default'
14976
+ },
14963
14977
  autoGainControl: true,
14964
14978
  echoCancellation: true,
14965
14979
  noiseSuppression: true,
14966
14980
  voiceIsolation: true
14967
14981
  };
14968
14982
  const videoDefaults = {
14969
- deviceId: 'default',
14983
+ deviceId: {
14984
+ ideal: 'default'
14985
+ },
14970
14986
  resolution: VideoPresets.h720.resolution
14971
14987
  };
14972
14988
  const roomOptionDefaults = {
@@ -17360,6 +17376,10 @@ class RTCEngine extends eventsExports.EventEmitter {
17360
17376
  this.negotiate();
17361
17377
  }
17362
17378
  this.clientConfiguration = joinResponse.clientConfiguration;
17379
+ // emit signal connected event after a short delay to allow for join response to be processed on room
17380
+ setTimeout(() => {
17381
+ this.emit(EngineEvent.SignalConnected);
17382
+ }, 10);
17363
17383
  return joinResponse;
17364
17384
  } catch (e) {
17365
17385
  if (e instanceof ConnectionError) {
@@ -18553,6 +18573,7 @@ class BaseStreamWriter {
18553
18573
  }
18554
18574
  }
18555
18575
  class TextStreamWriter extends BaseStreamWriter {}
18576
+ class ByteStreamWriter extends BaseStreamWriter {}
18556
18577
 
18557
18578
  class RemoteTrack extends Track {
18558
18579
  constructor(mediaTrack, sid, kind, receiver, loggerOptions) {
@@ -19413,6 +19434,176 @@ class LocalTrackPublication extends TrackPublication {
19413
19434
  }
19414
19435
  }
19415
19436
 
19437
+ /**
19438
+ * Creates a local video and audio track at the same time. When acquiring both
19439
+ * audio and video tracks together, it'll display a single permission prompt to
19440
+ * the user instead of two separate ones.
19441
+ * @param options
19442
+ */
19443
+ function createLocalTracks(options, loggerOptions) {
19444
+ return __awaiter(this, void 0, void 0, function* () {
19445
+ // set default options to true
19446
+ const internalOptions = Object.assign({}, options !== null && options !== void 0 ? options : {});
19447
+ let attemptExactMatch = false;
19448
+ let retryAudioOptions = options === null || options === void 0 ? void 0 : options.audio;
19449
+ let retryVideoOptions = options === null || options === void 0 ? void 0 : options.video;
19450
+ // if the user passes a device id as a string, we default to exact match
19451
+ if (internalOptions.audio && typeof internalOptions.audio === 'object' && typeof internalOptions.audio.deviceId === 'string') {
19452
+ const deviceId = internalOptions.audio.deviceId;
19453
+ internalOptions.audio.deviceId = {
19454
+ exact: deviceId
19455
+ };
19456
+ attemptExactMatch = true;
19457
+ retryAudioOptions = Object.assign(Object.assign({}, internalOptions.audio), {
19458
+ deviceId: {
19459
+ ideal: deviceId
19460
+ }
19461
+ });
19462
+ }
19463
+ if (internalOptions.video && typeof internalOptions.video === 'object' && typeof internalOptions.video.deviceId === 'string') {
19464
+ const deviceId = internalOptions.video.deviceId;
19465
+ internalOptions.video.deviceId = {
19466
+ exact: deviceId
19467
+ };
19468
+ attemptExactMatch = true;
19469
+ retryVideoOptions = Object.assign(Object.assign({}, internalOptions.video), {
19470
+ deviceId: {
19471
+ ideal: deviceId
19472
+ }
19473
+ });
19474
+ }
19475
+ // TODO if internal options don't have device Id specified, set it to 'default'
19476
+ if (internalOptions.audio === true || typeof internalOptions.audio === 'object' && !internalOptions.audio.deviceId) {
19477
+ internalOptions.audio = {
19478
+ deviceId: 'default'
19479
+ };
19480
+ }
19481
+ if (internalOptions.video === true || typeof internalOptions.video === 'object' && !internalOptions.video.deviceId) {
19482
+ internalOptions.video = {
19483
+ deviceId: 'default'
19484
+ };
19485
+ }
19486
+ const {
19487
+ audioProcessor,
19488
+ videoProcessor
19489
+ } = extractProcessorsFromOptions(internalOptions);
19490
+ const opts = mergeDefaultOptions(internalOptions, audioDefaults, videoDefaults);
19491
+ const constraints = constraintsForOptions(opts);
19492
+ // Keep a reference to the promise on DeviceManager and await it in getLocalDevices()
19493
+ // works around iOS Safari Bug https://bugs.webkit.org/show_bug.cgi?id=179363
19494
+ const mediaPromise = navigator.mediaDevices.getUserMedia(constraints);
19495
+ if (internalOptions.audio) {
19496
+ DeviceManager.userMediaPromiseMap.set('audioinput', mediaPromise);
19497
+ mediaPromise.catch(() => DeviceManager.userMediaPromiseMap.delete('audioinput'));
19498
+ }
19499
+ if (internalOptions.video) {
19500
+ DeviceManager.userMediaPromiseMap.set('videoinput', mediaPromise);
19501
+ mediaPromise.catch(() => DeviceManager.userMediaPromiseMap.delete('videoinput'));
19502
+ }
19503
+ try {
19504
+ const stream = yield mediaPromise;
19505
+ return yield Promise.all(stream.getTracks().map(mediaStreamTrack => __awaiter(this, void 0, void 0, function* () {
19506
+ const isAudio = mediaStreamTrack.kind === 'audio';
19507
+ let trackOptions = isAudio ? opts.audio : opts.video;
19508
+ if (typeof trackOptions === 'boolean' || !trackOptions) {
19509
+ trackOptions = {};
19510
+ }
19511
+ let trackConstraints;
19512
+ const conOrBool = isAudio ? constraints.audio : constraints.video;
19513
+ if (typeof conOrBool !== 'boolean') {
19514
+ trackConstraints = conOrBool;
19515
+ }
19516
+ // update the constraints with the device id the user gave permissions to in the permission prompt
19517
+ // otherwise each track restart (e.g. mute - unmute) will try to initialize the device again -> causing additional permission prompts
19518
+ const newDeviceId = mediaStreamTrack.getSettings().deviceId;
19519
+ if ((trackConstraints === null || trackConstraints === void 0 ? void 0 : trackConstraints.deviceId) && unwrapConstraint(trackConstraints.deviceId) !== newDeviceId) {
19520
+ trackConstraints.deviceId = newDeviceId;
19521
+ } else if (!trackConstraints) {
19522
+ trackConstraints = {
19523
+ deviceId: newDeviceId
19524
+ };
19525
+ }
19526
+ const track = mediaTrackToLocalTrack(mediaStreamTrack, trackConstraints, loggerOptions);
19527
+ if (track.kind === Track.Kind.Video) {
19528
+ track.source = Track.Source.Camera;
19529
+ } else if (track.kind === Track.Kind.Audio) {
19530
+ track.source = Track.Source.Microphone;
19531
+ }
19532
+ track.mediaStream = stream;
19533
+ if (isAudioTrack(track) && audioProcessor) {
19534
+ yield track.setProcessor(audioProcessor);
19535
+ } else if (isVideoTrack(track) && videoProcessor) {
19536
+ yield track.setProcessor(videoProcessor);
19537
+ }
19538
+ return track;
19539
+ })));
19540
+ } catch (e) {
19541
+ if (!attemptExactMatch) {
19542
+ throw e;
19543
+ }
19544
+ return createLocalTracks(Object.assign(Object.assign({}, options), {
19545
+ audio: retryAudioOptions,
19546
+ video: retryVideoOptions
19547
+ }), loggerOptions);
19548
+ }
19549
+ });
19550
+ }
19551
+ /**
19552
+ * Creates a [[LocalVideoTrack]] with getUserMedia()
19553
+ * @param options
19554
+ */
19555
+ function createLocalVideoTrack(options) {
19556
+ return __awaiter(this, void 0, void 0, function* () {
19557
+ const tracks = yield createLocalTracks({
19558
+ audio: false,
19559
+ video: options
19560
+ });
19561
+ return tracks[0];
19562
+ });
19563
+ }
19564
+ function createLocalAudioTrack(options) {
19565
+ return __awaiter(this, void 0, void 0, function* () {
19566
+ const tracks = yield createLocalTracks({
19567
+ audio: options,
19568
+ video: false
19569
+ });
19570
+ return tracks[0];
19571
+ });
19572
+ }
19573
+ /**
19574
+ * Creates a screen capture tracks with getDisplayMedia().
19575
+ * A LocalVideoTrack is always created and returned.
19576
+ * If { audio: true }, and the browser supports audio capture, a LocalAudioTrack is also created.
19577
+ */
19578
+ function createLocalScreenTracks(options) {
19579
+ return __awaiter(this, void 0, void 0, function* () {
19580
+ if (options === undefined) {
19581
+ options = {};
19582
+ }
19583
+ if (options.resolution === undefined && !isSafari17()) {
19584
+ options.resolution = ScreenSharePresets.h1080fps30.resolution;
19585
+ }
19586
+ if (navigator.mediaDevices.getDisplayMedia === undefined) {
19587
+ throw new DeviceUnsupportedError('getDisplayMedia not supported');
19588
+ }
19589
+ const constraints = screenCaptureToDisplayMediaStreamOptions(options);
19590
+ const stream = yield navigator.mediaDevices.getDisplayMedia(constraints);
19591
+ const tracks = stream.getVideoTracks();
19592
+ if (tracks.length === 0) {
19593
+ throw new TrackInvalidError('no video track found');
19594
+ }
19595
+ const screenVideo = new LocalVideoTrack(tracks[0], undefined, false);
19596
+ screenVideo.source = Track.Source.ScreenShare;
19597
+ const localTracks = [screenVideo];
19598
+ if (stream.getAudioTracks().length > 0) {
19599
+ const screenAudio = new LocalAudioTrack(stream.getAudioTracks()[0], undefined, false);
19600
+ screenAudio.source = Track.Source.ScreenShareAudio;
19601
+ localTracks.push(screenAudio);
19602
+ }
19603
+ return localTracks;
19604
+ });
19605
+ }
19606
+
19416
19607
  var ConnectionQuality;
19417
19608
  (function (ConnectionQuality) {
19418
19609
  ConnectionQuality["Excellent"] = "excellent";
@@ -20182,58 +20373,36 @@ class LocalParticipant extends Participant {
20182
20373
  var _a, _b;
20183
20374
  options !== null && options !== void 0 ? options : options = {};
20184
20375
  const mergedOptionsWithProcessors = mergeDefaultOptions(options, (_a = this.roomOptions) === null || _a === void 0 ? void 0 : _a.audioCaptureDefaults, (_b = this.roomOptions) === null || _b === void 0 ? void 0 : _b.videoCaptureDefaults);
20185
- const {
20186
- audioProcessor,
20187
- videoProcessor,
20188
- optionsWithoutProcessor
20189
- } = extractProcessorsFromOptions(mergedOptionsWithProcessors);
20190
- const constraints = constraintsForOptions(optionsWithoutProcessor);
20191
- let stream;
20192
20376
  try {
20193
- stream = yield navigator.mediaDevices.getUserMedia(constraints);
20377
+ const tracks = yield createLocalTracks(mergedOptionsWithProcessors, {
20378
+ loggerName: this.roomOptions.loggerName,
20379
+ loggerContextCb: () => this.logContext
20380
+ });
20381
+ const localTracks = tracks.map(track => {
20382
+ if (isAudioTrack(track)) {
20383
+ this.microphoneError = undefined;
20384
+ track.setAudioContext(this.audioContext);
20385
+ track.source = Track.Source.Microphone;
20386
+ this.emit(ParticipantEvent.AudioStreamAcquired);
20387
+ }
20388
+ if (isVideoTrack(track)) {
20389
+ this.cameraError = undefined;
20390
+ track.source = Track.Source.Camera;
20391
+ }
20392
+ return track;
20393
+ });
20394
+ return localTracks;
20194
20395
  } catch (err) {
20195
20396
  if (err instanceof Error) {
20196
- if (constraints.audio) {
20397
+ if (options.audio) {
20197
20398
  this.microphoneError = err;
20198
20399
  }
20199
- if (constraints.video) {
20400
+ if (options.video) {
20200
20401
  this.cameraError = err;
20201
20402
  }
20202
20403
  }
20203
20404
  throw err;
20204
20405
  }
20205
- if (constraints.audio) {
20206
- this.microphoneError = undefined;
20207
- this.emit(ParticipantEvent.AudioStreamAcquired);
20208
- }
20209
- if (constraints.video) {
20210
- this.cameraError = undefined;
20211
- }
20212
- return Promise.all(stream.getTracks().map(mediaStreamTrack => __awaiter(this, void 0, void 0, function* () {
20213
- const isAudio = mediaStreamTrack.kind === 'audio';
20214
- let trackConstraints;
20215
- const conOrBool = isAudio ? constraints.audio : constraints.video;
20216
- if (typeof conOrBool !== 'boolean') {
20217
- trackConstraints = conOrBool;
20218
- }
20219
- const track = mediaTrackToLocalTrack(mediaStreamTrack, trackConstraints, {
20220
- loggerName: this.roomOptions.loggerName,
20221
- loggerContextCb: () => this.logContext
20222
- });
20223
- if (track.kind === Track.Kind.Video) {
20224
- track.source = Track.Source.Camera;
20225
- } else if (track.kind === Track.Kind.Audio) {
20226
- track.source = Track.Source.Microphone;
20227
- track.setAudioContext(this.audioContext);
20228
- }
20229
- track.mediaStream = stream;
20230
- if (isAudioTrack(track) && audioProcessor) {
20231
- yield track.setProcessor(audioProcessor);
20232
- } else if (isVideoTrack(track) && videoProcessor) {
20233
- yield track.setProcessor(videoProcessor);
20234
- }
20235
- return track;
20236
- })));
20237
20406
  });
20238
20407
  }
20239
20408
  /**
@@ -20393,7 +20562,41 @@ class LocalParticipant extends Participant {
20393
20562
  if (opts.source) {
20394
20563
  track.source = opts.source;
20395
20564
  }
20396
- const publishPromise = _this2.publish(track, opts, isStereo);
20565
+ const publishPromise = new Promise((resolve, reject) => __awaiter(_this2, void 0, void 0, function* () {
20566
+ try {
20567
+ if (this.engine.client.currentState !== SignalConnectionState.CONNECTED) {
20568
+ this.log.debug('deferring track publication until signal is connected', Object.assign(Object.assign({}, this.logContext), {
20569
+ track: getLogContextFromTrack(track)
20570
+ }));
20571
+ const onSignalConnected = () => __awaiter(this, void 0, void 0, function* () {
20572
+ try {
20573
+ const publication = yield this.publish(track, opts, isStereo);
20574
+ resolve(publication);
20575
+ } catch (e) {
20576
+ reject(e);
20577
+ }
20578
+ });
20579
+ setTimeout(() => {
20580
+ this.engine.off(EngineEvent.SignalConnected, onSignalConnected);
20581
+ reject(new PublishTrackError('publishing rejected as engine not connected within timeout', 408));
20582
+ }, 15000);
20583
+ this.engine.once(EngineEvent.SignalConnected, onSignalConnected);
20584
+ this.engine.on(EngineEvent.Closing, () => {
20585
+ this.engine.off(EngineEvent.SignalConnected, onSignalConnected);
20586
+ reject(new PublishTrackError('publishing rejected as engine closed', 499));
20587
+ });
20588
+ } else {
20589
+ try {
20590
+ const publication = yield this.publish(track, opts, isStereo);
20591
+ resolve(publication);
20592
+ } catch (e) {
20593
+ reject(e);
20594
+ }
20595
+ }
20596
+ } catch (e) {
20597
+ reject(e);
20598
+ }
20599
+ }));
20397
20600
  _this2.pendingPublishPromises.set(track, publishPromise);
20398
20601
  try {
20399
20602
  const publication = yield publishPromise;
@@ -21090,23 +21293,57 @@ class LocalParticipant extends Participant {
21090
21293
  }
21091
21294
  _sendFile(streamId, file, options) {
21092
21295
  return __awaiter(this, void 0, void 0, function* () {
21093
- var _a, _b;
21094
- const totalLength = file.size;
21095
- const header = new DataStream_Header({
21096
- totalLength: numberToBigInt(totalLength),
21097
- mimeType: (_a = options === null || options === void 0 ? void 0 : options.mimeType) !== null && _a !== void 0 ? _a : file.type,
21296
+ var _a;
21297
+ const writer = yield this.streamBytes({
21098
21298
  streamId,
21299
+ totalSize: file.size,
21300
+ name: file.name,
21301
+ mimeType: (_a = options === null || options === void 0 ? void 0 : options.mimeType) !== null && _a !== void 0 ? _a : file.type,
21099
21302
  topic: options === null || options === void 0 ? void 0 : options.topic,
21100
- encryptionType: options === null || options === void 0 ? void 0 : options.encryptionType,
21303
+ destinationIdentities: options === null || options === void 0 ? void 0 : options.destinationIdentities
21304
+ });
21305
+ const reader = file.stream().getReader();
21306
+ while (true) {
21307
+ const {
21308
+ done,
21309
+ value
21310
+ } = yield reader.read();
21311
+ if (done) {
21312
+ break;
21313
+ }
21314
+ yield writer.write(value);
21315
+ }
21316
+ yield writer.close();
21317
+ return writer.info;
21318
+ });
21319
+ }
21320
+ streamBytes(options) {
21321
+ return __awaiter(this, void 0, void 0, function* () {
21322
+ var _a, _b, _c, _d, _e;
21323
+ const streamId = (_a = options === null || options === void 0 ? void 0 : options.streamId) !== null && _a !== void 0 ? _a : crypto.randomUUID();
21324
+ const destinationIdentities = options === null || options === void 0 ? void 0 : options.destinationIdentities;
21325
+ const info = {
21326
+ id: streamId,
21327
+ mimeType: (_b = options === null || options === void 0 ? void 0 : options.mimeType) !== null && _b !== void 0 ? _b : 'application/octet-stream',
21328
+ topic: (_c = options === null || options === void 0 ? void 0 : options.topic) !== null && _c !== void 0 ? _c : '',
21329
+ timestamp: Date.now(),
21330
+ attributes: options === null || options === void 0 ? void 0 : options.attributes,
21331
+ size: options === null || options === void 0 ? void 0 : options.totalSize,
21332
+ name: (_d = options === null || options === void 0 ? void 0 : options.name) !== null && _d !== void 0 ? _d : 'unknown'
21333
+ };
21334
+ const header = new DataStream_Header({
21335
+ totalLength: numberToBigInt((_e = info.size) !== null && _e !== void 0 ? _e : 0),
21336
+ mimeType: info.mimeType,
21337
+ streamId,
21338
+ topic: info.topic,
21101
21339
  timestamp: numberToBigInt(Date.now()),
21102
21340
  contentHeader: {
21103
21341
  case: 'byteHeader',
21104
21342
  value: new DataStream_ByteHeader({
21105
- name: file.name
21343
+ name: info.name
21106
21344
  })
21107
21345
  }
21108
21346
  });
21109
- const destinationIdentities = options === null || options === void 0 ? void 0 : options.destinationIdentities;
21110
21347
  const packet = new DataPacket({
21111
21348
  destinationIdentities,
21112
21349
  value: {
@@ -21115,45 +21352,60 @@ class LocalParticipant extends Participant {
21115
21352
  }
21116
21353
  });
21117
21354
  yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
21118
- function read(b) {
21119
- return new Promise(resolve => {
21120
- const fr = new FileReader();
21121
- fr.onload = () => {
21122
- resolve(new Uint8Array(fr.result));
21123
- };
21124
- fr.readAsArrayBuffer(b);
21125
- });
21126
- }
21127
- const totalChunks = Math.ceil(totalLength / STREAM_CHUNK_SIZE);
21128
- for (let i = 0; i < totalChunks; i++) {
21129
- const chunkData = yield read(file.slice(i * STREAM_CHUNK_SIZE, Math.min((i + 1) * STREAM_CHUNK_SIZE, totalLength)));
21130
- yield this.engine.waitForBufferStatusLow(DataPacket_Kind.RELIABLE);
21131
- const chunk = new DataStream_Chunk({
21132
- content: chunkData,
21133
- streamId,
21134
- chunkIndex: numberToBigInt(i)
21135
- });
21136
- const chunkPacket = new DataPacket({
21137
- destinationIdentities,
21138
- value: {
21139
- case: 'streamChunk',
21140
- value: chunk
21141
- }
21142
- });
21143
- yield this.engine.sendDataPacket(chunkPacket, DataPacket_Kind.RELIABLE);
21144
- (_b = options === null || options === void 0 ? void 0 : options.onProgress) === null || _b === void 0 ? void 0 : _b.call(options, (i + 1) / totalChunks);
21145
- }
21146
- const trailer = new DataStream_Trailer({
21147
- streamId
21148
- });
21149
- const trailerPacket = new DataPacket({
21150
- destinationIdentities,
21151
- value: {
21152
- case: 'streamTrailer',
21153
- value: trailer
21355
+ let chunkId = 0;
21356
+ const writeMutex = new _();
21357
+ const engine = this.engine;
21358
+ const log = this.log;
21359
+ const writableStream = new WritableStream({
21360
+ write(chunk) {
21361
+ return __awaiter(this, void 0, void 0, function* () {
21362
+ const unlock = yield writeMutex.lock();
21363
+ let byteOffset = 0;
21364
+ try {
21365
+ while (byteOffset < chunk.byteLength) {
21366
+ const subChunk = chunk.slice(byteOffset, byteOffset + STREAM_CHUNK_SIZE);
21367
+ yield engine.waitForBufferStatusLow(DataPacket_Kind.RELIABLE);
21368
+ const chunkPacket = new DataPacket({
21369
+ destinationIdentities,
21370
+ value: {
21371
+ case: 'streamChunk',
21372
+ value: new DataStream_Chunk({
21373
+ content: subChunk,
21374
+ streamId,
21375
+ chunkIndex: numberToBigInt(chunkId)
21376
+ })
21377
+ }
21378
+ });
21379
+ yield engine.sendDataPacket(chunkPacket, DataPacket_Kind.RELIABLE);
21380
+ chunkId += 1;
21381
+ byteOffset += subChunk.byteLength;
21382
+ }
21383
+ } finally {
21384
+ unlock();
21385
+ }
21386
+ });
21387
+ },
21388
+ close() {
21389
+ return __awaiter(this, void 0, void 0, function* () {
21390
+ const trailer = new DataStream_Trailer({
21391
+ streamId
21392
+ });
21393
+ const trailerPacket = new DataPacket({
21394
+ destinationIdentities,
21395
+ value: {
21396
+ case: 'streamTrailer',
21397
+ value: trailer
21398
+ }
21399
+ });
21400
+ yield engine.sendDataPacket(trailerPacket, DataPacket_Kind.RELIABLE);
21401
+ });
21402
+ },
21403
+ abort(err) {
21404
+ log.error('Sink error:', err);
21154
21405
  }
21155
21406
  });
21156
- yield this.engine.sendDataPacket(trailerPacket, DataPacket_Kind.RELIABLE);
21407
+ const byteWriter = new ByteStreamWriter(writableStream, info);
21408
+ return byteWriter;
21157
21409
  });
21158
21410
  }
21159
21411
  /**
@@ -23169,7 +23421,7 @@ class Room extends eventsExports.EventEmitter {
23169
23421
  switchActiveDevice(kind_1, deviceId_1) {
23170
23422
  return __awaiter(this, arguments, void 0, function (kind, deviceId) {
23171
23423
  var _this3 = this;
23172
- let exact = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
23424
+ let exact = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
23173
23425
  return function* () {
23174
23426
  var _a, _b, _c, _d, _e, _f, _g;
23175
23427
  var _h;
@@ -24162,131 +24414,6 @@ class ConnectionProtocolCheck extends Checker {
24162
24414
  }
24163
24415
  }
24164
24416
 
24165
- /**
24166
- * Creates a local video and audio track at the same time. When acquiring both
24167
- * audio and video tracks together, it'll display a single permission prompt to
24168
- * the user instead of two separate ones.
24169
- * @param options
24170
- */
24171
- function createLocalTracks(options) {
24172
- return __awaiter(this, void 0, void 0, function* () {
24173
- var _a, _b;
24174
- // set default options to true
24175
- options !== null && options !== void 0 ? options : options = {};
24176
- (_a = options.audio) !== null && _a !== void 0 ? _a : options.audio = {
24177
- deviceId: 'default'
24178
- };
24179
- (_b = options.video) !== null && _b !== void 0 ? _b : options.video = {
24180
- deviceId: 'default'
24181
- };
24182
- const {
24183
- audioProcessor,
24184
- videoProcessor
24185
- } = extractProcessorsFromOptions(options);
24186
- const opts = mergeDefaultOptions(options, audioDefaults, videoDefaults);
24187
- const constraints = constraintsForOptions(opts);
24188
- // Keep a reference to the promise on DeviceManager and await it in getLocalDevices()
24189
- // works around iOS Safari Bug https://bugs.webkit.org/show_bug.cgi?id=179363
24190
- const mediaPromise = navigator.mediaDevices.getUserMedia(constraints);
24191
- if (options.audio) {
24192
- DeviceManager.userMediaPromiseMap.set('audioinput', mediaPromise);
24193
- mediaPromise.catch(() => DeviceManager.userMediaPromiseMap.delete('audioinput'));
24194
- }
24195
- if (options.video) {
24196
- DeviceManager.userMediaPromiseMap.set('videoinput', mediaPromise);
24197
- mediaPromise.catch(() => DeviceManager.userMediaPromiseMap.delete('videoinput'));
24198
- }
24199
- const stream = yield mediaPromise;
24200
- return Promise.all(stream.getTracks().map(mediaStreamTrack => __awaiter(this, void 0, void 0, function* () {
24201
- const isAudio = mediaStreamTrack.kind === 'audio';
24202
- isAudio ? opts.audio : opts.video;
24203
- let trackConstraints;
24204
- const conOrBool = isAudio ? constraints.audio : constraints.video;
24205
- if (typeof conOrBool !== 'boolean') {
24206
- trackConstraints = conOrBool;
24207
- }
24208
- // update the constraints with the device id the user gave permissions to in the permission prompt
24209
- // otherwise each track restart (e.g. mute - unmute) will try to initialize the device again -> causing additional permission prompts
24210
- const newDeviceId = mediaStreamTrack.getSettings().deviceId;
24211
- if ((trackConstraints === null || trackConstraints === void 0 ? void 0 : trackConstraints.deviceId) && unwrapConstraint(trackConstraints.deviceId) !== newDeviceId) {
24212
- trackConstraints.deviceId = newDeviceId;
24213
- } else if (!trackConstraints) {
24214
- trackConstraints = {
24215
- deviceId: newDeviceId
24216
- };
24217
- }
24218
- const track = mediaTrackToLocalTrack(mediaStreamTrack, trackConstraints);
24219
- if (track.kind === Track.Kind.Video) {
24220
- track.source = Track.Source.Camera;
24221
- } else if (track.kind === Track.Kind.Audio) {
24222
- track.source = Track.Source.Microphone;
24223
- }
24224
- track.mediaStream = stream;
24225
- if (isAudioTrack(track) && audioProcessor) {
24226
- yield track.setProcessor(audioProcessor);
24227
- } else if (isVideoTrack(track) && videoProcessor) {
24228
- yield track.setProcessor(videoProcessor);
24229
- }
24230
- return track;
24231
- })));
24232
- });
24233
- }
24234
- /**
24235
- * Creates a [[LocalVideoTrack]] with getUserMedia()
24236
- * @param options
24237
- */
24238
- function createLocalVideoTrack(options) {
24239
- return __awaiter(this, void 0, void 0, function* () {
24240
- const tracks = yield createLocalTracks({
24241
- audio: false,
24242
- video: options
24243
- });
24244
- return tracks[0];
24245
- });
24246
- }
24247
- function createLocalAudioTrack(options) {
24248
- return __awaiter(this, void 0, void 0, function* () {
24249
- const tracks = yield createLocalTracks({
24250
- audio: options,
24251
- video: false
24252
- });
24253
- return tracks[0];
24254
- });
24255
- }
24256
- /**
24257
- * Creates a screen capture tracks with getDisplayMedia().
24258
- * A LocalVideoTrack is always created and returned.
24259
- * If { audio: true }, and the browser supports audio capture, a LocalAudioTrack is also created.
24260
- */
24261
- function createLocalScreenTracks(options) {
24262
- return __awaiter(this, void 0, void 0, function* () {
24263
- if (options === undefined) {
24264
- options = {};
24265
- }
24266
- if (options.resolution === undefined && !isSafari17()) {
24267
- options.resolution = ScreenSharePresets.h1080fps30.resolution;
24268
- }
24269
- if (navigator.mediaDevices.getDisplayMedia === undefined) {
24270
- throw new DeviceUnsupportedError('getDisplayMedia not supported');
24271
- }
24272
- const constraints = screenCaptureToDisplayMediaStreamOptions(options);
24273
- const stream = yield navigator.mediaDevices.getDisplayMedia(constraints);
24274
- const tracks = stream.getVideoTracks();
24275
- if (tracks.length === 0) {
24276
- throw new TrackInvalidError('no video track found');
24277
- }
24278
- const screenVideo = new LocalVideoTrack(tracks[0], undefined, false);
24279
- screenVideo.source = Track.Source.ScreenShare;
24280
- const localTracks = [screenVideo];
24281
- if (stream.getAudioTracks().length > 0) {
24282
- const screenAudio = new LocalAudioTrack(stream.getAudioTracks()[0], undefined, false);
24283
- screenAudio.source = Track.Source.ScreenShareAudio;
24284
- localTracks.push(screenAudio);
24285
- }
24286
- return localTracks;
24287
- });
24288
- }
24289
-
24290
24417
  class PublishAudioCheck extends Checker {
24291
24418
  get description() {
24292
24419
  return 'Can publish audio';