livekit-client 1.14.2 → 1.14.4
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/livekit-client.esm.mjs +169 -115
- 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/participant/publishUtils.d.ts.map +1 -1
- package/dist/src/room/track/RemoteAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +10 -4
- package/dist/src/room/track/options.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/dist/ts4.2/src/room/track/options.d.ts +10 -4
- 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 +7 -12
- package/src/room/participant/Participant.ts +1 -0
- package/src/room/participant/publishUtils.ts +6 -1
- package/src/room/track/RemoteAudioTrack.ts +7 -3
- package/src/room/track/Track.ts +6 -1
- package/src/room/track/options.ts +8 -2
@@ -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.4";
|
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');
|
@@ -17906,7 +17963,8 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
|
|
17906
17963
|
}
|
17907
17964
|
function computeTrackBackupEncodings(track, videoCodec, opts) {
|
17908
17965
|
var _a, _b, _c, _d;
|
17909
|
-
|
17966
|
+
// backupCodec should not be true anymore, default codec is set in LocalParticipant.publish
|
17967
|
+
if (!opts.backupCodec || opts.backupCodec === true || opts.backupCodec.codec === opts.videoCodec) {
|
17910
17968
|
// backup codec publishing is disabled
|
17911
17969
|
return;
|
17912
17970
|
}
|
@@ -18774,9 +18832,6 @@ class RemoteAudioTrack extends RemoteTrack {
|
|
18774
18832
|
} else {
|
18775
18833
|
super.attach(element);
|
18776
18834
|
}
|
18777
|
-
if (this.elementVolume) {
|
18778
|
-
element.volume = this.elementVolume;
|
18779
|
-
}
|
18780
18835
|
if (this.sinkId && supportsSetSinkId(element)) {
|
18781
18836
|
/* @ts-ignore */
|
18782
18837
|
element.setSinkId(this.sinkId);
|
@@ -18787,6 +18842,10 @@ class RemoteAudioTrack extends RemoteTrack {
|
|
18787
18842
|
element.volume = 0;
|
18788
18843
|
element.muted = true;
|
18789
18844
|
}
|
18845
|
+
if (this.elementVolume) {
|
18846
|
+
// make sure volume setting is being applied to the newly attached element
|
18847
|
+
this.setVolume(this.elementVolume);
|
18848
|
+
}
|
18790
18849
|
return element;
|
18791
18850
|
}
|
18792
18851
|
detach(element) {
|
@@ -20485,6 +20544,7 @@ class LocalParticipant extends Participant {
|
|
20485
20544
|
}
|
20486
20545
|
if (constraints.audio) {
|
20487
20546
|
this.microphoneError = undefined;
|
20547
|
+
this.emit(ParticipantEvent.AudioStreamAcquired);
|
20488
20548
|
}
|
20489
20549
|
if (constraints.video) {
|
20490
20550
|
this.cameraError = undefined;
|
@@ -20531,6 +20591,7 @@ class LocalParticipant extends Participant {
|
|
20531
20591
|
screenVideo.source = Track.Source.ScreenShare;
|
20532
20592
|
const localTracks = [screenVideo];
|
20533
20593
|
if (stream.getAudioTracks().length > 0) {
|
20594
|
+
this.emit(ParticipantEvent.AudioStreamAcquired);
|
20534
20595
|
const screenAudio = new LocalAudioTrack(stream.getAudioTracks()[0], undefined, false, this.audioContext);
|
20535
20596
|
screenAudio.source = Track.Source.ScreenShareAudio;
|
20536
20597
|
localTracks.push(screenAudio);
|
@@ -20645,18 +20706,7 @@ class LocalParticipant extends Participant {
|
|
20645
20706
|
return __awaiter(this, void 0, void 0, function* () {
|
20646
20707
|
const existingTrackOfSource = Array.from(this.tracks.values()).find(publishedTrack => track instanceof LocalTrack && publishedTrack.source === track.source);
|
20647
20708
|
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
|
-
}
|
20709
|
+
livekitLogger.info("publishing a second track with the same source: ".concat(track.source));
|
20660
20710
|
}
|
20661
20711
|
if (opts.stopMicTrackOnMute && track instanceof LocalAudioTrack) {
|
20662
20712
|
track.stopOnMute = true;
|
@@ -20735,7 +20785,13 @@ class LocalParticipant extends Participant {
|
|
20735
20785
|
cid: track.mediaStreamTrack.id
|
20736
20786
|
})];
|
20737
20787
|
// set up backup
|
20788
|
+
if (opts.backupCodec === true) {
|
20789
|
+
opts.backupCodec = {
|
20790
|
+
codec: defaultVideoCodec
|
20791
|
+
};
|
20792
|
+
}
|
20738
20793
|
if (opts.backupCodec && videoCodec !== opts.backupCodec.codec) {
|
20794
|
+
// multi-codec simulcast requires dynacast
|
20739
20795
|
if (!this.roomOptions.dynacast) {
|
20740
20796
|
this.roomOptions.dynacast = true;
|
20741
20797
|
}
|
@@ -21415,6 +21471,70 @@ class Room extends eventsExports.EventEmitter {
|
|
21415
21471
|
this.onPageLeave = () => __awaiter(this, void 0, void 0, function* () {
|
21416
21472
|
yield this.disconnect();
|
21417
21473
|
});
|
21474
|
+
/**
|
21475
|
+
* Browsers have different policies regarding audio playback. Most requiring
|
21476
|
+
* some form of user interaction (click/tap/etc).
|
21477
|
+
* In those cases, audio will be silent until a click/tap triggering one of the following
|
21478
|
+
* - `startAudio`
|
21479
|
+
* - `getUserMedia`
|
21480
|
+
*/
|
21481
|
+
this.startAudio = () => __awaiter(this, void 0, void 0, function* () {
|
21482
|
+
const elements = [];
|
21483
|
+
const browser = getBrowser();
|
21484
|
+
if (browser && browser.os === 'iOS') {
|
21485
|
+
/**
|
21486
|
+
* iOS blocks audio element playback if
|
21487
|
+
* - user is not publishing audio themselves and
|
21488
|
+
* - no other audio source is playing
|
21489
|
+
*
|
21490
|
+
* as a workaround, we create an audio element with an empty track, so that
|
21491
|
+
* silent audio is always playing
|
21492
|
+
*/
|
21493
|
+
const audioId = 'livekit-dummy-audio-el';
|
21494
|
+
let dummyAudioEl = document.getElementById(audioId);
|
21495
|
+
if (!dummyAudioEl) {
|
21496
|
+
dummyAudioEl = document.createElement('audio');
|
21497
|
+
dummyAudioEl.id = audioId;
|
21498
|
+
dummyAudioEl.autoplay = true;
|
21499
|
+
dummyAudioEl.hidden = true;
|
21500
|
+
const track = getEmptyAudioStreamTrack();
|
21501
|
+
track.enabled = true;
|
21502
|
+
const stream = new MediaStream([track]);
|
21503
|
+
dummyAudioEl.srcObject = stream;
|
21504
|
+
document.addEventListener('visibilitychange', () => {
|
21505
|
+
if (!dummyAudioEl) {
|
21506
|
+
return;
|
21507
|
+
}
|
21508
|
+
// set the srcObject to null on page hide in order to prevent lock screen controls to show up for it
|
21509
|
+
dummyAudioEl.srcObject = document.hidden ? null : stream;
|
21510
|
+
});
|
21511
|
+
document.body.append(dummyAudioEl);
|
21512
|
+
this.once(RoomEvent.Disconnected, () => {
|
21513
|
+
dummyAudioEl === null || dummyAudioEl === void 0 ? void 0 : dummyAudioEl.remove();
|
21514
|
+
});
|
21515
|
+
}
|
21516
|
+
elements.push(dummyAudioEl);
|
21517
|
+
}
|
21518
|
+
this.participants.forEach(p => {
|
21519
|
+
p.audioTracks.forEach(t => {
|
21520
|
+
if (t.track) {
|
21521
|
+
t.track.attachedElements.forEach(e => {
|
21522
|
+
elements.push(e);
|
21523
|
+
});
|
21524
|
+
}
|
21525
|
+
});
|
21526
|
+
});
|
21527
|
+
try {
|
21528
|
+
yield Promise.all([this.acquireAudioContext(), ...elements.map(e => {
|
21529
|
+
e.muted = false;
|
21530
|
+
return e.play();
|
21531
|
+
})]);
|
21532
|
+
this.handleAudioPlaybackStarted();
|
21533
|
+
} catch (err) {
|
21534
|
+
this.handleAudioPlaybackFailed(err);
|
21535
|
+
throw err;
|
21536
|
+
}
|
21537
|
+
});
|
21418
21538
|
this.handleRestarting = () => {
|
21419
21539
|
this.clearConnectionReconcile();
|
21420
21540
|
// also unwind existing participants & existing subscriptions
|
@@ -21970,72 +22090,6 @@ class Room extends eventsExports.EventEmitter {
|
|
21970
22090
|
}
|
21971
22091
|
});
|
21972
22092
|
}
|
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
22093
|
/**
|
22040
22094
|
* Returns true if audio playback is enabled
|
22041
22095
|
*/
|
@@ -22132,7 +22186,7 @@ class Room extends eventsExports.EventEmitter {
|
|
22132
22186
|
});
|
22133
22187
|
}
|
22134
22188
|
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);
|
22189
|
+
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
22190
|
}
|
22137
22191
|
recreateEngine() {
|
22138
22192
|
var _a;
|
@@ -22220,7 +22274,7 @@ class Room extends eventsExports.EventEmitter {
|
|
22220
22274
|
(_b = pub.track) === null || _b === void 0 ? void 0 : _b.stop();
|
22221
22275
|
}
|
22222
22276
|
});
|
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);
|
22277
|
+
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
22278
|
this.localParticipant.tracks.clear();
|
22225
22279
|
this.localParticipant.videoTracks.clear();
|
22226
22280
|
this.localParticipant.audioTracks.clear();
|