livekit-client 1.14.2 → 1.14.3

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.
@@ -723,6 +723,34 @@ var ScalarType;
723
723
  ScalarType[ScalarType["SINT32"] = 17] = "SINT32";
724
724
  ScalarType[ScalarType["SINT64"] = 18] = "SINT64";
725
725
  })(ScalarType || (ScalarType = {}));
726
+ /**
727
+ * JavaScript representation of fields with 64 bit integral types (int64, uint64,
728
+ * sint64, fixed64, sfixed64).
729
+ *
730
+ * This is a subset of google.protobuf.FieldOptions.JSType, which defines JS_NORMAL,
731
+ * JS_STRING, and JS_NUMBER. Protobuf-ES uses BigInt by default, but will use
732
+ * String if `[jstype = JS_STRING]` is specified.
733
+ *
734
+ * ```protobuf
735
+ * uint64 field_a = 1; // BigInt
736
+ * uint64 field_b = 2 [jstype = JS_NORMAL]; // BigInt
737
+ * uint64 field_b = 2 [jstype = JS_NUMBER]; // BigInt
738
+ * uint64 field_b = 2 [jstype = JS_STRING]; // String
739
+ * ```
740
+ */
741
+ var LongType;
742
+ (function (LongType) {
743
+ /**
744
+ * Use JavaScript BigInt.
745
+ */
746
+ LongType[LongType["BIGINT"] = 0] = "BIGINT";
747
+ /**
748
+ * Use JavaScript String.
749
+ *
750
+ * Field option `[jstype = JS_STRING]`.
751
+ */
752
+ LongType[LongType["STRING"] = 1] = "STRING";
753
+ })(LongType || (LongType = {}));
726
754
 
727
755
  // Copyright 2008 Google Inc. All rights reserved.
728
756
  //
@@ -1681,7 +1709,7 @@ function scalarEquals(type, a, b) {
1681
1709
  * Returns the default value for the given scalar type, following
1682
1710
  * proto3 semantics.
1683
1711
  */
1684
- function scalarDefaultValue(type) {
1712
+ function scalarDefaultValue(type, longType) {
1685
1713
  switch (type) {
1686
1714
  case ScalarType.BOOL:
1687
1715
  return false;
@@ -1690,7 +1718,8 @@ function scalarDefaultValue(type) {
1690
1718
  case ScalarType.INT64:
1691
1719
  case ScalarType.SFIXED64:
1692
1720
  case ScalarType.SINT64:
1693
- return protoInt64.zero;
1721
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison -- acceptable since it's covered by tests
1722
+ return longType == 0 ? protoInt64.zero : "0";
1694
1723
  case ScalarType.DOUBLE:
1695
1724
  case ScalarType.FLOAT:
1696
1725
  return 0.0;
@@ -1734,13 +1763,13 @@ function scalarTypeInfo(type, value) {
1734
1763
  wireType = WireType.Bit32;
1735
1764
  break;
1736
1765
  case ScalarType.INT64:
1737
- isIntrinsicDefault = isUndefined || value == 0;
1766
+ isIntrinsicDefault = isUndefined || value == 0; // Loose comparison matches 0n, 0 and "0"
1738
1767
  break;
1739
1768
  case ScalarType.UINT64:
1740
- isIntrinsicDefault = isUndefined || value == 0;
1769
+ isIntrinsicDefault = isUndefined || value == 0; // Loose comparison matches 0n, 0 and "0"
1741
1770
  break;
1742
1771
  case ScalarType.FIXED64:
1743
- isIntrinsicDefault = isUndefined || value == 0;
1772
+ isIntrinsicDefault = isUndefined || value == 0; // Loose comparison matches 0n, 0 and "0"
1744
1773
  wireType = WireType.Bit64;
1745
1774
  break;
1746
1775
  case ScalarType.BYTES:
@@ -1855,18 +1884,23 @@ function makeBinaryFormatCommon() {
1855
1884
  case "scalar":
1856
1885
  case "enum":
1857
1886
  const scalarType = field.kind == "enum" ? ScalarType.INT32 : field.T;
1887
+ let read = readScalar$1;
1888
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison -- acceptable since it's covered by tests
1889
+ if (field.kind == "scalar" && field.L > 0) {
1890
+ read = readScalarLTString;
1891
+ }
1858
1892
  if (repeated) {
1859
1893
  let arr = target[localName]; // safe to assume presence of array, oneof cannot contain repeated values
1860
1894
  if (wireType == WireType.LengthDelimited && scalarType != ScalarType.STRING && scalarType != ScalarType.BYTES) {
1861
1895
  let e = reader.uint32() + reader.pos;
1862
1896
  while (reader.pos < e) {
1863
- arr.push(readScalar$1(reader, scalarType));
1897
+ arr.push(read(reader, scalarType));
1864
1898
  }
1865
1899
  } else {
1866
- arr.push(readScalar$1(reader, scalarType));
1900
+ arr.push(read(reader, scalarType));
1867
1901
  }
1868
1902
  } else {
1869
- target[localName] = readScalar$1(reader, scalarType);
1903
+ target[localName] = read(reader, scalarType);
1870
1904
  }
1871
1905
  break;
1872
1906
  case "message":
@@ -1929,7 +1963,7 @@ function readMapEntry(field, reader, options) {
1929
1963
  }
1930
1964
  }
1931
1965
  if (key === undefined) {
1932
- let keyRaw = scalarDefaultValue(field.K);
1966
+ let keyRaw = scalarDefaultValue(field.K, LongType.BIGINT);
1933
1967
  key = field.K == ScalarType.BOOL ? keyRaw.toString() : keyRaw;
1934
1968
  }
1935
1969
  if (typeof key != "string" && typeof key != "number") {
@@ -1938,7 +1972,7 @@ function readMapEntry(field, reader, options) {
1938
1972
  if (val === undefined) {
1939
1973
  switch (field.V.kind) {
1940
1974
  case "scalar":
1941
- val = scalarDefaultValue(field.V.T);
1975
+ val = scalarDefaultValue(field.V.T, LongType.BIGINT);
1942
1976
  break;
1943
1977
  case "enum":
1944
1978
  val = 0;
@@ -1950,6 +1984,12 @@ function readMapEntry(field, reader, options) {
1950
1984
  }
1951
1985
  return [key, val];
1952
1986
  }
1987
+ // Read a scalar value, but return 64 bit integral types (int64, uint64,
1988
+ // sint64, fixed64, sfixed64) as string instead of bigint.
1989
+ function readScalarLTString(reader, type) {
1990
+ const v = readScalar$1(reader, type);
1991
+ return typeof v == "bigint" ? v.toString() : v;
1992
+ }
1953
1993
  // Does not use scalarTypeInfo() for better performance.
1954
1994
  function readScalar$1(reader, type) {
1955
1995
  switch (type) {
@@ -2340,7 +2380,7 @@ function makeJsonFormatCommon(makeWriteField) {
2340
2380
  break;
2341
2381
  case "scalar":
2342
2382
  try {
2343
- val = readScalar(field.T, jsonItem);
2383
+ val = readScalar(field.T, jsonItem, field.L);
2344
2384
  } catch (e) {
2345
2385
  let m = "cannot decode field ".concat(type.typeName, ".").concat(field.name, " from JSON: ").concat(this.debug(jsonItem));
2346
2386
  if (e instanceof Error && e.message.length > 0) {
@@ -2375,7 +2415,7 @@ function makeJsonFormatCommon(makeWriteField) {
2375
2415
  break;
2376
2416
  case "scalar":
2377
2417
  try {
2378
- val = readScalar(field.V.T, jsonMapValue);
2418
+ val = readScalar(field.V.T, jsonMapValue, LongType.BIGINT);
2379
2419
  } catch (e) {
2380
2420
  let m = "cannot decode map value for field ".concat(type.typeName, ".").concat(field.name, " from JSON: ").concat(this.debug(jsonValue));
2381
2421
  if (e instanceof Error && e.message.length > 0) {
@@ -2386,7 +2426,7 @@ function makeJsonFormatCommon(makeWriteField) {
2386
2426
  break;
2387
2427
  }
2388
2428
  try {
2389
- targetMap[readScalar(field.K, field.K == ScalarType.BOOL ? jsonMapKey == "true" ? true : jsonMapKey == "false" ? false : jsonMapKey : jsonMapKey).toString()] = val;
2429
+ targetMap[readScalar(field.K, field.K == ScalarType.BOOL ? jsonMapKey == "true" ? true : jsonMapKey == "false" ? false : jsonMapKey : jsonMapKey, LongType.BIGINT).toString()] = val;
2390
2430
  } catch (e) {
2391
2431
  let m = "cannot decode map key for field ".concat(type.typeName, ".").concat(field.name, " from JSON: ").concat(this.debug(jsonValue));
2392
2432
  if (e instanceof Error && e.message.length > 0) {
@@ -2422,7 +2462,7 @@ function makeJsonFormatCommon(makeWriteField) {
2422
2462
  break;
2423
2463
  case "scalar":
2424
2464
  try {
2425
- target[localName] = readScalar(field.T, jsonValue);
2465
+ target[localName] = readScalar(field.T, jsonValue, field.L);
2426
2466
  } catch (e) {
2427
2467
  let m = "cannot decode field ".concat(type.typeName, ".").concat(field.name, " from JSON: ").concat(this.debug(jsonValue));
2428
2468
  if (e instanceof Error && e.message.length > 0) {
@@ -2488,7 +2528,7 @@ function debugJsonValue(json) {
2488
2528
  }
2489
2529
  // May throw an error. If the error message is non-blank, it should be shown.
2490
2530
  // It is up to the caller to provide context.
2491
- function readScalar(type, json) {
2531
+ function readScalar(type, json, longType) {
2492
2532
  // every valid case in the switch below returns, and every fall
2493
2533
  // through is regarded as a failure.
2494
2534
  switch (type) {
@@ -2542,12 +2582,16 @@ function readScalar(type, json) {
2542
2582
  case ScalarType.SINT64:
2543
2583
  if (json === null) return protoInt64.zero;
2544
2584
  if (typeof json != "number" && typeof json != "string") break;
2545
- return protoInt64.parse(json);
2585
+ const long = protoInt64.parse(json);
2586
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
2587
+ return longType ? long.toString() : long;
2546
2588
  case ScalarType.FIXED64:
2547
2589
  case ScalarType.UINT64:
2548
2590
  if (json === null) return protoInt64.zero;
2549
2591
  if (typeof json != "number" && typeof json != "string") break;
2550
- return protoInt64.uParse(json);
2592
+ const uLong = protoInt64.uParse(json);
2593
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
2594
+ return longType ? uLong.toString() : uLong;
2551
2595
  // bool:
2552
2596
  case ScalarType.BOOL:
2553
2597
  if (json === null) return false;
@@ -3238,7 +3282,7 @@ const proto3 = makeProtoRuntime("proto3", makeJsonFormatProto3(), makeBinaryForm
3238
3282
  t[name] = {};
3239
3283
  break;
3240
3284
  case "scalar":
3241
- t[name] = scalarDefaultValue(member.T); // eslint-disable-line @typescript-eslint/no-unsafe-assignment
3285
+ t[name] = scalarDefaultValue(member.T, member.L); // eslint-disable-line @typescript-eslint/no-unsafe-assignment
3242
3286
  break;
3243
3287
  }
3244
3288
  }
@@ -3246,7 +3290,7 @@ const proto3 = makeProtoRuntime("proto3", makeJsonFormatProto3(), makeBinaryForm
3246
3290
  }));
3247
3291
  /* eslint-disable @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-argument */
3248
3292
  function normalizeFieldInfosProto3(fieldInfos) {
3249
- var _a, _b, _c;
3293
+ var _a, _b, _c, _d;
3250
3294
  const r = [];
3251
3295
  let o;
3252
3296
  for (const field of typeof fieldInfos == "function" ? fieldInfos() : fieldInfos) {
@@ -3254,12 +3298,15 @@ function normalizeFieldInfosProto3(fieldInfos) {
3254
3298
  f.localName = localFieldName(field.name, field.oneof !== undefined);
3255
3299
  f.jsonName = (_a = field.jsonName) !== null && _a !== void 0 ? _a : fieldJsonName(field.name);
3256
3300
  f.repeated = (_b = field.repeated) !== null && _b !== void 0 ? _b : false;
3301
+ if (field.kind == "scalar") {
3302
+ f.L = (_c = field.L) !== null && _c !== void 0 ? _c : LongType.BIGINT;
3303
+ }
3257
3304
  // From the proto3 language guide:
3258
3305
  // > In proto3, repeated fields of scalar numeric types are packed by default.
3259
3306
  // This information is incomplete - according to the conformance tests, BOOL
3260
3307
  // and ENUM are packed by default as well. This means only STRING and BYTES
3261
3308
  // are not packed by default, which makes sense because they are length-delimited.
3262
- f.packed = (_c = field.packed) !== null && _c !== void 0 ? _c : field.kind == "enum" || field.kind == "scalar" && field.T != ScalarType.BYTES && field.T != ScalarType.STRING;
3309
+ f.packed = (_d = field.packed) !== null && _d !== void 0 ? _d : field.kind == "enum" || field.kind == "scalar" && field.T != ScalarType.BYTES && field.T != ScalarType.STRING;
3263
3310
  // We do not surface options at this time
3264
3311
  // f.options = field.options ?? emptyReadonlyObject;
3265
3312
  if (field.oneof !== undefined) {
@@ -11998,7 +12045,7 @@ function getMatch(exp, ua) {
11998
12045
  return match && match.length >= id && match[id] || '';
11999
12046
  }
12000
12047
 
12001
- var version$1 = "1.14.2";
12048
+ var version$1 = "1.14.3";
12002
12049
 
12003
12050
  const version = version$1;
12004
12051
  const protocolVersion = 10;
@@ -12486,6 +12533,9 @@ var ParticipantEvent;
12486
12533
  // fired only on LocalParticipant
12487
12534
  /** @internal */
12488
12535
  ParticipantEvent["MediaDevicesError"] = "mediaDevicesError";
12536
+ // fired only on LocalParticipant
12537
+ /** @internal */
12538
+ ParticipantEvent["AudioStreamAcquired"] = "audioStreamAcquired";
12489
12539
  /**
12490
12540
  * A participant's permission has changed. Currently only fired on LocalParticipant.
12491
12541
  * args: (prevPermissions: [[ParticipantPermission]])
@@ -12782,7 +12832,12 @@ function attachToElement(track, element) {
12782
12832
  });
12783
12833
  mediaStream.addTrack(track);
12784
12834
  }
12785
- element.autoplay = true;
12835
+ if (!isSafari() || !(element instanceof HTMLVideoElement)) {
12836
+ // when in low power mode (applies to both macOS and iOS), Safari will show a play/pause overlay
12837
+ // when a video starts that has the `autoplay` attribute is set.
12838
+ // we work around this by _not_ setting the autoplay attribute on safari and instead call `setTimeout(() => el.play(),0)` further down
12839
+ element.autoplay = true;
12840
+ }
12786
12841
  // In case there are no audio tracks present on the mediastream, we set the element as muted to ensure autoplay works
12787
12842
  element.muted = mediaStream.getAudioTracks().length === 0;
12788
12843
  if (element instanceof HTMLVideoElement) {
@@ -16089,7 +16144,7 @@ class PCTransport extends eventsExports.EventEmitter {
16089
16144
  for (const fmtp of media.fmtp) {
16090
16145
  if (fmtp.payload === codecPayload) {
16091
16146
  if (!fmtp.config.includes('x-google-start-bitrate')) {
16092
- fmtp.config += ";x-google-start-bitrate=".concat(trackbr.maxbr * startBitrateForSVC);
16147
+ fmtp.config += ";x-google-start-bitrate=".concat(Math.round(trackbr.maxbr * startBitrateForSVC));
16093
16148
  }
16094
16149
  if (!fmtp.config.includes('x-google-max-bitrate')) {
16095
16150
  fmtp.config += ";x-google-max-bitrate=".concat(trackbr.maxbr);
@@ -16101,7 +16156,7 @@ class PCTransport extends eventsExports.EventEmitter {
16101
16156
  if (!fmtpFound) {
16102
16157
  media.fmtp.push({
16103
16158
  payload: codecPayload,
16104
- config: "x-google-start-bitrate=".concat(trackbr.maxbr * startBitrateForSVC, ";x-google-max-bitrate=").concat(trackbr.maxbr)
16159
+ config: "x-google-start-bitrate=".concat(Math.round(trackbr.maxbr * startBitrateForSVC), ";x-google-max-bitrate=").concat(trackbr.maxbr)
16105
16160
  });
16106
16161
  }
16107
16162
  return true;
@@ -16772,19 +16827,13 @@ class RTCEngine extends eventsExports.EventEmitter {
16772
16827
  this.regionUrlProvider = provider;
16773
16828
  }
16774
16829
  configure(joinResponse) {
16775
- var _a, _b;
16830
+ var _a;
16776
16831
  // already configured
16777
16832
  if (this.publisher || this.subscriber) {
16778
16833
  return;
16779
16834
  }
16780
16835
  this.participantSid = (_a = joinResponse.participant) === null || _a === void 0 ? void 0 : _a.sid;
16781
16836
  const rtcConfig = this.makeRTCConfiguration(joinResponse);
16782
- if ((_b = this.signalOpts) === null || _b === void 0 ? void 0 : _b.e2eeEnabled) {
16783
- livekitLogger.debug('E2EE - setting up transports with insertable streams');
16784
- // this makes sure that no data is sent before the transforms are ready
16785
- // @ts-ignore
16786
- rtcConfig.encodedInsertableStreams = true;
16787
- }
16788
16837
  const googConstraints = {
16789
16838
  optional: [{
16790
16839
  googDscp: true
@@ -16916,7 +16965,14 @@ class RTCEngine extends eventsExports.EventEmitter {
16916
16965
  };
16917
16966
  }
16918
16967
  makeRTCConfiguration(serverResponse) {
16968
+ var _a;
16919
16969
  const rtcConfig = Object.assign({}, this.rtcConfig);
16970
+ if ((_a = this.signalOpts) === null || _a === void 0 ? void 0 : _a.e2eeEnabled) {
16971
+ livekitLogger.debug('E2EE - setting up transports with insertable streams');
16972
+ // this makes sure that no data is sent before the transforms are ready
16973
+ // @ts-ignore
16974
+ rtcConfig.encodedInsertableStreams = true;
16975
+ }
16920
16976
  // update ICE servers before creating PeerConnection
16921
16977
  if (serverResponse.iceServers && !rtcConfig.iceServers) {
16922
16978
  const rtcIceServers = [];
@@ -17232,6 +17288,7 @@ class RTCEngine extends eventsExports.EventEmitter {
17232
17288
  let message = '';
17233
17289
  if (e instanceof Error) {
17234
17290
  message = e.message;
17291
+ livekitLogger.error(e.message);
17235
17292
  }
17236
17293
  if (e instanceof ConnectionError && e.reason === 0 /* ConnectionErrorReason.NotAllowed */) {
17237
17294
  throw new UnexpectedConnectionState('could not reconnect, token might be expired');
@@ -20485,6 +20542,7 @@ class LocalParticipant extends Participant {
20485
20542
  }
20486
20543
  if (constraints.audio) {
20487
20544
  this.microphoneError = undefined;
20545
+ this.emit(ParticipantEvent.AudioStreamAcquired);
20488
20546
  }
20489
20547
  if (constraints.video) {
20490
20548
  this.cameraError = undefined;
@@ -20531,6 +20589,7 @@ class LocalParticipant extends Participant {
20531
20589
  screenVideo.source = Track.Source.ScreenShare;
20532
20590
  const localTracks = [screenVideo];
20533
20591
  if (stream.getAudioTracks().length > 0) {
20592
+ this.emit(ParticipantEvent.AudioStreamAcquired);
20534
20593
  const screenAudio = new LocalAudioTrack(stream.getAudioTracks()[0], undefined, false, this.audioContext);
20535
20594
  screenAudio.source = Track.Source.ScreenShareAudio;
20536
20595
  localTracks.push(screenAudio);
@@ -20645,18 +20704,7 @@ class LocalParticipant extends Participant {
20645
20704
  return __awaiter(this, void 0, void 0, function* () {
20646
20705
  const existingTrackOfSource = Array.from(this.tracks.values()).find(publishedTrack => track instanceof LocalTrack && publishedTrack.source === track.source);
20647
20706
  if (existingTrackOfSource && track.source !== Track.Source.Unknown) {
20648
- try {
20649
- // throw an Error in order to capture the stack trace
20650
- throw Error("publishing a second track with the same source: ".concat(track.source));
20651
- } catch (e) {
20652
- if (e instanceof Error) {
20653
- livekitLogger.warn(e.message, {
20654
- oldTrack: existingTrackOfSource,
20655
- newTrack: track,
20656
- trace: e.stack
20657
- });
20658
- }
20659
- }
20707
+ livekitLogger.info("publishing a second track with the same source: ".concat(track.source));
20660
20708
  }
20661
20709
  if (opts.stopMicTrackOnMute && track instanceof LocalAudioTrack) {
20662
20710
  track.stopOnMute = true;
@@ -21415,6 +21463,70 @@ class Room extends eventsExports.EventEmitter {
21415
21463
  this.onPageLeave = () => __awaiter(this, void 0, void 0, function* () {
21416
21464
  yield this.disconnect();
21417
21465
  });
21466
+ /**
21467
+ * Browsers have different policies regarding audio playback. Most requiring
21468
+ * some form of user interaction (click/tap/etc).
21469
+ * In those cases, audio will be silent until a click/tap triggering one of the following
21470
+ * - `startAudio`
21471
+ * - `getUserMedia`
21472
+ */
21473
+ this.startAudio = () => __awaiter(this, void 0, void 0, function* () {
21474
+ const elements = [];
21475
+ const browser = getBrowser();
21476
+ if (browser && browser.os === 'iOS') {
21477
+ /**
21478
+ * iOS blocks audio element playback if
21479
+ * - user is not publishing audio themselves and
21480
+ * - no other audio source is playing
21481
+ *
21482
+ * as a workaround, we create an audio element with an empty track, so that
21483
+ * silent audio is always playing
21484
+ */
21485
+ const audioId = 'livekit-dummy-audio-el';
21486
+ let dummyAudioEl = document.getElementById(audioId);
21487
+ if (!dummyAudioEl) {
21488
+ dummyAudioEl = document.createElement('audio');
21489
+ dummyAudioEl.id = audioId;
21490
+ dummyAudioEl.autoplay = true;
21491
+ dummyAudioEl.hidden = true;
21492
+ const track = getEmptyAudioStreamTrack();
21493
+ track.enabled = true;
21494
+ const stream = new MediaStream([track]);
21495
+ dummyAudioEl.srcObject = stream;
21496
+ document.addEventListener('visibilitychange', () => {
21497
+ if (!dummyAudioEl) {
21498
+ return;
21499
+ }
21500
+ // set the srcObject to null on page hide in order to prevent lock screen controls to show up for it
21501
+ dummyAudioEl.srcObject = document.hidden ? null : stream;
21502
+ });
21503
+ document.body.append(dummyAudioEl);
21504
+ this.once(RoomEvent.Disconnected, () => {
21505
+ dummyAudioEl === null || dummyAudioEl === void 0 ? void 0 : dummyAudioEl.remove();
21506
+ });
21507
+ }
21508
+ elements.push(dummyAudioEl);
21509
+ }
21510
+ this.participants.forEach(p => {
21511
+ p.audioTracks.forEach(t => {
21512
+ if (t.track) {
21513
+ t.track.attachedElements.forEach(e => {
21514
+ elements.push(e);
21515
+ });
21516
+ }
21517
+ });
21518
+ });
21519
+ try {
21520
+ yield Promise.all([this.acquireAudioContext(), ...elements.map(e => {
21521
+ e.muted = false;
21522
+ return e.play();
21523
+ })]);
21524
+ this.handleAudioPlaybackStarted();
21525
+ } catch (err) {
21526
+ this.handleAudioPlaybackFailed(err);
21527
+ throw err;
21528
+ }
21529
+ });
21418
21530
  this.handleRestarting = () => {
21419
21531
  this.clearConnectionReconcile();
21420
21532
  // also unwind existing participants & existing subscriptions
@@ -21970,72 +22082,6 @@ class Room extends eventsExports.EventEmitter {
21970
22082
  }
21971
22083
  });
21972
22084
  }
21973
- /**
21974
- * Browsers have different policies regarding audio playback. Most requiring
21975
- * some form of user interaction (click/tap/etc).
21976
- * In those cases, audio will be silent until a click/tap triggering one of the following
21977
- * - `startAudio`
21978
- * - `getUserMedia`
21979
- */
21980
- startAudio() {
21981
- return __awaiter(this, void 0, void 0, function* () {
21982
- const elements = [];
21983
- const browser = getBrowser();
21984
- if (browser && browser.os === 'iOS') {
21985
- /**
21986
- * iOS blocks audio element playback if
21987
- * - user is not publishing audio themselves and
21988
- * - no other audio source is playing
21989
- *
21990
- * as a workaround, we create an audio element with an empty track, so that
21991
- * silent audio is always playing
21992
- */
21993
- const audioId = 'livekit-dummy-audio-el';
21994
- let dummyAudioEl = document.getElementById(audioId);
21995
- if (!dummyAudioEl) {
21996
- dummyAudioEl = document.createElement('audio');
21997
- dummyAudioEl.id = audioId;
21998
- dummyAudioEl.autoplay = true;
21999
- dummyAudioEl.hidden = true;
22000
- const track = getEmptyAudioStreamTrack();
22001
- track.enabled = true;
22002
- const stream = new MediaStream([track]);
22003
- dummyAudioEl.srcObject = stream;
22004
- document.addEventListener('visibilitychange', () => {
22005
- if (!dummyAudioEl) {
22006
- return;
22007
- }
22008
- // set the srcObject to null on page hide in order to prevent lock screen controls to show up for it
22009
- dummyAudioEl.srcObject = document.hidden ? null : stream;
22010
- });
22011
- document.body.append(dummyAudioEl);
22012
- this.once(RoomEvent.Disconnected, () => {
22013
- dummyAudioEl === null || dummyAudioEl === void 0 ? void 0 : dummyAudioEl.remove();
22014
- });
22015
- }
22016
- elements.push(dummyAudioEl);
22017
- }
22018
- this.participants.forEach(p => {
22019
- p.audioTracks.forEach(t => {
22020
- if (t.track) {
22021
- t.track.attachedElements.forEach(e => {
22022
- elements.push(e);
22023
- });
22024
- }
22025
- });
22026
- });
22027
- try {
22028
- yield Promise.all([this.acquireAudioContext(), ...elements.map(e => {
22029
- e.muted = false;
22030
- return e.play();
22031
- })]);
22032
- this.handleAudioPlaybackStarted();
22033
- } catch (err) {
22034
- this.handleAudioPlaybackFailed(err);
22035
- throw err;
22036
- }
22037
- });
22038
- }
22039
22085
  /**
22040
22086
  * Returns true if audio playback is enabled
22041
22087
  */
@@ -22132,7 +22178,7 @@ class Room extends eventsExports.EventEmitter {
22132
22178
  });
22133
22179
  }
22134
22180
  setupLocalParticipantEvents() {
22135
- this.localParticipant.on(ParticipantEvent.ParticipantMetadataChanged, this.onLocalParticipantMetadataChanged).on(ParticipantEvent.ParticipantNameChanged, this.onLocalParticipantNameChanged).on(ParticipantEvent.TrackMuted, this.onLocalTrackMuted).on(ParticipantEvent.TrackUnmuted, this.onLocalTrackUnmuted).on(ParticipantEvent.LocalTrackPublished, this.onLocalTrackPublished).on(ParticipantEvent.LocalTrackUnpublished, this.onLocalTrackUnpublished).on(ParticipantEvent.ConnectionQualityChanged, this.onLocalConnectionQualityChanged).on(ParticipantEvent.MediaDevicesError, this.onMediaDevicesError).on(ParticipantEvent.ParticipantPermissionsChanged, this.onLocalParticipantPermissionsChanged);
22181
+ this.localParticipant.on(ParticipantEvent.ParticipantMetadataChanged, this.onLocalParticipantMetadataChanged).on(ParticipantEvent.ParticipantNameChanged, this.onLocalParticipantNameChanged).on(ParticipantEvent.TrackMuted, this.onLocalTrackMuted).on(ParticipantEvent.TrackUnmuted, this.onLocalTrackUnmuted).on(ParticipantEvent.LocalTrackPublished, this.onLocalTrackPublished).on(ParticipantEvent.LocalTrackUnpublished, this.onLocalTrackUnpublished).on(ParticipantEvent.ConnectionQualityChanged, this.onLocalConnectionQualityChanged).on(ParticipantEvent.MediaDevicesError, this.onMediaDevicesError).on(ParticipantEvent.AudioStreamAcquired, this.startAudio).on(ParticipantEvent.ParticipantPermissionsChanged, this.onLocalParticipantPermissionsChanged);
22136
22182
  }
22137
22183
  recreateEngine() {
22138
22184
  var _a;
@@ -22220,7 +22266,7 @@ class Room extends eventsExports.EventEmitter {
22220
22266
  (_b = pub.track) === null || _b === void 0 ? void 0 : _b.stop();
22221
22267
  }
22222
22268
  });
22223
- this.localParticipant.off(ParticipantEvent.ParticipantMetadataChanged, this.onLocalParticipantMetadataChanged).off(ParticipantEvent.ParticipantNameChanged, this.onLocalParticipantNameChanged).off(ParticipantEvent.TrackMuted, this.onLocalTrackMuted).off(ParticipantEvent.TrackUnmuted, this.onLocalTrackUnmuted).off(ParticipantEvent.LocalTrackPublished, this.onLocalTrackPublished).off(ParticipantEvent.LocalTrackUnpublished, this.onLocalTrackUnpublished).off(ParticipantEvent.ConnectionQualityChanged, this.onLocalConnectionQualityChanged).off(ParticipantEvent.MediaDevicesError, this.onMediaDevicesError).off(ParticipantEvent.ParticipantPermissionsChanged, this.onLocalParticipantPermissionsChanged);
22269
+ this.localParticipant.off(ParticipantEvent.ParticipantMetadataChanged, this.onLocalParticipantMetadataChanged).off(ParticipantEvent.ParticipantNameChanged, this.onLocalParticipantNameChanged).off(ParticipantEvent.TrackMuted, this.onLocalTrackMuted).off(ParticipantEvent.TrackUnmuted, this.onLocalTrackUnmuted).off(ParticipantEvent.LocalTrackPublished, this.onLocalTrackPublished).off(ParticipantEvent.LocalTrackUnpublished, this.onLocalTrackUnpublished).off(ParticipantEvent.ConnectionQualityChanged, this.onLocalConnectionQualityChanged).off(ParticipantEvent.MediaDevicesError, this.onMediaDevicesError).off(ParticipantEvent.AudioStreamAcquired, this.startAudio).off(ParticipantEvent.ParticipantPermissionsChanged, this.onLocalParticipantPermissionsChanged);
22224
22270
  this.localParticipant.tracks.clear();
22225
22271
  this.localParticipant.videoTracks.clear();
22226
22272
  this.localParticipant.audioTracks.clear();