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.
- package/dist/livekit-client.esm.mjs +157 -111
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +1 -1
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +2 -0
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/Participant.d.ts +1 -0
- package/dist/src/room/participant/Participant.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/ts4.2/src/room/Room.d.ts +1 -1
- package/dist/ts4.2/src/room/events.d.ts +2 -0
- package/dist/ts4.2/src/room/participant/Participant.d.ts +1 -0
- package/package.json +4 -4
- package/src/room/PCTransport.ts +6 -4
- package/src/room/RTCEngine.ts +7 -7
- package/src/room/Room.ts +4 -2
- package/src/room/events.ts +4 -0
- package/src/room/participant/LocalParticipant.ts +3 -12
- package/src/room/participant/Participant.ts +1 -0
- package/src/room/track/Track.ts +6 -1
@@ -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
|
-
|
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(
|
1897
|
+
arr.push(read(reader, scalarType));
|
1864
1898
|
}
|
1865
1899
|
} else {
|
1866
|
-
arr.push(
|
1900
|
+
arr.push(read(reader, scalarType));
|
1867
1901
|
}
|
1868
1902
|
} else {
|
1869
|
-
target[localName] =
|
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
|
-
|
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
|
-
|
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 = (
|
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.
|
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
|
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
|
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
|
-
|
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();
|