livekit-client 2.5.1 → 2.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) 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 +4 -2
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +867 -425
  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/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  10. package/dist/src/room/PCTransportManager.d.ts +1 -0
  11. package/dist/src/room/PCTransportManager.d.ts.map +1 -1
  12. package/dist/src/room/Room.d.ts +7 -4
  13. package/dist/src/room/Room.d.ts.map +1 -1
  14. package/dist/src/room/events.d.ts +4 -1
  15. package/dist/src/room/events.d.ts.map +1 -1
  16. package/dist/src/room/participant/LocalParticipant.d.ts +11 -1
  17. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  18. package/dist/src/room/participant/Participant.d.ts +2 -1
  19. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  20. package/dist/src/room/track/LocalTrack.d.ts +1 -1
  21. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  22. package/dist/src/room/track/create.d.ts +7 -0
  23. package/dist/src/room/track/create.d.ts.map +1 -1
  24. package/dist/src/room/types.d.ts +6 -0
  25. package/dist/src/room/types.d.ts.map +1 -1
  26. package/dist/src/room/utils.d.ts +3 -2
  27. package/dist/src/room/utils.d.ts.map +1 -1
  28. package/dist/ts4.2/src/room/PCTransportManager.d.ts +1 -0
  29. package/dist/ts4.2/src/room/Room.d.ts +7 -4
  30. package/dist/ts4.2/src/room/events.d.ts +4 -1
  31. package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +11 -1
  32. package/dist/ts4.2/src/room/participant/Participant.d.ts +2 -1
  33. package/dist/ts4.2/src/room/track/LocalTrack.d.ts +1 -1
  34. package/dist/ts4.2/src/room/track/create.d.ts +7 -0
  35. package/dist/ts4.2/src/room/types.d.ts +6 -0
  36. package/dist/ts4.2/src/room/utils.d.ts +3 -2
  37. package/package.json +9 -9
  38. package/src/connectionHelper/checks/Checker.ts +1 -1
  39. package/src/e2ee/worker/FrameCryptor.ts +3 -1
  40. package/src/room/PCTransportManager.ts +12 -4
  41. package/src/room/Room.ts +67 -7
  42. package/src/room/events.ts +4 -0
  43. package/src/room/participant/LocalParticipant.ts +146 -52
  44. package/src/room/participant/Participant.ts +2 -1
  45. package/src/room/track/LocalTrack.ts +4 -2
  46. package/src/room/track/create.ts +27 -8
  47. package/src/room/types.ts +7 -0
  48. package/src/room/utils.ts +17 -2
@@ -3397,6 +3397,218 @@ target => {
3397
3397
  }
3398
3398
  });
3399
3399
 
3400
+ // Copyright 2021-2024 Buf Technologies, Inc.
3401
+ //
3402
+ // Licensed under the Apache License, Version 2.0 (the "License");
3403
+ // you may not use this file except in compliance with the License.
3404
+ // You may obtain a copy of the License at
3405
+ //
3406
+ // http://www.apache.org/licenses/LICENSE-2.0
3407
+ //
3408
+ // Unless required by applicable law or agreed to in writing, software
3409
+ // distributed under the License is distributed on an "AS IS" BASIS,
3410
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3411
+ // See the License for the specific language governing permissions and
3412
+ // limitations under the License.
3413
+ /**
3414
+ * A Timestamp represents a point in time independent of any time zone or local
3415
+ * calendar, encoded as a count of seconds and fractions of seconds at
3416
+ * nanosecond resolution. The count is relative to an epoch at UTC midnight on
3417
+ * January 1, 1970, in the proleptic Gregorian calendar which extends the
3418
+ * Gregorian calendar backwards to year one.
3419
+ *
3420
+ * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap
3421
+ * second table is needed for interpretation, using a [24-hour linear
3422
+ * smear](https://developers.google.com/time/smear).
3423
+ *
3424
+ * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By
3425
+ * restricting to that range, we ensure that we can convert to and from [RFC
3426
+ * 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings.
3427
+ *
3428
+ * # Examples
3429
+ *
3430
+ * Example 1: Compute Timestamp from POSIX `time()`.
3431
+ *
3432
+ * Timestamp timestamp;
3433
+ * timestamp.set_seconds(time(NULL));
3434
+ * timestamp.set_nanos(0);
3435
+ *
3436
+ * Example 2: Compute Timestamp from POSIX `gettimeofday()`.
3437
+ *
3438
+ * struct timeval tv;
3439
+ * gettimeofday(&tv, NULL);
3440
+ *
3441
+ * Timestamp timestamp;
3442
+ * timestamp.set_seconds(tv.tv_sec);
3443
+ * timestamp.set_nanos(tv.tv_usec * 1000);
3444
+ *
3445
+ * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
3446
+ *
3447
+ * FILETIME ft;
3448
+ * GetSystemTimeAsFileTime(&ft);
3449
+ * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
3450
+ *
3451
+ * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
3452
+ * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
3453
+ * Timestamp timestamp;
3454
+ * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
3455
+ * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
3456
+ *
3457
+ * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
3458
+ *
3459
+ * long millis = System.currentTimeMillis();
3460
+ *
3461
+ * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
3462
+ * .setNanos((int) ((millis % 1000) * 1000000)).build();
3463
+ *
3464
+ * Example 5: Compute Timestamp from Java `Instant.now()`.
3465
+ *
3466
+ * Instant now = Instant.now();
3467
+ *
3468
+ * Timestamp timestamp =
3469
+ * Timestamp.newBuilder().setSeconds(now.getEpochSecond())
3470
+ * .setNanos(now.getNano()).build();
3471
+ *
3472
+ * Example 6: Compute Timestamp from current time in Python.
3473
+ *
3474
+ * timestamp = Timestamp()
3475
+ * timestamp.GetCurrentTime()
3476
+ *
3477
+ * # JSON Mapping
3478
+ *
3479
+ * In JSON format, the Timestamp type is encoded as a string in the
3480
+ * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
3481
+ * format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
3482
+ * where {year} is always expressed using four digits while {month}, {day},
3483
+ * {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
3484
+ * seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
3485
+ * are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
3486
+ * is required. A proto3 JSON serializer should always use UTC (as indicated by
3487
+ * "Z") when printing the Timestamp type and a proto3 JSON parser should be
3488
+ * able to accept both UTC and other timezones (as indicated by an offset).
3489
+ *
3490
+ * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
3491
+ * 01:30 UTC on January 15, 2017.
3492
+ *
3493
+ * In JavaScript, one can convert a Date object to this format using the
3494
+ * standard
3495
+ * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
3496
+ * method. In Python, a standard `datetime.datetime` object can be converted
3497
+ * to this format using
3498
+ * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
3499
+ * the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
3500
+ * the Joda Time's [`ISODateTimeFormat.dateTime()`](
3501
+ * http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()
3502
+ * ) to obtain a formatter capable of generating timestamps in this format.
3503
+ *
3504
+ *
3505
+ * @generated from message google.protobuf.Timestamp
3506
+ */
3507
+ class Timestamp extends Message {
3508
+ constructor(data) {
3509
+ super();
3510
+ /**
3511
+ * Represents seconds of UTC time since Unix epoch
3512
+ * 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
3513
+ * 9999-12-31T23:59:59Z inclusive.
3514
+ *
3515
+ * @generated from field: int64 seconds = 1;
3516
+ */
3517
+ this.seconds = protoInt64.zero;
3518
+ /**
3519
+ * Non-negative fractions of a second at nanosecond resolution. Negative
3520
+ * second values with fractions must still have non-negative nanos values
3521
+ * that count forward in time. Must be from 0 to 999,999,999
3522
+ * inclusive.
3523
+ *
3524
+ * @generated from field: int32 nanos = 2;
3525
+ */
3526
+ this.nanos = 0;
3527
+ proto3.util.initPartial(data, this);
3528
+ }
3529
+ fromJson(json, options) {
3530
+ if (typeof json !== "string") {
3531
+ throw new Error("cannot decode google.protobuf.Timestamp from JSON: ".concat(proto3.json.debug(json)));
3532
+ }
3533
+ const matches = json.match(/^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(?:Z|\.([0-9]{3,9})Z|([+-][0-9][0-9]:[0-9][0-9]))$/);
3534
+ if (!matches) {
3535
+ throw new Error("cannot decode google.protobuf.Timestamp from JSON: invalid RFC 3339 string");
3536
+ }
3537
+ const ms = Date.parse(matches[1] + "-" + matches[2] + "-" + matches[3] + "T" + matches[4] + ":" + matches[5] + ":" + matches[6] + (matches[8] ? matches[8] : "Z"));
3538
+ if (Number.isNaN(ms)) {
3539
+ throw new Error("cannot decode google.protobuf.Timestamp from JSON: invalid RFC 3339 string");
3540
+ }
3541
+ if (ms < Date.parse("0001-01-01T00:00:00Z") || ms > Date.parse("9999-12-31T23:59:59Z")) {
3542
+ throw new Error("cannot decode message google.protobuf.Timestamp from JSON: must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive");
3543
+ }
3544
+ this.seconds = protoInt64.parse(ms / 1000);
3545
+ this.nanos = 0;
3546
+ if (matches[7]) {
3547
+ this.nanos = parseInt("1" + matches[7] + "0".repeat(9 - matches[7].length)) - 1000000000;
3548
+ }
3549
+ return this;
3550
+ }
3551
+ toJson(options) {
3552
+ const ms = Number(this.seconds) * 1000;
3553
+ if (ms < Date.parse("0001-01-01T00:00:00Z") || ms > Date.parse("9999-12-31T23:59:59Z")) {
3554
+ throw new Error("cannot encode google.protobuf.Timestamp to JSON: must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive");
3555
+ }
3556
+ if (this.nanos < 0) {
3557
+ throw new Error("cannot encode google.protobuf.Timestamp to JSON: nanos must not be negative");
3558
+ }
3559
+ let z = "Z";
3560
+ if (this.nanos > 0) {
3561
+ const nanosStr = (this.nanos + 1000000000).toString().substring(1);
3562
+ if (nanosStr.substring(3) === "000000") {
3563
+ z = "." + nanosStr.substring(0, 3) + "Z";
3564
+ } else if (nanosStr.substring(6) === "000") {
3565
+ z = "." + nanosStr.substring(0, 6) + "Z";
3566
+ } else {
3567
+ z = "." + nanosStr + "Z";
3568
+ }
3569
+ }
3570
+ return new Date(ms).toISOString().replace(".000Z", z);
3571
+ }
3572
+ toDate() {
3573
+ return new Date(Number(this.seconds) * 1000 + Math.ceil(this.nanos / 1000000));
3574
+ }
3575
+ static now() {
3576
+ return Timestamp.fromDate(new Date());
3577
+ }
3578
+ static fromDate(date) {
3579
+ const ms = date.getTime();
3580
+ return new Timestamp({
3581
+ seconds: protoInt64.parse(Math.floor(ms / 1000)),
3582
+ nanos: ms % 1000 * 1000000
3583
+ });
3584
+ }
3585
+ static fromBinary(bytes, options) {
3586
+ return new Timestamp().fromBinary(bytes, options);
3587
+ }
3588
+ static fromJson(jsonValue, options) {
3589
+ return new Timestamp().fromJson(jsonValue, options);
3590
+ }
3591
+ static fromJsonString(jsonString, options) {
3592
+ return new Timestamp().fromJsonString(jsonString, options);
3593
+ }
3594
+ static equals(a, b) {
3595
+ return proto3.util.equals(Timestamp, a, b);
3596
+ }
3597
+ }
3598
+ Timestamp.runtime = proto3;
3599
+ Timestamp.typeName = "google.protobuf.Timestamp";
3600
+ Timestamp.fields = proto3.util.newFieldList(() => [{
3601
+ no: 1,
3602
+ name: "seconds",
3603
+ kind: "scalar",
3604
+ T: 3 /* ScalarType.INT64 */
3605
+ }, {
3606
+ no: 2,
3607
+ name: "nanos",
3608
+ kind: "scalar",
3609
+ T: 5 /* ScalarType.INT32 */
3610
+ }]);
3611
+
3400
3612
  // @generated by protoc-gen-es v1.10.0 with parameter "target=js+dts"
3401
3613
  // @generated from file livekit_metrics.proto (package livekit, syntax proto3)
3402
3614
  /* eslint-disable */
@@ -3408,18 +3620,28 @@ target => {
3408
3620
  */
3409
3621
  const MetricsBatch = /*@__PURE__*/proto3.makeMessageType("livekit.MetricsBatch", () => [{
3410
3622
  no: 1,
3623
+ name: "timestamp_ms",
3624
+ kind: "scalar",
3625
+ T: 3 /* ScalarType.INT64 */
3626
+ }, {
3627
+ no: 2,
3628
+ name: "normalized_timestamp",
3629
+ kind: "message",
3630
+ T: Timestamp
3631
+ }, {
3632
+ no: 3,
3411
3633
  name: "str_data",
3412
3634
  kind: "scalar",
3413
3635
  T: 9 /* ScalarType.STRING */,
3414
3636
  repeated: true
3415
3637
  }, {
3416
- no: 2,
3638
+ no: 4,
3417
3639
  name: "time_series",
3418
3640
  kind: "message",
3419
3641
  T: TimeSeriesMetric,
3420
3642
  repeated: true
3421
3643
  }, {
3422
- no: 3,
3644
+ no: 5,
3423
3645
  name: "events",
3424
3646
  kind: "message",
3425
3647
  T: EventMetric,
@@ -3446,16 +3668,6 @@ const TimeSeriesMetric = /*@__PURE__*/proto3.makeMessageType("livekit.TimeSeries
3446
3668
  T: 13 /* ScalarType.UINT32 */
3447
3669
  }, {
3448
3670
  no: 4,
3449
- name: "start_timestamp",
3450
- kind: "scalar",
3451
- T: 3 /* ScalarType.INT64 */
3452
- }, {
3453
- no: 5,
3454
- name: "end_timestamp",
3455
- kind: "scalar",
3456
- T: 3 /* ScalarType.INT64 */
3457
- }, {
3458
- no: 6,
3459
3671
  name: "samples",
3460
3672
  kind: "message",
3461
3673
  T: MetricSample,
@@ -3467,11 +3679,16 @@ const TimeSeriesMetric = /*@__PURE__*/proto3.makeMessageType("livekit.TimeSeries
3467
3679
  */
3468
3680
  const MetricSample = /*@__PURE__*/proto3.makeMessageType("livekit.MetricSample", () => [{
3469
3681
  no: 1,
3470
- name: "timestamp",
3682
+ name: "timestamp_ms",
3471
3683
  kind: "scalar",
3472
3684
  T: 3 /* ScalarType.INT64 */
3473
3685
  }, {
3474
3686
  no: 2,
3687
+ name: "normalized_timestamp",
3688
+ kind: "message",
3689
+ T: Timestamp
3690
+ }, {
3691
+ no: 3,
3475
3692
  name: "value",
3476
3693
  kind: "scalar",
3477
3694
  T: 2 /* ScalarType.FLOAT */
@@ -3497,17 +3714,28 @@ const EventMetric = /*@__PURE__*/proto3.makeMessageType("livekit.EventMetric", (
3497
3714
  T: 13 /* ScalarType.UINT32 */
3498
3715
  }, {
3499
3716
  no: 4,
3500
- name: "start_timestamp",
3717
+ name: "start_timestamp_ms",
3501
3718
  kind: "scalar",
3502
3719
  T: 3 /* ScalarType.INT64 */
3503
3720
  }, {
3504
3721
  no: 5,
3505
- name: "end_timestamp",
3722
+ name: "end_timestamp_ms",
3506
3723
  kind: "scalar",
3507
3724
  T: 3 /* ScalarType.INT64 */,
3508
3725
  opt: true
3509
3726
  }, {
3510
3727
  no: 6,
3728
+ name: "normalized_start_timestamp",
3729
+ kind: "message",
3730
+ T: Timestamp
3731
+ }, {
3732
+ no: 7,
3733
+ name: "normalized_end_timestamp",
3734
+ kind: "message",
3735
+ T: Timestamp,
3736
+ opt: true
3737
+ }, {
3738
+ no: 8,
3511
3739
  name: "metadata",
3512
3740
  kind: "scalar",
3513
3741
  T: 9 /* ScalarType.STRING */
@@ -4185,6 +4413,12 @@ const DataPacket = /*@__PURE__*/proto3.makeMessageType("livekit.DataPacket", ()
4185
4413
  kind: "message",
4186
4414
  T: MetricsBatch,
4187
4415
  oneof: "value"
4416
+ }, {
4417
+ no: 9,
4418
+ name: "chat_message",
4419
+ kind: "message",
4420
+ T: ChatMessage,
4421
+ oneof: "value"
4188
4422
  }]);
4189
4423
 
4190
4424
  /**
@@ -4356,6 +4590,42 @@ const TranscriptionSegment = /*@__PURE__*/proto3.makeMessageType("livekit.Transc
4356
4590
  T: 9 /* ScalarType.STRING */
4357
4591
  }]);
4358
4592
 
4593
+ /**
4594
+ * @generated from message livekit.ChatMessage
4595
+ */
4596
+ const ChatMessage = /*@__PURE__*/proto3.makeMessageType("livekit.ChatMessage", () => [{
4597
+ no: 1,
4598
+ name: "id",
4599
+ kind: "scalar",
4600
+ T: 9 /* ScalarType.STRING */
4601
+ }, {
4602
+ no: 2,
4603
+ name: "timestamp",
4604
+ kind: "scalar",
4605
+ T: 3 /* ScalarType.INT64 */
4606
+ }, {
4607
+ no: 3,
4608
+ name: "edit_timestamp",
4609
+ kind: "scalar",
4610
+ T: 3 /* ScalarType.INT64 */,
4611
+ opt: true
4612
+ }, {
4613
+ no: 4,
4614
+ name: "message",
4615
+ kind: "scalar",
4616
+ T: 9 /* ScalarType.STRING */
4617
+ }, {
4618
+ no: 5,
4619
+ name: "deleted",
4620
+ kind: "scalar",
4621
+ T: 8 /* ScalarType.BOOL */
4622
+ }, {
4623
+ no: 6,
4624
+ name: "generated",
4625
+ kind: "scalar",
4626
+ T: 8 /* ScalarType.BOOL */
4627
+ }]);
4628
+
4359
4629
  /**
4360
4630
  * @generated from message livekit.ParticipantTracks
4361
4631
  */
@@ -4518,6 +4788,12 @@ const ClientInfo_SDK = /*@__PURE__*/proto3.makeEnum("livekit.ClientInfo.SDK", [{
4518
4788
  }, {
4519
4789
  no: 10,
4520
4790
  name: "CPP"
4791
+ }, {
4792
+ no: 11,
4793
+ name: "UNITY_WEB"
4794
+ }, {
4795
+ no: 12,
4796
+ name: "NODE"
4521
4797
  }]);
4522
4798
 
4523
4799
  /**
@@ -6236,7 +6512,7 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
6236
6512
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
6237
6513
  PERFORMANCE OF THIS SOFTWARE.
6238
6514
  ***************************************************************************** */
6239
- /* global Reflect, Promise, SuppressedError, Symbol */
6515
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
6240
6516
 
6241
6517
 
6242
6518
  function __awaiter(thisArg, _arguments, P, generator) {
@@ -10320,6 +10596,7 @@ var RoomEvent;
10320
10596
  * args: (kind: MediaDeviceKind, deviceId: string)
10321
10597
  */
10322
10598
  RoomEvent["ActiveDeviceChanged"] = "activeDeviceChanged";
10599
+ RoomEvent["ChatMessage"] = "chatMessage";
10323
10600
  /**
10324
10601
  * fired when the first remote participant has subscribed to the localParticipant's track
10325
10602
  */
@@ -10491,6 +10768,8 @@ var ParticipantEvent;
10491
10768
  * fired on local participant only, when the first remote participant has subscribed to the track specified in the payload
10492
10769
  */
10493
10770
  ParticipantEvent["LocalTrackSubscribed"] = "localTrackSubscribed";
10771
+ /** only emitted on local participant */
10772
+ ParticipantEvent["ChatMessage"] = "chatMessage";
10494
10773
  })(ParticipantEvent || (ParticipantEvent = {}));
10495
10774
  /** @internal */
10496
10775
  var EngineEvent;
@@ -10714,7 +10993,7 @@ function getOSVersion(ua) {
10714
10993
  return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
10715
10994
  }
10716
10995
 
10717
- var version$1 = "2.5.1";
10996
+ var version$1 = "2.5.3";
10718
10997
 
10719
10998
  const version = version$1;
10720
10999
  const protocolVersion = 15;
@@ -11872,6 +12151,20 @@ function extractTranscriptionSegments(transcription, firstReceivedTimesMap) {
11872
12151
  };
11873
12152
  });
11874
12153
  }
12154
+ function extractChatMessage(msg) {
12155
+ const {
12156
+ id,
12157
+ timestamp,
12158
+ message,
12159
+ editTimestamp
12160
+ } = msg;
12161
+ return {
12162
+ id,
12163
+ timestamp: Number.parseInt(timestamp.toString()),
12164
+ editTimestamp: editTimestamp ? Number.parseInt(editTimestamp.toString()) : undefined,
12165
+ message
12166
+ };
12167
+ }
11875
12168
 
11876
12169
  const defaultId = 'default';
11877
12170
  class DeviceManager {
@@ -12139,17 +12432,21 @@ class LocalTrack extends Track {
12139
12432
  * @returns DeviceID of the device that is currently being used for this track
12140
12433
  */
12141
12434
  getDeviceId() {
12142
- return __awaiter(this, void 0, void 0, function* () {
12143
- // screen share doesn't have a usable device id
12144
- if (this.source === Track.Source.ScreenShare) {
12145
- return;
12146
- }
12147
- const {
12148
- deviceId,
12149
- groupId
12150
- } = this._mediaStreamTrack.getSettings();
12151
- const kind = this.kind === Track.Kind.Audio ? 'audioinput' : 'videoinput';
12152
- return DeviceManager.getInstance().normalizeDeviceId(kind, deviceId, groupId);
12435
+ return __awaiter(this, arguments, void 0, function () {
12436
+ var _this2 = this;
12437
+ let normalize = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
12438
+ return function* () {
12439
+ // screen share doesn't have a usable device id
12440
+ if (_this2.source === Track.Source.ScreenShare) {
12441
+ return;
12442
+ }
12443
+ const {
12444
+ deviceId,
12445
+ groupId
12446
+ } = _this2._mediaStreamTrack.getSettings();
12447
+ const kind = _this2.kind === Track.Kind.Audio ? 'audioinput' : 'videoinput';
12448
+ return normalize ? DeviceManager.getInstance().normalizeDeviceId(kind, deviceId, groupId) : deviceId;
12449
+ }();
12153
12450
  });
12154
12451
  }
12155
12452
  mute() {
@@ -12353,45 +12650,45 @@ class LocalTrack extends Track {
12353
12650
  */
12354
12651
  setProcessor(processor_1) {
12355
12652
  return __awaiter(this, arguments, void 0, function (processor) {
12356
- var _this2 = this;
12653
+ var _this3 = this;
12357
12654
  let showProcessedStreamLocally = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
12358
12655
  return function* () {
12359
12656
  var _a;
12360
- const unlock = yield _this2.processorLock.lock();
12657
+ const unlock = yield _this3.processorLock.lock();
12361
12658
  try {
12362
- _this2.log.debug('setting up processor', _this2.logContext);
12363
- const processorElement = document.createElement(_this2.kind);
12659
+ _this3.log.debug('setting up processor', _this3.logContext);
12660
+ const processorElement = document.createElement(_this3.kind);
12364
12661
  const processorOptions = {
12365
- kind: _this2.kind,
12366
- track: _this2._mediaStreamTrack,
12662
+ kind: _this3.kind,
12663
+ track: _this3._mediaStreamTrack,
12367
12664
  element: processorElement,
12368
- audioContext: _this2.audioContext
12665
+ audioContext: _this3.audioContext
12369
12666
  };
12370
12667
  yield processor.init(processorOptions);
12371
- _this2.log.debug('processor initialized', _this2.logContext);
12372
- if (_this2.processor) {
12373
- yield _this2.stopProcessor();
12668
+ _this3.log.debug('processor initialized', _this3.logContext);
12669
+ if (_this3.processor) {
12670
+ yield _this3.stopProcessor();
12374
12671
  }
12375
- if (_this2.kind === 'unknown') {
12672
+ if (_this3.kind === 'unknown') {
12376
12673
  throw TypeError('cannot set processor on track of unknown kind');
12377
12674
  }
12378
- attachToElement(_this2._mediaStreamTrack, processorElement);
12675
+ attachToElement(_this3._mediaStreamTrack, processorElement);
12379
12676
  processorElement.muted = true;
12380
- processorElement.play().catch(error => _this2.log.error('failed to play processor element', Object.assign(Object.assign({}, _this2.logContext), {
12677
+ processorElement.play().catch(error => _this3.log.error('failed to play processor element', Object.assign(Object.assign({}, _this3.logContext), {
12381
12678
  error
12382
12679
  })));
12383
- _this2.processor = processor;
12384
- _this2.processorElement = processorElement;
12385
- if (_this2.processor.processedTrack) {
12386
- for (const el of _this2.attachedElements) {
12387
- if (el !== _this2.processorElement && showProcessedStreamLocally) {
12388
- detachTrack(_this2._mediaStreamTrack, el);
12389
- attachToElement(_this2.processor.processedTrack, el);
12680
+ _this3.processor = processor;
12681
+ _this3.processorElement = processorElement;
12682
+ if (_this3.processor.processedTrack) {
12683
+ for (const el of _this3.attachedElements) {
12684
+ if (el !== _this3.processorElement && showProcessedStreamLocally) {
12685
+ detachTrack(_this3._mediaStreamTrack, el);
12686
+ attachToElement(_this3.processor.processedTrack, el);
12390
12687
  }
12391
12688
  }
12392
- yield (_a = _this2.sender) === null || _a === void 0 ? void 0 : _a.replaceTrack(_this2.processor.processedTrack);
12689
+ yield (_a = _this3.sender) === null || _a === void 0 ? void 0 : _a.replaceTrack(_this3.processor.processedTrack);
12393
12690
  }
12394
- _this2.emit(TrackEvent.TrackProcessorUpdate, _this2.processor);
12691
+ _this3.emit(TrackEvent.TrackProcessorUpdate, _this3.processor);
12395
12692
  } finally {
12396
12693
  unlock();
12397
12694
  }
@@ -12410,24 +12707,24 @@ class LocalTrack extends Track {
12410
12707
  */
12411
12708
  stopProcessor() {
12412
12709
  return __awaiter(this, arguments, void 0, function () {
12413
- var _this3 = this;
12710
+ var _this4 = this;
12414
12711
  let keepElement = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
12415
12712
  return function* () {
12416
12713
  var _a, _b;
12417
- if (!_this3.processor) return;
12418
- _this3.log.debug('stopping processor', _this3.logContext);
12419
- (_a = _this3.processor.processedTrack) === null || _a === void 0 ? void 0 : _a.stop();
12420
- yield _this3.processor.destroy();
12421
- _this3.processor = undefined;
12714
+ if (!_this4.processor) return;
12715
+ _this4.log.debug('stopping processor', _this4.logContext);
12716
+ (_a = _this4.processor.processedTrack) === null || _a === void 0 ? void 0 : _a.stop();
12717
+ yield _this4.processor.destroy();
12718
+ _this4.processor = undefined;
12422
12719
  if (!keepElement) {
12423
- (_b = _this3.processorElement) === null || _b === void 0 ? void 0 : _b.remove();
12424
- _this3.processorElement = undefined;
12720
+ (_b = _this4.processorElement) === null || _b === void 0 ? void 0 : _b.remove();
12721
+ _this4.processorElement = undefined;
12425
12722
  }
12426
12723
  // apply original track constraints in case the processor changed them
12427
- yield _this3._mediaStreamTrack.applyConstraints(_this3._constraints);
12724
+ yield _this4._mediaStreamTrack.applyConstraints(_this4._constraints);
12428
12725
  // force re-setting of the mediaStreamTrack on the sender
12429
- yield _this3.setMediaStreamTrack(_this3._mediaStreamTrack, true);
12430
- _this3.emit(TrackEvent.TrackProcessorUpdate);
12726
+ yield _this4.setMediaStreamTrack(_this4._mediaStreamTrack, true);
12727
+ _this4.emit(TrackEvent.TrackProcessorUpdate);
12431
12728
  }();
12432
12729
  });
12433
12730
  }
@@ -14801,6 +15098,7 @@ class PCTransportManager {
14801
15098
  };
14802
15099
  this.state = PCTransportState.NEW;
14803
15100
  this.connectionLock = new Mutex();
15101
+ this.remoteOfferLock = new Mutex();
14804
15102
  }
14805
15103
  get logContext() {
14806
15104
  var _a, _b;
@@ -14873,10 +15171,15 @@ class PCTransportManager {
14873
15171
  sdp: sd.sdp,
14874
15172
  signalingState: this.subscriber.getSignallingState().toString()
14875
15173
  }));
14876
- yield this.subscriber.setRemoteDescription(sd);
14877
- // answer the offer
14878
- const answer = yield this.subscriber.createAndSetAnswer();
14879
- return answer;
15174
+ const unlock = yield this.remoteOfferLock.lock();
15175
+ try {
15176
+ yield this.subscriber.setRemoteDescription(sd);
15177
+ // answer the offer
15178
+ const answer = yield this.subscriber.createAndSetAnswer();
15179
+ return answer;
15180
+ } finally {
15181
+ unlock();
15182
+ }
14880
15183
  });
14881
15184
  }
14882
15185
  updateConfiguration(config, iceRestart) {
@@ -18209,83 +18512,218 @@ class LocalTrackPublication extends TrackPublication {
18209
18512
  }
18210
18513
  }
18211
18514
 
18212
- var ConnectionQuality;
18213
- (function (ConnectionQuality) {
18214
- ConnectionQuality["Excellent"] = "excellent";
18215
- ConnectionQuality["Good"] = "good";
18216
- ConnectionQuality["Poor"] = "poor";
18217
- /**
18218
- * Indicates that a participant has temporarily (or permanently) lost connection to LiveKit.
18219
- * For permanent disconnection a `ParticipantDisconnected` event will be emitted after a timeout
18220
- */
18221
- ConnectionQuality["Lost"] = "lost";
18222
- ConnectionQuality["Unknown"] = "unknown";
18223
- })(ConnectionQuality || (ConnectionQuality = {}));
18224
- function qualityFromProto(q) {
18225
- switch (q) {
18226
- case ConnectionQuality$1.EXCELLENT:
18227
- return ConnectionQuality.Excellent;
18228
- case ConnectionQuality$1.GOOD:
18229
- return ConnectionQuality.Good;
18230
- case ConnectionQuality$1.POOR:
18231
- return ConnectionQuality.Poor;
18232
- case ConnectionQuality$1.LOST:
18233
- return ConnectionQuality.Lost;
18234
- default:
18235
- return ConnectionQuality.Unknown;
18515
+ /** @internal */
18516
+ function extractProcessorsFromOptions(options) {
18517
+ let audioProcessor;
18518
+ let videoProcessor;
18519
+ if (typeof options.audio === 'object' && options.audio.processor) {
18520
+ audioProcessor = options.audio.processor;
18521
+ }
18522
+ if (typeof options.video === 'object' && options.video.processor) {
18523
+ videoProcessor = options.video.processor;
18236
18524
  }
18525
+ return {
18526
+ audioProcessor,
18527
+ videoProcessor
18528
+ };
18237
18529
  }
18238
- class Participant extends eventsExports.EventEmitter {
18239
- get logContext() {
18530
+ /**
18531
+ * Creates a local video and audio track at the same time. When acquiring both
18532
+ * audio and video tracks together, it'll display a single permission prompt to
18533
+ * the user instead of two separate ones.
18534
+ * @param options
18535
+ */
18536
+ function createLocalTracks(options) {
18537
+ return __awaiter(this, void 0, void 0, function* () {
18240
18538
  var _a, _b;
18241
- return Object.assign({}, (_b = (_a = this.loggerOptions) === null || _a === void 0 ? void 0 : _a.loggerContextCb) === null || _b === void 0 ? void 0 : _b.call(_a));
18242
- }
18243
- get isEncrypted() {
18244
- return this.trackPublications.size > 0 && Array.from(this.trackPublications.values()).every(tr => tr.isEncrypted);
18245
- }
18246
- get isAgent() {
18247
- var _a;
18248
- return ((_a = this.permissions) === null || _a === void 0 ? void 0 : _a.agent) || this.kind === ParticipantInfo_Kind.AGENT;
18249
- }
18250
- get kind() {
18251
- return this._kind;
18252
- }
18253
- /** participant attributes, similar to metadata, but as a key/value map */
18254
- get attributes() {
18255
- return Object.freeze(Object.assign({}, this._attributes));
18256
- }
18257
- /** @internal */
18258
- constructor(sid, identity, name, metadata, loggerOptions) {
18259
- let kind = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : ParticipantInfo_Kind.STANDARD;
18260
- var _a;
18261
- super();
18262
- /** audio level between 0-1.0, 1 being loudest, 0 being softest */
18263
- this.audioLevel = 0;
18264
- /** if participant is currently speaking */
18265
- this.isSpeaking = false;
18266
- this._connectionQuality = ConnectionQuality.Unknown;
18267
- this.log = livekitLogger;
18268
- this.log = getLogger((_a = loggerOptions === null || loggerOptions === void 0 ? void 0 : loggerOptions.loggerName) !== null && _a !== void 0 ? _a : LoggerNames.Participant);
18269
- this.loggerOptions = loggerOptions;
18270
- this.setMaxListeners(100);
18271
- this.sid = sid;
18272
- this.identity = identity;
18273
- this.name = name;
18274
- this.metadata = metadata;
18275
- this.audioTrackPublications = new Map();
18276
- this.videoTrackPublications = new Map();
18277
- this.trackPublications = new Map();
18278
- this._kind = kind;
18279
- this._attributes = {};
18280
- }
18281
- getTrackPublications() {
18282
- return Array.from(this.trackPublications.values());
18283
- }
18284
- /**
18285
- * Finds the first track that matches the source filter, for example, getting
18286
- * the user's camera track with getTrackBySource(Track.Source.Camera).
18287
- */
18288
- getTrackPublication(source) {
18539
+ // set default options to true
18540
+ options !== null && options !== void 0 ? options : options = {};
18541
+ (_a = options.audio) !== null && _a !== void 0 ? _a : options.audio = true;
18542
+ (_b = options.video) !== null && _b !== void 0 ? _b : options.video = true;
18543
+ const {
18544
+ audioProcessor,
18545
+ videoProcessor
18546
+ } = extractProcessorsFromOptions(options);
18547
+ const opts = mergeDefaultOptions(options, audioDefaults, videoDefaults);
18548
+ const constraints = constraintsForOptions(opts);
18549
+ // Keep a reference to the promise on DeviceManager and await it in getLocalDevices()
18550
+ // works around iOS Safari Bug https://bugs.webkit.org/show_bug.cgi?id=179363
18551
+ const mediaPromise = navigator.mediaDevices.getUserMedia(constraints);
18552
+ if (options.audio) {
18553
+ DeviceManager.userMediaPromiseMap.set('audioinput', mediaPromise);
18554
+ mediaPromise.catch(() => DeviceManager.userMediaPromiseMap.delete('audioinput'));
18555
+ }
18556
+ if (options.video) {
18557
+ DeviceManager.userMediaPromiseMap.set('videoinput', mediaPromise);
18558
+ mediaPromise.catch(() => DeviceManager.userMediaPromiseMap.delete('videoinput'));
18559
+ }
18560
+ const stream = yield mediaPromise;
18561
+ return Promise.all(stream.getTracks().map(mediaStreamTrack => __awaiter(this, void 0, void 0, function* () {
18562
+ const isAudio = mediaStreamTrack.kind === 'audio';
18563
+ isAudio ? opts.audio : opts.video;
18564
+ let trackConstraints;
18565
+ const conOrBool = isAudio ? constraints.audio : constraints.video;
18566
+ if (typeof conOrBool !== 'boolean') {
18567
+ trackConstraints = conOrBool;
18568
+ }
18569
+ // update the constraints with the device id the user gave permissions to in the permission prompt
18570
+ // otherwise each track restart (e.g. mute - unmute) will try to initialize the device again -> causing additional permission prompts
18571
+ if (trackConstraints) {
18572
+ trackConstraints.deviceId = mediaStreamTrack.getSettings().deviceId;
18573
+ } else {
18574
+ trackConstraints = {
18575
+ deviceId: mediaStreamTrack.getSettings().deviceId
18576
+ };
18577
+ }
18578
+ const track = mediaTrackToLocalTrack(mediaStreamTrack, trackConstraints);
18579
+ if (track.kind === Track.Kind.Video) {
18580
+ track.source = Track.Source.Camera;
18581
+ } else if (track.kind === Track.Kind.Audio) {
18582
+ track.source = Track.Source.Microphone;
18583
+ }
18584
+ track.mediaStream = stream;
18585
+ if (track instanceof LocalAudioTrack && audioProcessor) {
18586
+ yield track.setProcessor(audioProcessor);
18587
+ } else if (track instanceof LocalVideoTrack && videoProcessor) {
18588
+ yield track.setProcessor(videoProcessor);
18589
+ }
18590
+ return track;
18591
+ })));
18592
+ });
18593
+ }
18594
+ /**
18595
+ * Creates a [[LocalVideoTrack]] with getUserMedia()
18596
+ * @param options
18597
+ */
18598
+ function createLocalVideoTrack(options) {
18599
+ return __awaiter(this, void 0, void 0, function* () {
18600
+ const tracks = yield createLocalTracks({
18601
+ audio: false,
18602
+ video: options
18603
+ });
18604
+ return tracks[0];
18605
+ });
18606
+ }
18607
+ function createLocalAudioTrack(options) {
18608
+ return __awaiter(this, void 0, void 0, function* () {
18609
+ const tracks = yield createLocalTracks({
18610
+ audio: options,
18611
+ video: false
18612
+ });
18613
+ return tracks[0];
18614
+ });
18615
+ }
18616
+ /**
18617
+ * Creates a screen capture tracks with getDisplayMedia().
18618
+ * A LocalVideoTrack is always created and returned.
18619
+ * If { audio: true }, and the browser supports audio capture, a LocalAudioTrack is also created.
18620
+ */
18621
+ function createLocalScreenTracks(options) {
18622
+ return __awaiter(this, void 0, void 0, function* () {
18623
+ if (options === undefined) {
18624
+ options = {};
18625
+ }
18626
+ if (options.resolution === undefined && !isSafari17()) {
18627
+ options.resolution = ScreenSharePresets.h1080fps30.resolution;
18628
+ }
18629
+ if (navigator.mediaDevices.getDisplayMedia === undefined) {
18630
+ throw new DeviceUnsupportedError('getDisplayMedia not supported');
18631
+ }
18632
+ const constraints = screenCaptureToDisplayMediaStreamOptions(options);
18633
+ const stream = yield navigator.mediaDevices.getDisplayMedia(constraints);
18634
+ const tracks = stream.getVideoTracks();
18635
+ if (tracks.length === 0) {
18636
+ throw new TrackInvalidError('no video track found');
18637
+ }
18638
+ const screenVideo = new LocalVideoTrack(tracks[0], undefined, false);
18639
+ screenVideo.source = Track.Source.ScreenShare;
18640
+ const localTracks = [screenVideo];
18641
+ if (stream.getAudioTracks().length > 0) {
18642
+ const screenAudio = new LocalAudioTrack(stream.getAudioTracks()[0], undefined, false);
18643
+ screenAudio.source = Track.Source.ScreenShareAudio;
18644
+ localTracks.push(screenAudio);
18645
+ }
18646
+ return localTracks;
18647
+ });
18648
+ }
18649
+
18650
+ var ConnectionQuality;
18651
+ (function (ConnectionQuality) {
18652
+ ConnectionQuality["Excellent"] = "excellent";
18653
+ ConnectionQuality["Good"] = "good";
18654
+ ConnectionQuality["Poor"] = "poor";
18655
+ /**
18656
+ * Indicates that a participant has temporarily (or permanently) lost connection to LiveKit.
18657
+ * For permanent disconnection a `ParticipantDisconnected` event will be emitted after a timeout
18658
+ */
18659
+ ConnectionQuality["Lost"] = "lost";
18660
+ ConnectionQuality["Unknown"] = "unknown";
18661
+ })(ConnectionQuality || (ConnectionQuality = {}));
18662
+ function qualityFromProto(q) {
18663
+ switch (q) {
18664
+ case ConnectionQuality$1.EXCELLENT:
18665
+ return ConnectionQuality.Excellent;
18666
+ case ConnectionQuality$1.GOOD:
18667
+ return ConnectionQuality.Good;
18668
+ case ConnectionQuality$1.POOR:
18669
+ return ConnectionQuality.Poor;
18670
+ case ConnectionQuality$1.LOST:
18671
+ return ConnectionQuality.Lost;
18672
+ default:
18673
+ return ConnectionQuality.Unknown;
18674
+ }
18675
+ }
18676
+ class Participant extends eventsExports.EventEmitter {
18677
+ get logContext() {
18678
+ var _a, _b;
18679
+ return Object.assign({}, (_b = (_a = this.loggerOptions) === null || _a === void 0 ? void 0 : _a.loggerContextCb) === null || _b === void 0 ? void 0 : _b.call(_a));
18680
+ }
18681
+ get isEncrypted() {
18682
+ return this.trackPublications.size > 0 && Array.from(this.trackPublications.values()).every(tr => tr.isEncrypted);
18683
+ }
18684
+ get isAgent() {
18685
+ var _a;
18686
+ return ((_a = this.permissions) === null || _a === void 0 ? void 0 : _a.agent) || this.kind === ParticipantInfo_Kind.AGENT;
18687
+ }
18688
+ get kind() {
18689
+ return this._kind;
18690
+ }
18691
+ /** participant attributes, similar to metadata, but as a key/value map */
18692
+ get attributes() {
18693
+ return Object.freeze(Object.assign({}, this._attributes));
18694
+ }
18695
+ /** @internal */
18696
+ constructor(sid, identity, name, metadata, loggerOptions) {
18697
+ let kind = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : ParticipantInfo_Kind.STANDARD;
18698
+ var _a;
18699
+ super();
18700
+ /** audio level between 0-1.0, 1 being loudest, 0 being softest */
18701
+ this.audioLevel = 0;
18702
+ /** if participant is currently speaking */
18703
+ this.isSpeaking = false;
18704
+ this._connectionQuality = ConnectionQuality.Unknown;
18705
+ this.log = livekitLogger;
18706
+ this.log = getLogger((_a = loggerOptions === null || loggerOptions === void 0 ? void 0 : loggerOptions.loggerName) !== null && _a !== void 0 ? _a : LoggerNames.Participant);
18707
+ this.loggerOptions = loggerOptions;
18708
+ this.setMaxListeners(100);
18709
+ this.sid = sid;
18710
+ this.identity = identity;
18711
+ this.name = name;
18712
+ this.metadata = metadata;
18713
+ this.audioTrackPublications = new Map();
18714
+ this.videoTrackPublications = new Map();
18715
+ this.trackPublications = new Map();
18716
+ this._kind = kind;
18717
+ this._attributes = {};
18718
+ }
18719
+ getTrackPublications() {
18720
+ return Array.from(this.trackPublications.values());
18721
+ }
18722
+ /**
18723
+ * Finds the first track that matches the source filter, for example, getting
18724
+ * the user's camera track with getTrackBySource(Track.Source.Camera).
18725
+ */
18726
+ getTrackPublication(source) {
18289
18727
  for (const [, pub] of this.trackPublications) {
18290
18728
  if (pub.source === source) {
18291
18729
  return pub;
@@ -18632,7 +19070,14 @@ class LocalParticipant extends Participant {
18632
19070
  }
18633
19071
  if (!track.isMuted) {
18634
19072
  this.log.debug('track ended, attempting to use a different device', Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)));
18635
- yield track.restartTrack();
19073
+ if (track instanceof LocalAudioTrack) {
19074
+ // fall back to default device if available
19075
+ yield track.restartTrack({
19076
+ deviceId: 'default'
19077
+ });
19078
+ } else {
19079
+ yield track.restartTrack();
19080
+ }
18636
19081
  }
18637
19082
  } catch (e) {
18638
19083
  this.log.warn("could not restart track, muting instead", Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)));
@@ -18821,6 +19266,9 @@ class LocalParticipant extends Participant {
18821
19266
  source,
18822
19267
  enabled
18823
19268
  }));
19269
+ if (this.republishPromise) {
19270
+ yield this.republishPromise;
19271
+ }
18824
19272
  let track = this.getTrackPublication(source);
18825
19273
  if (enabled) {
18826
19274
  if (track) {
@@ -18828,11 +19276,14 @@ class LocalParticipant extends Participant {
18828
19276
  } else {
18829
19277
  let localTracks;
18830
19278
  if (this.pendingPublishing.has(source)) {
18831
- this.log.info('skipping duplicate published source', Object.assign(Object.assign({}, this.logContext), {
18832
- source
18833
- }));
18834
- // no-op it's already been requested
18835
- return;
19279
+ const pendingTrack = yield this.waitForPendingPublicationOfSource(source);
19280
+ if (!pendingTrack) {
19281
+ this.log.info('skipping duplicate published source', Object.assign(Object.assign({}, this.logContext), {
19282
+ source
19283
+ }));
19284
+ }
19285
+ yield pendingTrack === null || pendingTrack === void 0 ? void 0 : pendingTrack.unmute();
19286
+ return pendingTrack;
18836
19287
  }
18837
19288
  this.pendingPublishing.add(source);
18838
19289
  try {
@@ -18874,16 +19325,22 @@ class LocalParticipant extends Participant {
18874
19325
  this.pendingPublishing.delete(source);
18875
19326
  }
18876
19327
  }
18877
- } else if (track && track.track) {
18878
- // screenshare cannot be muted, unpublish instead
18879
- if (source === Track.Source.ScreenShare) {
18880
- track = yield this.unpublishTrack(track.track);
18881
- const screenAudioTrack = this.getTrackPublication(Track.Source.ScreenShareAudio);
18882
- if (screenAudioTrack && screenAudioTrack.track) {
18883
- this.unpublishTrack(screenAudioTrack.track);
19328
+ } else {
19329
+ if (!(track === null || track === void 0 ? void 0 : track.track)) {
19330
+ // if there's no track available yet first wait for pending publishing promises of that source to see if it becomes available
19331
+ track = yield this.waitForPendingPublicationOfSource(source);
19332
+ }
19333
+ if (track && track.track) {
19334
+ // screenshare cannot be muted, unpublish instead
19335
+ if (source === Track.Source.ScreenShare) {
19336
+ track = yield this.unpublishTrack(track.track);
19337
+ const screenAudioTrack = this.getTrackPublication(Track.Source.ScreenShareAudio);
19338
+ if (screenAudioTrack && screenAudioTrack.track) {
19339
+ this.unpublishTrack(screenAudioTrack.track);
19340
+ }
19341
+ } else {
19342
+ yield track.mute();
18884
19343
  }
18885
- } else {
18886
- yield track.mute();
18887
19344
  }
18888
19345
  }
18889
19346
  return track;
@@ -18921,6 +19378,11 @@ class LocalParticipant extends Participant {
18921
19378
  createTracks(options) {
18922
19379
  return __awaiter(this, void 0, void 0, function* () {
18923
19380
  var _a, _b;
19381
+ options !== null && options !== void 0 ? options : options = {};
19382
+ const {
19383
+ audioProcessor,
19384
+ videoProcessor
19385
+ } = extractProcessorsFromOptions(options);
18924
19386
  const mergedOptions = mergeDefaultOptions(options, (_a = this.roomOptions) === null || _a === void 0 ? void 0 : _a.audioCaptureDefaults, (_b = this.roomOptions) === null || _b === void 0 ? void 0 : _b.videoCaptureDefaults);
18925
19387
  const constraints = constraintsForOptions(mergedOptions);
18926
19388
  let stream;
@@ -18946,10 +19408,7 @@ class LocalParticipant extends Participant {
18946
19408
  }
18947
19409
  return Promise.all(stream.getTracks().map(mediaStreamTrack => __awaiter(this, void 0, void 0, function* () {
18948
19410
  const isAudio = mediaStreamTrack.kind === 'audio';
18949
- let trackOptions = isAudio ? mergedOptions.audio : mergedOptions.video;
18950
- if (typeof trackOptions === 'boolean' || !trackOptions) {
18951
- trackOptions = {};
18952
- }
19411
+ isAudio ? mergedOptions.audio : mergedOptions.video;
18953
19412
  let trackConstraints;
18954
19413
  const conOrBool = isAudio ? constraints.audio : constraints.video;
18955
19414
  if (typeof conOrBool !== 'boolean') {
@@ -18966,12 +19425,10 @@ class LocalParticipant extends Participant {
18966
19425
  track.setAudioContext(this.audioContext);
18967
19426
  }
18968
19427
  track.mediaStream = stream;
18969
- if (trackOptions.processor) {
18970
- if (track instanceof LocalAudioTrack) {
18971
- yield track.setProcessor(trackOptions.processor);
18972
- } else {
18973
- yield track.setProcessor(trackOptions.processor);
18974
- }
19428
+ if (track instanceof LocalAudioTrack && audioProcessor) {
19429
+ yield track.setProcessor(audioProcessor);
19430
+ } else if (track instanceof LocalVideoTrack && videoProcessor) {
19431
+ yield track.setProcessor(videoProcessor);
18975
19432
  }
18976
19433
  return track;
18977
19434
  })));
@@ -19030,109 +19487,121 @@ class LocalParticipant extends Participant {
19030
19487
  */
19031
19488
  publishTrack(track, options) {
19032
19489
  return __awaiter(this, void 0, void 0, function* () {
19033
- var _a, _b, _c, _d;
19034
- if (track instanceof LocalAudioTrack) {
19035
- track.setAudioContext(this.audioContext);
19036
- }
19037
- yield (_a = this.reconnectFuture) === null || _a === void 0 ? void 0 : _a.promise;
19038
- if (track instanceof LocalTrack && this.pendingPublishPromises.has(track)) {
19039
- yield this.pendingPublishPromises.get(track);
19040
- }
19041
- let defaultConstraints;
19042
- if (track instanceof MediaStreamTrack) {
19043
- defaultConstraints = track.getConstraints();
19044
- } else {
19045
- // we want to access constraints directly as `track.mediaStreamTrack`
19046
- // might be pointing to a non-device track (e.g. processed track) already
19047
- defaultConstraints = track.constraints;
19048
- let deviceKind = undefined;
19049
- switch (track.source) {
19050
- case Track.Source.Microphone:
19051
- deviceKind = 'audioinput';
19052
- break;
19053
- case Track.Source.Camera:
19054
- deviceKind = 'videoinput';
19490
+ return this.publishOrRepublishTrack(track, options);
19491
+ });
19492
+ }
19493
+ publishOrRepublishTrack(track_1, options_1) {
19494
+ return __awaiter(this, arguments, void 0, function (track, options) {
19495
+ var _this2 = this;
19496
+ let isRepublish = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
19497
+ return function* () {
19498
+ var _a, _b, _c, _d;
19499
+ if (track instanceof LocalAudioTrack) {
19500
+ track.setAudioContext(_this2.audioContext);
19055
19501
  }
19056
- if (deviceKind && this.activeDeviceMap.has(deviceKind)) {
19057
- defaultConstraints = Object.assign(Object.assign({}, defaultConstraints), {
19058
- deviceId: this.activeDeviceMap.get(deviceKind)
19059
- });
19502
+ yield (_a = _this2.reconnectFuture) === null || _a === void 0 ? void 0 : _a.promise;
19503
+ if (_this2.republishPromise && !isRepublish) {
19504
+ yield _this2.republishPromise;
19060
19505
  }
19061
- }
19062
- // convert raw media track into audio or video track
19063
- if (track instanceof MediaStreamTrack) {
19064
- switch (track.kind) {
19065
- case 'audio':
19066
- track = new LocalAudioTrack(track, defaultConstraints, true, this.audioContext, {
19067
- loggerName: this.roomOptions.loggerName,
19068
- loggerContextCb: () => this.logContext
19069
- });
19070
- break;
19071
- case 'video':
19072
- track = new LocalVideoTrack(track, defaultConstraints, true, {
19073
- loggerName: this.roomOptions.loggerName,
19074
- loggerContextCb: () => this.logContext
19506
+ if (track instanceof LocalTrack && _this2.pendingPublishPromises.has(track)) {
19507
+ yield _this2.pendingPublishPromises.get(track);
19508
+ }
19509
+ let defaultConstraints;
19510
+ if (track instanceof MediaStreamTrack) {
19511
+ defaultConstraints = track.getConstraints();
19512
+ } else {
19513
+ // we want to access constraints directly as `track.mediaStreamTrack`
19514
+ // might be pointing to a non-device track (e.g. processed track) already
19515
+ defaultConstraints = track.constraints;
19516
+ let deviceKind = undefined;
19517
+ switch (track.source) {
19518
+ case Track.Source.Microphone:
19519
+ deviceKind = 'audioinput';
19520
+ break;
19521
+ case Track.Source.Camera:
19522
+ deviceKind = 'videoinput';
19523
+ }
19524
+ if (deviceKind && _this2.activeDeviceMap.has(deviceKind)) {
19525
+ defaultConstraints = Object.assign(Object.assign({}, defaultConstraints), {
19526
+ deviceId: _this2.activeDeviceMap.get(deviceKind)
19075
19527
  });
19076
- break;
19077
- default:
19078
- throw new TrackInvalidError("unsupported MediaStreamTrack kind ".concat(track.kind));
19528
+ }
19079
19529
  }
19080
- } else {
19081
- track.updateLoggerOptions({
19082
- loggerName: this.roomOptions.loggerName,
19083
- loggerContextCb: () => this.logContext
19530
+ // convert raw media track into audio or video track
19531
+ if (track instanceof MediaStreamTrack) {
19532
+ switch (track.kind) {
19533
+ case 'audio':
19534
+ track = new LocalAudioTrack(track, defaultConstraints, true, _this2.audioContext, {
19535
+ loggerName: _this2.roomOptions.loggerName,
19536
+ loggerContextCb: () => _this2.logContext
19537
+ });
19538
+ break;
19539
+ case 'video':
19540
+ track = new LocalVideoTrack(track, defaultConstraints, true, {
19541
+ loggerName: _this2.roomOptions.loggerName,
19542
+ loggerContextCb: () => _this2.logContext
19543
+ });
19544
+ break;
19545
+ default:
19546
+ throw new TrackInvalidError("unsupported MediaStreamTrack kind ".concat(track.kind));
19547
+ }
19548
+ } else {
19549
+ track.updateLoggerOptions({
19550
+ loggerName: _this2.roomOptions.loggerName,
19551
+ loggerContextCb: () => _this2.logContext
19552
+ });
19553
+ }
19554
+ // is it already published? if so skip
19555
+ let existingPublication;
19556
+ _this2.trackPublications.forEach(publication => {
19557
+ if (!publication.track) {
19558
+ return;
19559
+ }
19560
+ if (publication.track === track) {
19561
+ existingPublication = publication;
19562
+ }
19084
19563
  });
19085
- }
19086
- // is it already published? if so skip
19087
- let existingPublication;
19088
- this.trackPublications.forEach(publication => {
19089
- if (!publication.track) {
19090
- return;
19564
+ if (existingPublication) {
19565
+ _this2.log.warn('track has already been published, skipping', Object.assign(Object.assign({}, _this2.logContext), getLogContextFromTrack(existingPublication)));
19566
+ return existingPublication;
19567
+ }
19568
+ const isStereoInput = 'channelCount' in track.mediaStreamTrack.getSettings() &&
19569
+ // @ts-ignore `channelCount` on getSettings() is currently only available for Safari, but is generally the best way to determine a stereo track https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackSettings/channelCount
19570
+ track.mediaStreamTrack.getSettings().channelCount === 2 || track.mediaStreamTrack.getConstraints().channelCount === 2;
19571
+ const isStereo = (_b = options === null || options === void 0 ? void 0 : options.forceStereo) !== null && _b !== void 0 ? _b : isStereoInput;
19572
+ // disable dtx for stereo track if not enabled explicitly
19573
+ if (isStereo) {
19574
+ if (!options) {
19575
+ options = {};
19576
+ }
19577
+ if (options.dtx === undefined) {
19578
+ _this2.log.info("Opus DTX will be disabled for stereo tracks by default. Enable them explicitly to make it work.", Object.assign(Object.assign({}, _this2.logContext), getLogContextFromTrack(track)));
19579
+ }
19580
+ if (options.red === undefined) {
19581
+ _this2.log.info("Opus RED will be disabled for stereo tracks by default. Enable them explicitly to make it work.");
19582
+ }
19583
+ (_c = options.dtx) !== null && _c !== void 0 ? _c : options.dtx = false;
19584
+ (_d = options.red) !== null && _d !== void 0 ? _d : options.red = false;
19091
19585
  }
19092
- if (publication.track === track) {
19093
- existingPublication = publication;
19586
+ const opts = Object.assign(Object.assign({}, _this2.roomOptions.publishDefaults), options);
19587
+ if (!isE2EESimulcastSupported() && _this2.roomOptions.e2ee) {
19588
+ _this2.log.info("End-to-end encryption is set up, simulcast publishing will be disabled on Safari versions and iOS browsers running iOS < v17.2", Object.assign({}, _this2.logContext));
19589
+ opts.simulcast = false;
19094
19590
  }
19095
- });
19096
- if (existingPublication) {
19097
- this.log.warn('track has already been published, skipping', Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(existingPublication)));
19098
- return existingPublication;
19099
- }
19100
- const isStereoInput = 'channelCount' in track.mediaStreamTrack.getSettings() &&
19101
- // @ts-ignore `channelCount` on getSettings() is currently only available for Safari, but is generally the best way to determine a stereo track https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackSettings/channelCount
19102
- track.mediaStreamTrack.getSettings().channelCount === 2 || track.mediaStreamTrack.getConstraints().channelCount === 2;
19103
- const isStereo = (_b = options === null || options === void 0 ? void 0 : options.forceStereo) !== null && _b !== void 0 ? _b : isStereoInput;
19104
- // disable dtx for stereo track if not enabled explicitly
19105
- if (isStereo) {
19106
- if (!options) {
19107
- options = {};
19108
- }
19109
- if (options.dtx === undefined) {
19110
- this.log.info("Opus DTX will be disabled for stereo tracks by default. Enable them explicitly to make it work.", Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)));
19111
- }
19112
- if (options.red === undefined) {
19113
- this.log.info("Opus RED will be disabled for stereo tracks by default. Enable them explicitly to make it work.");
19114
- }
19115
- (_c = options.dtx) !== null && _c !== void 0 ? _c : options.dtx = false;
19116
- (_d = options.red) !== null && _d !== void 0 ? _d : options.red = false;
19117
- }
19118
- const opts = Object.assign(Object.assign({}, this.roomOptions.publishDefaults), options);
19119
- if (!isE2EESimulcastSupported() && this.roomOptions.e2ee) {
19120
- this.log.info("End-to-end encryption is set up, simulcast publishing will be disabled on Safari versions and iOS browsers running iOS < v17.2", Object.assign({}, this.logContext));
19121
- opts.simulcast = false;
19122
- }
19123
- if (opts.source) {
19124
- track.source = opts.source;
19125
- }
19126
- const publishPromise = this.publish(track, opts, isStereo);
19127
- this.pendingPublishPromises.set(track, publishPromise);
19128
- try {
19129
- const publication = yield publishPromise;
19130
- return publication;
19131
- } catch (e) {
19132
- throw e;
19133
- } finally {
19134
- this.pendingPublishPromises.delete(track);
19135
- }
19591
+ if (opts.source) {
19592
+ track.source = opts.source;
19593
+ }
19594
+ const publishPromise = _this2.publish(track, opts, isStereo);
19595
+ _this2.pendingPublishPromises.set(track, publishPromise);
19596
+ try {
19597
+ const publication = yield publishPromise;
19598
+ return publication;
19599
+ } catch (e) {
19600
+ throw e;
19601
+ } finally {
19602
+ _this2.pendingPublishPromises.delete(track);
19603
+ }
19604
+ }();
19136
19605
  });
19137
19606
  }
19138
19607
  publish(track, opts, isStereo) {
@@ -19518,31 +19987,44 @@ class LocalParticipant extends Participant {
19518
19987
  }
19519
19988
  republishAllTracks(options_1) {
19520
19989
  return __awaiter(this, arguments, void 0, function (options) {
19521
- var _this2 = this;
19990
+ var _this3 = this;
19522
19991
  let restartTracks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
19523
19992
  return function* () {
19524
- const localPubs = [];
19525
- _this2.trackPublications.forEach(pub => {
19526
- if (pub.track) {
19527
- if (options) {
19528
- pub.options = Object.assign(Object.assign({}, pub.options), options);
19529
- }
19530
- localPubs.push(pub);
19531
- }
19532
- });
19533
- yield Promise.all(localPubs.map(pub => __awaiter(_this2, void 0, void 0, function* () {
19534
- const track = pub.track;
19535
- yield this.unpublishTrack(track, false);
19536
- if (restartTracks && !track.isMuted && track.source !== Track.Source.ScreenShare && track.source !== Track.Source.ScreenShareAudio && (track instanceof LocalAudioTrack || track instanceof LocalVideoTrack) && !track.isUserProvided) {
19537
- // generally we need to restart the track before publishing, often a full reconnect
19538
- // is necessary because computer had gone to sleep.
19539
- this.log.debug('restarting existing track', Object.assign(Object.assign({}, this.logContext), {
19540
- track: pub.trackSid
19541
- }));
19542
- yield track.restartTrack();
19993
+ if (_this3.republishPromise) {
19994
+ yield _this3.republishPromise;
19995
+ }
19996
+ _this3.republishPromise = new Promise((resolve, reject) => __awaiter(_this3, void 0, void 0, function* () {
19997
+ try {
19998
+ const localPubs = [];
19999
+ this.trackPublications.forEach(pub => {
20000
+ if (pub.track) {
20001
+ if (options) {
20002
+ pub.options = Object.assign(Object.assign({}, pub.options), options);
20003
+ }
20004
+ localPubs.push(pub);
20005
+ }
20006
+ });
20007
+ yield Promise.all(localPubs.map(pub => __awaiter(this, void 0, void 0, function* () {
20008
+ const track = pub.track;
20009
+ yield this.unpublishTrack(track, false);
20010
+ if (restartTracks && !track.isMuted && track.source !== Track.Source.ScreenShare && track.source !== Track.Source.ScreenShareAudio && (track instanceof LocalAudioTrack || track instanceof LocalVideoTrack) && !track.isUserProvided) {
20011
+ // generally we need to restart the track before publishing, often a full reconnect
20012
+ // is necessary because computer had gone to sleep.
20013
+ this.log.debug('restarting existing track', Object.assign(Object.assign({}, this.logContext), {
20014
+ track: pub.trackSid
20015
+ }));
20016
+ yield track.restartTrack();
20017
+ }
20018
+ yield this.publishOrRepublishTrack(track, pub.options, true);
20019
+ })));
20020
+ resolve();
20021
+ } catch (error) {
20022
+ reject(error);
20023
+ } finally {
20024
+ this.republishPromise = undefined;
19543
20025
  }
19544
- yield this.publishTrack(track, pub.options);
19545
- })));
20026
+ }));
20027
+ yield _this3.republishPromise;
19546
20028
  }();
19547
20029
  });
19548
20030
  }
@@ -19555,7 +20037,7 @@ class LocalParticipant extends Participant {
19555
20037
  */
19556
20038
  publishData(data_1) {
19557
20039
  return __awaiter(this, arguments, void 0, function (data) {
19558
- var _this3 = this;
20040
+ var _this4 = this;
19559
20041
  let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
19560
20042
  return function* () {
19561
20043
  const kind = options.reliable ? DataPacket_Kind.RELIABLE : DataPacket_Kind.LOSSY;
@@ -19566,17 +20048,57 @@ class LocalParticipant extends Participant {
19566
20048
  value: {
19567
20049
  case: 'user',
19568
20050
  value: new UserPacket({
19569
- participantIdentity: _this3.identity,
20051
+ participantIdentity: _this4.identity,
19570
20052
  payload: data,
19571
20053
  destinationIdentities,
19572
20054
  topic
19573
20055
  })
19574
20056
  }
19575
20057
  });
19576
- yield _this3.engine.sendDataPacket(packet, kind);
20058
+ yield _this4.engine.sendDataPacket(packet, kind);
19577
20059
  }();
19578
20060
  });
19579
20061
  }
20062
+ sendChatMessage(text) {
20063
+ return __awaiter(this, void 0, void 0, function* () {
20064
+ const msg = {
20065
+ id: crypto.randomUUID(),
20066
+ message: text,
20067
+ timestamp: Date.now()
20068
+ };
20069
+ const packet = new DataPacket({
20070
+ value: {
20071
+ case: 'chatMessage',
20072
+ value: new ChatMessage(Object.assign(Object.assign({}, msg), {
20073
+ timestamp: protoInt64.parse(msg.timestamp)
20074
+ }))
20075
+ }
20076
+ });
20077
+ yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
20078
+ this.emit(ParticipantEvent.ChatMessage, msg);
20079
+ return msg;
20080
+ });
20081
+ }
20082
+ editChatMessage(editText, originalMessage) {
20083
+ return __awaiter(this, void 0, void 0, function* () {
20084
+ const msg = Object.assign(Object.assign({}, originalMessage), {
20085
+ message: editText,
20086
+ editTimestamp: Date.now()
20087
+ });
20088
+ const packet = new DataPacket({
20089
+ value: {
20090
+ case: 'chatMessage',
20091
+ value: new ChatMessage(Object.assign(Object.assign({}, msg), {
20092
+ timestamp: protoInt64.parse(msg.timestamp),
20093
+ editTimestamp: protoInt64.parse(msg.editTimestamp)
20094
+ }))
20095
+ }
20096
+ });
20097
+ yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
20098
+ this.emit(ParticipantEvent.ChatMessage, msg);
20099
+ return msg;
20100
+ });
20101
+ }
19580
20102
  /**
19581
20103
  * Control who can subscribe to LocalParticipant's published tracks.
19582
20104
  *
@@ -19654,6 +20176,17 @@ class LocalParticipant extends Participant {
19654
20176
  });
19655
20177
  return publication;
19656
20178
  }
20179
+ waitForPendingPublicationOfSource(source) {
20180
+ return __awaiter(this, void 0, void 0, function* () {
20181
+ const publishPromiseEntry = Array.from(this.pendingPublishPromises.entries()).find(_ref3 => {
20182
+ let [pendingTrack] = _ref3;
20183
+ return pendingTrack.source === source;
20184
+ });
20185
+ if (publishPromiseEntry) {
20186
+ return publishPromiseEntry[1];
20187
+ }
20188
+ });
20189
+ }
19657
20190
  }
19658
20191
 
19659
20192
  class RemoteTrackPublication extends TrackPublication {
@@ -20724,6 +21257,8 @@ class Room extends eventsExports.EventEmitter {
20724
21257
  this.handleTranscription(participant, packet.value.value);
20725
21258
  } else if (packet.value.case === 'sipDtmf') {
20726
21259
  this.handleSipDtmf(participant, packet.value.value);
21260
+ } else if (packet.value.case === 'chatMessage') {
21261
+ this.handleChatMessage(participant, packet.value.value);
20727
21262
  }
20728
21263
  };
20729
21264
  this.handleUserPacket = (participant, userPacket, kind) => {
@@ -20746,6 +21281,10 @@ class Room extends eventsExports.EventEmitter {
20746
21281
  participant === null || participant === void 0 ? void 0 : participant.emit(ParticipantEvent.TranscriptionReceived, segments, publication);
20747
21282
  this.emit(RoomEvent.TranscriptionReceived, segments, participant, publication);
20748
21283
  };
21284
+ this.handleChatMessage = (participant, chatMessage) => {
21285
+ const msg = extractChatMessage(chatMessage);
21286
+ this.emit(RoomEvent.ChatMessage, msg, participant);
21287
+ };
20749
21288
  this.handleAudioPlaybackStarted = () => {
20750
21289
  if (this.canPlaybackAudio) {
20751
21290
  return;
@@ -20776,6 +21315,17 @@ class Room extends eventsExports.EventEmitter {
20776
21315
  }
20777
21316
  };
20778
21317
  this.handleDeviceChange = () => __awaiter(this, void 0, void 0, function* () {
21318
+ // check for available devices, but don't request permissions in order to avoid prompts for kinds that haven't been used before
21319
+ const availableDevices = yield DeviceManager.getInstance().getDevices(undefined, false);
21320
+ // inputs are automatically handled via TrackEvent.Ended causing a TrackEvent.Restarted. Here we only need to worry about audiooutputs changing
21321
+ const kinds = ['audiooutput'];
21322
+ for (let kind of kinds) {
21323
+ // switch to first available device if previously active device is not available any more
21324
+ const devicesOfKind = availableDevices.filter(d => d.kind === kind);
21325
+ if (devicesOfKind.length > 0 && !devicesOfKind.find(deviceInfo => deviceInfo.deviceId === this.getActiveDevice(kind))) {
21326
+ yield this.switchActiveDevice(kind, devicesOfKind[0].deviceId);
21327
+ }
21328
+ }
20779
21329
  this.emit(RoomEvent.MediaDevicesChanged);
20780
21330
  });
20781
21331
  this.handleRoomUpdate = room => {
@@ -20820,9 +21370,10 @@ class Room extends eventsExports.EventEmitter {
20820
21370
  (_a = processor === null || processor === void 0 ? void 0 : processor.onPublish) === null || _a === void 0 ? void 0 : _a.call(processor, this);
20821
21371
  };
20822
21372
  this.onLocalTrackPublished = pub => __awaiter(this, void 0, void 0, function* () {
20823
- var _a, _b, _c, _d, _e;
21373
+ var _a, _b, _c, _d, _e, _f;
20824
21374
  (_a = pub.track) === null || _a === void 0 ? void 0 : _a.on(TrackEvent.TrackProcessorUpdate, this.onTrackProcessorUpdate);
20825
- (_d = (_c = (_b = pub.track) === null || _b === void 0 ? void 0 : _b.getProcessor()) === null || _c === void 0 ? void 0 : _c.onPublish) === null || _d === void 0 ? void 0 : _d.call(_c, this);
21375
+ (_b = pub.track) === null || _b === void 0 ? void 0 : _b.on(TrackEvent.Restarted, this.onLocalTrackRestarted);
21376
+ (_e = (_d = (_c = pub.track) === null || _c === void 0 ? void 0 : _c.getProcessor()) === null || _d === void 0 ? void 0 : _d.onPublish) === null || _e === void 0 ? void 0 : _e.call(_d, this);
20826
21377
  this.emit(RoomEvent.LocalTrackPublished, pub, this.localParticipant);
20827
21378
  if (pub.track instanceof LocalAudioTrack) {
20828
21379
  const trackIsSilent = yield pub.track.checkForSilence();
@@ -20830,7 +21381,7 @@ class Room extends eventsExports.EventEmitter {
20830
21381
  this.emit(RoomEvent.LocalAudioSilenceDetected, pub);
20831
21382
  }
20832
21383
  }
20833
- const deviceId = yield (_e = pub.track) === null || _e === void 0 ? void 0 : _e.getDeviceId();
21384
+ const deviceId = yield (_f = pub.track) === null || _f === void 0 ? void 0 : _f.getDeviceId();
20834
21385
  const deviceKind = sourceToKind(pub.source);
20835
21386
  if (deviceKind && deviceId && deviceId !== this.localParticipant.activeDeviceMap.get(deviceKind)) {
20836
21387
  this.localParticipant.activeDeviceMap.set(deviceKind, deviceId);
@@ -20838,10 +21389,20 @@ class Room extends eventsExports.EventEmitter {
20838
21389
  }
20839
21390
  });
20840
21391
  this.onLocalTrackUnpublished = pub => {
20841
- var _a;
21392
+ var _a, _b;
20842
21393
  (_a = pub.track) === null || _a === void 0 ? void 0 : _a.off(TrackEvent.TrackProcessorUpdate, this.onTrackProcessorUpdate);
21394
+ (_b = pub.track) === null || _b === void 0 ? void 0 : _b.off(TrackEvent.Restarted, this.onLocalTrackRestarted);
20843
21395
  this.emit(RoomEvent.LocalTrackUnpublished, pub, this.localParticipant);
20844
21396
  };
21397
+ this.onLocalTrackRestarted = track => __awaiter(this, void 0, void 0, function* () {
21398
+ const deviceId = yield track.getDeviceId(false);
21399
+ const deviceKind = sourceToKind(track.source);
21400
+ if (deviceKind && deviceId && deviceId !== this.localParticipant.activeDeviceMap.get(deviceKind)) {
21401
+ this.log.debug("local track restarted, setting ".concat(deviceKind, " ").concat(deviceId, " active"), this.logContext);
21402
+ this.localParticipant.activeDeviceMap.set(deviceKind, deviceId);
21403
+ this.emit(RoomEvent.ActiveDeviceChanged, deviceKind, deviceId);
21404
+ }
21405
+ });
20845
21406
  this.onLocalConnectionQualityChanged = quality => {
20846
21407
  this.emit(RoomEvent.ConnectionQualityChanged, quality, this.localParticipant);
20847
21408
  };
@@ -20851,6 +21412,9 @@ class Room extends eventsExports.EventEmitter {
20851
21412
  this.onLocalParticipantPermissionsChanged = prevPermissions => {
20852
21413
  this.emit(RoomEvent.ParticipantPermissionsChanged, prevPermissions, this.localParticipant);
20853
21414
  };
21415
+ this.onLocalChatMessageSent = msg => {
21416
+ this.emit(RoomEvent.ChatMessage, msg, this.localParticipant);
21417
+ };
20854
21418
  this.setMaxListeners(100);
20855
21419
  this.remoteParticipants = new Map();
20856
21420
  this.sidToIdentity = new Map();
@@ -21025,9 +21589,8 @@ class Room extends eventsExports.EventEmitter {
21025
21589
  }
21026
21590
  /**
21027
21591
  * getLocalDevices abstracts navigator.mediaDevices.enumerateDevices.
21028
- * In particular, it handles Chrome's unique behavior of creating `default`
21029
- * devices. When encountered, it'll be removed from the list of devices.
21030
- * The actual default device will be placed at top.
21592
+ * In particular, it requests device permissions by default if needed
21593
+ * and makes sure the returned device does not consist of dummy devices
21031
21594
  * @param kind
21032
21595
  * @returns a list of available local devices
21033
21596
  */
@@ -21240,15 +21803,15 @@ class Room extends eventsExports.EventEmitter {
21240
21803
  var _this3 = this;
21241
21804
  let exact = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
21242
21805
  return function* () {
21243
- var _a, _b, _c;
21244
- var _d;
21806
+ var _a, _b, _c, _d, _e, _f;
21807
+ var _g;
21245
21808
  let deviceHasChanged = false;
21246
21809
  let success = true;
21247
21810
  const deviceConstraint = exact ? {
21248
21811
  exact: deviceId
21249
21812
  } : deviceId;
21250
21813
  if (kind === 'audioinput') {
21251
- const prevDeviceId = _this3.options.audioCaptureDefaults.deviceId;
21814
+ const prevDeviceId = (_a = _this3.getActiveDevice(kind)) !== null && _a !== void 0 ? _a : _this3.options.audioCaptureDefaults.deviceId;
21252
21815
  _this3.options.audioCaptureDefaults.deviceId = deviceConstraint;
21253
21816
  deviceHasChanged = prevDeviceId !== deviceConstraint;
21254
21817
  const tracks = Array.from(_this3.localParticipant.audioTrackPublications.values()).filter(track => track.source === Track.Source.Microphone);
@@ -21262,7 +21825,7 @@ class Room extends eventsExports.EventEmitter {
21262
21825
  throw e;
21263
21826
  }
21264
21827
  } else if (kind === 'videoinput') {
21265
- const prevDeviceId = _this3.options.videoCaptureDefaults.deviceId;
21828
+ const prevDeviceId = (_b = _this3.getActiveDevice(kind)) !== null && _b !== void 0 ? _b : _this3.options.videoCaptureDefaults.deviceId;
21266
21829
  _this3.options.videoCaptureDefaults.deviceId = deviceConstraint;
21267
21830
  deviceHasChanged = prevDeviceId !== deviceConstraint;
21268
21831
  const tracks = Array.from(_this3.localParticipant.videoTrackPublications.values()).filter(track => track.source === Track.Source.Camera);
@@ -21281,16 +21844,16 @@ class Room extends eventsExports.EventEmitter {
21281
21844
  }
21282
21845
  if (_this3.options.webAudioMix) {
21283
21846
  // setting `default` for web audio output doesn't work, so we need to normalize the id before
21284
- deviceId = (_a = yield DeviceManager.getInstance().normalizeDeviceId('audiooutput', deviceId)) !== null && _a !== void 0 ? _a : '';
21847
+ deviceId = (_c = yield DeviceManager.getInstance().normalizeDeviceId('audiooutput', deviceId)) !== null && _c !== void 0 ? _c : '';
21285
21848
  }
21286
- (_b = (_d = _this3.options).audioOutput) !== null && _b !== void 0 ? _b : _d.audioOutput = {};
21287
- const prevDeviceId = _this3.options.audioOutput.deviceId;
21849
+ (_d = (_g = _this3.options).audioOutput) !== null && _d !== void 0 ? _d : _g.audioOutput = {};
21850
+ const prevDeviceId = (_e = _this3.getActiveDevice(kind)) !== null && _e !== void 0 ? _e : _this3.options.audioOutput.deviceId;
21288
21851
  _this3.options.audioOutput.deviceId = deviceId;
21289
21852
  deviceHasChanged = prevDeviceId !== deviceConstraint;
21290
21853
  try {
21291
21854
  if (_this3.options.webAudioMix) {
21292
21855
  // @ts-expect-error setSinkId is not yet in the typescript type of AudioContext
21293
- (_c = _this3.audioContext) === null || _c === void 0 ? void 0 : _c.setSinkId(deviceId);
21856
+ (_f = _this3.audioContext) === null || _f === void 0 ? void 0 : _f.setSinkId(deviceId);
21294
21857
  }
21295
21858
  // also set audio output on all audio elements, even if webAudioMix is enabled in order to workaround echo cancellation not working on chrome with non-default output devices
21296
21859
  // see https://issues.chromium.org/issues/40252911#comment7
@@ -21311,7 +21874,7 @@ class Room extends eventsExports.EventEmitter {
21311
21874
  });
21312
21875
  }
21313
21876
  setupLocalParticipantEvents() {
21314
- this.localParticipant.on(ParticipantEvent.ParticipantMetadataChanged, this.onLocalParticipantMetadataChanged).on(ParticipantEvent.ParticipantNameChanged, this.onLocalParticipantNameChanged).on(ParticipantEvent.AttributesChanged, this.onLocalAttributesChanged).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);
21877
+ this.localParticipant.on(ParticipantEvent.ParticipantMetadataChanged, this.onLocalParticipantMetadataChanged).on(ParticipantEvent.ParticipantNameChanged, this.onLocalParticipantNameChanged).on(ParticipantEvent.AttributesChanged, this.onLocalAttributesChanged).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.ChatMessage, this.onLocalChatMessageSent).on(ParticipantEvent.ParticipantPermissionsChanged, this.onLocalParticipantPermissionsChanged);
21315
21878
  }
21316
21879
  recreateEngine() {
21317
21880
  var _a;
@@ -21405,7 +21968,7 @@ class Room extends eventsExports.EventEmitter {
21405
21968
  (_b = pub.track) === null || _b === void 0 ? void 0 : _b.stop();
21406
21969
  }
21407
21970
  });
21408
- this.localParticipant.off(ParticipantEvent.ParticipantMetadataChanged, this.onLocalParticipantMetadataChanged).off(ParticipantEvent.ParticipantNameChanged, this.onLocalParticipantNameChanged).off(ParticipantEvent.AttributesChanged, this.onLocalAttributesChanged).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);
21971
+ this.localParticipant.off(ParticipantEvent.ParticipantMetadataChanged, this.onLocalParticipantMetadataChanged).off(ParticipantEvent.ParticipantNameChanged, this.onLocalParticipantNameChanged).off(ParticipantEvent.AttributesChanged, this.onLocalAttributesChanged).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.ChatMessage, this.onLocalChatMessageSent).off(ParticipantEvent.ParticipantPermissionsChanged, this.onLocalParticipantPermissionsChanged);
21409
21972
  this.localParticipant.trackPublications.clear();
21410
21973
  this.localParticipant.videoTrackPublications.clear();
21411
21974
  this.localParticipant.audioTrackPublications.clear();
@@ -21851,7 +22414,7 @@ class Checker extends eventsExports.EventEmitter {
21851
22414
  if (this.room.state === ConnectionState.Connected) {
21852
22415
  return this.room;
21853
22416
  }
21854
- yield this.room.connect(this.url, this.token);
22417
+ yield this.room.connect(this.url, this.token, this.connectOptions);
21855
22418
  return this.room;
21856
22419
  });
21857
22420
  }
@@ -21906,127 +22469,6 @@ class Checker extends eventsExports.EventEmitter {
21906
22469
  }
21907
22470
  }
21908
22471
 
21909
- /**
21910
- * Creates a local video and audio track at the same time. When acquiring both
21911
- * audio and video tracks together, it'll display a single permission prompt to
21912
- * the user instead of two separate ones.
21913
- * @param options
21914
- */
21915
- function createLocalTracks(options) {
21916
- return __awaiter(this, void 0, void 0, function* () {
21917
- var _a, _b;
21918
- // set default options to true
21919
- options !== null && options !== void 0 ? options : options = {};
21920
- (_a = options.audio) !== null && _a !== void 0 ? _a : options.audio = true;
21921
- (_b = options.video) !== null && _b !== void 0 ? _b : options.video = true;
21922
- const opts = mergeDefaultOptions(options, audioDefaults, videoDefaults);
21923
- const constraints = constraintsForOptions(opts);
21924
- // Keep a reference to the promise on DeviceManager and await it in getLocalDevices()
21925
- // works around iOS Safari Bug https://bugs.webkit.org/show_bug.cgi?id=179363
21926
- const mediaPromise = navigator.mediaDevices.getUserMedia(constraints);
21927
- if (options.audio) {
21928
- DeviceManager.userMediaPromiseMap.set('audioinput', mediaPromise);
21929
- mediaPromise.catch(() => DeviceManager.userMediaPromiseMap.delete('audioinput'));
21930
- }
21931
- if (options.video) {
21932
- DeviceManager.userMediaPromiseMap.set('videoinput', mediaPromise);
21933
- mediaPromise.catch(() => DeviceManager.userMediaPromiseMap.delete('videoinput'));
21934
- }
21935
- const stream = yield mediaPromise;
21936
- return Promise.all(stream.getTracks().map(mediaStreamTrack => __awaiter(this, void 0, void 0, function* () {
21937
- const isAudio = mediaStreamTrack.kind === 'audio';
21938
- let trackOptions = isAudio ? options.audio : options.video;
21939
- if (typeof trackOptions === 'boolean' || !trackOptions) {
21940
- trackOptions = {};
21941
- }
21942
- let trackConstraints;
21943
- const conOrBool = isAudio ? constraints.audio : constraints.video;
21944
- if (typeof conOrBool !== 'boolean') {
21945
- trackConstraints = conOrBool;
21946
- }
21947
- // update the constraints with the device id the user gave permissions to in the permission prompt
21948
- // otherwise each track restart (e.g. mute - unmute) will try to initialize the device again -> causing additional permission prompts
21949
- if (trackConstraints) {
21950
- trackConstraints.deviceId = mediaStreamTrack.getSettings().deviceId;
21951
- } else {
21952
- trackConstraints = {
21953
- deviceId: mediaStreamTrack.getSettings().deviceId
21954
- };
21955
- }
21956
- const track = mediaTrackToLocalTrack(mediaStreamTrack, trackConstraints);
21957
- if (track.kind === Track.Kind.Video) {
21958
- track.source = Track.Source.Camera;
21959
- } else if (track.kind === Track.Kind.Audio) {
21960
- track.source = Track.Source.Microphone;
21961
- }
21962
- track.mediaStream = stream;
21963
- if (trackOptions.processor) {
21964
- if (track instanceof LocalAudioTrack) {
21965
- yield track.setProcessor(trackOptions.processor);
21966
- } else if (track instanceof LocalVideoTrack) {
21967
- yield track.setProcessor(trackOptions.processor);
21968
- }
21969
- }
21970
- return track;
21971
- })));
21972
- });
21973
- }
21974
- /**
21975
- * Creates a [[LocalVideoTrack]] with getUserMedia()
21976
- * @param options
21977
- */
21978
- function createLocalVideoTrack(options) {
21979
- return __awaiter(this, void 0, void 0, function* () {
21980
- const tracks = yield createLocalTracks({
21981
- audio: false,
21982
- video: options
21983
- });
21984
- return tracks[0];
21985
- });
21986
- }
21987
- function createLocalAudioTrack(options) {
21988
- return __awaiter(this, void 0, void 0, function* () {
21989
- const tracks = yield createLocalTracks({
21990
- audio: options,
21991
- video: false
21992
- });
21993
- return tracks[0];
21994
- });
21995
- }
21996
- /**
21997
- * Creates a screen capture tracks with getDisplayMedia().
21998
- * A LocalVideoTrack is always created and returned.
21999
- * If { audio: true }, and the browser supports audio capture, a LocalAudioTrack is also created.
22000
- */
22001
- function createLocalScreenTracks(options) {
22002
- return __awaiter(this, void 0, void 0, function* () {
22003
- if (options === undefined) {
22004
- options = {};
22005
- }
22006
- if (options.resolution === undefined && !isSafari17()) {
22007
- options.resolution = ScreenSharePresets.h1080fps30.resolution;
22008
- }
22009
- if (navigator.mediaDevices.getDisplayMedia === undefined) {
22010
- throw new DeviceUnsupportedError('getDisplayMedia not supported');
22011
- }
22012
- const constraints = screenCaptureToDisplayMediaStreamOptions(options);
22013
- const stream = yield navigator.mediaDevices.getDisplayMedia(constraints);
22014
- const tracks = stream.getVideoTracks();
22015
- if (tracks.length === 0) {
22016
- throw new TrackInvalidError('no video track found');
22017
- }
22018
- const screenVideo = new LocalVideoTrack(tracks[0], undefined, false);
22019
- screenVideo.source = Track.Source.ScreenShare;
22020
- const localTracks = [screenVideo];
22021
- if (stream.getAudioTracks().length > 0) {
22022
- const screenAudio = new LocalAudioTrack(stream.getAudioTracks()[0], undefined, false);
22023
- screenAudio.source = Track.Source.ScreenShareAudio;
22024
- localTracks.push(screenAudio);
22025
- }
22026
- return localTracks;
22027
- });
22028
- }
22029
-
22030
22472
  class PublishAudioCheck extends Checker {
22031
22473
  get description() {
22032
22474
  return 'Can publish audio';
@@ -22435,5 +22877,5 @@ function isFacingModeValue(item) {
22435
22877
  return item === undefined || allowedValues.includes(item);
22436
22878
  }
22437
22879
 
22438
- export { AudioPresets, BaseKeyProvider, CheckStatus, Checker, ConnectionCheck, ConnectionError, ConnectionQuality, ConnectionState, CriticalTimers, CryptorError, CryptorErrorReason, CryptorEvent, DataPacket_Kind, DefaultReconnectPolicy, DeviceUnsupportedError, DisconnectReason, EncryptionEvent, EngineEvent, ExternalE2EEKeyProvider, KeyHandlerEvent, KeyProviderEvent, LivekitError, LocalAudioTrack, LocalParticipant, LocalTrack, LocalTrackPublication, LocalVideoTrack, LogLevel, LoggerNames, MediaDeviceFailure, Mutex, NegotiationError, Participant, ParticipantEvent, ParticipantInfo_Kind as ParticipantKind, PublishDataError, RemoteAudioTrack, RemoteParticipant, RemoteTrack, RemoteTrackPublication, RemoteVideoTrack, Room, RoomEvent, ScreenSharePresets, SignalRequestError, SubscriptionError, Track, TrackEvent, TrackInvalidError, TrackPublication, UnexpectedConnectionState, UnsupportedServer, VideoPreset, VideoPresets, VideoPresets43, VideoQuality, attachToElement, createAudioAnalyser, createE2EEKey, createKeyMaterialFromBuffer, createKeyMaterialFromString, createLocalAudioTrack, createLocalScreenTracks, createLocalTracks, createLocalVideoTrack, deriveKeys, detachTrack, facingModeFromDeviceLabel, facingModeFromLocalTrack, getBrowser, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, getLogger, importKey, isBackupCodec, isBrowserSupported, isE2EESupported, isInsertableStreamSupported, isScriptTransformSupported, isVideoFrame, needsRbspUnescaping, parseRbsp, protocolVersion, ratchet, setLogExtension, setLogLevel, supportsAV1, supportsAdaptiveStream, supportsDynacast, supportsVP9, version, videoCodecs, writeRbsp };
22880
+ export { AudioPresets, BaseKeyProvider, CheckStatus, Checker, ConnectionCheck, ConnectionError, ConnectionQuality, ConnectionState, CriticalTimers, CryptorError, CryptorErrorReason, CryptorEvent, DataPacket_Kind, DefaultReconnectPolicy, DeviceUnsupportedError, DisconnectReason, EncryptionEvent, EngineEvent, ExternalE2EEKeyProvider, KeyHandlerEvent, KeyProviderEvent, LivekitError, LocalAudioTrack, LocalParticipant, LocalTrack, LocalTrackPublication, LocalVideoTrack, LogLevel, LoggerNames, MediaDeviceFailure, Mutex, NegotiationError, Participant, ParticipantEvent, ParticipantInfo_Kind as ParticipantKind, PublishDataError, RemoteAudioTrack, RemoteParticipant, RemoteTrack, RemoteTrackPublication, RemoteVideoTrack, Room, RoomEvent, ScreenSharePresets, SignalRequestError, SubscriptionError, Track, TrackEvent, TrackInvalidError, TrackPublication, UnexpectedConnectionState, UnsupportedServer, VideoPreset, VideoPresets, VideoPresets43, VideoQuality, attachToElement, createAudioAnalyser, createE2EEKey, createKeyMaterialFromBuffer, createKeyMaterialFromString, createLocalAudioTrack, createLocalScreenTracks, createLocalTracks, createLocalVideoTrack, deriveKeys, detachTrack, extractProcessorsFromOptions, facingModeFromDeviceLabel, facingModeFromLocalTrack, getBrowser, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, getLogger, importKey, isBackupCodec, isBrowserSupported, isE2EESupported, isInsertableStreamSupported, isScriptTransformSupported, isVideoFrame, needsRbspUnescaping, parseRbsp, protocolVersion, ratchet, setLogExtension, setLogLevel, supportsAV1, supportsAdaptiveStream, supportsDynacast, supportsVP9, version, videoCodecs, writeRbsp };
22439
22881
  //# sourceMappingURL=livekit-client.esm.mjs.map